추상클래스
메소드 오버라이드 강제화
public void test6() {
Animal[] animals = new Animal[5];
for(int i=0;i<animals.length;i++) {
animals[i]=animalGenerator();
}
for(int i=0;i<animals.length;i++) {
animals[i].say();
}
}
다음과 같은 test6메소드에서, Animal에서 say()메소드를 만들고
Tiger class와 Lion class에서 각각 오버라이드 하여
안녕하세요, 라이언입니다.
안녕하세요, 타이거입니다.
안녕하세요, 라이언입니다.
안녕하세요, 라이언입니다.
안녕하세요, 타이거입니다.
와 같은 결과물을 냈다.
하지만 여기서 까먹고 라이언을 오버라이드 하지 않았다면?
안녕하세요, 동물입니다.
안녕하세요, 타이거입니다.
안녕하세요, 동물입니다.
안녕하세요, 동물입니다.
안녕하세요, 타이거입니다.
다음과 같이 나오게 된다.
이러한 사고발생을 막기 위해 메소드 오버라이드 강제화가 존재한다.
방법은 1.부모 추상메소드에서 구현을 강제화할 메소드를 2.추상 메소드로 작성하는 것이다.
public class Animal{
public void say(){
System.out.println("안녕하세요, 동물입니다.");
}
public void attack(){
}
}
원래 위와 같았던 Animal 코드를 메소드 오버라이드 강제화 해보자.
public abstract class Animal {
public abstract void say();
public abstract void attack();
}
1. 부모추상메소드에서 작성해야하므로 public class -> public abstract class로 변경하고
2. say(), attack()를 추상메소드로 변경하기위해 abstract로 바꾼다.
그러면 Lion에서 오버라이드를 하지 않을 경우 Lion에서 오류가 발생하면서 컴파일이 제대로 되지 않는다.
추상클래스 & 인터페이스
|
추상클래스
|
인터페이스
|
공통점
|
추상 메소드를 통해 자식클래스의 메소드 구현을 강제화 한다.
객체화 할 수 없다. new Animal() x -> 자식클래스를 객체화해서 사용 |
|
차이점
|
추상클래스는 일반클래스 성격을 가지고 있다.
field와 method를 가지고, 자식클래스에 물려줄 수 있다. |
인터페이스는 일반 field와 method를 가질 수 없다.
Java 1.8부터 default/static 메소드를 사용할 수는 있다. |
특징
|
[추상클래스]
- 0개이상의 추상메소드를 가질 수 있다. (추상메소드가 0개인 경우 객체화를 막기위한 목적이라고 보면 됨) - 자식클래스는 반드시 부모의 추상메소드를 구현해야 한다. [추상메소드] - abstract 키워드 - 몸통부가 없음. 몸통부는 자식클래스에서 구현해야하므로 부모클래스에서 작성하지 X - 동적바인딩용 메소드로 사용, 자식클래스의 규격이 된다. |
- 추상메소드만 가질 수 있다.(public abstract 키워드 생략)
- 상수필드만 가질 수 있다. (public static final 키워드 생략) - 자식클래스에서는 <자식클래스 implements 인터페이스> 로 작성한다. - 자식클래스에서는 두개이상의 인터페이스를 구현할 수 있다. - 인터페이스가 인터페이스를 구현하는 경우, implements 키워드 대신 extends를 사용한다. |
특징이 엄청나게 많다. 먼저 인터페이스를 통해서 부모가 Animal이고 implement로 Barkable을 가지는 Dog 클래스를 만든다.
public class Dog extends Animal implements Barkable {
@Override
public void bark(String sound) {
System.out.println("도그가 "+sound+"하며 짖습니다.");
System.out.println(MAX_SOUND_LEVEL+"데시벨을 넘었습니다.");
}
@Override
public void attack() {
System.out.println("도그표 물어뜯기!");
}
@Override
public void say() {
System.out.println("안녕하세요, 개입니다.");
}
}
Barkable은 다음과 같이 작성한다.
public interface Barkable {
// public static final 생략된 것
int MAX_SOUND_LEVEL=100;
// public abstract 생략된것
void bark(String sound);
}
이를 통해 인터페이스의 특징을 알 수 있다.
main에서 실행하면, 다음과 같이 강제화하여 쓸 수 있다.
public void test7() {
Barkable tiger = new Tiger();
Barkable lion = new Lion();
Barkable dog = new Dog();
Barkable[] barkMembers = new Barkable[3];
barkMembers[0]=tiger;
barkMembers[1]=lion;
barkMembers[2]=dog;
for(Barkable b: barkMembers)
b.bark("야옹");
}
위에서 Barkable과 Animal은 따로인 것을 알 수 있다. 즉
Tiger 객체를 기준으로 볼때, Animal과 Barkable은 아예 따로이다.
즉 , Animal객체에서는 bark() 메소드를 사용할 수 없고, Barkable의 객체에서는 say()와 attack()을 사용할 수 없는 것이다.
하지만 Tiger일때는 다 사용이 가능하다.
public void test8() {
Tiger tiger=new Tiger();
Animal animal = tiger;
Barkable barkMember=tiger;
}
하지만 추상클래스와 인터페이스 클래스 모두 직접 객체화 할 수 없고, 다형성이 적용되어 test8과 같이 사용이 가능하다.
마지막으로 인터페이스의 default와 static 메소드 사용하는 것도 알아보자.
public interface Barkable {
// public static final 생략된 것
int MAX_SOUND_LEVEL=100;
// public abstract 생략된것
void bark(String sound);
//구현클래스에 물려줄수 있는 default 메소드
public default void foo() {
System.out.println("옛다~ 가져가 쓰거라");
}
//구현 클래스 생성 없이 호출해 쓸 수 있는 static메소드
public static void bar() {
System.out.println("baaaaaaar!!!!!");
}
}
Barkable을 다음과 같이 수정하면, default메소드와 static 메소드가 한개씩 생성된다.
public void test10() {
Barkable barkMember =new Dog();
barkMember.foo();//default 메소드를 물려줌
Barkable.bar();//static메소드
}
실제로 실행하는 메인 클래스에서 다음과 같이 사용하면 인터페이스에서도 static 및 default 메소드는 사용이 가능함을 알 수 있다.