티스토리 뷰

PL/JAVA

[JAVA] 자바 - 상속

poopooreum 2024. 5. 25. 21:25
반응형

✏️ 상속

부모 클래스에 만들어진 필드와 메소드를 자식 클래스가 물려받는 것을 상속이라고 한다. 상속 선언을 하면, 자식 클래스는 부모 클래스에 만들어진 필드와 메소드를 만들지 않고도 사용할 수 있다. 다만 상속은 클래스 사이의 개념이므로 객체 사이의 상속이 아니다. 상속을 선언 할 때는 extends를 사용한다. 상속이 가져다주는 장점은 아래와 같다.

  • 클래스의 간결화 - 멤버의 중복 작성 불필요
  • 클래스 관리 용이 - 클래스들의 계층적 분류
  • 소프트웨어의 생산성 향상 - 클래스 재사용과 확장 용이

 

✏️ 상속 선언

아래 코드는 상속을 선언하고 자식 클래스에서 부모 클래스의 메소드를 사용하는 예시 코드이다. 
출력 결과는 (1,2) / red(3,4)이다.

class Point{
    private int x,y;
    public void set(int x,int y){
    	this.x=x;
        this.y=y;
    }
    public void showPoint(){
    	System.out.println(x+","+y);
    }
}

class ColorPoint extends Point{
    private String color;
    public void setColor(String color){
    	this.color = color;
    }
    public void showColorPoint(){
    	System.out.print(color);
        showPoint();
    }
}

public class ColorPointEx{
   public static void main(String []args){
    	Point p = new Point();
        p.set(1,2);
        p.showPoint();
        
        ColorPoint cp = new ColorPoint();
        cp.set(3,4);
        cp.setColor("red");
        cp.showColorPoint();
    }
}

 

 

✏️ 상속의 특징

  • 서브 클래스는 슈퍼 클래스의 private 멤버를 제외하고 모든 멤버를 접근할 수 있다. 위의 코드에서 살펴보면 객체 cp는 Point 클래스의 x와 y에 접근할 수 없다.
  • 자바에서는 클래스의 다중 상속을 지원하지 않으므로 extends 다음에는 한 개의 클래스만 올 수 있다.
  • 상속의 횟수에는 제한이 없다.
  • 자바의 계층 구조에서 최상위에는 java.lang.Object 클래스가 있다.

※ 다중 상속은 부모 클래스들이 같은 이름의 함수를 가지고 있는 경우, 함수 호출의 모호성으로 인해 복잡한 문제를 유발시켜서 자바는 클래스 다중 상속을 없앴다.

 

 

✏️ 슈퍼 클래스에 대한 접근 지정

슈퍼 클래스에 접근하는 클래스 종류 슈퍼 클래스 멤버의 접근 지정자
private 디폴트 protected public
같은 패키지에 있는 클래스 X O O O
다른 패키지에 있는 클래스 X X X O
같은 패키지에 있는 서브 클래스 X O O O
다른 패키지에 있는 서브 클래스 X X O O

 

class Person{
    private int weight;
    int age;
    protected int height;
    public String name;
    
    public void setWeight(int weight){
    	this.weight=weight;
    }

    public int getWeight(){
    	return weight;
    }
}

class Student extends Person{
    public void set(){
    	age=30;
    	name="홍길동";
        height=175;
        //weight=99;
        setWeight(99);
    }
}

public class InheritanceEx{
    public static void main(String [] args){
    	Student s = new Student();
        s.set();    	
    }
}

위의 코드는 접근 지정자에 따라 슈퍼 클래스 멤버 접근에 관한 예시로,  Student 클래스는 Person 클래스를 상속받아서 Person 클래스의 age, name, height에 값을 지정하고 setWeight() 메소드를 사용하는 모습이다.
다만, weight는 private로 지정되어서 서브 클래스에서 접근 할 수 없어 주석 처리를 하였다.

 

 

✏️ 상속과 생성자

서브 클래스와 슈퍼 클래스는 모두 생성자를 가지고 있는데, 여기서 몇 가지 의문점이 생길 수 있다.

  1. "서브 클래스 객체가 생성될 때 서브 클래스의 생성자와 슈퍼 클래스의 생성자가 모두 실행되는가? 아니면 서브 클래스의 생성자만 실행되는가?"  
    답 : 둘 다 실행된다. 서브 클래스의 객체가 생성되면 이 객체 속에 서브 클래스와 멤버와 슈퍼 클래스의 멤버가 모두 들어 있다. 생성자의 목적은 객체 초기화에 있으므로, 서브 클래스의 생성자는 생성된 객체 속에 들어 있는 서브 클래스의 멤버 초기화나 필요한 초기화를 수행하고, 슈퍼 클래스의 생성자는 생성된 객체 속에 있는 슈퍼 클래스의 멤버 초기화나 필요한 초기화를 각각 수행한다.
  2. "서브 클래스의 생성자와 슈퍼 클래스의 생성자 중 누가 먼저 실행되는가?"
    답 : 슈퍼 클래스의 생성자가 생성된 후 서브 클래스의 생성자가 실행된다.

좀 더 이해가 쉽도록 코드로 살펴보자.
B는 A를 상속받고, C는 B를 상속받았으므로 계층 구조는 A -> B -> C이다. main() 메소드에서 객체 c를 생성하였으므로 가장 먼저 C 클래스의 생성자를 호출하고 C 클래스에서는 B 클래스의 생성자를 호출하고 B 클래스에서는 A 클래스의 생성자를 호출한다. A 클래스가 가장 상위 계층이므로 차례대로 생성자 A를 출력 후 B 클래스에서 생성자 B를 출력하고 C 클래스에서 생성자 C를 출력하면 코드가 종료된다. 방금 위에서 언급했던 2번 방식으로 실행되는 것이 옮을을 알 수 있다.

class A{
    public A(){
    	System.out.println("생성자 A");
    }
}

class B extends A{
    public B(){
    	System.out.println("생성자 B");
    }
}

class C extends B{
    public C(){
    	System.out.println("생성자 C");
    }
}

public class ConstructorEx{
    public void static main(String [] args){
    	C c;
        c = new C();
    }
}

 

 

✏️ 서브 클래스에서 슈퍼 클래스 생성자 선택

슈퍼 클래스에 여러 개의 생성자가 있는 경우, 서브 클래스의 생성자와 함께 실행될 슈퍼 클래스의 생성자가 결정되는 방법을 알아보자. 다만, 서브 클래스의 각 생성자에 대해 함께 실행될 슈퍼 클래스의 생성자를 지정하여야 한다. 그러지 않는다면 자바 컴파일러가 자동으로 슈퍼 클래스의 기본 생성자를 호출할 것이다.

 

● 슈퍼 클래스의 기본 생성자가 자동 선택되는 경우

기본적으로 서브 클래스의 생성자가 기본 생성자이든 매개변수 생성자이든 상관없이 슈퍼클래스에 만들어진 기본 생성자가 선택되는데 이는 자바 컴파일러에 의해 강제로 이루어진다. 아래 코드를 참조하자.
클래스 A에는 기본 생성자와 매개변수 생성자가 있지만 개발자의 명시적 지시가 없으므로 컴파일러는 서브 클래스의 기본 생성자에 대해 자동으로 슈퍼 클래스의 기본 생성자와 짝을 맞춰준다. 출력 결과는 생성자A / 생성자 B이다. 만약, 클래스 A에서 매개변수 생성자만 있고 기본 생성자가 없다면 컴파일 오류가 발생한다.

class A{
    public A(){
    	System.out.println("생성자A");
    }
    public A(int x){
     	...
    }
}

class B extends A{
    public B(){
    	System.out.println("생성자B");
    }
}

public class ConstructorEx2{
    public static void main(String []args){
    	B b = new B();
    }
}

 

이 경우에는 클래스 B에 있는 매개변수 생성자를 호출하도록 개발자가 코드를 입력했지만, 클래스 A에서는 위의 코드와 똑같이 기본 생성자가 호출된다. 결과는 생성자 A / 매개변수생성자B 이다.

class A{
    public A(){
    	System.out.println("생성자A");
    }
    public A(int x){
     	System.out.println("매개변수생성자A");
    }
}

class B extends A{
    public B(){
    	System.out.println("생성자B");
    }
    public B(int x){
    	System.out.println("매개변수생성자B");
    }
}

public class ConstructorEx2{
    public static void main(String []args){
    	B b = new B(5);
    }
}

 

 

● super()를 이용하여 명시적으로 슈퍼 클래스의 생성자 선택

 

서브 클래스의 생성자에서 슈퍼 클래스의 생성자를 명시적으로 선택하는 것이 원칙이다. 위에서는 개발자가 명시적으로 선택하지 않았을 때 컴파일러가 자동으로 슈퍼 클래스의 생성자를 호출하는 경우를 살펴보았다.
이번에는 super()를 이용하여 슈퍼 클래스 생성자를 명시적으로 선택하는 경우를 알아보자
이 경우에는 main 메소드에서 클래스 B의 매개변수 생성자를 호출한 후, 클래스 B에서 super(x)를 통해 클래스 A의 매개변수 생성자를 호출하게 된다. 출력 결과는 매개변수생성자A / 매개변수생성자B 이다.

class A{
    public A(){
    	System.out.println("생성자A");
    }
    public A(int x){
     	System.out.println("매개변수생성자A");
    }
}

class B extends A{
    public B(){
    	System.out.println("생성자B");
    }
    public B(int x){
    	super(x);
    	System.out.println("매개변수생성자B");
    }
}

public class ConstructorEx2{
    public static void main(String []args){
    	B b = new B(5);
    }
}

※ 주의할 점으로는 super()는 반드시 생성자의 첫 라인에 사용되어야 한다.

 

 

반응형

'PL > JAVA' 카테고리의 다른 글

[JAVA] 자바 - 모듈과 패키지  (0) 2024.05.27
[JAVA] 자바 - 상속 2  (0) 2024.05.26
[JAVA] 자바 - 클래스와 객체  (0) 2024.05.23
[JAVA] 자바 - 배열와 예외 처리  (0) 2024.05.22
[JAVA] 자바 - 기본 프로그래밍  (0) 2024.05.22
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함