객체를 직접 새성할 수 있는 클래스를 실체 클래스라고 하면 이 클래스들의 공통적인 특성을 추출해서 선언한 클래스를 추상 클래스라고 한다.
추상 클래스와 실체 클래스는 상속의 관계를 가지고 있다. 추상 클래스가 부모이고 실체 클래스가 자식으로 구현되어 실체 클래스는 추상 클래스의 모든 특성을 물려받고, 추가적인 특성을 가질 수 있다.
이 추상 클래스의 용도는
첫째, 실체 클래스들의 공통된 필드와 메소드의 이름을 통일할 목적이다.
실체 클래스를 설계하는 사람이 여러 사람일 경우 실체 클래스 마다 필드와 메소드가 제각기 다른 이름을 가질 수 있다. 이러한 케이스를 방지하기 위해 상속할 클래스를 만들어 필드와 메소드를 통일시킬 수 있다. Phone 추상 클래스를 상속하는 Telephone과 SmartPhone은 Phone필드의 owner와 turnOn()을 상속하기에 필드와 메소드의 이름을 통일 시킬 수 있따.
둘째, 실체 클래스를 작성할 때 시간을 절약한다.
공통적인 필드와 메소드는 추상 클래스인 Phone에 모두 선언해 두고, 실체 클래스마다 다른 점만 선언하면 시간을 절약할 수 있다. 위 그림에선 Telephone클래스와 SmartPhone클래스는 owner필드와 turnOn() 메소드를 선언할 필요가 없다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
abstract class Phone2{ public String owner; public Phone2(String owner) { this.owner = owner; } public void turnOn() { System.out.println("전원 on"); } public void trunOff() { System.out.println("전원 off"); } } class SmartPhone2 extends Phone{ public SmartPhone2(String owner) { super(owner); } public void internetSearch() { System.out.println("인터넷 검색"); } } public class PhoneExample { public static void main(String[] args) { // Phone p = new Phone(); ->추상클래스라서 객체 생성 불가능 SmartPhone2 sp = new SmartPhone2("홍길동"); sp.turnOn(); sp.internetSearch(); sp.turnOff(); } } Colored by Color Scripter |
위 예제를 보면 추상클래스 Phone과 이것을 상속하는 SmartPhone이 있다. super()를 통해 부모에게 값을 보내어 초기화 시켜줄 수 있고 또한 자신만의 메소드도 가지고 있다.
이러한 방식으로 쓰는 것이 추상 클래스이다.
추가적으로 추상 메소드도 존재한다. 예를 들어 다음과 같은 상황이라 하자.
강아지와 고양이는 Animal이다. 그래서 Animal클래스를 상속한다. 근데 이 둘은 둘다 sound()를 낸다. 강아지는 멍멍, 고양이는 야옹.
즉 상속하는 객체마다 실체 작업이 다르게 되어진다. 하지만 sound()라는 이름을 통일해야 한다.
이럴때 Animal클래스의 sound()메소드를 추상 메소드로 만들어 버린다.
추상 메소드는 메소드의 선언부만 있고 메소드 실행 내용인 중괄호{}는 없는 메소드를 말한다.
추상 클래스를 설계할 때 하위 클래스가 반드시 실행 내용을 채우도록 강요하고 싶은 메소드가 있는 경우 해당 메소드를 추상 메소드로 만들면 된다.
이때 자식 클래스는 반드시 이 추상 메소드를 오버라이딩 해야 하는데 하지 않으면 에러가 발생한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
package study_myself; abstract class Animal { public String kind; public void breathe() { System.out.println("숨을 쉽니다."); } public abstract void sound(); //추상 메소드 } class Dog3 extends Animal { public Dog3() { this.kind = "포유류"; } public void sound() //추상메소드 오버라이딩(재정의) { System.out.println("멍멍"); } public void dogS() { System.out.println("멍?"); } } class Cat3 extends Animal { public Cat3() { this.kind = "포유류"; } public void sound() { System.out.println("야옹"); } } public class AnimalExample { public static void main(String[] args) { Dog3 dog = new Dog3(); Cat3 cat = new Cat3(); dog.sound(); dog.breathe(); dog.dogS(); cat.sound(); Animal animal = null; animal = new Dog3(); animal.sound(); //animal.dogS(); animal = new Cat3(); animal.sound(); } } Colored by Color Scripter |
위 소스를 보면 Animal 추상 클래스가 있다.
Animal 클래스의 sound() 메소드는 추상 메소드라서 하위 클래스에서 이 메소드를 정의하지 않으면 에러가 나온다.
그래서 Dog, Cat은 각각 sound()메소드를 오버라이딩하여 각각 멍멍, 야옹의 출력값을 두었다. 그리고 이때는 dogS()메소드가 호출이 가능하다( dog 객체에서)
또한 Animal클래스의 객체를 생성해서 하위 클래스의 값으로 선언하면 자동 타입 변환이 일어나서 마찬가지로 멍멍, 야옹의 출력값이 나오게 된다.
단 이때는 dog기준으로 dogS()메소드는 호출이 불가능하다.
왜냐하면 부모기준으로 dogS()메소드가 존재하지 않기 때문이다.
'java' 카테고리의 다른 글
자바 인터페이스 - 2 (0) | 2017.08.16 |
---|---|
자바 인터페이스 - 1 (0) | 2017.08.16 |
자바 instanceof (0) | 2017.08.16 |
자바 클래스 자동 타입 변환 및 다형성 (0) | 2017.08.16 |
자바 상속과 오버라이딩, super (0) | 2017.08.16 |