[자바의정석]Chapter 07. 객체지향 프로그래밍 II

seungwon·2023년 1월 10일
0

자바의 정석

목록 보기
7/14

1. 상속(inheritance)

1.1 상속의 정의 & 장점

기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것

코드의 재사용성을 높이고 코드의 중복을 제거-> 프로그램의 생산성과 유지보수에 큰 기여

extends

ex)

class Child extends Parent { 
	// ...
}

조상 클래스 : 부모(parent)클래스, 상위 (super)클래스, 기반(base)클래스
자손 클래스 : 자식 (child)클래스, 하위 (sub)클래스, 파생된 (derived) 클래스

인스턴스를 생성하면 조상 클래스의 멤버와 자손 클래스의 멤버가 합쳐진 하나의 인스턴스로 생성된다.

*생성자와 초기화 블력은 상속되지 않는다. 멤버만 상속된다.

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

클래스내에 다른 클래스를 멤버변수로 선언하여 포함할 수 있음

class Point{
	int x;
    int y;
}

class Circle{
	Point c = new Point(); 
    int r;
}

상속관계 : ‘~은~이다.(is-a)’
포함관계 : ‘~은 ~을 가지고있다.(has-a)’

1.4 단일 상속(single inheritance)

↔️ 다중상속 : 자바에서 지원x

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

자동으로 Object클래스로부터 상속받게 함

ex)

-> toString(), equals() 사용 가능


2. 오버라이딩(overriding)

2.1 오버라이딩이란?

조상 클래스로부터 상속받은 메서드의 내용을 변경하는 것

2.2 오버라이딩의 조건

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

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

접근 제어자(access modifier)와 예외(exception)는 제한된 조건 하에서만 다르게 변경할 수 있다.
단,

  • 접근 제어자는 조상 클래스의 메서드보다 넓거나/같은 범위로만 변경 가능
  • 조상 클래스의 메서드보다 많은 수의 예외 - 단순한 개수 x
    (Exception : 모든 예외의 가장 상위 -> 가장 많은 예외를 던질 수 있음)를 선언할 수 없음
  • 인스턴스메서드->static메서드/그 반대로 변경할 수 없다.

2.4 super

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

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

Object 클래스를 제외한 모든 클래스의 생성자 첫 줄에 생성자 this( ) 또는 super( ) 를 호출해야 한다. 그렇지 않으면 컴파일러가 자동적으로 super(); 를 생성자의 첫 줄에 삽입한다.

*생성자가 정의되어 있는 클래스에는 컴파일러가 기본 생성자를 자동적으로 추가하지 않는다.

Point3D(int x, int y, int z) { // Point클래스를 상속 받은 클래스
	super(); //Point()가 없는 경우 super(x,y)로 변경 = Point(int x, int y) 호출
	this.x = x; 
    this.y = y; 
    this.z=z;

Point 클래스에 생성자 Point() 가 정의되어 있지 않으면 에러가 남
-> Point 클래스에 Point()를 추가하거나 생성자 Point3D(int x, int y, int z)의 첫줄에 Point(int x, int y)를 호출하도록 변경


3. package와 import

3.1 패키지(package)

패키지 : 클래스의 묶음 (클래스/인터페이스 포함)
클래스들을 그룹단위로 묶어 놓은 것, 물리적으로는 하나의 디렉토리

java.lang.String : java.lang패키지에 속한 String클래스

클래스 : 물리적으로 하나의 클래스 파일(.class)

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

패키지를 선언하지 않으면 자바에서 기본 제공하는 이름없는 패키지(unnamed package)에 속함

3.2 패키지의 선언

package 패키지명

  • 패키지 선언문은 반드시 소스파일에서 주석과 공백을 제외한 첫 번째 문장
  • 하나의 소스파일에 단 한번만 선언될 수 있음

3.3 import문

컴파일러에게 소스파일에 사용된 클래스의 패키지에 대한 정보를 제공
(다른 패키지의 클래스를 편리하게 사용하기 위함)

  • import문을 지정하지 않았다면 클래스 이름에 패키지 명도 적어줘야 함
  • java.lang패키지는 import문으로 따로 지정하지 않아도 묵시적으로 import문이 선언되어 있음
    (java.lang 패키지 \supset System, String 클래스)
  • 일반적인 소스파일 (*.Java)의 구성
    1. package문
    2. import문
    3. 클래스 선언

import문에서 클래스 이름 대신 *을 사용하는 것이 하위 패키지의 클래스까지 포함하지는 x
ex)
import java.util.*; + import java.text.* \neq import java.*;

3.5 static import 문

static import문을 사용하면 static멤버를 호출할 때 클래스 이름을 생략 가능
-> 특정 클래스의 static 멤버를 자주 사용할 때 편리

ex)
static java.lang.Math.random; -> System.out.println(random());
import static java.lang.System.out; -> out.println(random();


4. 제어자(modifier)

4.1 제어자

클래스, 변수 또는 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여

  • 접근 제어자 : public, protected, default, private
  • 그 외 : static, final, abstract, native, transient, synchronized, volatile, strictfp
  • 제어자는 클래스나 멤버변수/메서드에 주로 사용됨, 여러 제어자를 조합하여 사용 가능
  • 단, 접근제어자는 한번에 한개만 사용 가능

종류

1. static : 클래스의,공통적인

사용될 수 있는 곳 : 멤버변수, 메서드, 초기화 블럭

대상의미
멤버변수-모든 인스턴스에 공통적으로 사용되는 클래스변수가 된다. \\-클래스변수는 인스턴스를 생성하지 않고도 사용 가능하다. \\-클래스가 메모리에 로드될 때 생성된다.
메서드- 인스턴스를 생성하지 않고도 호출이 가능한 static 메서드가 된다. - static메서드 내에서는 인스턴스멤버들을 직접 사용할 수 없다.

\\

2. final : 마지막의,변경될 수 없는

사용될 수 있는 곳 : 클래스, 메서드, 멤버변수, 지역변수

대상의미
클래스변경/확장될 수 없는 클래스 -> final로 지정된 클래스는 다른 클래스의 조상이 될 수 없다.
메서드변경될 수 없는 메서드 -> 오버라이딩을 통해 재정의 될 수 없다.
멤버변수/지역변수변수 앞에 final이 붙으면 값을 변경할 수 없는 상수

생성자를 이용한 final멤버 변수의 초기화

일반적으로 선언과 초기화를 동시에 하지만,인스턴스 변수의 경우 생성자에서 초기화 되도록 할 수 있음
-> 각 인스턴스마다 final이 붙은 멤버변수가 다른 값을 갖도록 하는 것
이 가능

3. abstract : 추상의,미완성의

추상 메서드를 선언하는데 사용(메서드의 선언부만 작성하고 실제 수행내용은 구현하지 않은 메서드)

대상의미
클래스클래스 내에 추상 메서드가 선언되어 있음을 의미한다.
메서드선언부만 작성하고 구현부는 작성하지 않은 추상 메서드임을 알린다.
  • 추상 클래스 : 아직 완성되지 않은 메서드가 존재하는 '미완성 설계도' -> 인스턴스를 생성할 수 없음
    (드물지만 추상 메서드가 없는 클래스, 즉 완성된 클래스도 abstract를 붙여서 추상 클래스로 만드는 경우도 있음)

4.5 접근 제어자(access modifier)

접근 제어자가 사용될 수 있는 곳 - 클래스, 멤버변수, 메서드, 생성자

public > protected > (default) > private

  • private : 같은 클래스 내에서만 접근이 가능하다.
  • default : 같은 패키지 내에서만 접근이 가능하다.
  • protected : 같은 패키지 내에서 + 다른 패키지의 자손클래스에서 접근이 가능
  • public : 접근 제한이 전혀 없다.
대상사용가능한 접근 제어자
클래스public, (default)
메서드/멤버변수public, protected, (default), private
지역변수없음

접근 제어자를 사용하는 이유 : 캡슐화

  • 외부로부터 데이터를 보호하기 위해서
  • 외부에는 불필요한(내부적으로만 사용되는) 부분을 감추기 위해서

생성자의 접근제어자가 private인 경우

인스턴스를 생성해서 반환해주는 public메서드를 제공함으로써 외부에서 이 클래스 의 인스턴스를 사용하도록 할 수 있다. 이 메서드는 public인 동시에 static이어야 한다.

class Singleton {
	private Singleton() {
    ...
    }
}


class Singleton {
	private static Singleton s = new Singleton();
	private Singleton(){
    	...
	}
    
    // 인스턴스를생성하지않고도 호출할 수있어야 하므로 static이어야한다. public static Singleton 	  getlnstance() {
		return s ;
	}
}
    

제어자 조합시 주의사항

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

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

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


5. 다형성

5.1 다형성이란?

’여러 가지 형태를 가질 수 있는 능력’

자바 : 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 함
= 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 함
(그 반대인 자손타입의 참조변수로 조상타입의 인스턴스를 참조할 수는 없다.)

조상클래스 타입의 참조변수(더 작은 크기를 예상했는데) 자손클래스의 인스턴스를 참조(더 큰것을 가리키는 것은 가능)

그 반대의 경우 구현되지 않은 함수나 변수를 예상하고 접근하려 할수 있음 = 에러

5.2 참조변수의 형변환

서로 상속관계에 있는 클래스 사이에서만 가능

  • 조상타입 <- 자손타입 (Up- casting) : 형변환 생략가능
    • 조상타입 참조변수 = 자손타입 객체
    • 사용할 수 있는 멤버가 제한됨
  • 자손타입 <- 조상타입(Down-casting) : 형변환 생략불가

\\
\\

  • 형변환은 참조변수의 타입을 변환하는 것이지 인스턴스를 변환하는 것은 아니기 때문에 참조변수의 형변환은 인스턴스에 아무런 영향을 미치지 않는다.
  • 단지 참조변수의 형변환을 통해서, 참조하고 있는 인스턴스에서 사용할 수 있는 멤버의 범위(개수)를 조절하는 것뿐이다.

5.3 instanceof 연산자

인스턴스의 실제 타입을 알아보기 위해 사용
참조변수 instanceof 타입(클래스명) : 참조변수가 검사한 타입으로 형변환이 가능하면 true

해당 클래스를 상속받은 클래스의 instance에 대해서도 true

ex)

void doWork(Car c) {
	if (c instanceof FireEngine) {
		FireEngine fe = (FireEngine)c; 
        fe.water ();
        ..
	} else if (c instanceof Ambulance) { 
    	Ambulance a = (Ambulance)c; 
        a.siren();
	}
}

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

  • 멤버변수 : 자손의 클래스에서 오버라이딩 한 경우 참조변수의 타입에 따라 달라진다.
  • 메서드 : 조상 클래스의 메서드를 자손의 클래스에서 오버라이딩한 경우에도 참조 변수의 타입에 관계없이 항상 실제 인스턴스의 메서드(오버라이딩된 메서드)가 호출됨

5.5 매개변수의 다형성

매개변수를 부모클래스 타입으로 받으면 상속받은 모든 자손클래스를 매개변수로 받을 수 있음

ex)

class Product { 
	int price;
	int bonusPoint;
}

class Tv extends Product{} 
class Computer extends Product{} 
class Audio extends Product{}

class Buyer {
	int money = 1000;
	int bonusPoint = 0;
}

void buy(Product p); : 함수 오버라이딩 없이 Tv, Computer, Audio에 대해 모두 사용 가능

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

조상 타입의 참조변수 배열 -> 자소타입의 객체 참조 가능


6. 추상클래스(abstract class)

== 미완성 설계도

추상[抽象] : 낱낱의 구체적 표상(表象)이나 개념에서 공통된 성질을 뽑아 이를 일반적인 개념으로 파악하는 정신 작용

인스턴스 생성x, 상속을 통해서 자손클래스에 의해서만 완성될 수 있다.
(=추상메서드 포함)

abstract class 클래스이름{
	...
}
  • 생성자, 멤버변수, 메서드 가짐
  • 추상클래스로부터 상속받는 자손클래스는 오버라이딩 해서 추상클래스의 추상 메서드를 모두 구현해주어야 함
    <-> 추상메서드 중 하나라도 구현하지 않는다면,자손클래스 역시 추상클래스로 지정해 주어야 한다

6.2 추상메서드(abstract method)

abstract 리턴타입 메서드이름();

자손 클래스에서 추상메서드를 반드시 구현하도록 강요하기 위해서 사용

6.3 추상클래스의 작성

  • 상속 : 자손 클래스를 만드는데 조상 클래스를 사용하는 것
  • 추상화 : 기존의 클래스의 공통부분을 뽑아내서 조상 클래스를 만드는 것 (<-> 구체화)

7. 인터페이스(interface)

7.1 인터페이스란

== 기본 설계도

추상클래스처럼 추상메서드를 갖지만 추상클래스보다 추상화 정도가 높음
-> 오직 추상메서드 + 상수만 멤버로 가짐 (일반메서드/멤버변수x)

7.2 인터페이스의 작성

interface 인터페이스이름 { 
	public static final 타입 상수이름 =;
	public abstract 메서드이름 (매개변수목록);
}

제약 사항

  • 모든 멤버변수는 public static final 이어야 하며,이를 생략할 수 있다.
  • 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다.
    (JDK1.8부터 static메서드와 디폴트 메서드 추가 가능)

7.3 인터페이스의 상속

인터페이스로부터만 상속받을 수 있음, 다중상속 가능

7.4 인터페이스의 구현

class 클래스이름 implements 인터페이스이름 {

} // 인터페이스에 정의된 추상메서드를 구현.
  • 인터페이스의 메서드 중 일부만 구현한다면,abstract를 붙여서 추상클래스로 선언
  • 상속과 구현을 동시에 할 수도 있음 (ex.class Fighter extends Unit implements Fightable{..})
    • 인터페이스의 이름은 주로 ~able
  • 오버라이딩 할 때는 조상의 메서드보다 넓은 범위의 접근제어자를 지정해야 함

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

  • 인터페이스는 다중상속이 가능하지만 거의 사용x
  • 만일 두 개의 클래스로부터 상속을 받아야 할 상황이라면,두 조상클래스 중에서 비중이 높은 쪽을 선택하고 다른 한쪽은 클래스 내부에 멤버로 포함시키는 방식으로 처리

ex)

public class TVCR extends Tv implements IVCR { 
	VCR vcr = new VCR();
	
    public void play(){
		vcr.play();
	}
	public void stop() { 
    	vcr.stop();
	}
	public void reset() { 
    	vcr.reset();
	}
	public int getCounter()
		return vcr.getCounter();
    }
    public void setCounter(int c) { 
   		vcr.setCounter(c);
	}
}

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

인터페이스 : 구현한 클래스의 조상
-> 해당 인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있음, 형변환 가능

ex) Fightable f = (Fightable)new Fighter(); or Fightable f = new Fighter();

매개변수의 타입이나
void attack(Fightable f);

리턴 타입으로도 사용 가능

Fightable method() {
	Fighter f = new Fighter(); 
    return f;
	// = return new Fighter();
}

"리턴타입이 인터페이스"
= 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환

7.7 인터페이스의 장점

  • 개발시간을 단축시킬 수 있다.
    인터페이스를 구현하는 클래스를 작성하는 동안 이를 사용하는 쪽도 동시에 개발할 수 있다.

  • 표준화가 가능하다.
    기본틀을 인터페이스로 작성 -> 구현

  • 서로 관계없는 클래스들에게 관계를 맺어줄 수 있다.
    인터페이스를 이용해서 클래스의 선언과 구현을 분리 -> 실제구현에 독립적인 프로그램 작성

    ex)
    -> SCV, Tank, Dropship 클래스 에 대해서만 repair()를 추가하고 싶다면 인터페이스 활용

  • 독립적인 프로그래밍이 가능하다.

7.8 인터페이스의 이해

  • 클래스를 사용하는 쪽 (User)과 클래스를 제공하는 쪽 (Provider) 이 있다.
  • 메서드를 사용(호출)하는 쪽(User)에서는 사용하려는 메서드의 선언부만 알면 된다.(내용은 몰라도 된다)

인터페이스를 사용할 때의 장점
: 클래스를 사용하는 쪽이 클래스의 변경에 영향을 받지 않는다

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

인터페이스에 추상 메서드만 선언할 수 있다
<-> JDK1.8부터 디폴트 메서드와 static 메서드도 추가할 수 있게 됨

ex) java.util.Collection 인터페이스, 이와 관련된 static 메서드들 : Collections라는 클래스

👽 default method

추상 메서드의 기본적인 구현을 제공하는 메서드

public default+함수 (public은 생략 가능)
ex) default void newMethod(){ .. }

  • 필요성 : 인터페이스에 메서드를 추가하면 이 인터페이스를 구현한 기존의 모든 클래스들이 새로 추가된 메서드를 구현해야 한다 \\
    -> 디폴트 메서드 \neq 추상메서드 -> 기존의 클래스드를 변경하지 않아도 됨

  • 기존의 메서드와 이름이 중복되어 충돌하는 경우

    • 여러 인터페이스의 디폴트 메서드 간의 충돌
      : 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩해야 한다.
    • 디폴트 메서드와 조상 클래스의 메서드 간의 충돌
      : 조상 클래스의 메서드가 상속되고. 디폴트 메서드는 무시된다.
      -> 그냥 필요한 쪽의 메서드와 같은 내용으로 오버라이딩 해도 됨

8. 내부클래스 (inner class)

클래스 내에 선언된 클래스
(두 클래스가 서로 긴밀한 관계에 있는 경우 사용)

장점

  • 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 있다.
  • 코드의 복잡성을 줄일 수 있다(캡슐화).

class Outer {
	private class Instancelnner {}
    protected static class Staticlnner {}
	
    void myMethod( ) { 
    	class Locallnner {}
	}
}
  • 접근 제어자 : abstract, final, private, protected 사용 가능

  • 지역클래스 : 지역 클래스가 포함된 메서드에 정의된 지역변수는 final 이 붙은 지역변수만 접근 가능
    (∵ 메서드가 수행을 마쳐서 지역변수가 소멸된 시 점에도,지역 클래스의 인스턴스가 소멸된 지역변수를 참조하려는 경우가 발생할 수 있기 때문)

ex)

class InnerEx3 {
	private int outerlv = 0; 
    static int outerCv = 0;

	class Instancelnner {
		int iiv = outerlv; // 외부 클래스의 private멤버도 접근가능하다. 
        int iiv2 = outerCv;

	static class Staticlnner {
        // 스태틱 클래스는 외부 클래스의 인스턴스멤버에 접근할 수 없다.
        // int siv = outerlv;

        static int scv = outerCv;
	}

	void myMethod() { 
    	int lv = 0;
		final int LV = 0; // JDK1.8부터 社nal 생략가능

        class Locallnner {
            int liv = outerlv; 
            int liv2 = outerCv;
    // 외부 클래스의 지역변수는 final이 붙은 변수 (상수)만 접근가능하다.
    // int liv3 = lv; // 에러!!!(JDK1.8부터 final 생략 가능)
            int liv4 = LV; // OK
        }
	}
}

8.5 익명 클래스(annonymous class)

클래스의 선언과 객체의 생성을 동시에
= 단 한번만 사용, 오직 하나의 객체만을 생성

생성자x, 상속+인터페이스 구현 x, 둘 이상의 인터페이스 구현 x

ex)

class InnerEx6 {
	Object iv = newObject(){ void method(){} }; // 익명 클래스
    static Object cv = newObject(){ voidmethod(){} }; //익명 클래스
	
    void myMethod() {
    	Objectlv=newObject(){ void method(){} }; // 익명 클래스
    }
}
  • 예제 7-37 -> 예제 7-38(익명클래스 이용)

1개의 댓글

comment-user-thumbnail
2023년 12월 8일

Sometimes, setup files outside of the game can be used to change certain settings. You can usually find the game's setup files in the installation directory. Check those out to see if you can make changes right there. quordle

답글 달기