[JAVA] 상속
상속 (Inheritance)
상위클래스를 상속받아서 하위클래스를 정의하는 방법
class 하위클래스 extends 상위클래스
자바 에선 오로지 '하나의 부모'로부터 상속받을수 있습니다 (단일 상속) 다중 상속 허용하지 않음
(용어)
Super Class(상위 클래스), Parent Class(부모/조상 클래스), Basic Class(기본 클래스)
Sub Class(하위 클래스), Child Class(자식 클래스), Derived Class(유도 클래스)
※ 상속받는다..(동사) inherit , subclass
sub class에서는 super class가 가지고 있는 멤버 변수들은 선언하지 않아도 사용할 수 있다.
super class에 없는 멤버 변수만 선언해 주면 됨
상속의 이점 :
상속을 통하여 기존의 객체를 그대로 활용하면서, 새로운 객체에서
추가, 변경되는 부분만 작성함으로 소프트웨어 개발 효율을 높일수 있다.
package com.lec.java.inherit02;
public class BasicTV {
// 멤버 변수
boolean isPowerOn;
int channel;
int volume;
// 메소드
public void displayInfo() {
System.out.println("--- TV 현재 상태 ---");
System.out.println("전원: " + isPowerOn);
System.out.println("채널: " + channel);
System.out.println("볼륨: " + volume);
} // end displayInfo()
} // class BasicTV
package com.lec.java.inherit02;
// BasicTV
// └─ SmartTV
public class SmartTV extends BasicTV{
// 새로이 추가할 멤버
String ip;
public void displayInfo() {
super.displayInfo(); // 부모(super) 의 displayInfo() 를 먼저 실행하고
System.out.println("IP 주소: " + ip); // 추가되는 실행 코드
}
}
public class Inherit02Main {
public static void main(String[] args) {
System.out.println("상속 (Inheritance)");
// BasicTV 클래스의 인스턴스 생성
BasicTV tv1 = new BasicTV();
tv1.displayInfo();
System.out.println();
// SmartTV 클래스의 인스턴스 생성
SmartTV tv2 = new SmartTV();
tv2.isPowerOn = true;
tv2.channel = 100;
tv2.volume = 10;
tv2.ip = "192.168.0.110";
tv2.displayInfo();
System.out.println("\n프로그램 종료");
} // end main()
} // end class
* 자바의 모든 클래스는 java.lang.Object로부터 상속 받는다.
* java.lang.Object 클래스는 모든 클래스의 부모클래스이다.
* Object 클래스에 있는 메소드를 다른 클래스에서도 사용 가능
package com.lec.java.inherit03;
public class Person {
String name;
public void whoAmI() {
System.out.println("제 이름은 " + name + " 입니다.");
}
}
package com.lec.java.inherit03;
public class BusinessPerson extends Person {
String company;
public void showInfo() {
whoAmI();
System.out.println("회사는 " + company + " 입니다");
}
}
public class Inherit03Main {
public static void main(String[] args) {
System.out.println("상속 연습");
System.out.println("java.lang.Object");
Person p1 = new Person();
p1.name = "홍길동";
p1.whoAmI();
System.out.println();
BusinessPerson p2 = new BusinessPerson();
p2.name = "허균";
p2.whoAmI();
// toString() 은 Object의 메소드
System.out.println(p2);
System.out.println(p2.toString());
p2.company = "(주)재택";
p2.showInfo();
System.out.println("\n프로그램 종료");
} // end main()
} // end class
상속에서 생성자 호출순서
1. 자식 클래스의 생성자에서 명시적으로 부모 클래스의 생성자가 호출되지 않으면,
자동으로 부모 클래스의 "디폴트 생성자"가 호출됨.
2. 자식 클래스의 생성자에서 명시적으로 부모 클래스의 생성자를 호출하기도 함
1) super(...) 키워드 사용 -> 부모 클래스의 생성자를 호출
2) (주의) super는 항상 제일 처음에 호출되어야 함
3) 부모 클래스에 디폴트 생성자가 없는 경우도 있을 수 있다.
그런 경우에는 다른 생성자를 "반드시 명시적으로 호출"해 줘야만 함.
어떤 경우에 상속으로 객체를 설계하나?
HAS-A 관계 ===> 멤버로 설계
Car, Tire
Car is-a Tire (X)
Tire is-a Car (X)
Car has-a Tire (OK)
IS-A 관계 ===> 상속으로 설계
Vehicle is-a Car (NO)
Car is-a Vehicle (OK)
HybricCar is-a Car (OK)
package com.lec.java.inherit04;
public class Vehicle {
int speed;
// 생성자
public Vehicle() {
System.out.println("Vehicle() 생성");
}
public Vehicle(int speed) {
this.speed = speed;
System.out.println("Vehicle(int) 생성: speed=" + speed);
}
}
package com.lec.java.inherit04;
public class Car extends Vehicle {
int oil;
// 생성자
public Car() {
// 부모클래스의 기본생성자 호출 --> Vehicle()
// 명시적으로 super() 가 없으면 기본적으로 부오의 기본생성자 호출
System.out.println("Car() 생성");
}
public Car(int oil) {
// 명시적으로 부모 생성자 호출
super(); // super 는 반.드.시 첫번째 문장이어야 한다.
System.out.println("Car(int) 생성: oil=" + oil);
this.oil = oil;
}
public Car(int speed, int oil) {
super(speed); // Vehicle(int) 호출
this.oil = oil;
System.out.println("Car(int,int) 생성: speed=" + speed
+ "oil=" + oil);
}
}
package com.lec.java.inherit04;
public class HybridCar extends Car {
int electricity;
// 생성자
public HybridCar() {
System.out.println("HybridCar() 생성");
}
}
public class Inherit04Main {
public static void main(String[] args) {
System.out.println("상속과 생성자");
System.out.println();
// Vehicle 클래스의 인스턴스 생성
Vehicle v1 = new Vehicle();
System.out.println();
// Car 클래스의 인스턴스 생성
Car car1 = new Car();
System.out.println();
// HybridCar 클래스의 인스턴스 생성
HybridCar car2 = new HybridCar();
System.out.println();
Car car3 = new Car(450);
System.out.println();
Car car4 = new Car(100, 6);
System.out.println("\n프로그램 종료");
} // end main()
} // end class
상속과 접근권한
private: 자기 클래스에서만 사용 가능
default: 자기 글래스 + 같은 패키지 안에서 사용 가능
protected: 자기 글래스 + 같은 패키지 + '상속 클래스'에서 사용 가능 ★
public: 어디서나 직접 사용 가능
package com.lec.java.inherit05;
//private: 자기 클래스에서만
//default: 자기 클래스 + 같은 패키지 안에서
//protected: 자기 클래스 + 같은 패키지안 + 상속 관계에 있을 때
//public: 어디서나
//직접 사용 가능
public class Test01 {
private int privateNum;
int defaultNum;
protected int protectedNum;
public int publicNum;
public void showInfo() {
System.out.println("private = " + privateNum);
System.out.println("default = " + defaultNum);
System.out.println("protected = " + protectedNum);
System.out.println("public = " + publicNum);
}
} // end class Test01
메소드 재정의(Overriding)
'상속'관계에서 부모 클래스에 있는 메소드를 자식 클래스에서
리턴 타입, 매개변수 모두 동일하게 유지하면서 메소드의 본체를 다시 정의하는 것
부모 클래스에 있는 메소드와 매개변수 리스트가 동일해야 함
부모 클래스에 있는 메소드와 접근권한 수식어가 동일할 필요는 없지만, 접근권한의 범위가 축소될 수는 없다.
즉, 접근권한은 같거나 더 넓은 수식어를 사용해야 함.
! 메소드 오버로딩(Overloading)과 혼돈하지 말자!
메소드 중복정의(Overloading)
1. 매개변수의 타입이 다르거나
2. 매개변수의 개수가 다를 때
3. 매개변수의 순서를 달리하여
같은 이름으로 (다른 기능을 하는) 메소드를 중복 정의하는 것
final 메소드 : 더이상 오버라이딩 불가
final 클래스 : 더이상 상속 불가
package com.lec.java.inherit07;
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
protected void showInfo() {
System.out.println("이름: " + name);
}
// final 메소드는 더이상 오버라이딩 불가
public final void whoAreYou() {
System.out.println("이름: " + name);
}
}
package com.lec.java.inherit07;
public class BusinessPerson extends Person {
private String company;
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
@Override
protected void showInfo() {
// public void showInfo() {
// private void showInfo() { // 에러. 접근권한범위가 더 좁아질수는 없다.
super.showInfo(); // 부모(super)의 showInfo() 호출
System.out.println("회사: " + company);
}
// 메소드 중복정의(Overloading)
// 1. 매개변수의 타입이 다르거나
// 2. 매개변수의 개수가 다를 때
// 3. 매개변수의 순서를 달리하여
// 같은 이름으로 (다른 기능을 하는) 메소드를 중복 정의하는 것
public void showInfo(int id){
System.out.println("id: " + id);
System.out.println("이름: " + getName());
System.out.println("회사: " + company);
}
// Object 의 메소드들도 오버라이딩 가능
@Override
public String toString() {
return "BusinessPerson:" + getName() + " " + getCompany();
}
// 이클립스에서
// ALT + SHIFT + S, V 를 누르면 오버라이드 진행
// ※ ALT + SHIFT + S 를 Show Source Quick Menu 라 함
// @Override
// public void whoAreYou() {
//
// }
클래스 접근권한 수식어:
1. public class: 어디서나 상속이 가능한 클래스
2. (default) class: 같은 패키지 안에서만 상속이 가능한 클래스
3. final class: 상속될 수 없는 클래스
public 클래스인 TestPublic은 다른 패키지에 있는 클래스(Test1)에서도 상속될 수 있다.
default 클래스는 다른 패키지의 클래스에서는 보이지 않는다.
다른 패키지의 클래스에서는 상속될 수 없다.