부모 클래스의 필드와 메소드를 자식 클래스에게 물려줄 수 있음
재사용성이 상속의 목적임
이미 개발된 클래스를 재사용하므로 중복 코드를 줄일 수 있으며, 클래스 수정을 최소화함
상속의 구조

// 부모 클래스
class A{
}
// 자식 클래스
class B extends A{
super(); // 부모클래스를 호출하는 기능
}
// B클래스는 A클래스를 상속받음
class C extends A,B{ // X
}
//부모클래스는 반드시 하나의 부모클래스에서만 상속받음
package ch07.sec02;
public class Phone {
public String model;
public String color;
// 필드는 private로 생성하는 것이 좋음
public void bell() {
System.out.println("벨이 울립니다");
}
// bell() 기본메소드 생성
public void sendVoice(String message) {
System.out.println("자기: " + message);
}
// sendVoice() 일반메소드 생성
public void receiveVoice(String message) {
System.out.println("상대방: " + message);
}
// receiveVoice() 일반메소드 생성
public void hangUp() {
System.out.println("전화를 끊습니다");
}
// hangUp() 기본메소드 생성
}
package ch07.sec02;
public class SmartPhone extends Phone{
//Phone 객체를 상속받겠다는 의미
//첫 줄에 숨겨져있는 super()가 상속하는 역할을 함
//Phone 객체를 상속받았기 때문에 Phone에 있는 모든 메소드를 그대로 사용할 수 있음
// 필드 선언
public boolean wifi;
// 매개변수 2개 일반생성자 선언
public SmartPhone(String m, String c) {
this.model = m;
this.color = c;
// Phone으로부터 필드를 상속 받았기 때문에
// 그대로 사용 가능
}
// 메소드 선언
public void setWifi(boolean wifi) {
this.wifi = wifi;
System.out.println("와이파이 상태를 변경하였습니다");
}
public void internet() {
System.out.println("인터넷에 연결합니다.");
}
}
package ch07.sec02;
public class SmartPhoneExam {
public static void main(String[] args) {
// SmartPhone 객체 생성
SmartPhone phone = new SmartPhone("갤럭시", "은색");
// Phone으로 부터 상속받은 필드값을 읽음
// 위에 생성한 SmartPhone 객체가 Phone 객체에 상속을 받았기 때문에
// Phone 객체에 있는 필드를 SmartPhone 객체를 통해서도 사용이 가능함
System.out.println("모델: " + phone.model); // 갤럭시
System.out.println("색상: " + phone.color); // 은색
// SmartPhone 객체의 필드 읽기
System.out.println("와이파이 상태: " + phone.wifi); //false
// Phone 객체에 생성된 메소드 호출
phone.bell(); // 벨이 울립니다
phone.sendVoice("We are Landers 화이팅");
phone.receiveVoice("우리의 함성을 하나로 모아");
phone.sendVoice("달려가자 승리를 향해 나가자");
phone.receiveVoice("우리의 랜더스여 워어어");
phone.sendVoice("We are Landers 화이팅");
phone.receiveVoice("우리의 열정을 하나로 모아");
phone.sendVoice("날아올라 정상을 향해 나가자");
phone.receiveVoice("우리의 랜더스여");
phone.hangUp(); // 전화를 끊습니다
// SmartPhone 객체에 생성된 메소드 호출
phone.setWifi(true);
phone.internet();
}
}
package ch07.sec03.exam01;
public class Phone {
public String model;
public String color;
// 필드는 private로 쓰는 것이 좋음
// 인자가 없는 기본메소드 생성
public Phone() {
System.out.println("Phone 생성자 실행");
}
}
package ch07.sec03.exam01;
public class SmartPhone extends Phone{
// Phone 객체로부터 상속받음
// String 인자가 2개인 일반생성자 선언
public SmartPhone(String model, String color) {
super();
// super() : 부모 클래스를 호출하는 것을 의미
// 인자가 없는 생성자를 실행할 때에는 생략 가능
this.model = model;
this.color = color;
// Phone 객체에서 생성된 필드를 그대로 사용할 수 있음
System.out.println("SmartPhone 생성자 실행됨");
}
}
package ch07.sec03.exam01;
public class SmartPhoneExam {
public static void main(String[] args) {
// SmartPhone 객체 생성
SmartPhone phone = new SmartPhone("갤럭시", "은색");
// Phone 객체에서 생성한 필드값을 출력함
// SmartPhone 객체가 Phone 객체에 상속받았기 때문에 사용 가능
System.out.println("모델: " + phone.model); // 갤럭시
System.out.println("색상: " + phone.color); // 은색
}
}
package ch07.sec03.exam02;
public class Phone {
public String model;
public String color;
// 필드에는 private를 사용하는 것이 좋음
// 인자가 2개인 Phone 일반생성자
public Phone(String model, String color) {
this.model = model;
this.color = color;
// 매개변수를 필드에 대입
System.out.println("Phone 생성자 실행");
}
}
package ch07.sec03.exam02;
public class SmartPhone extends Phone{
//Phone 객체를 상속받음
// String 인자가 2개인 일반생성자
public SmartPhone(String model, String color) {
super(model, color);
// 부모 생성자에 인자가 있을 경우 super 생략 절대 불가
// super에 부모 생성자의 인자 수와 타입에 맞게 넣어줌
System.out.println("SmartPhone 생성자 실행");
}
}
package ch07.sec03.exam02;
public class SmartPhoneExam {
public static void main(String[] args) {
// TODO Auto-generated method stub
SmartPhone phone = new SmartPhone("갤럭시", "은색");
// SmartPhone 객체 생성
// 문자열 타입 인자가 2개인 일반생성자이기 때문에 인자값을 알맞게 넣어줌
// Phone 객체를 상속받았기 때문에 Phone에 생성자도 같이 실행됨 (먼저 호출)
// Phone 객체를 상속받았기 때문에 Phone 객체의 필드를 사용 가능
System.out.println("모델: " + phone.model); // 갤럭시
System.out.println("색상: " + phone.color); // 은색
}
}
package ch07.sec04.exam01;
public class Calculator {
// 원주율 구하는 인자 1개인 일반메소드
public double areaCircle(double r) {
System.out.println("Calculator 객체의 메소드 실행");
return 3.14159 * r * r;
// 기본형 타입의 함수이므로 반드시 타입에 맞게 리턴해야함
}
}
package ch07.sec04.exam01;
// Calculator 객체를 상속받음
public class Computer extends Calculator{
// Calculator 객체에 동일한 메소드가 생성되었고, 매개변수의 타입과 갯수가 모두 동일
// 이 경우 오버라이딩이라는 과정을 진행하는데, 부모메소드를 감추고 자식메소드의 메소드를 호출함
// @Override라는 구문을 쓰는데 생략 가능함
public double areaCircle(double r) {
System.out.println("Computer 객체의 메소드 실행");
return Math.PI * r * r;
// Math.PI : Math 클래스에서 제공하는 함수
}
}
package ch07.sec04.exam01;
public class ComputerExam {
public static void main(String[] args) {
int r = 20;
Calculator cal = new Calculator();
// Calculator 객체 생성 (기본생성자)
System.out.println("원 면적: " + cal.areaCircle(r));
// Calculator 객체의 메소드가 실행됨
System.out.println();
Computer com = new Computer();
// Computer 객체 생성 (기본 생성자)
System.out.println("원 면적: " + com.areaCircle(r));
// 오버라이딩 과정을 거쳤기 때문에 Computer 객체의 메소드가 실행됨
System.out.println();
cal = com;
System.out.println("원 면적: " + cal.areaCircle(r));
// Computer 객체의 메소드를 Calculator 객체의 메소드에 대입하였는데
// 두 메소드가 같기 때문에 Calculator 객체의
// 메소드가 실행된다고 볼 수 있지만
// Computer 객체에서 메소드를 오버라이딩 했기 때문에
// Computer 객체의 메소드가 실행됨
}
}
Car
package ch07.sec05;
public class Car {
public int speed;
public void speedUp() {
speed += 1;
}
public final void stop() {
System.out.println("차를 멈춤");
speed = 0;
}
}
SportsCar (Car에서 상속받음)
package ch07.sec05;
public class SportsCar extends Car{
// Car 객체에서 상속받음
@Override
public void speedUp() {
speed += 10;
}
/*
@Override
public void stop() {
// Car 객체의 stop() 메소드가 final로 지정되었기 때문에
// 상속받은 현재 객체에서 선언이 불가하다
System.out.println("스포츠카를 멈춤");
speed = 0;
}
*/
}
class A
package ch07.sec06.package1;
public class A {
// protected : public과 default의 중간 개념으로
// 같은 패키지 안에 있는 클래스이거나 자식클래스에서만 사용 가능
protected String field;
// 필드 생성
protected A() {
}
// 생성자
protected void method() {
}
// 메소드
}
class B (A와 같은 패키지)
package ch07.sec06.package1;
public class B {
public void method() {
A a = new A();
a.field = "value";
a.method();
// A와 같은 패키지에 속해있기 때문에
// 필드와 메소드 호출 및 객체 생성이 가능
}
}
class C(A와 다른 패키지, 상속관계 x)
package ch07.sec06.package2;
import ch07.sec06.package1.A;
public class C {
public void method() {
// A a = new A();
// a.field = "value";
// a.method();
// A 클래스와 소속되어있는 패키지가 다름
// import를 하였더라도 protected 특성상
// 상속받지 않은 클래스에서는 사용이 불가능
}
}
class D (A와 다른 패키지, 상속관계 o)
package ch07.sec06.package2;
import ch07.sec06.package1.A;
// A와 패키지가 다르므로 import 선언을 반드시 해줘야함
public class D extends A{
public D(){
super();
// A로 부터 상속받기 때문에 A의 생성자를 호출함
}
public void method1() {
this.field = "value";
this.method();
// 상속받는 필드와 메소드 : this를 이용해 호출 가능함
}
public void method2() {
// A a = new A();
// a.field = "value";
// a.method();
// 하지만 A와 소속된 패키지가 다르기 때문에
// A 객체를 직접 생성해서 사용은 불가하다
// super를 통해 상속받은 객체를 생성함
}
}
부모 클래스
package ch07.sec07.exam02;
public class Parent {
// method1() 메소드 선언
public void method1() {
System.out.println("Parent-method1");
}
// method2() 메소드 선언
public void method2() {
System.out.println("Parent-method2");
}
}
자식 클래스
package ch07.sec07.exam02;
public class Child extends Parent{
@Override
// @Override : 부모 클래스에 있는 동일 메소드를 받아
// 자식 메소드에서 재정의하는 것
// 따라서 부모 메소드는 감춰지게 됨
public void method2() {
System.out.println("Child-method2");
}
// method3() 메소드 선언
public void method3() {
System.out.println("Child-method3");
}
}
실행 클래스
package ch07.sec07.exam02;
public class ChildExam {
public static void main(String[] args) {
Child ch = new Child();
// Child(자식) 객체 생성
Parent parent = ch;
// Parent 객체를 사옹할 수 있는 이유 : Child 객체가 Parent에게 상속받았기 때문
// parent 참조변수에 Child 참조변수를 대입하는 것
// 부모객체에 자식객체를 대입하는 과정을 자동 타입 변환이라고 함
// 앞서 배웠던 자동 형변환이랑 원리가 같음
// 이렇게 하면 Parent 참조변수에서도 Child 객체의 메소드나 필드를 이용할 수 있음
parent.method1();
// Parent 객체에 있는 method1 호출
parent.method2();
// Child 객체에서 Parent2의 method2를 재정의했기 때문에
// Child 객체에 있는 method2가 호출이 됨!
}
}
부모 클래스
package ch07.sec07.exam03;
public class Parent {
// 필드 선언
public String field1;
// 메소드1 선언
public void method1() {
System.out.println("Parent-method1");
}
// 메소드2 선언
public void method2() {
System.out.println("Parent-method2");
}
}
자식 클래스
package ch07.sec07.exam03;
public class Child extends Parent{
public String field2;
// 필드 선언
// method3 메소드 선언
public void method3() {
System.out.println("Child-method3");
}
}
실행 클래스
package ch07.sec07.exam03;
public class ChildExam {
public static void main(String[] args) {
Parent parent = new Child();
// Child라는 객체를 생성했지만 Parent(부모)타입 변수에 저장했기 때문에
// Parent의 메소드나 필드만 사용 가능함
// Child가 Parent의 자식 객체이기 때문에 자동적으로 타입 변환이 일어남
parent.field1 = "data1";
parent.method1();
parent.method2();
// Child 객체는 Parent 클래스를 상속받기 때문에
// Parent에 있는 객체의 필드나 메소드를 호출 가능
// parent.field2 = "data2";
// parent.method3();
// Parent(부모)객체 타입을 사용하였기 때문에 Parent(부모)안에 있는 메소드나 필드만 사용 가능
// 따라서 Child 객체 안에 있는 메소드나 필드는 Parent가 모르므로 실행되지 않음
Child child = (Child) parent;
// Child 객체에 있는 필드나 메소드를 사용하기 위해서는 Child 타입으로 형변환을 해야함
// Child 클래스는 Parent 클래스보다 하위 클래스이기 때문에
// 타입 변환을 위해서는 강제 타입 변환을 해야함 : 강제 형변환과 동일한 원리
child.method3();
// Child 타입으로 변환했으므로 Child 객체 내부에 있는 메소드나 필드르 사용 가능
}
}
Tire
package ch07.sec08.exam01;
public class Tire {
// roll() 함수 선언
public void roll() {
System.out.println("회전합니다");
}
}
Hankook Tire
package ch07.sec08.exam01;
// Tire 클래스를 상속받음
public class HankookTire extends Tire{
@Override
// @Override : 부모 클래스에서 받은 동일한 메소드를 자식 메소드의 것으로 재정의함
public void roll() {
System.out.println("한국 타이어가 회전합니다");
}
}
Kumho Tire
package ch07.sec08.exam01;
// Tire 클래스를 상속받음
public class KumhoTire extends Tire{
@Override
// @Override : 부모 클래스에서 받은 동일한 메소드를 자식 메소드의 것으로 재정의함
public void roll() {
System.out.println("금호 타이어가 회전합니다");
}
}
Car
package ch07.sec08.exam01;
public class Car {
// Tire 객체를 사용하기 위한 필드 선언
public Tire tire;
// 메소드 선언
public void run() {
// Tire의 roll() 메소드를 호출한 것이지만
// KumhoTire와 HankookTire가 Tire의 객체를 상속받아
// 같은 메소드를 가지고 있어 오버라이딩 되므로
// HankookTire와 KumhoTire의 객체를 생성하면
// 해당 roll() 메소드를 호출함
tire.roll();
}
}
CarExample
package ch07.sec08.exam01;
public class CarExample {
public static void main(String[] args) {
// Car 객체를 생성함
Car c = new Car();
// Car 객체 내부에 있는 tire라는 필드에 Tire라는 객체 생성
c.tire = new Tire();
// Car 객체 안에 run() 함수 실행됨
c.run(); // 회전합니다
// Car의 tire 필드에 HankookTire라는 객체 생성
c.tire = new HankookTire();
// Car 객체 안에 run() 함수 실행됨
c.run();
// run 함수 내부에서 roll 함수가 HankookTire 내부의 roll 함수로 오버라이딩되어
// 결과 값은 : 한국타이어가 굴러갑니다
// Car의 tire 필드에 HankookTire라는 객체 생성
c.tire = new KumhoTire();
// Car 객체 안에 run() 함수 실행됨
c.run();
// run 함수 내부에서 roll 함수가 KumhoTire 내부의 roll 함수로 오버라이딩되어
// 결과 값은 : 금호타이어가 굴러갑니다
}
}
Vehicle
package ch07.sec08.exam02;
public class Vehicle {
// run() 메소드 선언
public void run() {
System.out.println("차량이 달립니다");
}
}
Bus
package ch07.sec08.exam02;
public class Bus extends Vehicle{
// Vehicle 클래스에서 상속받음
@Override
// @Override : 부모 클래스 Vehicle의 run() 메소드를
// 현재 Bus 클래스에서 재정의함
public void run() {
System.out.println("버스가 달립니다");
}
}
Taxi
package ch07.sec08.exam02;
public class Taxi extends Vehicle{
// Vehicle 클래스에서 상속받음
@Override
// @Override : 부모 클래스 Vehicle의 run() 메소드를
// 현재 Bus 클래스에서 재정의함
public void run() {
System.out.println("택시가 달립니다");
}
}
Driver
package ch07.sec08.exam02;
public class Driver {
// 동작을 위한 클래스
// 클래스의 매개변수를 대입하여 해당 클래스의 run 함수가 실행되게끔 하기
public void drive(Vehicle v) {
v.run();
}
}
DriverExam
package ch07.sec08.exam02;
public class DriverExam {
public static void main(String[] args) {
Driver driver = new Driver();
// Driver 객체 생성 및 참조변수 설정
Bus bus = new Bus();
// Bus 객체 생성 및 참조변수 설정
driver.drive(bus);
// Driver 클래스에 drive()라는 함수를 선언하였고
// 함수에 객체의 매개변수에 따라 run 함수를 실행함
// 따라서 Bus 클래스의 run 함수가 실행되어
// 결과값은 버스가 달립니다
Taxi taxi = new Taxi();
// Taxi 객체 생성 및 참조변수 설정
driver.drive(taxi);
// Driver 클래스에 drive()라는 함수를 선언하였고
// 함수에 객체의 매개변수에 따라 run 함수를 실행함
// 따라서 Taxi 클래스의 run 함수가 실행되어
// 결과값은 버스가 달립니다
}
}
부모 클래스 (Person)
package ch07.sec09;
public class Person {
public String name;
// 필드 선언
// 인자가 1개인 일반생성자 선언
public Person(String name) {
this.name = name;
// name 매개변수가 위의 name 필드에 저장
}
// walk() 메소드 생성
public void walk() {
System.out.println("걷습니다.");
}
}
자식 클래스 (Student)
package ch07.sec09;
public class Student extends Person{
// Person 클래스를 상속받음
public int studentNo;
// 필드 선언
// 인자가 2개인 일반생성자 선언
public Student(String name, int studentNo) {
super(name);
// Person 생성자는 String 타입 매개변수를 1개 가지므로
// super에 String 타입 매개변수를 1개 넣기
// super는 부모 클래스의 생성자를 호출하기 위해 사용, 인자가 있을 경우에는 꼭 호출해주기
this.studentNo = studentNo;
// 매개변수로 받은 studentNo를 해당 클래스의 studentNo 필드에 적용
}
// study 메소드 선언
public void study() {
System.out.println("공부를 합니다.");
}
}
Instanceof 실행 클래스
package ch07.sec09;
public class InstanceofExam {
// 해당 클래스에 바로 사용할 것이기 때문에 static (정적)선언
// Person 클래스 타입의 매개변수 한 개를 가짐
// Person이 부모 클래스이기 때문
public static void personInfo(Person person) {
System.out.println("name: " + person.name);
// 입력받은 매개변수를 Person 클래스의 name 필드에 저장
person.walk();
// Person 클래스의 walk() 메소드 실행함
// 걷습니다 실행
// if(person instanceof Student) {
// a instanceof b : a의 객체를 b의 객체로 변환이 가능한지 (상속관계에 있는지)
// 맞으면 true, 틀리면 false
// Student student = (Student) person;
// Person 타입의 변수를 Student 타입으로 강제 타입 변환
// 강제 타입 변환 이유 : Person 객체가 Student 객체의 부모 클래스이기 때문에
// 자식 클래스의 타입으로 사용하기 위해서는 강제로 형변환이 필요함
// System.out.println("StudentNo : " + student.studentNo);
// Student 클래스에 있는 studentNo 필드에 저장
// student.study();
// Student 클래스의 study() 함수 실행
// }
// Person 타입으로 매개변수를 받았기에
// 자식 클래스인 Student 필드와 메소드를 이용하기 위해서는
// 강제 타입 변환이 필요함
if(person instanceof Student student) {
// a instanceof B b
// a 객체를 B클래스 타입으로 변환이 가능하면 변수 b에 해당 객체를 저장
// Student 클래스에 studentNo 필드에 해당 값을 저장함
System.out.println("StudentNo: " + student.studentNo);
student.study();
// Student 객체의 study() 함수 실행
}
}
public static void main(String[] args) {
Person p1 = new Person("이동주");
// Person 생성자의 인자가 String 타입 1개였으므로, String 인자값을 넣기
personInfo(p1);
// personInfo(p1)에서 Person 객체를 전달하면, walk() 메소드가 Person 클래스에서 실행됩니다.
System.out.println();
Person p2 = new Student("홍길동", 10);
// Person 타입의 변수이지만 Student 객체를 생성하여 자동 형변환이 수행됨
// Student 생성자의 인자는 String 1개와 정수타입 1개
personInfo(p2);
// personInfo(p2)에서 Student 객체를 전달하면, instanceof가 true를 반환하여 Student 객체의 studentNo와 study() 메소드가 실행됩니다.
}
}
객체를 생성할 수 있는 실체 클래스들의 공통적인 필드나 메소드를 추출해서 선언한 클래스
실체 클래스들의 부모 역할 (참조 변수) 을 함. 공통적인 필드나 메소드를 물려받을 수 있음
클래스를 선언할 때 abstrcat 키워드를 붙여 사용한다.
new 연산자를 이용하여 객체를 직접 만들지 못하고 상속을 통해서 자식 클래스만 만들 수 있다.
추상 메소드의 경우 부모 클래스에서 함수 선언은 하되 구현은 자식 클래스에서 재정의하기 때문에 실행문은 선언하지 않는다. (함수만 선언)
의존성 역전 원칙 : 실체를 보지 않고 부모를 볼 수 있도록 의존 관계를 반대로 한다는 것!
명확하지 않고 특별한 기능이 없는 것!
특별한 코드를 일반화 시킴
Phone(추상 클래스)
package ch07.sec10.exam01;
public abstract class Phone {
// abstract : 추상이라는 의미로 추상 클래스나 메소드를 사용할 때
// 클래스나 메소드명 앞에 명시함
String owner;
// 필드 선언
// 인자가 1개인 생성자 만들기 (String 타입)
Phone(String owner){
this.owner = owner;
// 매개변수를 위의 필드에 저장
}
// 메소드 선언
void turnOn() {
System.out.println("폰 전원을 켭니다");
}
void turnOff() {
System.out.println("폰 전원을 끕니다");
}
}
SmartPhone 클래스(자식 클래스)
package ch07.sec10.exam01;
public class SmartPhone extends Phone{
// 추상 클래스인 Phone을 상속받음
// 인자가 1개인 일반생성자 선언
SmartPhone(String owner){
super(owner);
// Phone 생성자 호출 : String 타입의 인자를 1개 가지기 때문에
// Phone 생성자에 String 타입 매개변수 하나를 넣어주기
// 추상 클래스는 new 연산자를 통해 선언할 수 없으므로 반드시 super()로 호출해줘야함
}
// internetSearch() 메소드 선언
void internetSearch() {
System.out.println("인터넷 검색을 합니다");
}
}
실행 클래스
package ch07.sec10.exam01;
public class PhoneExam {
public static void main(String[] args) {
// TODO Auto-generated method stub
SmartPhone smartPhone = new SmartPhone("이동주");
// SmartPhone 객체 생성
smartPhone.turnOn();
smartPhone.internetSearch();
// SmartPhone 객체에 있는 internetSearch() 함수 호출
smartPhone.turnOff();
// SmartPhone 클래스는 추상메소드 Phone을 상속받기 때문에
// Phone에 있는 메소드들(turnOn, turnOff)을 실행 가능!
}
}
추상 메소드가 있는 클래스
package ch07.sec10.exam02;
public abstract class Animal {
// 추상 메소드를 선언하면 반드시 클래스명에도 abstract를 붙여 추상클래스로 만들기
public void breathe() {
System.out.println("숨을 쉰다");
}
// 메소드 선언
public abstract void sound();
// 추상 메소드 사용
// 추상 메소드는 실행문이 없고, 자식 클래스에서 반드시 재정의(오버라이딩)해야 한다.
// 대신 메소드를 호출하는 용도로 사용해야 하기 때문에 메소드 자체는 선언하고 세미콜론(;) 붙이기
}
Dog 클래스
package ch07.sec10.exam02;
public class Dog extends Animal{
// 추상 클래스 Animal을 상속받음
@Override
public void sound() {
System.out.println("멍멍");
}
// 추상 메소드 sound()를 현재 클래스에서 재정의함
// 추상 클래스는 직접 객체를 생성할 수 없고, 반드시 자식 클래스를 통해서만 객체를 생성할 수 있다.
}
Cat 클래스
package ch07.sec10.exam02;
public class Cat extends Animal{
// 추상 클래스 Animal을 상속받음
@Override
public void sound() {
System.out.println("야옹");
}
// 추상 메소드 sound()를 현재 클래스에서 재정의함
// 추상 클래스는 직접 객체를 생성할 수 없고, 반드시 자식 클래스를 통해서만 객체를 생성할 수 있다.
}
실행 클래스
package ch07.sec10.exam02;
public class AbstractMethodExam {
public static void main(String[] args) {
// TODO Auto-generated method stub
Dog dog = new Dog();
// Dog 객체 생성
dog.sound();
// Dog에서 재정의된 sound 메소드 실행
Cat cat = new Cat();
// Cat 객체 생성
cat.sound();
// Cat에서 재정의된 sound 메소드 실행
animalSound(new Dog());
// Dog의 객체를 생성하여 이를 매개변수로 사용
// Dog 클래스에 있는 sound() 메소드로 재정의되어 실행
animalSound(new Cat());
// Cat의 객체를 생성하여 이를 매개변수로 사용
// Cat 클래스에 있는 sound() 메소드로 재정의되어 실행
}
public static void animalSound(Animal animal) {
animal.sound();
}
// 현재 클래스에서 메소드를 사용하기 위해 static(정적) 형태로 메소드 생성
// Animal 객체에 있는 sound() 메소드 실행
// 매개변수로 Animal 클래스 타입 사용
}
sealed
package ch07.sec11;
public sealed class Person permits Employee, Manager {
// sealed : 자식 클래스를 마음대로 생성하지 못하게함
// permits : 상속할 수 있는 클래스들 나열하기
// sealed 클래스에서 상속받는 클래스들은 똑같이 sealed를 사용해서 같은 방식으로 봉인하거나
// non-sealed로 봉인을 풀기 또는 final로 상속을 종료하겠다고 선언하기
public String name;
public void work() {
System.out.println("하는 일이 결정되지 않았습니다");
}
}
final
package ch07.sec11;
public final class Employee extends Person{
// final : 더 이상 상속을 할 수 없음을 뜻함 (최종적인 클래스)
@Override
public void work() {
System.out.println("제품을 생산합니다");
}
}
non-sealed
package ch07.sec11;
public non-sealed class Manager extends Person{
// non-sealed : 봉인을 해제한다는 뜻으로 다른 클래스에 상속이 가능해짐
@Override
public void work() {
System.out.println("생산 관리를 합니다");
}
}
봉인 해제 후 상속
package ch07.sec11;
public class Director extends Manager{
// Manager 클래스를 상속받음
// Manager 클래스가 봉인을 해제했기 때문에 상속 받을 수가 있음
@Override
public void work() {
System.out.println("제품을 기획합니다");
}
}
실행 클래스
package ch07.sec11;
public class SealedExam {
public static void main(String[] args) {
Person p = new Person();
Employee e = new Employee();
Manager m = new Manager();
Director d = new Director();
p.work();
e.work();
m.work();
d.work();
}
}