객체 지향 프로그래밍
- 객체들을 먼저 만들고, 이것들을 하나씩 조립해서 완성된 프로그램을 만드는 기법이 객체 지향 프로그램(OOP)
객체
- 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있고 다른 것과 식별 가능한 것을 말함
- 속성과 동작으로 구성되어 있음
- 속성-필드(field), 동작(method)
- 객체를 소프트웨어 객체로 설계하는 것을 객체 모델링이라고 함
객체의 상호작용
- 객체들은 각각 독립적으로 존재
다른 객체와 서로 상호작용하면서 동작 - 메소드 호출은 다음과 같은 형태
리턴값 = 전자계산기객체.메소드(매개값1, 매개값2, ...);
- 매개값은 메소드를 실행하기 위해 필요한 데이터임
int result = Calculator.add(10,20);
- 객체의 상호작용은 객체 간의 메소드 호출을 의미하며 매개값과 리턴값을 통해서 데이터를 주고 받음
객체 간의 관계
- 집합 관계, 사용 관계, 상속 관계
- 집합 관계: 하나는 부품이고 하나는 완성품에 해당
ex) 자동차는 엔진, 타이어, 핸들 등으로 구성 - 사용 관계: 객체 간의 상호작용을 말함
ex) 사람은 자동차를 사용하므로 사람과 자동차는 사용의 관계라고 볼 수 있음 - 상속 관계: 상위(부모) 객체를 기반으로 하위(자식) 객체를 생성하는 관계를 말함
상위 객체는 종류를 의미하고, 하위 객체는 구체적은 사물에 해당
객체 지향 프로그래밍의 특징
- 캡슐화: 객체의 필드, 메소드를 하나로 묶고, 실제 구현 내용을 감추는 것을 말함
- 상속: 상위 객체를 재사용해서 하위 객체를 쉽고 빨리 설계할 수 있도록 도와주고, 이미 잘 개발된 객체를 재사용해서 새로운 객체를 만들기 때문에 반복된 코드의 중복을 줄여줌
- 다형성: 같은 타입이지만 실행 결과가 다양한 객체를 이요할 수 있는 성질을 말함
부모 타입에는 모든 자식 객체가 대입될 수 있고, 인터페이스 타입에는 모든 구현 객체가 대입될 수 있음
객체는 부품화가 가능
객체와 클래스
- 설계도가 클래스(class) -p.191
객체를 생성하기 위한 필드와 메소드가 정의되어 있음
클래스로부터 만들어진 객체를 해당 클래스의 인스턴스(instance)라고 함
클래스로부터 객체를 만드는 과정이 인스턴스화
객체 지향 프로그래밍 개발 세 가지 단계
- 클래스 설계
- 설계된 클래스를 가지고 사용할 객체 생성
- 생성된 객체를 이용하는 것
클래스 선언
- 영어 대소문자를 다른 문자로 취급함
- 클래스 이름이 단일 단어라면 첫 자를 대문자로 하고 나머지는 소문자로 작성
혼합된 이름을 사용한다면 각 단어의 첫 머리 글자는 대문자로 작성하는 것이 관례 - 파일 이름과 동일한 이름의 클래스 선언에만 public 접근 제한자를 붙일 수 있음
public class Car {
}
객체 생성과 클래스 변수
- 클래스로부터 객체를 생성하는 방법은 new 연산자 사용
new 클래스();
- new는 클래스로부터 객체를 생성시키는 연산자임
- new 연산자 뒤에는 생성자가 오는데, 생성자는 클래스() 형태를 가지고 있음
- new 연산자로 생성된 객체는 메모리 힙 영역에 생성
클래스 변수 = new 클래스();
// 클래스 선언
package thisisjava.chap06.num04;
public class Student {
}
// 클래스로부터 객체 생성
package thisisjava.chap06.num04;
public class StudentExample {
public static void main(String[] args) {
Student s1 = new Student();
System.out.println("s1 변수가 Student 객체를 참조합니다");
Student s2 = new Student();
System.out.println("s2 변수가 또 다른 Student 객체를 참조합니다");
}
}
- Student 클래스는 하나지만 new 연산자를 사용한 만큼 객체가 메모리에 생성됨
이러한 객체들은 Student 클래스의 인스턴스들
같은 클래스로부터 생성되었지만 각각의 Student 객체는 자신만의 고유 데이터를 가지면서 메모리에서 활동
클래스의 두 가지 용도
- 라이브러리(AIP: Application Program Interface)용
다른 클래스에서 이용할 목적으로 설계 - 실행용
main() 메소드를 제공하는 역할을 함
- 프로그램 전체에서 사용되는 클래스가 100개라면 99개가 라이브러리이고 단 하나가 실행 클래스임
클래스의 구성 멤버
- 클래스에는 객체가 가져야 할 구성 멤버가 선언됨
- 구성 멤버에는 필드, 생성자, 메소드가 있음
- 구성 멤버들은 생략되거나 복수 개가 작성될 수 있음
public class ClassName {
//필드
int fieldName; // 객체의 데이터가 저장되는 곳
//생성자
ClassName() { ... } // 객체 생성 시 초기화 역할 담당
//메소드
void methodName() { ... } // 객체의 동작에 행당하는 실행 블록
필드
- 객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳
- 선언 형태는 변수와 비스하지만, 필드를 변수라고 부르지 않는다
변수는 생성자와 메소드 내에서만 사용되고 생성자와 메소드가 실행 종료되면 자동 소멸함 - 필드는 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체와 함께 존재
생성자
- new 연산자로 호출되는 특별한 중괄호 {} 블록임
- 객체 생성 시 초기화를 담당
필드를 초기화하거나, 메소드를 호출해서 객체를 사용할 준비를 함 - 메소드와 비슷하게 생김. 클래스 이름으로 되어 있고 리턴 타입이 ㅇ벗음
메소드
- 객체의 동작에 해당하는 중괄호 {} 블록을 말함
필드
- 객체의 고유 데이터, 객체가 가져야 할 부품, 객체의 현재 상태 데이터를 저장하는 곳
필드 선언
- 필드 선언은 클래스 중괄호 {} 블록 어디서든 존재할 수 있음
타입 필드 = 초기값;
String company = "현대자동차";
필드 사용
- 필드값을 읽고, 변경하는 작업을 말함
- 필드는 생성자와 모든 메소드에서 사용 가능
- 도트(.) 연산자는 객체 접근 연산자로 객체가 가지고 있는 필드나, 메소드를 사용하고자 할 때 사용됨
// Car 클래스 필드 선언
package thisisjava.chap06.num06;
public class Car {
//필드
String company = "현대자동차";
String model = "그랜저";
String color = "검정";
int maxSpeed = 350;
int speed;
}
// 외부 클래스에서 Car 필드값 읽기와 변경
package thisisjava.chap06.num06;
public class CarExample {
public static void main(String[] args) {
//객체 생성
Car myCar = new Car();
System.out.println("제작회사: " + myCar.company);
System.out.println("모델명: " + myCar.model);
System.out.println("색깔: " + myCar.color);
System.out.println("최고속도: " + myCar.maxSpeed);
System.out.println("현재속도: " + myCar.speed);
//필드값 변경
myCar.speed = 60;
System.out.println("수정된 속도: " + myCar.speed);
}
}
//필드 자동초기화
package thisisjava.chap06.num06;
public class FieldInitValue {
//필드
byte byteField;
short shortField;
int intField;
long longField;
boolean booleanField;
char charField;
float floatField;
double doubleField;
int[] arrField;
String referenceField;
}
//필드값 출력
package thisisjava.chap06.num06;
public class FieldInitValueExample {
public static void main(String[] args) {
FieldInitValue fiv = new FieldInitValue();
System.out.println("byteField: " + fiv.byteField);
System.out.println("shortField: " + fiv.shortField);
System.out.println("intField: " + fiv.intField);
System.out.println("longField: " + fiv.longField);
System.out.println("booleanField: " + fiv.booleanField);
System.out.println("charField: " + fiv.charField);
System.out.println("floatField: " + fiv.floatField);
System.out.println("doubleField: " + fiv.doubleField);
System.out.println("arrField: " + fiv.arrField);
System.out.println("referenceField: " + fiv.referenceField);
}
}
생성자
- new 연산자와 같이 사용되어 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화 담당
- 객체 초기화란 필드를 초기화하거나, 메소드를 호출해서 객체를 사용할 준비를 하는 것을 말함
기본 생성자
- 모든 클래스는 생성자가 반드시 존재, 하나 이상 가질 수 있음
- 우리가 클래스 내부에 생성자 선언을 생략했다면 컴파일러는 중괄호 {} 블록 내용이 비어있는 기본 생성자를 바이트 코드에 자동 추가함
[public] 클래스() { }
- 클래스가 public class로 선언되면 기본 생성자에서도 public이 붙음
생성자 선언
클래스( 매개변수선언, ... ) {
//객체의 초기화 코드
}
- 리턴 타입 없고, 클래스 이름과 동일
- 매개 변수 선언은 생략할 수도 있고, 여러 개를 선언해도 좋음
- 매개 변수는 new 연산자로 생성자를 호출할 때 외부의 값을 생성자 블록 내부로 전달하는 역할을 함
//생성자 선언
package thisisjava.chap07;
public class Car {
// 생성자
Car(String color, int cc) {
}
}
// 생성자를 호출해서 객체 생성
package thisisjava.chap07;
public class CarExample {
public static void main(String[] args) {
Car myCar = new Car("black", 3000);
// Car myCar = new Car(); // 기본 생성자를 호출할 수 없음
}
}
필드 초기화
- 필드를 선언할 때 초기값을 주는 방법
- 생성자에서 초기값을 주는 방법
//생성자에서 필드 초기화
package thisisjava.chap07;
public class Korean {
//필드
String nation = "대한민국";
String name;
String ssn;
//생성자
Korean(String n, String s) {
name = n;
ssn = s;
}
}
//객체 생성 후 필드값 출력
package thisisjava.chap07;
public class KoreanExample {
public static void main(String[] args) {
Korean k1 = new Korean("박자바", "011225-1234567");
System.out.println("k1.name: " + k1.name);
System.out.println("k1.ssn: " + k1.ssn);
Korean k2 = new Korean("김자바", "930525 - 0654321");
System.out.println("k2.name: " + k2.name);
System.out.println("k2.ssn: " + k2.ssn);
}
}
생성자 오버로딩
- 매개 변수를 달리하는 생성자를 여러 개 선안하는 것을 말함
타입, 개수, 순서가 다르게 선언 - 매개 변수의 타입과 개수 그리고 선언된 순서가 똑같을 경우 매개 변수 이름만 바꾸는 것은 생성자 오버로딩 아님
//생성자의 오버로딩
package thisisjava.chap07;
public class Car1 {
//필드
String company = "현대자동차";
String model;
String color;
int maxSpeed;
//생성자
Car1() {
}
Car1(String model) {
this.model = model;
}
Car1(String model, String color) {
this.model = model;
this.color = color;
}
Car1(String model, String color, int maxSpeed) {
this.model = model;
this.color = color;
this.maxSpeed = maxSpeed;
}
}
//객체 생성 시 생성자 선택
package thisisjava.chap07;
public class CarExample1 {
public static void main(String[] args) {
Car1 car1 = new Car1();
System.out.println("car1.company: " + car1.company);
System.out.println();
Car1 car2 = new Car1("자가용");
System.out.println("car2.company: " + car2.company);
System.out.println("car2.model: " + car2.model);
System.out.println();
Car1 car3 = new Car1("자가용", "빨강");
System.out.println("car3.company: " + car3.company);
System.out.println("car3.model: " + car3.model);
System.out.println("car3.color: " + car3.color);
System.out.println();
Car1 car4 = new Car1("택시", "검정", 200);
System.out.println("car4.company: " + car4.company);
System.out.println("car4.model: " + car4.model);
System.out.println("car4.color: " + car4.color);
System.out.println("car4.maxSpeed: " + car4.maxSpeed);
}
}
다른 생성자 호출(this())
- 생성자 오버로딩이 많아질 경우 생성자 간의 중복된 코드가 발생할 수 있음
- 필드 초기화 내용은 한 생성자에만 집중적으로 작성하고
나머지 생성자는 초기화 내용을 가지고 있는 생성자를 호출하는 방법으로 개선할 수 있음
클래스( [ 매개변수선언, ... ] ) {
this( 매개변수, ..., 값, ...);
실행문;
}
- this()는 자신의 다른 생성자를 호출하는 코드로 반드시 생성자의 첫줄에서만 허용됨
- this()의 매개값은 호출되는 생성자의 매개 변수 타입에 맞게 제공해야 함
// 다른 생성자를 호출해서 중복 코드 줄이기
package thisisjava.chap07.thisCar;
public class Car {
//필드
String company = "현대자동차";
String model;
String color;
int maxSpeed;
//생성자
Car() {
}
Car(String model) {
this(model, "은색", 250);
}
Car(String model, String color) {
this(model, color, 250);
}
Car(String model, String color, int maxSpeed) {
this.model = model;
this.color = color;
this.maxSpeed = maxSpeed;
}
}
// 객체 생성 시 생성자 선택
package thisisjava.chap07.thisCar;
public class CarExample {
public static void main(String[] args) {
Car car1 = new Car();
System.out.println("car1.company: " + car1.company);
System.out.println();
Car car2 = new Car("자가용");
System.out.println("car2.company" + car2.company);
System.out.println("car2.model" + car2.model);
System.out.println();
Car car3 = new Car("자가용", "빨강");
System.out.println("car3.company: " + car3.company);
System.out.println("car3.model: " + car3.model);
System.out.println("car3.color: " + car3.color);
System.out.println();
Car car4 = new Car("택시", "검정", 200);
System.out.println("car4.company: " + car4.company);
System.out.println("car4.model: " + car4.model);
System.out.println("car4.color: " + car4.color);
System.out.println("car4.maxSpeed: " + car4.maxSpeed);
}
}
메소드
- 객체의 동작에 해당하는 중괄호 {} 블록을 말함
중괄호 블록은 이름을 가지고 있는데, 이것이 메소드 이름 - 메소드를 호출하게 되면 중괄호 블록에 있는 몯느 코드들이 일괄적으로 실행됨
메소드 선언
- 선언부(리턴타입, 메소드이름, 매개변수선언)와 실행 블록으로 구성
메소드 선언부를 메소드 시그니처라고도 함
리턴타입 메소드이름 ([매개변수선언, ...]) {
실행할 코드를 작성하는 곳
}
리턴 타입
- 메소드가 실행 후 리턴하는 값의 타입을 말함
- 메소드는 리턴값이 있을 수도 있고 없을 수도 있음
- 리턴값이 없는 메소드는 리턴 타입에 void가 와야 함
- 리턴값이 있는 메소드는 리턴값의 타입이 와야 함
메소드 이름
- 메소드명은 소문자로 작성
- 서로 다른 단어가 혼한된 이름이라면 뒤이어 오는 단어의 첫머리 글자는 대문자로 작성
매개 변수 선언
- 메소드가 실행할 때 필요한 데이터를 외부로부터 받기 위해 사용
//메소드 선언
package thisisjava.chap06.num08;
public class Calculator {
//메소드
void powerOn() { // return값 없어
System.out.println("전원을 켭니다");
}
int plus(int x, int y) {
int result = x + y;
return result;
}
double divide(int x, int y) {
double result = (double) x / (double) y;
return result;
}
void powerOff() {
System.out.println("전원을 끕니다");
}
}
//메소드 호출
package thisisjava.chap06.num08;
public class CalculatorExample {
public static void main(String[] args) {
Calculator myCalc = new Calculator();
myCalc.powerOn();
int result1 = myCalc.plus(5, 6);
System.out.println("result1: " + result1);
byte x = 10;
byte y = 4;
double result2 = myCalc.divide(x, y);
System.out.println("result2: " + result2);
myCalc.powerOff();
}
}
매개 변수의 수를 모를 경우 -p.219
- 메소드의 매개 변수는 개수가 이미 정해져 있는 것이 일반적이지만
경우에 따라서는 메소드를 선언할 때 매개 변수의 개수를 알 수 없는 경우 있음 - 해결책: 매개 변수를 배열 타입으로 선언
int sum1(int[] values) { }
- 배열을 생성하지 않고 값의 리스트만 넘겨주는 방법도 있음
- ...로 선언된 매개 변수는 배열 타입
int sum2(int ... values) { }
// 매개 변수의 수를 모를 경우
package thisisjava.chap06.num08;
public class Computer {
int sum1(int[] values) {
int sum = 0;
for (int i = 0; i < values.length; i++) {
sum += values[i];
}
return sum;
}
int sum2(int... values) {
int sum = 0;
for (int i = 0; i < values.length; i++) {
sum += values[i];
}
return sum;
}
}
// 매개 변수의 수를 모를 경우
package thisisjava.chap06.num08;
public class ComputerExample {
public static void main(String[] args) {
Computer myCom = new Computer();
int[] values1 = {1, 2, 3};
int result1 = myCom.sum1(values1);
System.out.println("result1: " + result1);
int result2 = myCom.sum1(new int[]{1, 2, 3, 4, 5});
System.out.println("result2: " + result2);
int result3 = myCom.sum2(1, 2, 3);
System.out.println("result3: " + result3);
int result4 = myCom.sum2(1, 2, 3, 4, 5);
System.out.println("result4: " + result4);
}
}
리턴(return)문
- 리턴 타입이 있는 메소드는 반드시 리턴문을 사용해서 리턴값을 지정해야 함
return문이 없다면 컴파일 오류 발생 - return문이 실행되면 메소드는 즉시 종료
return 리턴값;
- return문을 사용할 때 주의할 점은 return문 이후에 실행문이 오면 "Unreachable code"라는 컴파일 오류가 발생
return문 이후의 실행문은 결코 실행되지 않기 때문
int plus(int x, int y) {
int result = x + y;
return result;
System.out.println(result); // Unreachable code
}
> return문 이후는 실행 ㄴㄴ
리턴값이 없는 메소드(void)
- void로 선언된 리턴값이 없는 메소드에서도 return문을 사용할 수 있음
- return문을 사용하면 메소드 실행을 강제 종료시킴
return;
//return문
package thisisjava.chap06.num08;
public class Car {
//필드
int gas;
//생성자
//메소드
void setGas(int gas) {
this.gas = gas;
}
boolean isLeftGas() {
if (gas == 0) {
System.out.println("gas가 없습니다");
return false;
}
System.out.println("gas가 있습니다");
return true;
}
void run() {
while (true) {
if (gas > 0) {
System.out.println("달립니다. (gas잔량:" + gas + ")");
gas -= 1;
} else {
System.out.println("멈춥니다. (gas잔량:" + gas + ")");
return;
}
}
}
}
// return문
package thisisjava.chap06.num08;
public class CarExample {
public static void main(String[] args) {
Car myCar = new Car();
myCar.setGas(5);
boolean gasState = myCar.isLeftGas();
if (gasState) {
System.out.println("출발합니다");
myCar.run();
}
if (myCar.isLeftGas()) {
System.out.println("gas를 주입할 필요가 없습니다");
} else {
System.out.println("gas를 주입하세요");
}
}
}
메소드 호출
- 클래스 내·외부의 호출에 의해 실행됨
객체 내부에서 호출
메소드 ( 매개값, ... );
// 클래스 내부에서 메소드 호출
package thisisjava.chap06.num08.inCal;
public class Calculator {
int plus(int x, int y) {
int result = x + y;
return result;
}
double avg(int x, int y) {
double sum = plus(x, y);
double result = sum / 2;
return result;
}
void execute() {
double result = avg(7, 10);
println("실행결과: " + result);
}
void println(String message) {
System.out.println(message);
}
}
// Calculator의 execute() 실행
package thisisjava.chap06.num08.inCal;
public class CalculatorExample {
public static void main(String[] args) {
Calculator myCalc = new Calculator();
myCalc.execute();
}
}
객체 외부에서 호출
클래스 참조변수 = new 클래스(매개값, ...);
참조변수.메소드(매개값, ...); // 리턴값이 없거나, 있어도 리턴값을 받지 않을 경우
타입 변수 = 참조변수.메소드(매개값, ...); //리턴값이 있고, 리턴값을 받고 싶을 경우
// 클래스 외부에서 메소드 호출
package thisisjava.chap06.num08.inCar;
public class Car {
//필드
int speed;
//생성자
//메소드
int getSpeed() {
return speed;
}
void keyTurnOn() {
System.out.println("키를 돌립니다");
}
void run() {
for (int i = 10; i <= 50; i += 10) {
speed = i;
System.out.println("달립니다.(시속" + speed + "km/h)");
}
}
}
// 클래스 외부에서 메소드 호출
package thisisjava.chap06.num08.inCar;
public class CarExample {
public static void main(String[] args) {
Car myCar = new Car();
myCar.keyTurnOn();
myCar.run();
int speed = myCar.getSpeed();
System.out.println("현재 속도: " + speed + "km/h");
}
}
메소드 오버로딩
- 클래스 내에 같은 이름의 메소드를 여러 개 선언하는 것을 메소드 오버로딩이라고 함
- 하나의 메소드 이름으로 여러 기능을 담는다 하여 붙여진 이름
- 매개 변수의 타입, 개수, 순서 중 하나가 달라야 함
- 메소드 오버로딩이 필요한 이유는 매개값을 다양하게 받아 처리할 수 있도록 하기 위해서
//메소드 오버로딩
package thisisjava.chap06.num08.inCal2;
public class Calculator {
//정사각형의 넓이
double areaRectangle(double width) {
return width * width;
}
//직사각형의 넓이
double areaRectangle(double width, double height) {
return width * height;
}
}
// 메소드 오버로딩
package thisisjava.chap06.num08.inCal2;
public class CalculatorExample {
public static void main(String[] args) {
Calculator myCalc = new Calculator();
//정사각형의 넓이 구하기
double result1 = myCalc.areaRectangle(10);
//직사각형의 넓이 구하기
double resutl2 = myCalc.areaRectangle(10, 20);
//결과 출력
System.out.println("정사각형 넓이=" + result1);
System.out.println("직사각형 넓이=" + resutl2);
}
}
'이것이 자바다' 공부 기록
300x250
'Language > JAVA' 카테고리의 다른 글
[JAVA] 6 데이터와 연산 Number String (new line, escape) (0) | 2022.01.29 |
---|---|
[JAVA] 1~5 생활코딩 자바 입문 수업 시작! Hello World!! (0) | 2022.01.28 |
[JAVA] 참조 타입 // String 배열 열거 (0) | 2021.09.16 |
[JAVA] 반복문 // for문 while문 do-while문 break문 continue문 (0) | 2021.09.15 |
[JAVA] 조건문 // if문 switch문 (0) | 2021.09.14 |