(오키) 자바의정석, 2주차 챕터 7 - 객체지향 개념2

1. 상속

  • 기존의 클래스로 새로운 클래스를 작성 하는 것 (코드의 재사용)
  • 두 클래스를 부모와 자식으로 관계를 맺어 주는 것
1
2
3
class 자식클래스 extends 부모클래스 {
// ...
}

자식 —(extends/확장)—> 부모

1
2
3
4
5
6
7
8
class Point2D {
int x;
int y;
}

class Point3D extends Point2D {
int z;
}

3. 포함 관계 (Composite)

  • 클래스의 멤버로 참조 변수를 선언 하는 것
  • Cicle 안에 Point 의 참조 변수를 포함
1
2
3
4
5
6
7
8
9
10
11
12
13
class Circle {
int x, y, r;
}

class Circle {
Point c = new Point(); // 원점
int r; // 반지름
}

class Car {
Engine e = new Engine();
Door[] d = new Door[4];
}

차는 엔진과 4개의 도어를 포함

4. 클래스 간의 관계 결정 하기

  • 상속 관계 : A는 B이다. (is-a)
  • 포함 관계 : A는 B를 가지고 있다. (has-a)
1
2
3
4
5
6
7
8
class Circle {
point c = new Point();
int r;
}

class Circle extends Point {
int r;
}

대부분은 포함 일 것이다.

5. 단일 상속 (Single inheritance)

  • 자바는 단일 상속만 허용한다.
  • 조상은 하나만 허용 한다.
1
2
3
class TvDVD extends TV, DVD {  // 둘중에 하나만 가능

}
  • 비중이 높은 클래스하나만 상속 관계로 하고 나머지는 포함 관계로 하면
    다중 상속 처럼 구현 가능 하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class TV {
boolean power;
int channel;
void power() {power = !=power;}
}
class DVD {
boolean power;
void power() ..
void play() ..
void stop() ..
}
class TvDVD extends TV {
DVD dvd = new DVD();

void play () {dvd.play();}
...
}

6. Object 클래스 - 모든 클래스의 조상

  • 부모가 없는 클래스는 자동적으로 Object 클래스를 상속 받게 된다.
  • Object 클래스에 정의된 11개의 메소드를 상속 받는다.
  • toString(), equals(Object obj), hashCode() …

상속 계층도

  • SmartTV —> TV —> Object

7. 오버라이딩 (overriding)

  • 상속 받은 조상의 메서드를 자신에 맞게 변경 하는 것
  • 덮어 쓰기

8. 오버라이딩의 조건 3가지

9. 오버라이딩 vs. 오버로딩

  • 오버로딩 : 기존의 없는 메서드를 새로 정의
  • 오버라이딩 : 상속 받은 메서드의 내용을 변경, 재 정의

10. 참조 변수 super

  • 객체 자신을 가리키는 참조 변수

11. 조상의 생성자 super()

  • 생성자의 첫줄에 반드시 호출
  • 없다면 컴파일러가 자동으로 삽입 해줌
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
class Point {
int x;
int y;

point (int x, int y) {
this.x = x;
this.y = y;
}

String getLocation() {
return "x:"+x +"y:"+y;
}
}

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

컴파일 에러 발생, Point3D 생성자 첫줄에 super() 넣어짐
Point 클래스 정의에 기본 생성자가 없어 에러 발생

12. 패키지 (package)

  • 서로 관련된 클래스의 묶음
  • .class
  • 실제 이름(Full name) -> java.lang.String
  • rt.jar 에 압축된 파일, JDK 설치경로\jre\lib에 위치 (Java 8 까지)
  • Java9 부터는 rt.jar 없어짐, 모듈 개념이 생겨서 더 작은 단위로 쪼갬
  • package 선언 없으면 default package에 들어가게 됨

14. 클래스 패스 (classpath)

  • 클래스 파일의 위치를 알려주는 경로
  • 환경변수 classpath로 관리, 경로간의 구분자는 ; 를 사용

15. import 문

  • java.lang 패키지의 클래스는 import 하지 않고도 사용 할숭 ㅣㅆ다.
  • String, Object, System, Thread…
  • import 패키지명.클래스명; 또는 import 패키지명.*;

16. static import 문

  • static 멤버를 사용 할때 클래스 이름 생략 가능
1
2
3
import static java.lang.Integer.*; // 클래스의 모든 static 메서드
import static java.lang.Math.random; // Math 클래스의 random()만
import static java.lang.System.out; // System.out을 out 만으로 참조가능

17. 제어자 (modifier)

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

20. abstract - 추상의, 미완성의

  • 클래스 : 추상 메서드가 선언되어 있음을 의미한다.
  • 메서드 선언부만 작성하고 구현부는 작성 하지 않은 추상 메서드임을 알린다.
    추상 클래스의 인스턴스 생성 불가
1
2
3
abstract class AbstractTest {
abstract void move();
}

21. 접근 제어자

  • private 같은 클래스내에서만
  • default 같은 패키지내에서만
  • protected 같은 패키지내, 다른 패키지의 자손
  • public 접근 제한 없음

22. 캡슐화와 접근 제어자

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

  • 외부로부터 데이터를 보호 하기 위해서

23. 다형성 (polymorphism)

  • 여러가지 형태를 가질수 있는 능력
  • 조상 타입 참조 변수로 자손 타입 객체를 다루는 것

‘Tv t = new SmartTV();’ 타입 불일치 하지만 다룰수 있는 것

24. 참조 변수의 형 변환

  • 사용 할수 있는 멤버의 갯수를 조절 하는 것
  • 조상 자손 관계의 참조 변수는 서로 형변환 가능
  • 상속 관계가 아닌 클래스 간의 형 변환 불가

조상의 객체를 자식의 참조변수 대입 할때 명시적 형변환 하면 컴파일 에러는 안 생기시지만
런타임에서 형변환 실행 에러 가 발생 함. java.lang.ClassCastException

26. instanceof 연산자

  • 참조 변수의 형변환 가능여부 확인에 사용, 가능하면 true 반환
  • 형변환 전에 반드시 instanceof로 확인해야 함
1
2
3
4
5
6
7
void doWork(Car c) {
if (c instanceof FireEngine) {
FireEngine fe = (FireEngine) c;
fe.water();
...
}
}

다형성 정리

  1. 조상 = 자손 (예: Tv t = new SmartTV();)
  2. 참조 변수의 형변환 - 리모콘 바꾸기, 사용 가능한 멤버 갯수 조절
  3. instanceof 연산자 - 형변환 가능 여부 확인

27. 매개변수의 다형성

  • 참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손 타입의 인스턴스를 넘겨 줄수 있다.
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
class Product {
int price;
int bonusPoint;
}

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

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

// 각각의 Product 종류 마다 buy 메서드 작성
void buy(Tv t) {
money -= t.price;
bonusPoint += t.bonusPoint;
}

// 아래 처럼 매개변수의 다형성 사용 하면 하나의 buy 메서드로 처리 가능 해짐
void buy(Product p) {
money -= p.price;
bonusPoint += p.bonusPoint;
}

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

  • 조상 타입의 배열에 자손들의 객체를 담을 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();

Product p[] = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();

public class Vector extends AbstractList
implments List, Cloneable, java.io.Serializable
{
protected Object elementData[];

}

31 추상 클래스 (abstract class)

  • 미완성 설계도. 미완성 메서드를 갖고 있는 클래스
  • 다른 클래스 작성에 도움을 주기 위한 것. 인스턴스 생성 불가
  • 상속을 통해 추상 메서드 완성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
abstract class Player { // 추상 클래스, 미완성
boolean pause;
int currentPos;

Player() {
pause = false;
currentPos = 0;
}

abstract void play(int pos); // 추상 메서드 {}, 몸통 없음
abstract void stop();
}

Player p = new Player(); // 에러

class AudioPlayer extends Player {
void play(int pos) { /* ... */ }
void stop() { /* ... */ }
}

AudioPlayer ap = new AudioPlayer(); // 인스턴스 생성

32 추상 메서드 (abstract method)

  • 미완성 메서드. 구현부 몸통 {} 없는 메서드
  • 꼭 필요하지만 자손 마다 다르게 구현 될것으로 예상 되는 경우 사용
1
2
3
abstract class AbstractPlayer extends Player { // Player가 2개 추상 메서드
void play(int pos) { /* ... */ } // 1개만 구현 했음. 그래서 이 클래스도 abstract
}

33,34 추상 클래스의 작성

  • 상속 받는 자식 클래스가 꼭 구현해야 하는 메서드를 명시적으로 강제
  • 기존 클래스의 공통 부분을 뽑아서 추상 클래스를 만듬
  • 추상화 <-> 구체화
  • 추상화된 코드는 구체화된 코드보다 유연하다. 변경에 유리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GregorianCalendar cal = new GregorianCalendar(); // 구체적
Calendar cal = Calendar.getInstance(); // 추상적

public static Calendar getInstance(Local aLocale) {
return createCalendar(TimeZone.getDefault(), aLocale);
}

private static Calendar createCalendar(TimeZone zone, Local aLocale) {
// ...
if(caltype == 'budda') // 에 따라서 다른 caledar

else if (caltype == 'japanese')

else if (caltype == 'western')
}

35 인터페이스 (interface)

  • 추상 메서드의 집합
  • 구현된 것이 전혀 없는 설계도. 껍데기 (모든 멤버가 public)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface 인터페이스이름 {
public static final 타입 상수이름 = 값; //변수 iv, cv 안됨 오직 상수만
public abstract 메서드이름(매개변수목록); // 추상 메서드
}

interface PlayingCard {
public static final int SPADE = 4;
final int DIAMOND = 3;
static int HEART = 2; // public 이 생략됨
int CLOVER = 1; // final static 이 생략 됨

public abstract String getCardNumber();
String getCardKind(); // public abstract 이 생략 됨
}
  • 인터페이스의 조상은 인터페이스만 가능 (Object가 최고 조상 아님)
  • 다중 상속이 가능 (추상 메서드는 충돌 해도 문제 없음)
1
2
3
4
5
6
7
8
inteface Fightable extends Movable, Attackable { }
interface Movable {
void move(int x, int y);
}

interface Attackable {
void attack(Unit u);
}

37 인터페이스 구현

  • 인터페이스에 정의된 추상 메서드를 완성 하는 것
1
2
3
4
5
6
7
8
9
class 클래스이름 implements 인터페이스이름 {
// 인터페이스에 정의된 추상 메서드를 모두 구현 해야 한다.
}

class Fighter implements Fightable
{
public void move(int x, int y) { /* .. */ }
public void attack(Unit u) { /* .. */ }
}
  • 일부만 구현하는 경우, 클래스 앞에 abstract를 붙히면 됨
1
2
3
abstract class Fighter2 implements Fightable {
public void move(int x, int y) { /* .. */ }
}

정리

  • Q 인터페이스란?

(핵심) 추상 메서드의 집합
static 메서드, 디폴드 메서드가 JDK 1.8에 추가

  • Q 인터페이스 구현이라?

추상 메서드 몸통{} 만들기, 미완성 설계도 완성

  • Q 추상 클래스와 인터페이스의 공통점은?

추상 메서드를 가지고 있다 (미완성 설계도)

  • Q 추상 클래스와 인터페이스의 틀린점은?

cv, iv 을 가질수 없다

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

  • 인터페이스도 구현 클래스의 부모
  • 인터페이스 타입 매개변수는 인터페이스 구현한 클래스의 객체만 가능
  • 인터페이스를 메서드의 리턴타입으로 지정 할수 있다

39 인터페이스의 장점1

  • 두 대상 객체간의 연결 대화 소통을 돕는 중간 역할 을 한다
  • 선언(설계)와 구현을 분리 시킬수 있게 한다
  • 인터페이스 덕분에 B가 변경 되어도 A는 안 바꿀수 있게 된다. (느슨한 결합)

39 인터페이스의 장점2

  • 개발 시간을 단축
  • 변경에 유리한 유연한 설계 가능
  • 표준화 가능
  • 서로 관계 없는 클래스들에 대해 관계를 맺어 줄수 있다 (Collection의 상속 계층도)
    예:

Unit <-상속- GroundUnit, AirUnit
GroundUnit <-상속- Marine, SCV, Tank
Air Unit <-상속- Dropship
Repairable <-구현- SCV, Tank, Dropship

1
2
3
4
5
6
7
8
void repair(Repairable r) {
if (r instanceof Unit) {
Unit u = (Unit) r;
while (u.hitPoint != u.Max_UP) {
u.hitPoint++;
}
}
}

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

  • 인터페이스에 디폴트 메서드, static 메서드 추가 가능 (JDK1.8 부터)
  • 인터페이스에 새로운 메서드 (추상 메서드)를 추가 하기 어려움

해결책 => 디폴트 메서드 (default method) 소개

  • 디폴트 메서드는 인스턴스 메서드 (사실 인터페이스 원칙 위반)
1
2
3
4
5
6
7
8
9
interface MyInterface {
void method();
void newMethod(); // 추상 메서드
}

interface MyInterface {
void method();
default void newMethod() { /* .. */ }
}
  • 디폴트 메서드가 기존의 메서드와 충돌 할때

오버라이딩 원칙으로 동작 (즉 구현된 클래스의 메서드가 있으면 그게 호출 됨)

42 내부 클래스 (inner class)

  • 클래스 안의 클래스
1
2
3
4
5
6
class A { // 외부 클래스

class B { // 내부 클래스
// 객체 생성 없어도 A의 멤버 접근 가능
}
}
  • 장점
  1. 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근 할수 있다
  2. 코드의 복잡성을 줄일수 있다 (캡슐화)

43,44 내부 클래스의 종류와 특징

  • 내부 클래스의 종류와 유효범위는 변수와 동일
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Outer {
int iv =0; // --> 1
static int cv =0; // --> 2

void myMethod() {
int lv=0; // --> 3
}
}

class Outer {
class InstanceInner {} // --> 1
static class StaticInner {} // --> 2

void myMethod() {
class LocalInner {} // --> 3
}
}

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

  • 내부 클래스의 제어자는 변수에 사용 가능한 제어자와 동일

46 내부 클래스의 제어자와 접근성 예제 1

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

class Example {

// 인스턴스 내부 클래스
class InstanceInner {
int iv = 100;
static int cv = 100; // 에러
final static int CONST = 100; // final static은 상수임으로 허용
}

// Static 내부 클래스
static class StaticInner {
int iv = 200;
static int cv = 200; // static 클래스에만 static 멤버 정의 강의
}

void myMethod() {
// 지역 내부 클래스
class LocalInner {
int iv = 300;
static int cv = 300; // 에러
final static int CONST = 300; // final static은 상수임으로 허용
}
}
}

JDK 1.8 부터 지역변수가 변경 안하면 final 로 자동으로 잡아줌, constant pool

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Example {
public static void main(String[] args) {
Outer2 oc = new Outer2(); // 외부 클래스의 인스턴스 생성 해야
Outer2.InstanceInner ii = oc.new InstanceInner(); // 내부 클래스 생성 가능

Outer2.StaticInner.cv;
Outer2.StaticInner si = new Outer2.StaticInner();
}
}

class Outer2 {
class InstanceInner {
int iv = 100;
}
static class StaticInner {
int iv = 200;
static int cv = 300;
}
void myMethod() {
class LocalInner {
int iv = 400;
}
}
}

51 익명 클래스 (anonyumous class)

  • 이름이 없는 일회용 클래스. 정의와 생성을 동시에
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
new 조상클래스이름() {
// 멤버 선언
}
// 또는
new 구현인터페이스이름() {
// 멤버 선언
}

class Example {
Object iv = new Object() { void method() {} }; // 익명 클래스
static Object cv = new Object() { void method(){} };

void myMethod() {
Object lv = new Object() { void method(){} };
}
}