[스터디]Java의 정석 11일차

Kristopher·2022년 1월 6일
0

Java 스터디

목록 보기
11/31

(Ch7) 1. 상속 ~ 3.5 static import 문

클래스간의 관계 - 상속이란?

기존의 클래스를 재사용하여 새로운 클래스를 작성하는 방식을 말한다. 상속을 통해 중복되는 코드를 줄일 수 있으며 공통의 코드를 사용하기 때문에 관리가 용이하다.

//Child_class(자손 클래스), Parent_class(조상 클래스)
class Child_class extends Parent_class{
	// Child_class에 해당하는 코드 작성
}

상속은 작성하고자 하는 클래스에 extends를 붙이며, 상속을 받으면 Child_class에 Parent_class에서 작성한 코드도 포함되게 된다. 포함관계로 이해하자면 Child_class가 Parent_class를 포함하고 있으니 더 큰 개념으로 볼 수 있다.

상속이 이루어질 때 두가지 특징이 있다.

  1. 생성자와 초기화 블록은 상송되지 않는다. 멤버만 상속된다.
  2. 자손 클래스의 멤버 개수는 조상 클래스보다 많거나 같다.

클래스간의 관계 - 포함관계란?

상속이외에도 클래스를 재사용하는 방법으로 포함관계를 맺어주는 것이 있다. 아래의 코드를 보자.

class Point {
	int x; //x좌표
    int y; //y좌표
}

class Circle{
	int x; // x좌표
    int y; // y좌표
    int r; // 반지름(radius)
}

원을 표현하기 위한 클래스(Circle)과 좌표를 표현하기 위한 클래스(Point)가 존재한다. 사실 두 클래스는 좌표평면 위의 x,y좌표를 정의해야한다는 점에서 공통적인 성질을 갖기 때문에 다음과 같이 축약할 수 있다.

class Point {
	int x; //x좌표
    int y; //y좌표
}

class Circle{
    Point p = new Point(); 
    int r; // 반지름(radius)
}

이처럼 extends를 사용하지 않고 다른 클래스를 멤버변수로 선언하여 사용하면 코드의 중복을 피할 수 있고 효율적으로 관리할 수 있다. 그렇다면 앞에서 배운 상속과 포함관계의 차이는 무엇일까?

위에서 작성한 예시를 상속관계로 표현하면 다음과 같다.

class Circle extends Point{ 
    int r; // 반지름(radius)
}

결과적으로 살펴보면 상속과 포함관계가 차이가 없어 보인다. 이런 경우에는 is-a와 has-a를 넣어 비교해보면 어떤 것이 적절한지 파악할 수 있다.

Circle is a Point. // is-a가 자연스러우면 상속관계
Circle has a Point. // has-a가 자연스러우면 포함관계

두가지 문장을 보면 두번째 문장이 더 적절하다는 것을 알 수 있다. 그렇기에 Circle과 Point 클래스는 포함관계로 사용하는 것이 더 적절하다.

단일 상속의 원칙

자바에서는 하나의 조상 클래스에서만 상속을 받을 수 있는 단일 상속의 원칙을 고수한다. 다중 상속을 허용하게 된다면 코드가 더 간결해질수는 있으나, 클래스간의 관계가 매우 복잡해져 오히려 관리하기가 어려워진다는 단점이 있다.

Object 클래스란?

Object클래스는 최상위에 존재하는 조상클래스로 상속받지 않는 클래스의 경우 컴파일러가 자동으로 Object 클래스를 상속받도록 한다. 그렇기에 조상 클래스를 따라올라가다보면 Object 클래스에서 만나게 된다.

오버라이딩(Overriding)

조상 클래스를 상속받게 되면 멤버를 상속받기 때문에 메소드도 사용할 수 있게 된다. 하지만 조상 클래스에서 사용하는 메소드와 달리 자손 클래스에서 적용해야할 경우가 있을 것이다. 이러한 경우에 조상 클래스의 메소드를 오버라이딩하여(변형하여) 자손 클래스에서 사용하게 된다.

class Point {
	int x;
    int y;
    
    String getLocation(){
    	return "x :" + x+ "y : "+y;
    }
}
class Point3D extends Point{
	int z;
    
    String getLocation() {
    	return "x :" + x+ "y : "+y + "z : "+z;
    }
}

Point클래스를 상속받고 있는 Point3D클래스는 기존 2차원에서 사용하던 좌표를 반환하는 getLocation메소드를 3차원으로 확장하여 사용하면 z좌표가 추가로 필요하기 때문에 z좌표를 추가해서 오버라이딩한 모습이다. 오버라이딩을 하게 되면 기존 Point클래스를 사용하던 사용자들도 따로 메소드를 외울 필요 없이 같은 효과를 기대하고 사용하고 있으므로 긍정적 효과가 발생한다.

오버라이딩의 조건 ( 자손 클래스의 메소드와 조상 클래스의 메소드)
1. 이름이 같아야 한다.
2. 매개변수가 같아야 한다.
3. 반환타입이 같아야 한다.

조건을 요약하면 선언부에 존재하는 모든 값이 일치해야한다는 것이다. 다만 접근 제어자와 예외는 제한된 조건하에서 변경이 가능하다.

  1. 접근 제어자를 조상 클래스의 메소드보다 좁은 범위로 설정할 수 없다.
  2. 예외의 개수는 조상 클래스의 메소드보다 적어야 한다.
  3. 인스턴스 메소드를 static 메소드로 변경하거나 그 역이 성립할 수 없다.

super/super()의 개념

앞에서 this라는 단어를 사용하여 지역변수로 구분해주거나 다른 생성자를 불러왔다. 이와 비슷하게 상속받은 멤버와 자신의 멤버 이름이 같을 때 구별해주기 위해 super를 사용한다.

class SuperTest {
    public static void main(String args[]){
    Child c = new Child();
    c.method();
    }
}
class Parent{
    int x=10;
}
class Child extends Parent{
    int x=20;
    
    void method(){
    	System.out.println("x = "+x);
       	System.out.println("this.x = "+this.x);
	System.out.println("super.x = "+super.x);
    }
}
//실행결과
// x=20
// this.x = 20
// super.x = 10

실행 결과에서 볼 수 있듯이 Child 클래스 내부에서 x값을 변경하였지만 Parent에서 사용하고 있는 x값에는 영향을 주지 않아 super.x의 값이 10으로 출력되는 것을 볼 수 있다. 이는 변수뿐만 아니라 메소드에도 super를 붙여 호출할 수 있다.

this와 this()가 구분되었던것처럼 super()의 역할도 존재한다. this()는 같은 클래스내의 다른 생성자를 호출할 때 사용하지만, super()는 조상 클래스의 생성자를 호출하는데 사용한다. super()역시 생성자 코드의 첫줄에서 호출해야하며 그렇지 않으면 컴파일러가 자동으로 super();를 삽입한다.

package와 import

패키지란 클래스의 묶음이다. 관련된 클래스들끼리 묶어 클래스를 효율적으로 관리할 수 있으며, 다른 패키지에 존재하는 같은 이름의 클래스에 존재하는 것이 가능하므로 이름이 충돌하는 것을 막을 수 있다. 패키지는 주석과 공백을 제외한 첫줄에서 선언되어야 하며 하나의 소스파일에서 한번만 선언될 수 있다.

Reference

Java의 정석
남궁성의 정석코딩

profile
개발자 지망생입니다.

1개의 댓글

comment-user-thumbnail
2022년 1월 8일

오늘도 좋은글 잘 보고 갑니다!

답글 달기