부모가 자식에게 물려주는 행위
로 중복 코드를 줄여 개발 시간을 단축시키고, 클래스 수정을 최소화할 수 있다.package ch07.sec02;
public class Phone {
public String model;
public String color;
public Phone() {
System.out.println("부모 생성자 호출");
}
public void bell() {
System.out.println("[부모] 벨이 울린다.");
}
public void hangup() {
System.out.println("[부모] 전화를 끊습니다.");
}
public void sendVoice(String message) {
System.out.println("[부모] " + message);
}
}
package ch07.sec02;
public class SmartPhone extends Phone{
public boolean wifi;
public SmartPhone(String model, String color) {
this.model = model;
this.color = color;
}
public void setWifi(boolean wifi) {
this.wifi = wifi;
System.out.println("[자식] 와이파이 상태를 변경했습니다.");
}
}
package ch07.sec02;
public class SmartPhoneEx {
public static void main(String[] args) {
SmartPhone smartPhone = new SmartPhone("Galaxy", "Gary"); // 부모 생성자 호출
System.out.println(smartPhone.model); // Galaxy
System.out.println(smartPhone.color); // Gary
System.out.println(smartPhone.wifi); // false
smartPhone.bell(); // [부모] 벨이 울린다.
smartPhone.sendVoice("Hi~"); // [부모] Hi~
smartPhone.hangup(); // [부모] 전화를 끊습니다.
smartPhone.setWifi(true); // [자식] 와이파이 상태를 변경했습니다.
}
}
super()
가 추가된다.super(매개값, …)
를 추가해줘야 한다.package ch07.sec02;
public class Phone {
public String model;
public String color;
// public Phone() {
// System.out.println("부모 생성자 호출");
// }
public Phone(String model, String color) {
this.model = model;
this.color = color;
System.out.println("[부모] Phone(String model, String color) 생성자 호출");
}
// 코드 생략…
}
public SmartPhone(String model, String color) {
super(model, color);
this.model = model;
this.color = color;
}
상속
된 메서드를 자식 클래스에서 재정의
하는 것을 말한다.(public → private로 변경 불가)
@Override
애노테이션을 붙이면 컴파일 단계에서 정확히 오버라이딩 되었는지 체크하고, 문제가 있다면 커파일 에러를 출력한다.package ch07.sec02;
public class SmartPhone extends Phone{
public boolean wifi;
public SmartPhone(String model, String color) {
super(model, color);
this.model = model;
this.color = color;
}
public void setWifi(boolean wifi) {
this.wifi = wifi;
System.out.println("[자식] 와이파이 상태를 변경했습니다.");
}
@Override
public void bell() {
super.bell();
System.out.println("[자식] 벨이 울린다.");
}
}
package ch07.sec02;
public class SmartPhoneEx {
public static void main(String[] args) {
SmartPhone smartPhone = new SmartPhone("Galaxy", "Gary"); // [부모] Phone(String model, String color) 생성자 호출
smartPhone.bell(); // [자식] 벨이 울린다.
}
}
super
키워드와 도트.
연산자를 사용해 부모 클래스를 호출할 수 있다.package ch07.sec02;
public class SmartPhone extends Phone{
// 코드 생략…
@Override
public void bell() {
super.bell();
System.out.println("[자식] 벨이 울린다.");
}
}
package ch07.sec02;
public class SmartPhoneEx {
public static void main(String[] args) {
SmartPhone smartPhone = new SmartPhone("Galaxy", "Gary"); // [부모] Phone(String model, String color) 생성자 호출
smartPhone.bell(); // [부모] 벨이 울린다. // [자식]벨이 울린다.
}
}
더 이상 상속할 수 없다.
즉, 부모 클래스가 될 수 없다.package ch07.sec05.exam02;
public final class Car {
}
package ch07.sec05.exam02;
public class SportsCar extends Car{ // 컴파일 에러 : Cannot inherit from final 'ch07.sec05.exam02.Car'
}
오버라이딩할 수 없다.
package ch07.sec05.exam02;
public class Car {
public int speed;
public void SpeedUp() {
speed += 1;
}
public final void stop() {
System.out.println("차가 멈춥니다.");
speed = 0;
}
}
package ch07.sec05.exam02;
public class SportsCar extends Car{
@Override
public void SpeedUp() {
speed += 10;
}
public final void stop() { // 컴파일 에러 : 'stop()' cannot override 'stop()' in 'ch07.sec05.exam02.Car'; overridden method is final
System.out.println("차가 멈춥니다.");
speed = 0;
}
}
접근 제한자 | 제한 범위 |
---|---|
public | 없음 |
protected | 같은 패키지이거나 자식 객체만 사용 가능 |
default | 같은 패키지 |
private | 객체 내부 |
package ch07.sec06.package1;
public class A {
protected String field;
protected A() {}
protected void method() {
System.out.println("A 클래스입니다.");
}
}
package ch07.sec06.package1;
public class B {
public static void main(String[] args) {
A a = new A();
a.method(); // A 클래스입니다.
}
}
package ch07.sec06.package2;
import ch07.sec06.package1.A;
public class C extends A {
public C() {
super(); // 생략 가능
}
public void method1() {
this.method();
}
}
package ch07.sec06.package2;
public class D {
public static void main(String[] args) {
C c = new C();
c.method1(); // A 클래스입니다.
}
}
상속 관계
에 있는 클래스 사이에서 발생한다.package ch07.sec07.exam01;
public class Parent {
public Parent() {}
public void method01() {
System.out.println("Parent - method01()");
}
public void method02() {
System.out.println("Parent - method02()");
}
}
package ch07.sec07.exam01;
public class Child extends Parent {
public Child() {}
@Override
public void method01() {
System.out.println("@Override : Child - method01()");
}
public void method03() {
System.out.println("Child - method03()");
}
}
package ch07.sec07.exam01;
public class Ex01 {
public static void main(String[] args) {
Parent parent = new Child(); // 자동 타입 변환
parent.method01(); // @Override : Child - method01()
// parent.method03(); // 컴파일 에러 : Cannot resolve method 'method03' in 'Parent'
Child child = new Child();
Parent parent1 = child;
System.out.println(parent1 == child); // true
}
}
자식 → 부모
타입 변환 후 다시 부모 → 자식
으로 변환할 때만 사용할 수 있다.package ch07.sec07.exam01;
public class Ex01 {
public static void main(String[] args) {
// Child child = (Child) new Parent(); // 런타임 에러 : ClassCastException Exception
Parent parent = new Child();
Child child = (Child) parent;
child.method03(); // Child - method03()
}
}
package ch07.sec08.exam;
public class Chef {
public Menu menu;
public void cook() {
menu.make();
}
public void order(Menu menu) {
menu.prepare();
}
}
package ch07.sec08.exam;
public class Menu {
public void make() {
System.out.println("요리하다");
}
public void prepare() {
System.out.println("메뉴를 준비하다");
}
}
package ch07.sec08.exam;
public class KoreanFood extends Menu {
@Override
public void make() {
System.out.println("한식을 요리하다");
}
@Override
public void prepare() {
System.out.println("한식을 준비하다");
}
}
package ch07.sec08.exam;
package ch07.sec08.exam;
public class WesternFood extends Menu {
@Override
public void make() {
System.out.println("양식을 요리하다");
}
@Override
public void prepare() {
System.out.println("양식을 준비하다");
}
}
package ch07.sec08.exam;
public class Ex {
public static void main(String[] args) {
Chef chef = new Chef();
chef.menu = new Menu();
chef.cook(); // 요리하다
chef.menu = new KoreanFood();
chef.cook(); // 한식을 요리하다
chef.menu = new WesternFood();
chef.cook(); // 양식을 요리하다
}
}
어떤 객체가(e.g. Menu, KoreanFood, WesternFood) 대입됐는지에 따라 cook()의 실행 결과가 달라지게 된다.
package ch07.sec08.exam;
public class Ex {
public static void main(String[] args) {
Chef chef = new Chef();
Menu menu = new Menu();
chef.order(menu); // 메뉴를 준비하다
KoreanFood koreanFood = new KoreanFood();
chef.order(koreanFood); // 한식을 준비하다
WesternFood westernFood = new WesternFood();
chef.order(westernFood); // 양식을 준비하다
}
}
어떤 객체가(e.g. Menu, KoreanFood, WesternFood) 대입됐는지에 따라 order()의 실행 결과가 달라지게 된다.
instanceof
연산자 사용package ch07.sec08.exam;
public class Ex {
public static void menuInfo(Menu menu) {
if (menu instanceof KoreanFood food) {
KoreanFood koreanFood = (KoreanFood) menu;
koreanFood.prepare();
// food.prepare(); // java 12부터
} else if (menu instanceof WesternFood food) {
WesternFood westernFood = (WesternFood) menu;
westernFood.prepare();
// food.prepare(); // java 12부터
}
}
public static void main(String[] args) {
Menu koreanMenu = new KoreanFood();
Menu westernMenu = new WesternFood();
System.out.println(koreanMenu instanceof KoreanFood); // true
System.out.println(westernMenu instanceof WesternFood); // true
System.out.println(koreanMenu instanceof WesternFood); // false
System.out.println(westernMenu instanceof KoreanFood); // false
menuInfo(koreanMenu); // 한식을 준비하다
menuInfo(westernMenu); // 양식을 준비하다
}
}
공통적인 필드나 메서드를 추출
해서 선언한 클래스로 new 연산자를 사용해 객체를 직접 생성할 수 없다.클래스의 부모 역할만
을 한다.abstract 키워드
를 붙이면 추상 클래스가 된다.package ch07.sec10.exam01;
public abstract class Phone {
// 필드 선언
String owner;
// 생성자 선언
public Phone(String owner) {
this.owner = owner;
}
//메서드 선언
void turnOn() {
System.out.println("전원 ON");
}
void turnOff() {
System.out.println("전원 OPF");
}
public abstract void sound();
}
package ch07.sec10.exam01;
public class SmartPhone extends Phone{
public SmartPhone(String owner) {
super(owner);
}
void internetSearch() {
System.out.println("인터넷 검색을 하다.");
}
@Override
public void sound() {
System.out.println("삐리리리~");
}
}
package ch07.sec10.exam01;
public class PhoneEx {
public static void main(String[] args) {
// Phone phone = new Phone(); // 컴파일 에러 : 'Phone' is abstract; cannot be instantiated
SmartPhone smartPhone = new SmartPhone("홍길동");
smartPhone.turnOn(); // 전원 ON
smartPhone.turnOff(); // 전원 OPF
smartPhone.internetSearch(); // 인터넷 검색을 하다.
smartPhone.sound(); // 삐리리리~
}
}
{}
가 없다.sealed
키워드를 사용하면 permits
키워드 뒤에 상속 가능한 자식 클래스를 지정해야 한다.package ch07.sec10.exam02;
public sealed class Person permits Employee, Manager, Owner{
public void work() {
System.out.println("하는 일이 결정되지 않았습니다.");
}
}
package ch07.sec10.exam02;
public final class Employee extends Person {
@Override
public void work() {
System.out.println("제품을 생산합니다.");
}
}
package ch07.sec10.exam02;
public non-sealed class Manager extends Person {
@Override
public void work() {
System.out.println("생산을 관리합니다.");
}
}
package ch07.sec10.exam02;
public class SalesManager extends Manager{
@Override
public void work() {
System.out.println("영업을 관리합니다.");
}
}
package ch07.sec10.exam02;
public sealed class Owner extends Person permits Company { // sealed, non-sealed or final modifiers expected
@Override
public void work() {
System.out.println("회사를 운영합니다.");
}
}
package ch07.sec10.exam02;
public final class Company extends Owner {
String name;
public Company(String name) {
this.name = name;
}
public void operate() {
System.out.println(this.name + " 회사가 운영 중입니다.");
}
}
package ch07.sec10.exam02;
public class SealedEx {
public static void main(String[] args) {
Person person = new Person();
person.work(); // 하는 일이 결정되지 않았습니다.
Employee employee = new Employee();
employee.work(); // 제품을 생산합니다.
Manager manager = new Manager();
manager.work(); // 생산을 관리합니다.
SalesManager salesManager = new SalesManager();
salesManager.work(); // 영업을 관리합니다.
Owner owner = new Owner();
owner.work(); // 회사를 운영합니다.
Company company = new Company("화장품");
company.operate(); // 화장품 회사가 운영 중입니다.
}
}