객체지향프로그래밍에서는 클래스를 통해 객체를 생성하고, 그 객체들이 상호작용하며 프로그램의 기능을 수행한다.
인간, 침팬지, 고릴라가 영장류에 속해 있는 것처럼 현실세계에 존재하는 개념들은 상위, 하위 개념으로 나뉜다. 또는 자동차를 구성하는 부품 중 엔진이 있는 것 처럼 한 개념이 다른 개념의 부분일 수도 있다. 이처럼 프로그램의 클래스도 다양한 관계를 맺고 있다.
클래스의 멤버 변수로 또 다른 클래스를 정의한 관계다. 즉, 객체의 속성으로 다른 객체를 갖는다.
다음은 Car
클래스의 멤버변수로 Engine
클래스를 정의한 예제이다.
public class Car {
String maker;
String type;
// Engine객체를 멤버변수로 갖는다.
Engine engine;
}
public class Engine {
String fuelType;
int maxRpm;
double maxTorque;
}
Engine
객체를 생성한 후, Car
객체의 멤버변수에 대입했다.
public class CarApp {
public static void main(String[] args) {
Engine engine = new Engine();
engine.fuelType = "gasoline";
engine.maxRpm = 6000;
engine.maxTorque = 54.8;
Car car = new Car();
car.engine = engine;
car.maker = "BMW";
car.type = "sedan";
}
}
위와 같이 Car
객체의 멤버변수에 직접 대입하는 방법 외에도 생성자나 set()
메소드를 통해 간접적으로 대입하는 방법이 있다. 이를 의존성주입(Dependency Injection) 이라고 한다. 객체지향 5원칙 중 하나인데, 이는 추후에 보다 자세히 다루도록 하겠다. 아래 예제를 통해 이해해보자.
public class Car {
String maker;
String type;
// Engine객체를 멤버변수로 갖는다.
Engine engine;
public Car() {}
// engine객체를 매개변수로 전달받는 생성자
public Car(Engine engine) {
this.engine = engine;
}
// engine객체를 매개변수로 전달받는 메소드
public void setEngine(Engine engine) {
this.engine = engine;
}
}
public class CarApp {
public static void main(String[] args) {
Engine engine1 = new Engine();
engine1.fuelType = "gasoline";
engine1.maxRpm = 6000;
engine1.maxTorque = 54.8;
// 생성자를 통한 engine1객체 대입
Car car1 = new Car(engine1);
car1.maker = "BMW";
car1.type = "sedan";
Engine engine2 = new Engine();
engine2.fuelType = "diesel";
engine2.maxRpm = 5000;
engine2.maxTorque = 60.2;
// setter메소드를 통한 engine2객체 대입
Car car2 = new Car();
car2.setEngine(engine2);
car2.maker = "Benz";
car2.type = "SUV";
}
}
클래스를 상위 클래스와 하위 클래스로 나누어 상위 클래스의 필드와 메소드를 하위 클래스가 말 그대로 '상속'받는 관계이다. 하위 클래스는 상속받은 필드와 메소드를 상위 클래스와 같이 완전히 동일하게 이용할 수 있다. 이때 하위 클래스만의 고유한 필드와 메소드롤 추가로 정의할 수 있다. extends
키워드를 사용해 상속 관계를 정의한다. 상속에 대해서는 다음 포스팅에서 보다 자세히 다루도록 한다.
다음은 Phone
클래스를 정의하고 그 속성과 기능을 SmartPhone
클래스가 상속받은 예제이다.
public class Phone {
String number;
public void tel() {
System.out.println("[" + this.number + "]의 전화 기능 실행");
}
public void sms() {
System.out.println("[" + this.number + "]의 문자 기능 실행");
}
}
// Phone클래스로부터 상속받은 클래스다.
public class SmartPhone extends Phone {
// 상속받은 필드 외에 별로도 정의한 필드다.
String email;
String ip;
// 상속받은 필드 외에 별로도 정의한 메소드다.
public void sendEmail() {
System.out.println("["+email+"] 이메일을 보내기 기능을 실행합니다.");
}
public void internet() {
System.out.println("["+ip+"] 인터넷 기능을 실행합니다.");
}
}
public class PhoneApp {
public static void main(String[] args) {
// 멤버변수 number는 SmartPhone에서 정의하지 않았지만
// Phone으로부터 상속받았기 때문에 사용 가능하다.
SmartPhone smartPhone = new SmartPhone();
smartPhone.number = "010-2222-4444";
smartPhone.email = "aa@gmail.com";
smartPhone.ip = "125.177.000.00";
// tel()과 sms()메소드는 SmartPhone에서 정의하지 않았지만
// Phone으로부터 상속받았기 때문에 사용 가능하다.
smartPhone.tel();
smartPhone.sms();
smartPhone.sendEmail();
smartPhone.internet();
}
}
출력
[010-2222-4444]의 전화 기능 실행
[010-2222-4444]의 문자 기능 실행
[aa@gmail.com] 이메일을 보내기 기능을 실행합니다.
[125.177.000.00] 인터넷 기능을 실행합니다.