상속만으로 문제를 해결하려 하면 복잡한 상속구조를 가지게 되는 것이 부지기수.
이러한 문제를 피하기 위해 구성을 활용한다.
abstract class 오리{
public void 날기(){
System.out.println("납니다");
}
public void 헤엄치기(){
System.out.println("헤엄칩니다.");
}
}
class 청둥오리 extends 오리{
}
class 고무오리 extends 오리{
public void 날기(){
System.out.println("못 날아요");
}
public void 헤엄치기(){
System.out.println("그냥 떠요.");
}
}
위와 같은 상속 구조를 가질 때 하늘을 날면서 그냥 떠다니는 로켓오리를 추가하고 싶다고 하자.
그럼 로켓오리는 오리 추상클래스를 바로 상속받아야 할까 아니면 고무오리를 상속받아야 할까.
구성을 통해 이 딜레마를 해결할 수 있다.
abstract class 오리{
Wing wing;
Leg leg;
public void 날기(){
wing.fly();
}
public void 헤엄치기(){
leg.swim();
}
}
class 청둥오리 extends 오리{
public 청둥오리(){
wing = new RealWing();
leg = new RealLeg();
}
}
class 고무오리 extends 오리{
public 고무오리(){
wing = new FakeWing();
leg = new FakeLeg();
}
}
class 로켓오리 extends 오리{
public 로켓오리(){
wing = new RealWing();
leg = new FakeLeg();
}
}
abstract class Wing{
abstract public void fly();
}
class RealWing extends Wing{
public void fly(){
System.out.println("납니다");
}
}
class FakeWing extends Wing{
public void fly(){
System.out.println("못 날아요");
}
}
abstract class Leg{
abstract public void swim();
}
class RealLeg extends Leg{
public void swim(){
System.out.println("헤엄칩니다.");
}
}
class FakeLeg extends Leg{
public void swim(){
System.out.println("그냥 떠요");
}
}
위와 같이 하면 원하는 속성을 가지면서도 각 오리가 가지는 속성의 중복을 해결할 수 있다.
해엄칠 때의 문구를 바꾸고 싶으면 RealLeg의 swim() 메서드를 수정하면 된다.
인터페이스는 모든 메서드가 추상메서드인 클래스이다.
인터페이스는 특이하게 다중 상속이 가능하며 방법은 다음과 같다.
interface Interface1{
void method1();
}
interface Interface2{
void method2();
}
class Impl implements Interface1, Interface2 {
@Override
public void method1() {
int a = 7;
}
@Override
public void method2() {
int a = 7;
}
}
프로그램 실행 중에 예외가 발생했을 때 이를 어떻게 처리할 지 정의할 수 있다.
public class Main {
public static void main(String[] args) {
// divideByZero(1);
divide(1, 0);
}
private static void divideByZero(int a) throws ArithmeticException {
int q = a / 0;
}
private static void divide(int a, int b) {
try {
int q = a / b;
} catch (ArithmeticException e) {
System.out.println("0으로 나누지 마시오");
}
}
}
divideByZero 메서드는 뒤에 throws ArithmeticException이라는 구문이 더 붙는다. 이는 이 메서드가 해당 예외를 발생시킬 수도 있음을 divideByZero를 호출한 사람에게 알리는 것이다. 이 경우 main 함수가 이 예외를 처리하는 책임을 갖게 된다.
아래 divide 함수는 try catch 구문을 이용해서 예외를 직접 처리한다. 만약
위의 코드를 실행시킨다면 int b는 0이 될 것이고 예외가 catch구문에 걸려서
"0으로 나누지 마시오"
라는 문구가 출력될 것이다.