정의: 상위 개체의 속성이 하위 개체에 물려져서 하위 개체가 상위 개체의 속성을 모두 가지는 관계.
기존의 클래스를 재사용하여 보다 적은 양의 코드로 새 클래스를 작성할 수 있고 코드를 공통적으로 관리할 수 있어 코드의 추가, 변경에 유리하다.
자식 클래스는 부모 클래스의 모든 멤버를 상속받는다.(단, 생성자와 초기화블럭은 상속X)
자식 클래스의 멤버 개수는 부모 클래스보다 항상 많거나 같다.
슈퍼 클래스 (super class) : 부모 클래스
서브 클래스 (sub class) : 자식 클래스
키워드 : extends
class 자식클래스 extends 부모클래스 {} : 부모클래스를 자식클래스가 상속받음.
- Animal.class -
package inheritance;
public class Animal { // 부모 클래스 : 슈퍼 클래스
public void eat() {
System.out.println("동물은 먹는다...");
}
}
- Bird.class -
package inheritance;
// class 자식클래스 extends 부모클래스 {} : 부모 클래스(슈퍼 클래스)를 자식클래스(서브 클래스)가 상속받게 됨
public class Bird extends Animal { // 자식 클래스 : 부모 클래스를 상속한다
public void fly() {
System.out.println("하늘을 난다...");
}
}
- App.class -
package inheritance;
public class App {
public static void main(String[] args) {
// Animal 클래스는 메서드 eat()
Animal ani = new Animal();
ani.eat();
// Bird 클래스는 메서드 fly()
Bird bi = new Bird();
bi.eat(); // Bird 클래스에 eat메서드는 없음, 부모로부터 상속 받았기에 사용가능
bi.fly();
}
}
Bird 클래스에는 eat메서드가 없지만 Bird가 상속받은 부모클래스인 Animal에게는 eat메서드가 있으므로 Bird클래스를 호출하여 eat메서드를 사용할 수 있다.
부모 클래스에서 상속받은 같은 메서드를 덮어쓰는 개념.
모든 클래스의 부모 클래스는 오브젝트(object) 클래스이다.
오버라이딩할 때 지켜야 할 조건
1) 선언부가 부모 클래스의 메서드와 일치해야 함.
2) 접근 제어자를 부모 클래스의 메서드보다 좁읍 범위로 변경불가.
3) 예외를 부모 클래스의 메서드보다 많이 선언할 수 없다.
- Cat.class -
// 클래스명 뒤에 extends Object 가 생략된 것, 모든 클래스는 Object클래스를 부모로 둔다
public class Cat { // 고양이 메서드는 vocal메서드와 hunt 메서드
public void vocal() {
System.out.println("야옹");
}
public void hunt() {
System.out.println("사냥중~~!");
}
}
- HouseCat.class -
public class HouseCat extends Cat {
@Override // 어노테이션 오버라이드
public void vocal() { // 부모클래스인 Cat의 vocal과 같은 메소드
System.out.println("미야우~");
}
}
- RoadCat.class -
public class RoadCat extends Cat {
public void vocal() {
System.out.println("애오옹~!~");
}
}
- Tiger.class -
public class Tiger extends Cat {
@Override
public void vocal() {
System.out.println("어흥!!");
}
}
- App.class -
public class App {
public static void main(String[] args) {
// 메소드 오버라이딩 (부모클래스에서 상속받은 같은 메소드를 덮어쓰는 개념)
// : 자식클래스에서 부모와 똑같은 메소드를 만듬
// 모든 클래스의 부모클래스는 오브젝트 클래스이다
Cat cat1 = new Cat();
cat1.vocal();
HouseCat cat2 = new HouseCat();
cat2.vocal();
cat2.hunt(); // 단순히 상속받은 메소드
RoadCat cat3 = new RoadCat();
cat3.vocal();
cat3.hunt();
}
}
오버라이드 어노테이션(@Override)이 붙어있으면 메서드의 이름이 상속한 부모 클래스의 메서드와 같아야 한다. 다를 시 에러발생.
public class Cat {
public void vocal() {
System.out.println("야옹");
}
}
public class HouseCat extends Cat {
@Override // 어노테이션 오버라이드
// 메소드를 오버라이딩 했다는 표시, 이걸 써 주면 아래 오버라이딩 메서드가 부모의 메서드와 이름이 다르면 오류발생
public void vocal() { // 부모클래스인 Cat의 vocal과 같은 메소드
System.out.println("미야우~");
}
}
Cat, HouseCat, RoadCat, Tiger 클래스는 메서드 오버라이딩의 예제와 동일하여 생략.
예제의 App.class와 모든 클래스는 같은 패키지 내 위치함.
- App.class -
public class App {
public static void main(String[] args) {
// 다형성 : 자식 클래스 타입을 부모 타입으로 형 변환
// 집고양이 길고양이 호랑이 클래스는 모두고양이 클래스를 상속받았으므로 고양이 클래스로 선언가능
Cat[] cats = { new HouseCat(), new RoadCat(), new Tiger() };
// 위처럼 선언하면 아래에 선언한 것과 동일하게 배열에 대입됨
// cats[0] == new HouseCat();
// cats[1] == new RoadCat();
// cats[2] == new Tiger();
// 21번행을 출력하기 위한 코드를 for문으로 작성
for(int i = 0; i < cats.length; i++) {
cats[i].vocal();
cats[i].hunt();
}
// for each 반복문, 위의 for문과 동일함
for(Cat c : cats) {
c.vocal();
c.hunt();
}
System.out.println("아래는 형변환, 업-다운캐스팅 예제");
// 캐스팅 형변환 (기본 데이터 타입)
int a = (int)1.7345; // 실수를 정수형으로 형변환, 소수점자리의 데이터는 삭제됨
System.out.println(a);
// 참조형 타입 (배열 등) : 상속관계일때 가능
Cat cat1 = new HouseCat(); // 업 캐스팅 : 부모 타입으로 형변환 한 것
HouseCat cat2 = (HouseCat)cat1; // 다운 캐스팅 : 업 캐스팅 된 객체를 다시 다운캐스팅, 다시 자식타입으로 형변환한 것
}
}
int a = (int)1.7345; // 실수를 정수형으로 형변환, 소수점자리의 데이터는 삭제됨
System.out.println(a);
Cat cat1 = new HouseCat();
Cat cat1 = new HouseCat();
HouseCat cat2 = (HouseCat)cat1;
같은 클래스 내에서만 접근가능.
=> 같은 클래스O
같은 패키지 내에서만 접근 가능.
=> 같은 클래스O, 같은 패키지O
(default) 는 아무 접근 제어자도 붙이지 않는 경우를 의미.
같은 패키지이거나 다른 패키지의 자손 클래스에서 접근 가능.
=> 같은 클래스O, 같은 패키지O, 자손클래스O
접근 제한 없음.
=> 전부O
- entities/Fruit.class -
package entities;
public class Fruit {
protected int id; // protected : 다른 패키지에서는 사용불가, 상속한 자식클래스에서는 사용가능
@Override
public String toString() {
return "Fruit [아이디= " + id + "]";
}
}
- entities/Apple.class -
package entities;
public class Apple extends Fruit {
public Apple() {
id = 0; // Fruit에 있는 id를 Apple의 생성자에서 사용
}
}
- entities/Banana.class -
package entities;
public class Banana extends Fruit {
public Banana() {
id = 1; // Fruit에 있는 id를 Banana의 생성자에서 사용
}
}
- application/App.class -
package application;
import entities.*; // entities패키지의 모든 클래스를 import
public class App {
public static void main(String[] args) {
// protected 접근 지정자 사용 시 다른 패키지에서는 사용할 수 없고 상속받은 자식클래스에서는 사용가능
Fruit f1 = new Apple();
// f1.id = 7; // 다른 패키지에서 사용불가, Apple에서 사용한 값(Apple은 자식클래스라 사용가능)을 받아와 출력하는건 가능
System.out.println(f1.toString());
Fruit f2 = new Banana();
System.out.println(f2.toString());
}
}