20211206 상속, 다형성
상속
클래스를 확장한다 -> 확장시킬 대상을 상속하여 확장한다.
- 확장된 클래스는 상속받은 클래스 멤버를 가지고 있다.
- 상속한 클래스 -> 슈퍼 클래스
- 상속받은 클래스 -> 서브 클래스.
- 상속받은 클래스(서브 클래스)가 객체화시, 슈퍼클래스가 먼저 객체화가 되어야 한다.
- 슈퍼클래스 추상적인 클래스어야 한다.
- 상속 방법 : class 클래스(자식) extends 클래스(부모)
//슈퍼클래스
class User2{
public User2(){
System.out.println("슈퍼클래스 생성자 메서드 호출");
}
private String userName;
private int userAge;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getUserAge() {
return userAge;
}
public void setUserAge(int userAge) {
this.userAge = userAge;
}
}
Student 클래스는 User2 클래스를 상속받는다.
//서브 클래스
class Student extends User2{
public Student() {
System.out.println("서브클래스 생성자 메서드 호출");
}
}
콘솔창 : 1. 슈퍼클래스 콘솔창 출력 -> 2. 서브클래스 콘솔창 출력
슈퍼클래스의 생성자가 먼저 실행된다.
서브 클래스의 생성자 호출에 앞서
슈퍼 클래스의 생성자가 호출된다
Student 클래스는 User2 클래스를 포함하고 있다
서브 클래스가 객체화시 참조타입으로 슈퍼클래스 타입이 올 수 있다.
Student st = new Student();
st.setUserAge(20);
st.setUserName("홍길동");
상속관계를 가진 대상끼리 업캐스팅과 다운캐스팅이 가능하다.
User2 us2 = st; // 업캐스팅
Student st2 = (Student) us2; // 다운 캐스팅
User2가 객체화시 Student 를 가지고 있지 않으므로 캐스팅이 불가능하다.
즉 캐스팅이 원활하게 되어야 한다면
캐스팅 될 대상은 모두 객체화가 되어야 캐스팅이 가능하다.
1) 형변환 기호 생략 불가능
2) 업캐스팅이 선행되지 않을 경우 에러 발생.
자식클래스 참조변수 = (자식클래스) new 부모클래스();
User2 us3 = new User2();
Student st3 = (Student) us3; // 다운 캐스팅
class SuperA{
String superNameA;
public SuperA() {
System.out.println("superA 생성자 메서드");
}
}
class SuperB extends SuperA{
String superNameB;
public SuperB() {
System.out.println("SuperB 생성자 메서드");
}
}
class Sub extends SuperB{
String subName;
public Sub() {
System.out.println("Sub 생성자 메서드");
}
}
1)
s 식별자에 객체 주소가 저장(슈퍼 클래스 객체 주소도 포함)
Sub s = new Sub();
서브클래스는 슈퍼클래스의 멤버에 접근이 가능하다.
s.subName = "subName";
s.superNameA = "superA";
s.superNameB = "superB";
2)
서브클래스가 객체화 되었더라도 참조타입에 의한 멤버만 접근이 가능하다.
슈퍼클래스 참조타입에서 서브클래스 멤버로 접근은 불가능하다.
sb.subName 에는 접근이 불가능하다.
SuperB sb = s;
System.out.println(sb.superNameA+"/"+sb.superNameB);
sb.superNameA = "superAA";
sb.superNameB = "superBB";
캐스팅이 되었더라도 실체 객체화된 대상은 사라지지 않았다.
SuperA sa = sb;
System.out.println(sa.superNameA);
sa.superNameA = "superAAA";
객체의 주소가 변화한 것은 아니므로, 위에서 저장한 데이터값이 그대로 출력
Sub s2 = (Sub) sa;
System.out.println(s2.subName);
System.out.println(s2.superNameA);
System.out.println(s2.superNameB);
하나의 참조타입으로 공통 코드 작성
다형성
- 하나의 참조타입으로 여러객체를 참조할 수 있다.
상속을 사용하는 이유 :
슈퍼 클래스 참조 타입으로 공통 비즈니스 로직 작성
모듈이 달라도 슈퍼클래스 타입으로 공통 로직을 진행할 수 있다.
실습.
package kr.or.ksmart;
class MySumNumber{
private int n1;
private int n2;
public int getN1() {
return n1;
}
public void setN1(int n1) {
this.n1 = n1;
}
public int getN2() {
return n2;
}
public void setN2(int n2) {
this.n2 = n2;
}
}
class MySum{
public void sum(MySumNumber sum) {
System.out.println();
}
}
class MySumNum1 extends MySumNumber{}
class MySumNum2 extends MySumNumber{}
public class javaBasicEx03 {
public static void main(String[] args) {
/*
* 실습. 아래의 코드의 에러를 해결하도록 하여라.
* */
MySumNumber num1 = new MySumNum1();
num1.setN1(10);
num1.setN2(30);
MySumNumber num2 = new MySumNum2();
num2.setN1(20);
num2.setN2(30);
MySum m = new MySum();
m.sum(num1);
m.sum(num2);
}
}
개념 재정리하기.
상속 :
- 기존의 클래스로 새로운 클래스를 작성하는 것 (코드의 재사용)
- 두 클래스를 부모와 자식으로 관계를 맺어주는 것
class 자식클래스 extends 부모클래스 {}
- 자손은 조상의 모든 멤버를 상속받는다. (생성자, 초기화 블럭 제외)
- 조상 : 부모의 부모~ 까지 포함한다.
- 자손의 멤버 개수는 조상보다 적을 수 없다.(같거나 많다)
- 자손의 변경은 조상에 영향을 미치지 않는다.
실습1.
1) 2차원 좌표 클래스
class point{
int x;
int y;
}
2-1) 3차원 좌표 - z가 추가 되었다.
class Point3D{
int x;
int y;
int z;
}
2-2) Point 클래스를 상속받는 Point3D 로 다시 정의해주기.
public Point3D extends Point{
int z;
}
3) 객체를 생성했을 때 data 영역은?
- 2-1 과 2-2 는 같다!
Point3D p = new Point3D();
포함이란?
- 클래스의 멤버로 참조변수를 선언하는 것
- 작은 단위의 클래스를 만들고, 이들을 조합해서 클래스를 만든다.
---> 객체화 했을 경우
1번 | 2번 |
x값 : c.x y값 : c.y |
x 값: c.c.x y값 : c.c.y |
캡슐화
접근제어자를 사용하는 이유?
- 외부로부터 데이터를 보호하기 위해서
- 내부적으로만 사용되는 부분을 감추기 위해서
다형성
- 여러가지 형태를 가질 수 있는 능력
- 조상타입 참조변수로 자손타입 객체를 다루는 것
- 자손 타입의 참조변수로 조상 타입의 객체를 가리킬 수 없다.
---> 큰 개념에는 작은 개념을 넣을 수 있지만, 작은 개념에는 큰 개념을 넣을 수 없다.
1)
---> 오버라이딩된 call 메서드만 호출 가능하다!
2)
⬇