[21일차] 상속
2023. 1. 19. 17:33ㆍ데이터 엔지니어링 과정/java
목차
1. 상속
2. 타입 변환과 다형성
1. 상속
0. 상속 개념
- 정의 : 부모가 자식에게 물려주는 행위
➡ 부모 클래스 (상위 클래스)가 자식 클래스(하위 클래스 또는 파생 클래스)에게 물려준다. - 효과
① 중복되는 코드를 줄여준다.
➡ 효율적이고 개발 시간을 절약해준다.
② 부모 클래스의 수정으로 모든 자식 클래스들도 수정되는 효과를 가져온다.
➡ 유지 보수 시간을 최소화 할 수 있다.
1. 클래스 상속
- 상속 방법
: 자식 클래스를 선언할 때 어떤 부모 클래스를 상속받을 것인지 결정하고, 선택된 부모 클래스는 extends 뒤에 기술
class 자식클래스 extends 부모 클래스 {
//필드
//생성자
//메소드
}
- 특징
① extends 뒤에는 단 하나의 부모 클래스만 와야 한다.
② 부모 클래스에서 private 접근 제한을 갖는 필드와 메소드는 상속 대상에서 제외된다.
③ 부모 클래스와 자식 클래스가 다른 패키지에 존재한다면, default 접근 제한을 갖는 필드와 메소드도 상속 대상에서 제외된다.
- 💻 핸드폰 (CellPhone) 클래스 상속해서 DMB폰(DmbCellPhone) 클래스를 작성
package sec01.exam01;
public class CellPhone {
//필드
String model;
String color;
//생성자
//메소드
void powerOn() { System.out.println("전원을 켭니다."); }
void popwerOff() {System.out.println("전원을 끕니다."); }
void bell() {System.out.println("벨이 울립니다.");}
void sendVoince(String message) {System.out.println("자기: " + message);}
void receiveVoice(String message) {System.out.println("상대방: " + message);}
void hangUp() {System.out.println("전화를 끊습니다.");}
}
package sec01.exam01;
public class DmbCellPhone extends CellPhone{
//필드
int channel;
//생성자
DmbCellPhone (String model, String color, int channel) {
this.model = model;
this.color = color;
this.channel = channel;
}
//메소드
void turnOnDmb() {
System.out.println("채널 " + channel + "번 DMB 방송 수신을 시작합니다.");
}
void changeChannelDmb(int channel) {
this.channel = channel;
System.out.println("채널 " + channel + "번으로 바꿉니다.");
}
void turnOffDmb() {
System.out.println("DMB 방송 수신을 멈춥니다.");
}
}
package sec01.exam01;
public class DmbCellPhoneExample {
public static void main(String[] args) {
//DmbCellPhone 객체 생성
DmbCellPhone dmbCellPhone = new DmbCellPhone("자바폰", "검정", 10);
//CellPhone 클래스로부터 상속받은 필드
System.out.println("모델: " + dmbCellPhone.model);
System.out.println("색상: " + dmbCellPhone.color);
//DmbCellPhone 클래스의 필드
System.out.println("채널: " + dmbCellPhone.channel);
//CellPhone 클래스로부터 상속받은 메소드 호출
dmbCellPhone.powerOn();
dmbCellPhone.bell();
dmbCellPhone.sendVoince("여보세요");
dmbCellPhone.receiveVoice("안녕하세요! 저는 홍길동인데요");
dmbCellPhone.sendVoince("아~ 네 반갑습니다.");
dmbCellPhone.hangUp();
//DmbClassPhone 클래스의 메소드 호출
dmbCellPhone.turnOnDmb();
dmbCellPhone.changeChannelDmb(12);
dmbCellPhone.turnOffDmb();
}
}
>>> 모델: 자바폰
>>> 색상: 검정
>>> 채널: 10
>>> 전원을 켭니다.
>>> 벨이 울립니다.
>>> 자기: 여보세요
>>> 상대방: 안녕하세요! 저는 홍길동인데요
>>> 자기: 아~ 네 반갑습니다.
>>> 전화를 끊습니다.
>>> 채널 10번 DMB 방송 수신을 시작합니다.
>>> 채널 12번으로 바꿉니다.
>>> DMB 방송 수신을 멈춥니다.
2. 부모 생성자 호출
- 모든 객체는 클래스의 생성자를 호출해야만 생성된다.
- 부모 생성자는 자식 생성자의 맨 첫 줄에서 호출된다.
➡ super()를 통해 부모의 기본 생성자 호출 - super(매개값, ···)
- 매개값의 타입과 일치하는 부모 생성자 호출
- 만약 매개값의 타입과 일치하는 부모 생성자가 없을 경우 컴파일 에러 발생
- 💻 부모 클래스 People , 자식 클래스 Student, 자식 객체 이용
package sec01.exam02;
public class People {
//필드
public String name;
public String ssn;
public People (String name, String ssn) {
this.name = name;
this.ssn = ssn;
}
}
package sec01.exam02;
public class Student extends People {
public int studentNo;
public Student(String name, String ssn, int studentNo) {
super(name, ssn);
this.studentNo = studentNo;
}
}
package sec01.exam02;
public class StudentExample {
public static void main(String[] args) {
Student student = new Student("홍길동", "123456-1234567", 1);
System.out.println("name : " + student.name);
System.out.println("ssn : "+ student.ssn);
System.out.println("studentNo : " + student.studentNo);
}
}
>>> name : 홍길동
>>> ssn : 123456-1234567
>>> studentNo : 1
3. 메소드 재정의
- 정의
: 부모의 메소드가 자식 클래스가 사용하기에 적합하지 않을 경우, 자식 클래스에서 부모 클래스의 메소드를 다시 정의하는 것 - 메소드 재정의 규칙
① 부모의 메소드와 동일한 시그니처(리턴 타입, 메소드 이름, 매개 변수 목록)을 가져와야 한다.
② 접근 제한을 더 강하게 재정의 할 수 없다.
③ 새로운 예외를 throws 할 수 없다.
❗주의할점❗
- 부모 메소드가 public 접근 제한을 갖고 있을 경우, 재정의하는 자식 메소드는 default나 private 접근 제한으로 수정할 수 없다.
- 반대로, 부모 메소드가 default 접근 제한을 가지면 재정의하는 자식 메소드는 default 또는 public 접근 제한을 가질 수 있다.
- 💻 Calcualator의 자식 클래스인 Computer에서 원의 넓이를 구하는 Calculator의 areaCircle() 메소드를 재정의
package sec01.exam03;
public class Calculator {
double areaCircle(double r) {
System.out.println("Calcaulator 객체의 areaCircle() 실행");
return 3.14159 * r * r;
}
}
package sec01.exam03;
public class Computer extends Calculator{
@Override
double areaCircle(double r) {
System.out.println("Computer 객체의 areaCircle() 실행");
return Math.PI * r * r;
}
}
package sec01.exam03;
public class ComputerExample {
public static void main(String[] args) {
int r = 10;
Calculator calculator = new Calculator();
System.out.println("원면적 : " + calculator.areaCircle(r));
System.out.println();
Computer computer = new Computer();
System.out.println("원면적: " + computer.areaCircle(r));
}
}
>>> Calcaulator 객체의 areaCircle() 실행
>>> 원면적 : 314.159
>>>
>>> Computer 객체의 areaCircle() 실행
>>> 원면적: 314.1592653589793
- 부모 메소드 호출
: 자식 클래스 내부에서 재정의된 부모 클래스의 메소드를 호출해야하는 상황이라면,, 명시적으로 super 키워드를 붙여서 부모 메소드를 호출할 수 있다.
- 💻 Airplane 클래스를 상속한 SupersonicAirplane 클래스의 초음속 비행 모드와 일반 비행 모드
package sec01.exam04;
public class Airplane {
public void land() {
System.out.println("착륙합니다.");
}
public void fly() {
System.out.println("일반비행합니다.");
}
public void takeOff() {
System.out.println("이륙합니다.");
}
}
package sec01.exam04;
public class SupersonicAirplane extends Airplane{
public static final int NORMAL = 1;
public static final int SUPERSONIC = 2;
public int flyMode = NORMAL;
@Override
public void fly() {
if (flyMode == SUPERSONIC) {
System.out.println("초음속비행합니다.");
} else {
//Airplane 객체의 fly() 메소드 호출
super.fly();
}
}
}
package sec01.exam04;
public class SupersonicAirplaneExample {
public static void main(String[] args) {
SupersonicAirplane sa = new SupersonicAirplane();
sa.takeOff();
sa.fly();
sa.flyMode = SupersonicAirplane.SUPERSONIC;
sa.fly();
sa.flyMode = SupersonicAirplane.NORMAL;
sa.fly();
sa.land();
}
}
>>> 이륙합니다.
>>> 일반비행합니다.
>>> 초음속비행합니다.
>>> 일반비행합니다.
>>> 착륙합니다.
4. final 클래스와 final 메소드
- 상속할 수 없는 final 클래스
: 클래스를 선언할 때 final 키워드를 class 앞에 붙이면 이 클래스는 최종적인 클래스이다.
➡ 부모 클래스가 될 수 없어 자식 클래스를 만들 수 없다.
- 💻 Member 클래스를 선언할 때 final을 지정함으로써 VeryImportantPerson은 Member를 상속 불가
package sec01.exam05;
public final class Member {
}
package sec01.exam05;
//Member 상속 불가
public class VeryImportantPerson extends Member{
}
- 재정의할 수 없는 final 메소드
: 메소드를 선언할 때 final 키워드를 붙이면 최종적인 메소드이므로, 재정의할 수 없는 메소드가 된다.
➡ 부모 클래스를 상속해서 자식 클래스를 선언할 때,부모 클래스에서 선언된 final 메소드는 자식 클래스에서 재정의할 수 없다.
- 💻 Car 클래스의 stop() 메소드를 final로 선언하여 Car를 상속한 SportCar 클래스에서는 stop() 메소드 재정의 불가
package sec01.exam06;
public class Car {
//필드
public int speed;
//메소드
public void speedUp() {speed += 1;}
//final 메소드
public final void stop() {
System.out.println("차를 멈춤");
speed = 0;
}
}
package sec01.exam06;
public class SportsCar extends Car {
@Override
public void speedUp() { speed += 10;}
//재정의 불가
@Ovrride
public void stop() {
System.out.println("스포츠카를 멈춤");
speed=0;
}
}
5. protected 접근 제한자
- 같은 페이지에서는 default처럼 접근 제한이 없다.
- 다른 패키지에서는 자식 클래스만 접근을 허용한다.
- 필드, 생성자, 메소드 선언에 사용될 수 있다.
- 💻 protected 접근 제한자가 있는 A 클래스
package sec01.exam07.pack1;
public class A {
protected String field;
protected A() {
}
protected void method() {
}
}
//A클래스와 동일한 패키지에 있는 B클래스
package sec01.exam07.pack1;
public class B {
public void method() {
A a = new A();
a.field = "value";
a.method();
}
}
//A패키지와 다른 패키지에 있는 C클래스➡ A클래스의 protected 필드, 생성자, 메소드 접근 불가
package sec01.exam07.pack2;
public class C {
A a = new A();
a.field = "value";
a.method();
}
/*A클래스와 다른 패키지에 있지만, A클래스의 자식 클래스인 D클래스
➡ A클래스의 protected 필드, 생성자, 메소드 접근 가능*/
package sec01.exam07.pack2;
import sec01.exam07.pack1.A;
public class D extends A{
public D() {
super();
this.field = "Value";
this.method();
}
}
2. 타입 변환과 다형성
0. 다형성
- 정의 : 사용 방법은 동일하지만, 다양한 객체를 이용해서 다양한 실행결과가 나오도록 하는 성질
- 다형성 = 메소드 재정의 + 타입 변환
1. 자동 타입 변환
- 타입 변환 : 타입을 다른 타입으로 변환하는 행위
- 클래스의 타입 변환
- 클래스의 변환은 상속 관게에 있는 클래스 사이에서 발생
- 자식은 부모 타입으로 자동 타입 변환 가능
- 자동 타입 변환 : 프로그램 실행 도중에 자동적으로 타입 변환이 일어나는 것
- 조건 : 부모 타입 변수 = 자식타입;
- 💻 자동 타입 변환 예제 코드
package sec02.exam01;
classs A {}
class B extends A {}
class C extends A {}
class D extends B {}
class E extends C {}
public class PromotionExample {
public static void main(String[] args) {
B b = new B();
C c = new C();
D d = new D();
E e = new E();
A a1 = b;
A a2 = c;
A a3 = d;
A a4 = e;
B b1 = d;
C c1 = e;
//B b3 = e;
//C c2 = d;
}
}
- 부모 타입은 자동 타입 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근이 가능함
- 변수는 자식 객체를 참조하지만, 변수로 접근 가능한 멤버는 부모 클래스 멤버로만 한정됨
- ❗예외❗
메소드가 자식 클래스에서 재정의 되었다면 자식 클래스의 메소드가 대신 호출된다.
- 💻 자동 타입 변환 후의 멤버 접근
package sec02.exam02;
public class Parent {
public void method1() {
System.out.println("Parent-method()");
}
public void method2() {
System.out.println("Parent-method2()");
}
}
package sec02.exam02;
public class Child extends Parent{
@Override
public void method2() {
System.out.println("Child-method2()");
}
public void method3() {
System.out.println("Child-method2()");
}
}
package sec02.exam02;
public class ChildExample {
public static void main(String[] args) {
Child child = new Child();
Parent parent = child;
parent.method1();
parent.method2();
//parent.method3();
}
}
>>> Parent-method()
>>> Child-method2()
2. 강제 타입 변환
- 정의 : 부모 타입을 자식 타입으로 변환하는 것
- 자식 타입이 부모 타입으로 자동 타입 변환한 후 다시 자식 타입으로 변환할 때 강제 타입 변환 사용 가능
- 💻 강제 타입 변환 코딩
package sec02.exam05;
public class Parent {
public String field1;
public void method1() {
System.out.println("Parent-method1()");
}
public void method2() {
System.out.println("Parent-method2()");
}
}
package sec02.exam05;
public class Child extends Parent {
public String field2;
public void method3() {
System.out.println("Child-method3()");
}
}
package sec02.exam05;
public class ChildExample {
public static void main(String[] args) {
Parent parent = new Child();
parent.field1 = "data1";
parent.method1();
parent.method2();
/*
* parent.filed2 = "data2";
* parent.method3();
*/
Child child = (Child) parent;
child.field2 = "yyy";
child.method3();
}
}
>>> Parent-method1()
>>> Parent-method2()
>>> Child-method3()
3. 객체 타입 확인
- instasnceof 연산자 사용
- 💻 예시
package sec02.exam06;
public class Parent {
}
package sec02.exam06;
public class Child extends Parent{
}
package sec02.exam06;
public class InstanceofExample {
public static void method1(Parent parent) {
if (parent instanceof Child) {
Child child = (Child) parent;
System.out.println("method1 - Child로 변환성공");
} else {
System.out.println("method1 - Child로 변환되지 않음");
}
}
public static void method2(Parent parent) {
Child child = (Child) parent;
System.out.println("method2 - Child로 변환 성공");
}
public static void main(String[] args) {
Parent parentA = new Child();
method1(parentA);
method2(parentA);
Parent parentB = new Parent();
method1(parentB);
method2(parentB);
}
}
>>> method1 - Child로 변환성공
>>> method2 - Child로 변환 성공
>>> method1 - Child로 변환되지 않음
>>> Exception in thread "main" java.lang.ClassCastException
'데이터 엔지니어링 과정 > java' 카테고리의 다른 글
[23일차] 중첩 클래스와 중첩 인터페이스 (1) | 2023.01.25 |
---|---|
[22일차] 추상 클래스 & 인터페이스 (0) | 2023.01.20 |
[20일차] 메소드 (0) | 2023.01.18 |
[19일차] 참조 타입 & 클래스 (0) | 2023.01.17 |
[18일차] 조건문 & 반복문 & 참조 타입과 참조 변수 & 배열 (0) | 2023.01.16 |