클래스의 상속1: 상속의 기본

gustjtmd·2022년 1월 28일
0

Java

목록 보기
9/40

상속의 기본 문법 이해

상속에 대한 매우 치명적인 오해

"상속은 코드의 재활용을 위한 문법입니다", 
상속의 코드는 재활용을 묵적으로 사용하는 문법이 아니다. 연관된 일련의 클래스들에 대해 공통적인 규약을 정의할 수 있다.

상속의 기본적인 특성

class Man{
    String name;
    public void tellYourName(){
        System.out.println("My name is " +name);
    }
}

class BusinessMan extends Man{
    String compnay;
    String position;
    public void tellYourInfo(){
        System.out.println("My company is "+compnay);
        System.out.println("My position is "+position);
        tellYourName(); //Man 클래스를 상속했기 때문에 호출 가능
    }
}

BusinessMan 인스턴스에는 Man 클래스의 변수와 메소드가 존재한다 
이는 BusinessMan 클래스가 Man 클래스를 상속했기 때문이다. 
때문에 BusinessMan 클래스 내에서는 tellYourName 메소드를 호출할 수 있다.
이것이 '상속의 가장 기본적인 특성'

'만약 상위 클래스의 멤버를 private으로 선언하면 하위 클래스에서 존재는 하지만 접근은 불가'

상속의 관계의 UML구도

상속과 생성자

코드로 확인해보자

class SuperCLS{
    public SuperCLS(){  //생성자
        System.out.println("I'm Super Class");
    }
}
class SubCls extends SuperCLS{
    public SubCls(){
        System.out.println("I'm Sub Class");
    }
}
public class SuperSubCon {
    public static void main(String[] args) {
        new SubCls();
    }
}


I'm Super Class
I'm Sub Class

---------------------------------------------------------------------

위의 실행 결과는 다음 사실을 알려준다

"하위 클래스의 인스턴스 생성시 상위 클래스, 하위 클래스의 생성자 모두 호출한다."
"하위 클래스의 인스턴스 생성시 상위 클래스의 생성자가 먼저 호출된다."

class SubCls extends SuperCLS{
    public SubCls(){
    	SuperCLS();	//상위 클래스의 생성자가 이 순간에 호출됨을 의미함.
        System.out.println("I'm Sub Class");
    }
}

위 코드에서 보이듯이 하위 클래스의 생성자에서 상위 클래스의 생성자를 명시적으로 호출하지
않으면 인자를 받지 않는 생성자가 자동 호출된다. 
키워드 super를 이용해서 명시적으로 호출해보자

class SuperCLS{
    public SuperCLS() {
        System.out.println("Con : SuperCLS()");
    }
    public SuperCLS(int i){
        System.out.println("Con: SuperCLS(int i)");
    }
    public SuperCLS(int i, int j){
        System.out.println("Con: SuperCLS(int i, int j)");
    }
}

class SubCLS extends SuperCLS{
    public SubCLS(){
        super();
        System.out.println("Con : SubCLS()");
    }
    public SubCLS(int i){
        super(i);
        System.out.println("Con: SubCLS(int i)");
    }
    public SubCLS(int i, int j){
        super(i,j);
        System.out.println("Cond: SubCLS(int i, int j)");
    }
}

public class SuperSubCon2 {
    public static void main(String[] args) {
        System.out.println("1");
        new SubCLS();
        System.out.println();

        System.out.println("2");
        new SubCLS(1);
        System.out.println();

        System.out.println("3");
        new SubCLS(1,2);
        System.out.println();
    }
}


1
Con : SuperCLS()
Con : SubCLS()

2
Con: SuperCLS(int i)
Con: SubCLS(int i)

3
Con: SuperCLS(int i, int j)
Cond: SubCLS(int i, int j)

----------------------------------------------------------------------

이렇듯 생성자 내에서 사용된 키워드 super'상위 클래스의 생성자 호출'을 의미한다.
그리고 다음과 같은 방식으로 호출할 상위 클래스의 생성자를 지정한다.

super(1);	//1을 인자로 전달받을수 있는 생성자 호출
super(1,2);	//1과 2를 인자로 전달받을수 있는 생성자 호출

상위 클래스의 생성자는 하위 클래스의 몸체 부분에 앞서 실행되어야 한다.
항상 첫 문장으로 등장해야 한다.

public SubCLS(int i){
	System.out.println("...");
    	super(i);	//이 위치에 있으면 컴파일 오류
}

상속 관계에 있는 두 클래스의 적절한 생성자 정의

자바는 상속 관계에 있을지라도 상위 클래스의 멤버는 상위 클래스의 생성자를 통해서
초기화하도록 권장한다. 코드로 확인하자

class Man{
    private String name;

    public Man(String name){
        this.name = name;
    }
    public void tellYourName(){
        System.out.println("My name is " +name);
    }
}

class BusinessMan extends Man{
    String compnay;
    String position;
    public BusinessMan(String name, String company, String position){
        super(name);
        this.compnay = company;
        this.position = position;
    }

    public void tellYourInfo(){
        System.out.println("My company is "+compnay);
        System.out.println("My position is "+position);
        tellYourName(); //Man 클래스를 상속했기 때문에 호출 가능
    }
}
public class MyBusinessMan {
    public static void main(String[] args) {
        BusinessMan man = new BusinessMan("SEO","??","Staff");
        man.tellYourInfo();
    }
}

My company is ??
My position is Staff
My name is SEO

-----------------------------------------------------------------------

위 코드에서는 상속 관계에 있는 두 클래스의 적절한 생성자 정의 모델을 보이고 있다.
결론은 상속 관계에 있을지라도 인스턴스 변수는 각 클래스의 생성자를 통해서 초기화해야 한다는 것.

단일 상속만을 지원하는 자바

자바는 프로그램이 과도하게 복잡해지는 것을 막기 위해 단일 상속만을 지원한다
하나의 클래스가 상속할 수 있는 클래스는 최대 하나.

class AAA{}
class ZZZ extends AAA {}

상속의 깊이를 더하는 것은 가능하다

class AAA{}
class ZZZ extends AAA {}
class MMM extends ZZZ {}

클래스 변수, 클래스 메소드와 상속

static 선언이 붙는 '클래스 변수'와 '클래스 메소드'의 상속

클래스 변수와 클래스 메소드의 특징을 정리하면 다음과 같다.

1. 인스턴스의 생성과 상관이 없이 접근이 가능하다
2. 클래스 내부와 외부에서(접근 수준 지시자가 허용하면) 접근이 가능하다.
3. 클래스 변수와 클래스 메소드가 위치한 클래스 내에서는 직접 접근이 가능하다.

즉 클래스 변수와 클래스 메소드는 인스턴스에 속하지 않는 딱 하나만 존재하는 변수와 메소드이다.
따라서 상속의 대상이 아니다.

그러나 변수의 이름만으로 접근이 가능하다
즉 상위 클래스와 마찬가지로 이를 상속하는 하위 클래스에서도 이름만으로 클래스 변수와
클래스 메소드에 접근이 가능하다 단 선언된 접근 수준 지시자가 접근을 허용해야 접근이 가능하다.

protected, private


protected는 하위 클래스의 접근을 허용
private으로 선언이 되면 '클래스 내부에서만 접근 가능 하위 클래스는 접근 불가능하다.'

코드를 통해 확인해보자 

class SuperCL{
    protected static int count = 0; //protected는 하위 클래스의 접근을 허용한다.

    public SuperCL(){
        count++;
    }
}
class SubCL extends SuperCL{
    public void showCount(){
        //상위 클래스에 위치한 클래스 변수 count에 접근
        System.out.println(count);
    }
}
public class SuperSubStatic {
    public static void main(String[] args) {
        SuperCL obj1 = new SuperCL(); //count값 1 증가
        SuperCL obj2 = new SuperCL(); //count값 1 증가

        // 아래 인스턴스 생성 과정에서 SuperCL 생성자 호출되므로
        SubCL obj3 = new SubCL();   // count값 1 증가
        obj3.showCount();
    }
}


3

--------------------------------------------------------------------


private으로 변경해보기

class SuperCL{
    private static int count = 0; 

    public SuperCL(){
        count++;
    }
    public void showCount(){
        System.out.println(count);
    }
}
class SubCL extends SuperCL{
	public void showCount(){
        //private 선언 되었으므로 상위 클래스에 위치한 클래스 변수 count에 접근불가
  	//     System.out.println(count); 컴파일 오류
    }
    
}
public class SuperSubStatic {
    public static void main(String[] args) {
        SuperCL obj1 = new SuperCL(); //count값 1 증가
        SuperCL obj2 = new SubCL(); //count값 1 증가

        // 아래 인스턴스 생성 과정에서 SuperCL 생성자 호출되므로
        SubCL obj3 = new SubCL();   // count값 1 증가
        obj1.showCount();
    }
}


3
profile
반갑습니다

0개의 댓글