LostCatBox

Java 배우기 CH07

Word count: 3.3kReading time: 20 min
2022/12/23 8 Share

객체지향개념 2

상속(Inheritance)

  • 기존의 클래스로 새로운 클래스를 작성하는 것(코드의 재사용)
  • 두 클래스를 부모와 자식으로 관계를 맺어주는 것
  • 자손은 조상(부모와 그위모든애들)의 모든 멤버를 상속받는다
    (생성자, 초기화블럭 제외)
  • 자손의 멤버 개수는 조상보다 같거나 많다.
  • 자손의 변경이 조상에 영향을 미치지 않는다.

Untitled

Untitled

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
// Ex7_1.java
class Tv {
boolean power; // 전원상태(on/off)
int channel; // 채널

void power() { power = !power; }
void channelUp() { ++channel; }
void channelDown() { --channel; }
}

class SmartTv extends Tv { // CaptionTv는 Tv에 캡션(자막)을 보여주는 기능을 추가
boolean caption; // 캡션상태(on/off)
void displayCaption(String text) {
if (caption) { // 캡션 상태가 on(true)일 때만 text를 보여 준다.
System.out.println(text);
}
}
}

class Ex7_1 {
public static void main(String args[]) {
SmartTv stv = new SmartTv();
stv.channel = 10; // 조상 클래스로부터 상속받은 멤버
stv.channelUp(); // 조상 클래스로부터 상속받은 멤버
System.out.println(stv.channel);
stv.displayCaption("Hello, World");
stv.caption = true; // 캡션(자막) 기능을 켠다.
stv.displayCaption("Hello, World");

}
}

포함 관계

  • 클래스의 관계 (2가지)
    • 상속
    • 포함

포함이란?

  • 클래스의 멤버로 참조변수를 선언하는 것
  • 작은 단위의 클래스를 만들고, 이들을 조합해서 클래스를 만든다.
  • 자료구조가 달라짐 >> 메모리 그림 잘보기

Untitled

  • 아래처럼 재사용성 높이고, 복잡성 줄이기위해

Untitled

클래스 간의 관계 결정하기

  • 상속관계 = 상속관계 A는 B이다
  • 포함관계 = A는 B를 가지고있다
  • 대부분의 경우 포함관계를 사용

Untitled

단일 상속 & Object클래스

단일상속

  • java는 단일상속만을 허용하다.
  • 다중이 필요할 경우, 하나만 상속관계로, 나머지는 포함관계로 처리한다
1
2
3
class TvDVD extends Tv, DVD { // 에러 조상은 하나만 허용된다.

}
  • 이유는 두 조상에게 모두 void fuction(){A},void fuction(){B} 가있다면 어느것을 상속할것인지? >> 충돌위험 높음

Untitled

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

  • 부모가 없는 클래스는 자동적으로 Object 클래스를 상속받게 된다
  • 모든 클래스는 Object클래스에 정의된 11개의 메서드를 상속받는다
    toString(), equals(Object obj), hashCode() 등등
1
2
3
4
5
class Tv {  // 부모가 없는 클래스는
}

class Tv extends Object { //항상 컴파일러가 이렇게 상속받게함
}
  • println에 참조변수가 들어오면 참조변수.toString()을 호출
1
2
3
4
5
6
7
8
9
10
11
12
class Tv2 {
int y=3;
}

public class vesta14 {

public static void main(String[] args) {
Tv2 c = new Tv2();
Tv2 c2 = new Tv2();
System.out.println(c.toString()); //Tv2@2a139a55 출력
System.out.println(c2); //Tv2@15db9742 출력, println에 참조변수가 들어오면 참조변수.toString()을 호출
}

오버라이딩

오버라이딩(overriding) = 메서드 오버라이딩(덮어쓰다)

  • 상속받은 조상의 메서드를 자신에 맞게 변경하는 것
  • 메서드 선언문(반환타입 함수이름) 못바꿈, 내용만 변경가능

Untitled

  • (오버라이딩 + 생성자 활용) 간결한코딩(!!!)

    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
    import java.util.*;

    class MyPoint3 extends Object {
    int x;
    int y;

    MyPoint3(int x, int y){
    this.x =x;
    this.y = y;

    }
    //Object 클래스의 toString()을 오버라이딩
    public String toString() {
    return 'x'+x+",y"+y;
    }
    }

    public class vesta14 {

    public static void main(String[] args) {
    MyPoint3 p = new MyPoint3(5,3); // p.x , p.y초기화 코드없이 바로 생성자이
    System.out.println(p); //print(참조변수)호출시 참조변수.toString()를 오버라이딩해놓
    }

    }

오버라이딩의 조건(!!!)

1. 선언부가 조상 클래스의 메서드와 일치해야한다

  • 선언부(반환 타입, 메서드 이름, 매개변수 목록) 일치!!!!

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

  • public, protected, (default), private

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

Untitled

오버로딩 vs 오버라이딩

  • 오버로딩
    이름이 같은 기존에 없는 새로운 메서드를 정의하는 것(new)
  • 오버라이딩
    상속받은 메서드의 내용을 변경하는 것(change, modify)

Untitled

참조변수 super, 생성자 super()

참조변수 super

  • 객체 자신을 가르키는 참조변수. 인스턴스 메서드,생성자 내에만 존재
  • 조상의 멤버를 자신의 멤버와 구별할 때 사용
  • static 메서드내에서 사용불가(당연히 this가 못썻던이유와같음)

참조변수 this와유사
this는 iv, lv를 구별하기 위해 사용됨

Untitled

  • 이름이 겹쳐도 상속됨.( super, this로 구별됨)

  • 변수 x 만 쓴다면 당연히 가까운순이므로 this.x 값이다

  • 만약 변수명과 겹치는것이 상속받은 클래스에 정의가 없으면
    x==this.x==super.x

  • 이때는 참조변수 this, super 가르키는 주소 모두 같은 객체주소가짐

Untitled

super() - 조상의 생성자

  • 상속시 생성자, 초기화 블록은 상속안됨!!
  • 필요하다면, 조상의 생성자를 호출할때 사용
  • 조상의 멤버는 조상의 생성자를 호출해서 초기화

생성자 this()와 유사

  • x,y는 조상의 멤버 임으로 super(x,y)를 통해 조상의 생성자를 호출이 마땅하다.

Untitled

super() - 조상의 생성자(2)(!!!)

  • 생성자의 첫줄의 반드시 생성자를 호출해야 한다.(!!!)
  • 그렇지 않으면 컴파일러가 생성자의 첫 줄에 super();를 삽입한다. (에러이유)

Untitled

  • 많이 하는 실수 반드시 이유 찾아보기

Untitled

  • 이유는 Point3D 생성자 명령문의 첫줄에는 super();가 들어가며, 이를 수행시 Point에 기본 생성자 Point() {} 를 호출한다. 하지만 Point 클래스의 생성자가 이미 있었기 때문에 기본생성자가 기본적으로 만들어지지 않으므로, 에러가 나온다.

Untitled

  • 항상 클래스 만들때, 기본 생성자 항상 무조건 반드시 넣어주자
    (다른 생성자 선언 있다면, 자동으로 안들어가므로)
  • 해결방법
    • Point 클래스에 기본 생성자 넣어주기
    • Point3D 클래스 생성자에서 this.x, this.y 대신
      상속 생성자에게 생성하게 시키는 super(x,y) 로 교체

패키지

  • 서로 관련된 클래스의 묶음( java9 약 400개 클래스)
  • 클래스는 클래스 파일(*.class), 패키지는 폴더. 하위 패키지는 하위 폴더 (파일전까지,,폴더로구성)
  • 클래스의 실제 이름(full name)은 패키지를 포함
    (java.lang.String)
  • rt.jar는 클래스들을 압축한 파일(java9부터는 module개념으로 rt.jar없다.)

패키지의 선언

  • 패키지는 소스파일의 첫 번째 문장으로 단 한번 선언
  • 같은 소스 파일의 클래스들은 모두 같은 패키지에 속하게된다.
  • 패키지 선언이없으면, 이름없는(unnamed)패키지에 속하게된다. (default package)
1
package ~~~~~;

클래스 패스(classpath)

  • 클래스 파일(*.class)의 위치를 알려주는 경로(path)
  • 환경변수 classpath로 관리하며, 경로간의 구분자는 ;로 사용
    classpath(환경변수)에 패키지의 루트를 등록해줘야함

import문 & static import문

  • 클래스를 사용할 때 패키지이름을 생략할 수 있다.
  • 컴파일러에게 클래스가 속한 패키지를 알려준다.
  • java.lang패키지의 클래스는 import하지 않고도 사용가능하다
    (String, Object, System, Thread)

import 문의 선언

  • import문을 선언하는 방법은 다음과 같다.
  • import문은 컴파일 시에 처리되므로 프로그램의 성능에 영향없다.

Untitled

IMG_6B2A17E4A7FB-1.jpeg

static import 문

  • static 멤버를 사용할 때 클래스 이름을 생략할수있게해준다.

Untitled

제어자(modifier)

  • 클래스와 클래스의 멤버(멤버 변수, 메서드)에 부가적인 의미 부여
  • 접근제어자는 4개중 1개만 붙일수있다
  • 보통 접근 제어자를 가장 왼쪽에 씀

Untitled

static - 클래스의, 공통적인

  • iv, im 사용불가

Untitled

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

  • 제어자 사용시 대상도 구별해야함

Untitled

abstract - 추상의, 미완성의

  • 추상화에서 배움
  • 미완성을 의미하며, 구현부없는 메서드(=추상 메서드) 앞에 붙여아함
  • 추상 메서드를 포함한 클래스(=추상 클래스) 앞에 붙여야함
  • 미완성이므로 추상 클래스의 인스턴스 생성 불가
  • 따라서 추상 클래스는 무조건 상속받아서 추상 메서드를 완성해야 쓸수있다!
    완전한 클래스 만든 후 객체 생성가능

Untitled

접근 제어자(access modifier)

  • 하나의 대상에 접근 제어자 4개중 1개만 사용가능
  • 접근 제어자 없는경우 자동 default
  • 클래스에는 public, default가능
    • 주의할점은 클래스 파일하나에 public은 하나만 존재!!
      따라서 public변경하고, 파일이름도 public 클래스 이름과 같아야함
  • 멤버들에게는 4개모두 가능

Untitled

  • 다른패키지에서 사용시 private, default 멤버는 에러 / protected public 멤버는 사용성공
  • 다른패키지에 자손도 아니라면 public멤버만 사용성공

Untitled

  • 컴파일후 폴더+파일 기준으로 보면

Untitled

캡슐화와 접근 제어자(!!!)

  • 접근 제어자를 사용하는 이유
    외부로부터 데이터를 보호하기 위해서
  • 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해서

예시(데이터보호)

  • 아래와 같이 직접 접근 막고, 간접접근 하도록 설계
  • setHour(25)는 결국 23을 넘기 때문에, hour 변수값이 변하지 않는다.
    (범위에 값이 항상 들어가게 되므로, 값보호)

Untitled

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
32
33
34
// 내부 접근은 함수를 통해 하도록 변경하면, 캡슐화 가능
class Time {
private int hour; //0~23 을 가져야
private int minute ;
private int second ;

public void setHour(int hour) {
if (isnotValidHour(hour))
return;
this.hour = hour;
}
//매개변수로 념겨진 hour가 유효한지 알려주는 메서드
//(내부에서만사용하므로private)
private boolean isnotValidHour(int hour) {
return hour < 0 ||hour>23;
}

public int getHour() {
return hour;
}
}

public class TimeTest {

public static void main(String[] args) {
Time t = new Time();
t.setHour(21);
System.out.println(t.getHour()); //21
t.setHour(100);
System.out.println(t.getHour()); //21, 통과하지 못했

}

}

다형성(polymorphism)(!!!)

  • 조상 타입 참조 변수로 자손 타입 객체를 다루는 것
  • 여러 가지 형태를 가질 수 있는 능력
    • 추상클래스, 인터페이스 등 이해하는데 기초
  • 타입 불일치 하여도 다룰수있음..
    (보통 참조변수 타입과 객체 타입은 일치해야함)

Untitled

타입일치와 불일치 차이

  • 참조 변수와 객체 타입일치시 모든 멤버 사용가능
  • 참조 변수와 객체 타입 불일치시 조상에서 정의된 멤버만 사용가능
  • 참조변수로 사용할수있는 멤버의 갯수가달라짐
    즉 리모콘(참조변수) 버튼수!!라고 생각하자.

Untitled

  • 반대의 경우인 자손 타입의 참조변수로 조상 타입의 객체를 가르킬수없다.(에러)
    • 리모콘 기능 수보다 멤버가 많으면안돼!!! 없는것 호출해서 에러가뜸

Untitled

참조변수의 형변환

참조변수의 형변환(!!!)

  • 결론: 사용할 수 있는 멤버의 갯수를 조절하는 것 (값, 주소, 객체 안달라서 딱 갯수만달라짐)

  • 조상, 자손 관계의 참조변수는 서로 형변환 가능 (부모자식간만됨)

  • 자손타입 ← 조상타입. 형변환 생략 불가

  • 자손타입 → 조상타입. 형변환 생략 가능

  • 항상 참조변수 타입간 관계가 맞으면 컴파일러는 OK
    하지만, 실제 인스턴스가 가지고있는 갯수를 넘는 참조변수타입은 에러뜸!(컴퍼일러는 oK함)

  • 예시를 확인해보자

Untitled

  • 객체는 그대로 이지만, 참조변수(리모콘)의 타입을 변경하므로, 사용가능한 멤버갯수를 변경가능하다.
  • Car c = (Car) f >> 참조 변수 c가 인스턴스 주소를 가르킨다. (쓸수있는 멤버함수 4개)
  • FireEngin f2 = (FireEngine)c; >> 참조 변수 c가 가르키던 인스턴스 주소를 f2도 가르킨다. 쓸수있는 멤버함수 5개

instanceof 연산자

  • 참조변수의 형변환 가능여부 확인에 사용, 가능하면 true반환
  • 형변환 전에 반드시 instanceof로 확인해야함.(자식-조상만 가능)
  • 자기자신, 조상들은 ture >> (같거나 범위줄어드는) 형변환가능 알려줌

Untitled

매개변수의 다형성(다형성 장점1)

  • 참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다.
  • 참조형 매개변수는 오버로딩을 통해 일일히 함수를 정의 내려줄필요없어진다.

Untitled

  • 매개변수로 Product p를 하면, Tv,Computer, Audio타입인 자식관계 인스턴스가 들어와도, 다형성 특성에 의해 모두 한 함수로 처리가능하다.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class Product {
int price; // 제품의 가격
int bonusPoint; // 제품구매 시 제공하는 보너스점수

Product(int price) {
this.price = price;
bonusPoint = (int)(price/10.0); // 보너스점수는 제품가격의 10%
}
}

class Tv1 extends Product {
Tv1() {
// 조상클래스의 생성자 Product(int price)를 호출한다.
super(100); // Tv의 가격을 100만원으로 한다.
}

// Object클래스의 toString()을 오버라이딩한다.
public String toString() { return "Tv"; }
}

class Computer extends Product {
Computer() { super(200); }

public String toString() { return "Computer"; }
}

class Buyer { // 고객, 물건을 사는 사람
int money = 1000; // 소유금액
int bonusPoint = 0; // 보너스점수

void buy(Product p) { //p리모콘으로 받음
if(money < p.price) {
System.out.println("잔액이 부족하여 물건을 살 수 없습니다.");
return;
}

money -= p.price; // 가진 돈에서 구입한 제품의 가격을 뺀다.
bonusPoint += p.bonusPoint; // 제품의 보너스 점수를 추가한다.
System.out.println(p + "을/를 구입하셨습니다."); //p == p.toString()이므로
}
}

class Ex7_8 {
public static void main(String args[]) {
Buyer b = new Buyer();
// Product p = new Tv1();
// b.buy(p);
b.buy(new Tv1()); // 위에 두문장 합친것과 같다, 대신 참조변수(리모콘)가 없다..
b.buy(new Computer());

System.out.println("현재 남은 돈은 " + b.money + "만원입니다.");
System.out.println("현재 보너스점수는 " + b.bonusPoint + "점입니다.");
}
}

Untitled

여러 종류의 객체를 배열로 다루기(다형성 장점2)

  • 조상타입의 배열에 자손들의 객체를 담을 수있다.

Untitled

Untitled

  • 이렇게 조상타입의 배열에는 자손들의 타입이 달라도 저장가능하다(다형성가능)

  • 만약 Object로 이뤄진 배열(Vector)이있다면 모두의 조상이기에 모든 종류의 객체저장가능

  • 예시

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
class Product2 {
int price; // 제품의 가격
int bonusPoint; // 제품구매 시 제공하는 보너스점수

Product2(int price) {
this.price = price;
bonusPoint = (int)(price/10.0);
}

Product2() {} // 기본 생성자
}

class Tv2 extends Product2 {
Tv2() { super(100); }

public String toString() { return "Tv"; }
}

class Computer2 extends Product2 {
Computer2() { super(200); }
public String toString() { return "Computer"; }
}

class Audio2 extends Product2 {
Audio2() { super(50); }
public String toString() { return "Audio"; }
}

class Buyer2 { // 고객, 물건을 사는 사람
int money = 1000; // 소유금액
int bonusPoint = 0; // 보너스점수
Product2[] cart = new Product2[10]; // 구입한 제품을 저장하기 위한 배열
int i =0; // Product배열에 사용될 카운터

void buy(Product2 p) {
if(money < p.price) {
System.out.println("잔액이 부족하여 물건을 살 수 없습니다.");
return;
}

money -= p.price; // 가진 돈에서 구입한 제품의 가격을 뺀다.
bonusPoint += p.bonusPoint; // 제품의 보너스 점수를 추가한다.
cart[i++] = p; // 제품을 Product[] cart에 저장한다.
System.out.println(p + "을/를 구입하셨습니다.");
}
// 뒷 페이지에 계속됩니다.
void summary() { // 구매한 물품에 대한 정보를 요약해서 보여 준다.
int sum = 0; // 구입한 물품의 가격합계
String itemList =""; // 구입한 물품목록

// 반복문을 이용해서 구입한 물품의 총 가격과 목록을 만든다.
for(int i=0; i<cart.length;i++) {
if(cart[i]==null) break;
sum += cart[i].price;
itemList += cart[i] + ", "; //cart[i]는 결국 객체의 toString()호출된다.
}
System.out.println("구입하신 물품의 총금액은 " + sum + "만원입니다.");
System.out.println("구입하신 제품은 " + itemList + "입니다.");
}
}

class Ex7_9 {
public static void main(String args[]) {
Buyer2 b = new Buyer2();

b.buy(new Tv2());
b.buy(new Computer2());
b.buy(new Audio2());
b.summary();
}
}

Untitled

추상 클래스, 추상 메서드

추상 클래스(abstract class)

  • 미완성 설계도 == 미완성 메서드를 갖고있는 클래스
  • 추상 클래스 == 추상 메서드(몸통이없는 메서드)를 갖고있는 클래스
  • 반드시 abstract 붙여야함
  • 다른 클래스 작성에 도움을 주기 위한것 (상속후, 추상메서드 구현완성!!후 객체 생성 목적)
  • 인스턴스 생성 불가

Untitled

  • 상속후 구현완료되면 abstract없는것을 확인가능
  • AudioPlayer또한 완성된 설계도임 >> 인스턴트 생성 가능해짐
  • 만약 Player ap = new AudioPlayer() 한다면 조상 참조변수로 가능하며, 오버라이딩되었으므로 참조변수(리모콘) 으로 play(), stop() 호출시 정상 동작 가능

추상 메서드(abstract method)

  • 미완성 메서드. 구현부(몸통, { })가 없는 메서드
  • 꼭 필요하지만 자손마다 다르게 구현될 것으로 예상되는 경우

Untitled

  • 상속받은후 모두 구현완료해야하지만, 1개만 구현한다면 abstract필요
  • abstract로 구현해놓으면 반드시 기능을 만들고 써야함을 강제할수있다.
  • 객체 생성이 불가함에 따라 추상 메서드 인스턴스 메서드에서 호출도가능(어차피 선언문만있고, 구현완료해야 되니까)

Untitled

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
abstract class Player {
abstract void play(int pos);
abstract void stop();

}

class AudioPlayer extends Player {
int pos = 1;
void play (int pos) {
this.pos = pos;

}
void stop () {
System.out.println(pos);
}
}
public class vesta16 {

public static void main(String[] args) {
// Player p = new Player();
//아래 종속된 참조변수가 조상이지만, 기능을 다 가지고있고, 실제 객체가 구현된 함수가짐, 정상동작가능
Player p = new AudioPlayer();
p.play(100);
p.stop();

}

}

Untitled

추상클래스의 작성

  • 여러 클래스에 공통적으로 사용될 수 있는 추상클래스르 바로 작성하거나
  • 기존클래스의 공통 부분을 뽑아서 추상 클래스를 만든다.

Untitled

Untitled

  • 리모콘이 조상것이라도, 리모콘이 가르키는것의 실제 인스턴스의 함수가 동작한다.
  • 조상이 같다면, 하나의 배열에 다양한 객체를 담아 처리할수있다.(다형성)
  • 조상에 abstract로 반드시 넣어야하는것들을 넣어놓음

Untitled

  • 이처럼 담아낼수있지만, move()가 각 종속 객체에 정의가 되어있지않아 에러다. 따라서 abstract로 정해놔야한다!!그래야 종속해서 만들때 move()도 만든테니까
  • 반드시 아래 코드 쳐보기
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
32
33
34
35
36
37
public class Ex7_10 {
public static void main(String[] args) {
// 객체 배열 생성 및 초기화 한번에..
Unit[] group = { new Marine(), new Tank(), new Dropship() };

for (int i = 0; i < group.length; i++)
group[i].move(100, 200);
}
}

abstract class Unit {
int x, y;
abstract void move(int x, int y);
void stop() { /* 현재 위치에 정지 */ }
}

class Marine extends Unit { // 보병
void move(int x, int y) {
System.out.println("Marine[x=" + x + ",y=" + y + "]");
}
void stimPack() { /* 스팀팩을 사용한다. */ }
}

class Tank extends Unit { // 탱크
void move(int x, int y) {
System.out.println("Tank[x=" + x + ",y=" + y + "]");
}
void changeMode() { /* 공격모드를 변환한다. */ }
}

class Dropship extends Unit { // 수송선
void move(int x, int y) {
System.out.println("Dropship[x=" + x + ",y=" + y + "]");
}
void load() { /* 선택된 대상을 태운다. */ }
void unload() { /* 선택된 대상을 내린다. */ }
}

Untitled

인터페이스의 선언, 상속, 구현

  • 결론: 추상 메서드의 집합
  • 구현된 것이 전혀 없는 설계도. 껍데기(모든 멤버가 public, abstract)

추상클래스와 인터페이스의 차이
추상클래스=일반클래스인데 추상메서드를 가짐((iv, 생성자등 있음)
인터페이스= 추상 메서드로만 구성됨 (iv, 생성자등 없음)(=원칙)

Untitled

  • 항상 public , 항상 static, 항상 abstract 그래서 항상 생략 가능

Untitled

인터페이스의 상속

  • 인터페이스의 조상은 인터페이스만 가능(Object가 최고 조상 아님)
  • extends로 조상 인터페이스 상속받음
  • 다중 상속이 가능함
    (추상메서드는 충돌해도 문제없음)
    (어차피 같은 이름 메서드의 구현부없음)

인터페이스의 구현

  • 인터페이스에 정의된 추상 메서드를 완성하는 것
    추상 클래스도 결국 extends로 받아서 구현모두해야 완성(매우 유사)
  • 클래스에 인터페이스를 implements로 받아서 구현모두해야 완성
  • 클래스에서 한개만 구현했을경우 abstract를 클래스앞에 붙여야함

Untitled

  • interface의 함수는 모두 public, abstract 생략되었다
  • class 클래스명 implements 인터페이스명 으로 받아서 미완성 메서드 모두 구현하면 이를 인터페이스 구현이라고함!

인터페이스 Q&A

Untitled

  • 미완성 설계도를 완성하는 것이 결국 구현

Untitled

  • (핵심!!)iv차이

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

  • 인터페이스도 구현 클래스의 부모!! 비슷하다
  • 즉, 진짜 부모(조상클래스)는 상속(extends),
    인터페이스도 상속(implements) 동시 가능
  • 인터페이스, 조상클래스 똑같이 다형성 특성으로, 조상참조변수(리모콘) 사용가능

매개변수로 인터페이스로 지정 의미

Untitled

  • 예시에서 Fightable 참조변수로 활용시 정의되어있는 함수2개밖에사용못함
  • 매개변수가 Fightable f로 되어있는것의 의미는 Fightable인터페이스로 구현한 클래스의 인스턴스만 가능 의미 (!!!)

반환타입을 인터페이스로 지정 의미

Untitled

  • 반환타입이 Fightable의미는 Fightable인터페이스를 구현한 클래스의 인스턴스를 반환한다는 의미(!!!)
  • 형변환가능한 Fighter를 반환됬으니까.. 가능함
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
32
33
34
35
abstract class Unit12 {
int x,y;
abstract void move(int x, int y);
void stop() {System.out.println("멈춥니");
}
}

interface Fightable {
void move (int x,int y); //public abstract 생략
void attack (Fightable f); //public abstract 생략
}

class Fighter extends Unit12 implements Fightable {
//오버라이딩규 조상보다 접근제어자가 좁으면안된다.
public void move (int x, int y) {
System.out.println(x+y+"이동");
}
public void attack (Fightable f) {
System.out.println(f+"공"+"attck function실행 ");
}
}

public class vesta17 {


public static void main(String[] args) {
//Fighter f = new Fighter(); 대신 fightable로 써도 정상동작
//Unit12를 대신쓰면, f.attack에서 오류발생 (리모콘에없는기능!)
Fightable f = new Fighter();
f.move(100, 200);
f.attack(new Fighter());
}


}

인터페이스 구조가 변경유리

  • 두 대상(객체)간의 ‘연결, 대화, 소통’을 돕는 ‘중간 역할’을 한다
  • 기계의 껍데기 == 인터페이스(인간↔기계 사이존재)
  • 선언(설계)와 구현을 분리시킬 수있게 한다.
  • 선언만 때어내기!!!!!!
  • 즉, A가 B에 의존할때 B의 껍데기(인터페이스)는 그대로 놧두고 알맹이(B의 구현내용)을 변경할수있다. (A입장에서는 변경할것없다)

Untitled

Untitled

  • A 클래스가 인터페이스에 의존하면 간접적으로 B와 소통!!
  • B 변경시 A클래스 변경 필요없다! 매우 중요!!

인터페이스의 장점

  • 개발 시간을 단축할 수 있다.
    A와 B가 따로 작업가능(wait 불필요)

  • 변경에 유리한 설계가 가능하다
    A는 가만히 B만 알맹이 바꿀수있다.

  • 표준화가 가능하다
    JDBC처럼 사용하는 쪽이나 구현하는 쪽에서 인터페이스를 지키게함

  • 서로 관계없는 클래스들을 관계를 맺어줄 수 있다

    Untitled

    • 이처럼 클래스 상속(상속계층)과 다른 특성을 가진 애들의 관계를 맺어줄수있다.
      인터페이스를 중복으로 상속가능하므로 다양한 관계 가능

인터페이스의 디폴트 메서드와 static메서드

  • 인터페이스에 디폴트 메서드, static메서드 추가 가능( JDK1.8부터)
  • 인터페이스에 새로운 메서드(추상 메서드)를 추가하기 어려움
    • 이 인터페이스를 사용하는 모든 클래스에 새로운 메서드를 다 구현해야됨
      문제
  • 디폴트 메서드는 인스턴스 메서드(인터페이스 원칙 위반)
    (몸통이있는 메서드를 추가할수있게 해줌)
  • 디폴트 메서드가 기존의 메서드와 충돌할 떄의 해결책 (몸통이있으니까 충돌됨..)
  • 해결책(충돌나면 일단 오버라이딩한다 생각하자.조상클래스가 우선됨)

Untitled

내부 클래스(inner class)

  • 클래스 안의 클래스
    (바깥클래스에서 쓸 맴버를 만드는것!목적)

Untitled

  • 내부 클래스 장점
    • 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할수있다
      (외부 클래스의 멤버인 내부 클래스이므로 거의 내부에서만 쓰인다)
    • 코드의 복잡성을 줄일 수있다.
      (캡슐화)(완전 외부에서는 classB접근 거의불가)
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
class AAA {  ///AAA는 BBB의 외부 클래스
int i =100;
BBB b = new BBB();

class BBB{ ///BBB는 AAA의 내부 클래스
void method () {
// AAA a = new AAA();
// System.out.println(a.i);
System.out.println(i); // 객체 생성없이 외부클래스의 멤버 접근가능
}
}

}
class CCC {
// BBB b = new BBB(); 내부 클래스되었으므로 활용못함

}
public class InterfaceTest2 {

public static void main(String[] args) {
// TODO Auto-generated method stub
AAA a = new AAA();

}

}

내부 클래스의 종류와 특징

  • 내부 클래스의 종류와 유효범위(scope)는 변수와 동일

Untitled

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

  • 내부 클래스의 제어자는 변수에 사용 가능한 제어자와 동일
  • 원래 클래스는 deflaut와 public 밖에없지만, 내부클래스는 4종류 제어자 모두 사용가능

Untitled

  • static클래스만 static멤버를 정의할수있다
    따라서 static이 필요할경우 클래스도 static이여야함
    또한 static 내부 클래스에서는 외부 클래스의 인스턴스 멤버에 접근할수없다.(당연히 static 메서드에서 iv참조못하는것과비슷)

  • final static 상수는 3종류의 내부클래스 모두 사용가능
    final static같은 경우는 클래스명.변수이름 으로 접근가능

  • 예제2

Untitled

  • 인스턴스멤버는 인스턴스 멤버와 static맴버사용가능
    static멤버는 인스턴스멤버사용불가

  • private 핵심 사용가능.(private는 클래스안에서만사용가능)

    • 내부 클래스는 외부 클래스의 private 멤버 접근 가능하다
    • 내부 지역 클래스는 해당 메서의 지역변수는 final이 붙은 변수(상수)만 접근가능하다. (그냥iv는 먼저 메서드종료로사라질수있다)
      (JDK1.8부터는 값변경안되면 final생략취급)

Untitled

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
class Outer {
private int outerIv = 0;
static int outerCv = 0;

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

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

void myMethod() {
int lv = 0; //값이 끝까지 바뀌지 않으니 상수로 간주
final int LV = 0; // JDK1.8부터 final 생략 가능

class LocalInner {
int liv = outerIv;
int liv2 = outerCv;
// 외부 클래스의 지역변수는 final이 붙은 변수(상수)만 접근가능하다.
// int liv3 = lv; // 에러!!!(JDK1.8부터 에러 아님)
int liv4 = LV; // OK
}
}
}
  • 완전 외부에서 내부클래스 사용방법

Untitled

  • 접근방법

Untitled

익명 클래스(anonymous class)

  • 이름이 없는 일회용 클래스. 정의와 생성을 동시에

Untitled

  • 이름도 없고 바로 객체 생성해야하며, 조상클래스이름 또는 구현인터페이스이름 쓰면됨
CATALOG
  1. 1. 객체지향개념 2
  2. 2. 상속(Inheritance)
  3. 3. 포함 관계
  4. 4. 단일 상속 & Object클래스
  5. 5. 오버라이딩
  6. 6. 참조변수 super, 생성자 super()
  7. 7. 패키지
  8. 8. import문 & static import문
  9. 9. 제어자(modifier)
  10. 10. 캡슐화와 접근 제어자(!!!)
  11. 11. 다형성(polymorphism)(!!!)
  12. 12. 추상 클래스, 추상 메서드
  13. 13. 인터페이스의 선언, 상속, 구현
  14. 14. 내부 클래스(inner class)