Java의 정석 - Chapter7 객체지향 프로그래밍2

hoegon kim·2023년 8월 29일
0

JAVA

목록 보기
25/26
post-thumbnail

1. 상속(inheritance)

1.1 상속의 정의와 장점

상속이란, 기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것이다.

  • 기존의 클래스로 새로은 클래스를 작성하는 것
  • 두 클래스를 부모와 자식으로 관계를 맺어주는 것

사용하는 방법

class 자식클래스 extends 부모클래스 {
	// ....
} 

조상클래스 : 부모(parent)클래스, 상위(super)클래스, 기반(base)클래스

자손클래스 : 자식(childd)클래스, 하위(sub)클래스, 파생된(derived)클래스

  • 자손은 조상의 모든 멤버를 상속받는다.(생성자, 초기화블럭 제외)
  • 자손의 멤버 개수는 조상보다 적을 수 없다.(같거나 많다)

조상 클래스가 변경되면 자손 클랫는 자동적으로 영향을 받게 되지만, 자손클래스가 변경되는 것은 조상클래스에 아무런 영향을 주지 못한다.

즉, 상속을 거듭할수록 상속받는 클래스의 멤버 개수는 점점 늘어나게 된다.

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

※ 참고
접근제어자가 private 또는 default인 멤버들은 상속되지 않는다기 보다는 상속은 받지만 자손 클래스로 부터의 접근이 제한되는 것이다.

class Parent { }
class child extends Parent {} 
![](https://velog.velcdn.com/images/hoegon02/post/0480ef9a-e34f-4794-a5ae-c476df6b3058/image.png)
class child2 extends Parent {} 
class grandchild extends child {} 


1.2 클래스간의 관계 - 포함관계

클래스간의 관계를 맺어 주고 클래스를 재사용하는 방법

  • 상속
  • 포함관계

포함이란?

  • 클래스의 멤버로 참조변수를 선언하는 것

예제

여기서 다른 클래스에서 호출하고싶을때(예를들어 main함수) 인스턴스 객체이기 때문에 객체를 생성했을때

Circle c = new Circle(); 

왼쪽에서 코드의 참조변수 c가 가르키는 인스턴스 멤버변수는
c.x
c.y
c.r

오른쪽에서 코드의 참조변수 c가 가르키는 인스턴스 멤버변수는
c.c.x
c.c.y
c.r

이와 같이 한 클래스를 작성하는 데 다른 클래스를 멤버 변수로 선언하여 포함시크는 것은 좋은 생각이다.


1.3 클래스간의 관계 결정하기

상속관계 : ~은 ~이다
포함관계 : ~은 ~을 가지고 있다

① 포함 : 90% (잘모르겠다 하면 포함해서 코드개선)
② 상속 : 꼭 필요할때만


1.4 단일상속(single inheritance)

자바에서는 오직 단일 상속만을 허용한다.
둘이상의 클래스로 부터 상속을 받을 수 없다.

추상화(다중상속가능 메서드가 정의되지 않은 것이기 때문에)

단일 상속 : 하나의 클래스로부터 상속받는것을 단일 상속이라고 한다.

단일 상속을 하는 이유 : 두개의 조상클래스로 부터 상속을 받게된다면, 각각의 클래스 내부의 동일한 메서드명을가진 메서드끼리 충돌이 발생하게된다. 그러하면 오버로딩을 진행하여 매개변수를 변경해주거나 조상 클래스의 메서드명을 변경해줘야한다. 이렇게 하면 그 조상 클래스의 메서드를 사용하는 모든 클래스들도 변경을 해야하므로 그리 간단한 문제는 아니다.

자바에서는 다중상속의 이러한 문제점을 해결하기 위해 다중상속의 장점을 포기하고 단일 상속만을 허용한다.

장점 : 하나의 조상 클래스만을 가질 수 있기 때문에 다중상속에 비해 불편한 점도 있지만, 클래스 간의 관계가 보다 명확해지고 코드를 더욱 신뢰할 수 있게 만들어 준다는 점에서 다중상속보다 유리하다.

다중상속과 비슷한 효과를 나타내는 방법 :

① 하나의 조상클래스로부터 단일상속을 받는다.
② 두번째 해당하는 조상클래스를 클래스간의 관계에서의 포함관계를 이용하여 활용한다.

이러하면 메서드간의 충돌을 최소화할수 있다.


1.5 Object클래스 - 모든 클래스의 조상

  • 부모가 없는 클래스는 자동적으로 Object클래스를 상속받게 된다.
  • 모든 클래스는 Object클래스에 정의된 11개의 메서드를 상속받는다.

상속 계층도를 단순화하기 위해서는 Object클래스를 생략하는 경우가 많다.


2. 오버라이딩(overriding)

2.1 오버라이딩이란?

조상클래스로 부터 상속받은 메서드의 내용을 변경하는 것을 오버라이딩 이라고한다.

< 오버라이딩 1차 조건 >
① 조상클래스로부터 상속 받아야한다.
② 조상의 메서드를 오버라이딩 한다. (재정의한다.)
② 구현부를 수정한다.

ex

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;
    }
}


2.2 오버라이딩 조건

자손 클래스에서 오버라이딩하는 메서드는 조상 클래스의 메서드와

  • 이름이 같아야 한다.
  • 매개변수가 같아야 한다.
  • 반환타입이 같아야 한다.

한마디로 요약하면 선언부가 서로 일치해야한다.

다만, 접근 제어자와 예외는 제한된 조건 하에만 다르게 변경할 수 있다.

  1. 접근 제어자는 조상 클래스의 메서드보다 좁은 범위로 변경 할 수 없다.

만일 조상 클래스에 정의된 메서드의 접근 제어자가 protected라면, 이를 오버라딩하는 자손 클래스의 메서드는 접근 제어자가 protected나 public이어야 한다. 대부분의 경우 같은 범위의 접근 제어자를 사용한다. 접근 제어자의 접근범위를 넓은 것에서 좁은 것 순으로 나열하면 public, protected, (default), private이다.

  1. 조상 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.

코드로 이해

예외처리 + 오버라이딩을 진행할때 다음과같이 진행을 해야한다.

예외의 조상 Exception

조상 클래스의 메서드를 자손클래스에서 오버라이딩 할때

  1. 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.

  2. 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.

  3. 인스턴스메서드를 static메서드로 또는 그 반대로 변경할 수 없다.


2.3 오버로딩 vs 오버라이딩

오버로딩과 오버라이딩은 서로 혼동하기 쉽지만 사실 그 차이는 명백하다.

오버로딩(overloading) 적재한다

  • 기존에 없는 새로운 메서드를 정의하는 것 (new)
  • 조건1. 메서드명이 동일
  • 조건2. 매개변수 타입이 달라야함
  • 조건3. 반환타입 영향 없다

오버라이딩(overrriding) 덮어쓴다

  • 상속받은 메서드의 내용을 변경하는 것
  • 조건0. 상속받아야 한다.
  • 조건1. 이름이 같아야 한다.
  • 조건2. 매개변수가 같아야 한다.
  • 조건3. 반환타입이 같아야 한다.


2.4 super

super : super는 자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수 이다.

멤버변수와 지역변수의 이름이 같을 때 this를 붙여서 구별했듯이 상속받은 멤버와 자신의 멤버와 이름이 같을 때는 super를 붙여서 구별할 수 있다.

조상 클래스로부터 상속받은 멤버도 자손 클래스 자신의 멤버이므로 super 대신 this를 사용할 수 있다. 그래도 조상 클래스의 멤버와 자손클래스의 멤버가 중복 정의되어 서로 구별해야하는 경우에만 super를 사용하는 것이 좋다.

컴파일러 실행결과

① 컴파일러가 Child c = new Child(); 객체생성을 읽음
② c.method(); 호출
③ System.out.println("x=" +x); 메서드의 int x = 20; 을 가져옴
④ System.out.println("this.x=" +this.x); 메서드의 인스턴스 멤버변수를 가져옴
⑤ System.out.println("super.x=" +super.x); 조상의 초기값을 가져옴


2.5 super() - 조상 클래스의 생성자

this() 와 마찬가지로 super() 역시 생성자 이다. this()는 같은 클래스의 다른 생성자를 호출하는 데 사용하지만,

super()는 조상 클래스의 생성자를 호출하는데 사용된다.

자손 클래스의 인스턴스를 생성하면(상속을 받은 후 인스턴스 객체화를 진행하면) 자손의 멤버와 조상의 멤버가 모두 합쳐진 하나의 인스턴스가 생성된다. 즉 상속을 받게되면 상속받은 변수들은 조상 클래스의 멤버들을 사용하려면 초기화 작업이 수행되어야 하는데 이때 조상클래스의 멤버들의 초기화를 하는 방식이 super()를 사용하는 것이다.

인스턴스를 생성할 때 주의하고 생각해야되는 점
1. 클래스 - 어떤 클래스의 인스턴스를 생성할 것인가?
2. 생성자 - 선택한 클래스의 어떤 생성자를 이용해서 인스턴스를 생성할 것인가?

코드의 이해


3. Package와 import

3.1 패키지(package)

패키지 : 클래스의 묶음

String 클래스의 실제 이름은 java.lang.String 이다

java.lang 패키지에 속한 String 클래스 라는 의미이다.

클래스가 물리적으로 하나의 클래스파일(.class)인 것과 같이 패키지는 물리적으로 하나의 디렉토리이다.

개발자 규칙

  • 하나의 소스파일에는 첫 번쨰 문장으로 단 한 번의 패키지 선언만 허용한다.

  • 모든 클래스는 반드시 하나의 패키지에 속해야 한다.

  • 패키지는 점(.)을 구분자로 하여 계층구조로 구성할 수 있다.

  • 패키지는 물리적으로 클래스 파일(.class)을 포함하는 하나의 디렉토리 이다.


3.2 패키지의 선언

classpath 는 컴파일러(javac.exe)나 JVM등 클래스의 위치를 찾는데 사용되는 경로이다.

윈도우즈에서 환경 변수 설정하는 방버


3.3 import문

소스코드를 작성 할때 다른 패키지의 클래스를 사용하려면 패키지명이 포함된 클래스 이름을 사용해야한다.

클래스의 코드를 작성하기 전에 import문으로 사용하고자 하는 클래스의 패키지를 미리 명시해주면 소스코드에 사용되는 클래스이름에서 패키지명을 생략할 수 있다.

이클립스 단축키 ctrl + shift + o 를 누르면, 자동으로 import 문을 추가해주는 편리한 기능을 제공한다.

참고

import 문은 프로그램의 성능에 전혀 영향을 미치지 않는다. import 문을 많이 사용하면 컴파일 시간이 아주 조금 더 걸릴 뿐이다


3.4 import문의 선언

일반적인 소프아일 (*.java)의 구성은 다음의 순서로 되어있다.

① package문
② import 문
③ 클래스 선언


3.5 static import문

import 문을 사용하면 클래스의 패키지명을 생략할 수 있는 것과 같이 static import문을 사용하면 static멤버를 호출 할 때 클래스 이름을 생략할 수 있다. 특정 클래스의 static 멤버를 자주 사용할 때 편리하다.

ex

import static java.lang.Integer.*;
import static java.lang.Math.random;
import static java.lang.System.out;

만일 위와 같이 static import 문을 선언하였다면, 아래의 왼쪽 코드를 오른쪽 코드와 같이 간략히 할 수 있다.


4. 제어자(modifier)

4.1 제어자란?

제어자는 클래스, 변수 또는 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여한다. 제어자의 종류는 크게 접근 제어자와 그 외의 제어자로 나눌 수 있다.

접근 제어자 : public, protected, default, private
그 외 : static, final, abstract, native, transient, synchronized, volatile, strictfp

제어자는 클래스나 멤버변수와 메서드에 주로 사용되며, 하나의 대상에 대해서 여러 제어자를 조합하여 사용하는 것이 가능하다.

참고

제어자들 간의 순서는 관계없지만 주로 접근 제어자를 제일 왼쪽에 놓는 경향이 있다.


4.2 static - 클래스의, 공통적인


4.3 final - 마지막의, 변경될 수 없는


4.4 abstract - 추상의, 미완성의


4.5 접근 제어자(access modifier)

캡슐화와 접근 제어자

접근 제어자를 사용하는 이유?

  • 외부로부터 데이터를 보호하기 위해서, 직접 접근은 막고 메소드를 통한 간접 접근을 허용하려고

  • 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해서


4.6 제어자(modifier)의 조합

접근제어자 주의해야 할 점

  1. 메서드에 static과 abstract를 함께 사용할 수 없다.
    static 메서드는 몸통이 있는 메서드에만 사용할 수 있기 때문이다.

  2. 클래스에 abstract와 final을 동시에 사용할 수 없다.
    클래스에 사용되는 final은 클래스를 확장할 수 없다는 의미이고 abstract는 상속을 통해서 완성되어야 한다는 의미이므로 서로 모순되기 때문이다.

  3. abstract 메서드의 접근 제어자가 private일 수 없다
    abstract메서드는 자손 클래스에서 구현해주어야 하는데 접근 제어자가 private이면, 자손클래스에서 접근할 수 없기 때문이다.

  4. 메서드에 private과 final을 같이 사용할 필요는 없다.
    접근 제어자가 private인 메서드는 오버라이딩될 수 없기 때문이다. 이 둘 중 하나만 사용해도 의미가 충분하다.


5. 다형성

5.1 다형성이란?

  • 여러 가지 형태를 가질 수 있는 능력
  • 조상 타입 참조변수로 자손 타입 객체를 다루는 것
  • 객체와 참조변수의 타입이 일치할때와 일치하지 않을 때의 차이

※참고

클래스는 상속을 통해서 확장될 수는 있어도 축소 될 수는 없어서, 조상 인스턴스의 멤버 개수는 자손 인스턴스의 멤버 개수보다 항상 적거나 같다.

조상타입의 참조변수로 자손타입의 인스턴스를 참조할 수 있다.
반대로 자손타입의 참조변수로 조상타입의 인스턴스를 참조할 수는 없다.

Q. 참조변수의 타입은 인스턴스의 타입과 반드시 일치해야 하나요?
아닙니다. 일치하는 것이 보통이지만 일치 하지 않을 수도 있습니다.

Q. 참조변수가 조상타입일 때와 자손타입일 때의 차이?
참조변수로 사용할 수 있는 멤버의 갯수가 달라집니다.

Q. 자손 타입의 참조변수로 조상 타입의 객체를 가리킬 수 있나요?
아니요 허용되지 않습니다.


5.2 참조변수의 형변환

기본형 변수와 같이 참조변수도 형변환이 가능하다. 단, 서로 상속관게에 있는 클래스사이에서만 가능하기 때문에 자손타입의 참조변수를 조상타입의 참조변수로, 조상타입의 참조변수를 자손타입의 참조변수로의 형변환만 가능하다.

  • 결론 : 사용할 수 있는 멤버의 갯수를 조절하는 것
  • 조상 자손 관계의 참조변수는 서로 형변환 가능
  • 형제끼리는 불가능

5.3 instanceof 연산자

  • 참조변수의 형변환 가능여부 확인에 사용, 가능하며 true 반환
  • 형변환 전에 반드시 instanceof로 확인해야함

형변환 과정

① 확인 : 형변환 해도 되는지

  • 확인하는 방법은 instanceof 로 확인해야함

② 형변환

  • 확인하는 방법은 instanceof 로 확인해야함

확인하는 방법

void dowork(Car c) {
	if(c instanceof FireEngine) {
    	FireEngine fe = (FireEngine)c;
        fe.water();
    }
}

5.4 참조변수와 인스턴스의 연결


5.5 매개변수의 다형성


5.6 여러 종류의 객체를 배열로 다루기


6. 추상클래스(abstract class)

6.1 추상클래스란?


6.2 추상메서드(abstract method)


6.3 수창클래스의 작성


7. 인터페이스(interface)

7.1 인터페이스란?


7.2 인터페이스의 작성


7.3 인터페이스의 상속


7.4 인터페이스의 구현


7.5 인터페이스의 이용한 다중상속


7.6 인터페이스를 이용한 다형성


7.7 인터페이스의 장점


7.8 인터페이스의 이해


7.9 디폴트 메서드와 static 메서드


8. 내부 클래스(inner class)

8.1 내부 클래스란?


8.2 내부 클래스의 종류와 특징


8.3 내부 클래스의 선언


8.4 내부 클래스의 제어자와 접근성


8.5 익명 클래스(anonymouss class)


0개의 댓글