상위클래스를 상속받아서 하위클래스를 정의하는 방법
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 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
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); // 추가되는 실행 코드
}
}
[상속 사용하지 않는 경우 예시]
package com.lec.java.inherit01;
public class Inherit01Main {
public static void main(String[] args) {
System.out.println("상속(Inheritance) 을 사용하지 않는 경우");
// BasicTV의 인스턴스
BasicTV tv1 = new BasicTV();
tv1.isPowerOn = true;
tv1.volume = 10;
tv1.displayInfo();
// SmartTV의 인스턴스
SmartTV tv2 = new SmartTV();
tv2.isPowerOn = true;
tv2.channel = 123;
tv2.volume = 12;
tv2.ip = "192.168.0.111";
tv2.displayInfo();
System.out.println("\n프로그램 종료");
} // end main()
} // end class
package com.lec.java.inherit01;
// 클래스: 멤버변수 (+ 생성자) + 메소드 => 데이터 타입
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()
} // end class BasicTV
package com.lec.java.inherit01;
public class SmartTV {
// 멤버변수
// 기존의 BasicTV 에 만들었던 멤버들이 그대로 또 작성?
boolean isPowerOn;
int channel;
int volume;
String ip; // <-- SmartTV 에서 새로이 추가된 필드
// 메소드
public void displayInfo() {
System.out.println("--- TV 현재 상태 ---");
System.out.println("전원: " + isPowerOn);
System.out.println("채널: " + channel);
System.out.println("볼륨: " + volume);
System.out.println("IP주소: " + ip); // <- SmartTV 에 추가된 코드
} // end displayInfo()
}
- 자바의 모든 클래스는 java.lang.Object로부터 상속 받는다.
- java.lang.Object 클래스는 모든 클래스의 부모클래스이다.
- Object 클래스에 있는 메소드를 다른 클래스에서도 사용 가능
package com.lec.java.inherit03;
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
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 + " 입니다");
}
}
- 자식 클래스의 생성자에서 명시적으로 부모 클래스의 생성자가 호출되지 않으면, 자동으로 부모 클래스의 "디폴트 생성자"가 호출됨
- 자식 클래스의 생성자에서 명시적으로 부모 클래스의 생성자를 호출하기도 함
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 (X)
Car is-a Vehicle (OK)
HybricCar is-a Car (OK)
package com.lec.java.inherit04;
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
package com.lec.java.inherit04;
public class Vehicle {
int speed;
// 생성자
public Vehicle() {
System.out.println("Vehicle() 생성");
}
public Vehicle(int speed) { // -> 위의 기본생성자 주석처리시 에러 발생. (Implicit super constructor Vehicle() is undefined. Must explicitly invoke another constructor
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는 반.드.시 첫번째 문장이어야 한다. 첫번째줄 아닐시 ERROR (Constructor call must the first statement in a constructor)
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() 생성");
}
}
메소드 재정의(Overriding)
- '상속'관계에서 '부모 클래스에 있던 메소드'를 '재정의'하는 것.
- 부모 클래스에 있는 메소드와 매개변수 리스트가 동일해야 함
- 부모 클래스에 있는 메소드와 접근권한 수식어가 동일할 필요는 없지만, 접근권한의 범위가 축소될 수는 없다.
- 즉, 접근권한은 같거나 더 넓은 수식어를 사용해야 함.
! 메소드 오버로딩(Overloading)과 혼돈하지 말자!
final 메소드 : 더이상 오버라이딩 불가
final 클래스 : 더이상 상속 불가
package com.lec.java.inherit07;
public class Inherit07Main {
public static void main(String[] args) {
System.out.println("상속: Method Overriding(재정의)");
System.out.println();
// Person 클래스의 인스턴스 생성
Person p1 = new Person();
p1.setName("abc");
p1.showInfo();
System.out.println();
// BusinessPerson 클래스의 인스턴스를 생성
BusinessPerson p2 = new BusinessPerson();
p2.setName("홍길동");
p2.setCompany("활빈당");
p2.showInfo();
// toString() 결과 (java의 객체를 문자열로 표현)
System.out.println("p1: " + p1);
System.out.println("p2: " + p2);
System.out.println("\n프로그램 종료");
} // end main()
} // end class
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() { // ERROR: cannot reduce the visibility of the inherited method from Person (접근범위가 더 좁아질 수는 없다)
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() { // ERROR : Cannot override the final method from Person.
//
// }
}
package com.lec.java.inherit07;
//final 이 변수 앞에 붙으면 더이상 변경 불가(상수화)
//final 이 클래스 앞에 붙으면 더이상 상속 불가
//final 이 메소드 앞에 붙으면 더이상 오버라이딩 불가
public final class PostPerson extends Person {
}
package com.lec.java.inherit07;
public class PostBoy /*extends PostPerson*/ {
}
✨TIPs!
1. Open Type Hierarchy (F4) : 클래스명 위 마우스
2. Open Declaration (F3) : 해당하는 클래스로 이동 (선언한 파일 보여줌)