[JAVA] 상속, 업캐스팅, 오버라이딩, super, 추상클래스, 인터페이스
1. 상속
- 다중상속 지원 X.
[슈퍼클래스]
= 부모 클래스
class SuperClass {...} // 슈퍼클래스
[서브 클래스]
= 자식 클래스. extends를 사용
class SubClass extends SuperClass {...} // SuperClass를 상속받는 자식클래스
[서브 클래스 객체 생성]
- 서브클래스의 객체 생성하면 이 객체는 슈퍼 클래스의 멤버와 서브 클래스의 멤버를 모두 가지게 됨.
- 단, 자식클래스는 부모클래스의 private 속성에는 접근 불가
SubClass sub = new SubClass(); // 서브 클래스 객체 생성
[슈퍼클래스 접근지정]
서브클래스에서 접근 가능한 속성: public / protected / 같은 패키지 내의 디폴트 속성
[생성자]
- 서브클래스 객체 생성 시, 슈퍼클래스 생성자 → 서브클래스 생성자 순으로 실행됨. (두 생성자 모두 실행됨)
- 슈퍼클래스의 생성자는 기본적으로 기본생성자가 선택됨. (서브클래스의 생성자에 매개변수가 있더라도)
[super( )]
슈퍼클래스 생성자 명시적 선택.
* 반드시 생성자의 첫 라인에 사용되어야 함.
2. 업캐스팅, 다운캐스팅
[업캐스팅]
- 서브클래스 타입을 슈퍼클래스 타입으로 변환. (슈퍼클래스의 레퍼런스가 서브 클래스 객체를 가리키도록 치환되는 것.)
- parents은 슈퍼클래스의 멤버에만 접근 가능. child는 슈퍼클래스+서브클래스 멤버 모두 접근 가능.
- 서브클래스 관리 용이하게 하기 위해 사용. ( https://whitehairhan.tistory.com/224 참조 )
Parents parents; // 슈퍼클래스
Child child = new Child(); // 서브클래스
parents = child; // ex1. 업캐스팅
parents = (Parents)child; // ex2. 업캐스팅
Parents parents = new Child(); // ex3. 업캐스팅
[다운캐스팅]
- 슈퍼클래스 타입을 서브클래스 타입으로 변환. 업캐스팅의 반대
- 명시적 타입변환
Child child = (Child)parents; // 다운캐스팅
[instanceof 연산자]
- 레퍼런스가 가리키는 객체가 해당 클래스 타입이면 true, 아니면 false 반환.
- 레퍼런스가 가리키는 객체의 클래스 타입 구분을 위해 사용
class Parents { }
class Child extends Parents { }
class GrandChild extends Child { }
Parents parents1 = new Child(); // 업캐스팅
Parents parents2 = new GrandChild(); // 업캐스팅
if(parents1 instanceof Parents) // true
if(parents1 instanceof Child) // true
if(parents2 instanceof Child) // true. GrandChild는 Child타입이기도 하므로.
3. 메소드 오버라이딩
- 슈퍼클래스의 메소드를 무시하고 서브클래스에서 오버라이딩된 메소드가 실행되도록 함
- 슈퍼클래스의 메소드와 동일형태로 작성하기.(매개변수타입, 이름 등 변경 X)
- 슈퍼클래스 메소드의 접근지정자보다 범위 좁힐 수 X
- static / private / final 메소드는 오버라이딩 X
- @override 주석문 사용해 오버라이딩이 정확한지 컴파일러에게 확인하도록 지시
[오버라이딩 메소드 호출]
class Parents {
public void name() { System.out.println("parent"); }
}
class Child {
@override // 오버라이딩 주석문. 오버라이딩이 정확한지 컴파일러가 확인
public void name() { System.out.println("child"); }
}
Child child = new Child();
child.name(); // "child" (Child클래스의 name()호출)
업캐스팅 시, 오버라이딩된 메소드(자식클래스의 메소드) 호출. 동적바인딩.
Parents parents = new Child(); // 업캐스팅
parents.name(); // "child" (Child클래스의 name()호출)
[동적바인딩]
- 실행할 메소드를 실행시에 결정(run-time).
- 오버라이딩된 메소드가 항상 실행되도록 보장.
class Parents {
public void run() { name(); }
public void name() { System.out.println("parents"); }
}
class Child {
public void name() { System.out.println("child"); }
}
Parents parents = new Child();
parents.name(); // 동적바인딩 -> Child의 name()이 호출됨
[super 키워드]
슈퍼클래스의 멤버에 접근
super.name(); // Parents의 name() 호출됨
4. 추상클래스
- 선언만 되어있고 코드 구현 안된 코드. 원형만 작성. 설계와 구현 분리.
- abstract 키워드 이용
- 추상클래스는 객체 생성 X
- 구현은 서브클래스에서
추상 메소드를 가지고 있으면 무조건 추상 클래스로 선언해야 함. (추상메소드 없어도 추상클래스로 선언해도 됨)
abstract class Parents { // 추상 클래스 선언
public void run() { name(); }
abstract public void name(); // 추상 메소드 선언
}
추상클래스를 상속'만' 받는 자식클래스에도 추상클래스임을 명시해야 함. (메소드 오버라이딩하지 않을경우)
abstract class Child extends Parents { }
5. 인터페이스
- 인터페이스는 객체 생성 X
- 멤버변수(필드) 생성 X
- 인터페이스끼리 상속 O
- 인터페이스 상속받아 클래스 작성 시, 인터페이스의 모든 추상 메소드 구현해야 함.
- 상수, 추상메소드(public abstract), default 메소드, private 메소드, static 메소드 로 구성
[인터페이스 선언]
interface Phone { // 인터페이스 선언
public abstract void sendCall(); // 추상메소드. public abstract 생략가능
}
[인터페이스 구현]
- 인터페이스의 모든 추상 메소드를 구현한 클래스 작성하는 것.
- implements 키워드 사용
class Samsung implements Phone { // 인터페이스 구현
@Override
public void sendCall() {
System.out.println("따르릉");
}
}
Samsung samsung = new Samsung();
samsung.sendCall();
[인터페이스 상속]
- 다중상속 허용
interface Mobile extends Phone, MP3interface { }
* 추상클래스 : 서브클래스에서 사용할 대부분의 기능을 구현해두고, 몇 개만 추상메소드 선언해 서브클래스에서 구현하도록 하는 목적.
* 인터페이스 : 인터페이스를 상속받는 클래스의 목적에 따라 인터페이스의 모든 추상 메소드를 만들도록 함. 인터페이스는 스펙을 주고 클래스들이 그 기능을 서로 다르게 구현할 수 있도록 함.
명품 JAVA Programming 참고