자바의 상속에 대해서 알아보자. 많은 실제 예제를 가지고 코딩해보면서 익혀보자
class 하위클래스 extends 상위클래스 {
}
상위클래스
: 덜 구체적이다.하위클래스
: 상위클래스의 멤버변수와 메소드를 상속받아 더욱 구체적이다.🔍 필요한 추가 속성과 기능을 하위클래스를 통해 추가 구현할 수 있다.
🤔 하위 객체를 생성할 때 상위객체의 멤버변수와 메소드를 쓸 수 있는 건 알았다.
그런데 어떻게 쓸 수 있는 걸까?
➡️ 하위클래스 생성자에서 자동으로 상위클래스 생성자를 컴파일 하기 때문이다.
class Extend0 {
public Extend0() {
System.out.println("Extend0 생성");
}
}
class Extend1 extends Extend0{
public Extend1() {
System.out.println("Extend1 생성");
}
}
public class Inheritance {
public static void main(String[] args) {
//Extend0을 상속받은 Extend1 객체를 생성
Extend1 e1 = new Extend1();
}
}
✍️ 실행화면
먼저 호출되는 것을 확인 할 수 있다.
Extend0 생성
Extend1 생성
super
예약어를 사용한다. class Extend0 {
//상위클래스에 매개변수가 있는 경우 → 명시적으로 상위생성자 추가 필요
public Extend0(int i) {
}
class Extend1 extends Extend0 {
//하위클래스에서 상위클래스 생성자를 super예약어를 통해 작성
public Extend1(int i) {
//첫 줄에 작성 & 동일한 타입의 매개변수
super(i);
}
super
예약어super
예약어가 필수이다.사용방법
1. 하위생성자에서 상위클래스 생성자 작성 : super();
2. 상위클래스 멤버변수참조 : super.상위클래스멤버변수;
3. 상위클래스 메소드 참조 : super.상위클래스메소드();
//상위 클래스 생성
class Extend0 {
int i;
//i값을 0으로 설정
public Extend0() {
this.i = 0;
}
}
//하위 클래스 생성
class Extend1 extends Extend0 {
int i;
//i값을 1로 설정
public Extend1() {
this.i = 1;
}
//상위 i값 반환
int getsuperI() {
return super.i;
}
}
public class Inheritance {
public static void main(String[] args) {
Extend1 e1 = new Extend1();
System.out.println("extend1의 i값: "+e1.i); // 1
System.out.println("extend1의 상위 i값: "+e1.getsuperI()); // 0
}
}
✍️ 실행화면
extend1의 i값: 1
extend1의 상위 i값: 0
<//상위 클래스 생성
class Extend0 {
int i;
//i값을 0으로 설정
public Extend0() {
this.i = 0;
}
}
//하위 클래스 생성
class Extend1 extends Extend0 {
int i;
//i값을 1로 설정
public Extend1() {
this.i = 1;
}
//상위 i값 반환
int getsuperI() {
return super.i;
}
}
//Extend2는 Extend1의 하위클래스
class Extend2 extends Extend1{
int i;
public Extend2() {
this.i = 2;
}
}
public class Inheritance {
public static void main(String[] args) {
Extend0 e0 = new Extend0();
Extend1 e1 = new Extend1();
Extend2 e2 = new Extend2();
System.out.println("extend0의 i값: "+e0.i); //0
System.out.println("extend1의 i값: "+e1.i); //1
System.out.println("extend1의 상위 클래스의 i값: "+e1.getsuperI()); //0
System.out.println("extend2의 i값: "+e2.i); //2
System.out.println("extend2의 상위 클래스의 i값: "+e2.getsuperI()); //0
//getsuperI()는 e2의 상위클래스인 e1의 메소드: 따라서 e1의 상위클래스인 e0의 i값 반환
}
}
✍️ 실행화면
extend0의 i값: 0
extend1의 i값: 1
extend1의 상위 클래스의 i값: 0
extend2의 i값: 2
extend2의 상위 클래스의 i값: 0
🔍 e2에게도 getsuperI()가 있다면 어떨까?
반환형, 메소드 이름, 매개변수 개수, 매개변수 타입이 동일해야한다.
@Override
로 컴파일러에게 알려준다. (없어도 실행이 되기는 하지만 써야함!!)
//Extend2는 Extend1의 하위클래스
class Extend2 extends Extend1{
int i;
public Extend2() {
this.i = 2;
}
@Override
int getsuperI() {
return super.i;
}
}
public class Inheritance {
public static void main(String[] args) {
Extend0 e1 = new Extend0();
Extend1 e1 = new Extend1();
Extend2 e2 = new Extend2();
System.out.println("extend0의 i값: "+e0.i); //0
System.out.println("extend1의 i값: "+e1.i); //1
System.out.println("extend1의 상위 클래스의 i값: "+e1.getsuperI()); //0
System.out.println("extend2의 i값: "+e2.i); //2
System.out.println("extend2의 상위 클래스의 i값: "+e2.getsuperI()); //1
//e2의 오버라이딩된 getsuperI()호출 : e2의 부모클래스인 e1값 호출
}
}
✍️ 실행화면
오버라이딩 전: extend2의 상위 클래스의 i값: 0
오버라이딩 후: extend2의 상위 클래스의 i값 : 1
extend0의 i값: 0
extend1의 i값: 1
extend1의 상위 클래스의 i값: 0
extend2의 i값: 2
extend2의 상위 클래스의 i값: 1
//상위클래스 클래스명 = new 하위클래스의 생성자;
Extend0 e00 = new Extend1();
스택영역 : 지역변수,참조변수등이 저장되는 곳
힙영역 : 인스턴스가 저장되는 영역
메소드영역(코드영역) : 메소드가 저장되는 영역
👉 같은 객체의 인스턴스들은 동일한 메소드 영역을 참조해서 사용한다.
: 각 메소드 이름과 실제 메소드가 저장된 메모리주소
싱위클래스형으로 묵시적 형변환을 한 인스턴스에 오버라이딩된 메서드가 존재할 때 생성된 인스턴스의 메서드가 실행된다.
✍️ 예시코드
Extend0 e00 = new Extend1();
//상위클래스로 형변환이 된 경우에는 본래 클래스의 변수를 사용할 수 없다.
System.out.println(e00.e0); //가능
// System.out.println(e00.e1); //오류
//상위클래스로 형변환이 된 경우에는 본래 클래스의 메소드를 사용할 수 없다.
e00.extend0f(); //가능
// newe1.extend1f(); //오류
//오버라이딩 된 경우에만 본래 클래스의 메소드 사용가능
e00.extendf();
조금 뒤죽박죽으로 정리를 한 것 같긴하다...
좋은 글 감사합니다!