|
| 1 | +자바는 객체지향언어이고, 이 언어는 객체를 부품화하는데 이때 이 부품에 다양한 타입을 대입하여 각각 다른 결과물을 도출해내는 특징을 '다형성'이라 한다. |
| 2 | +자바의 상속과 인터페이스는 이 다형성을 극대화하는 기능이다. |
| 3 | +extends, implements를 큰 생각없이 습관적으로 쓰다가, 이렇게 들여다보니 결국 다형성의 개념과 맞닿는 기능임이 흥미로웠다. |
| 4 | + |
| 5 | +# 7. 상속 |
| 6 | +상속 : 부모가 자식에게 물려주는 행위 |
| 7 | +- 부모 클래스의 멤버를 자식 클래스에게 물려줄 수 있다. |
| 8 | +- extends |
| 9 | +- |
| 10 | +## 클래스 상속 |
| 11 | + |
| 12 | +## 부모 생성자 호출 |
| 13 | + |
| 14 | +## 메소드 재정의 |
| 15 | + |
| 16 | +## final 클래스와 final 메소드 |
| 17 | + |
| 18 | +## protected 접근 제한자 |
| 19 | + |
| 20 | +## 타입변환과 다형성 |
| 21 | + |
| 22 | +## 추상클래스 |
| 23 | + |
| 24 | + |
| 25 | + ``` |
| 26 | + try { |
| 27 | +} |
| 28 | + ``` |
| 29 | + |
| 30 | + |
| 31 | + |
| 32 | + |
| 33 | +# 8. 인터페이스 |
| 34 | +## 인터페이스 |
| 35 | +- 객체의 사용방법을 정의한 타입 |
| 36 | +- 자바의 람다식은 함수적 인터페이스의 구현 객체를 생성하기 때문에 인터페이스의 중요성은 더욱 커졌다 :) |
| 37 | +-  |
| 38 | +- 개발코드를 수정하지 않고, 사용하는 객체를 변경할 수 있도록 하기 위해 인터페이스를 중간에 둔다. -> 이게 넘 재밌었다 |
| 39 | +- 하나의 객체가 아니라, 여러 객체들과 사용이 가능하므로 어떤 객체를 사용하느냐에 따라ㅏ 실행내용과 리턴값이 다를 수 있다. 따라서 개발코드측면에서 코드 변경 없이 실행 내용과 리턴값을 다양화할 수 있다. |
| 40 | + |
| 41 | +## 인터페이스 선언 |
| 42 | + ``` |
| 43 | +interface 인터페이스 명{ |
| 44 | + //상수 |
| 45 | + 타입 상수명 = 값; |
| 46 | + //추상 메소드 |
| 47 | + 타입 메소드명(매개변수, ...); |
| 48 | + //디폴트 메소드 |
| 49 | + default 타입 메소드명(매개변수,...){...} |
| 50 | + //정적 메소드 |
| 51 | + static 타입 메소드명(매개변수){...} |
| 52 | +} |
| 53 | + ``` |
| 54 | + |
| 55 | +- 상수 필드(Constant Field) |
| 56 | +1) 인터페이스는 객체 사용 설명서이므로 런타임 시 데이터를 저장할 수 있는 필드를 선언할 수 없다. 그러나 상수 필드는 가능하다. 반드시 초기값을 대입해야 한다. |
| 57 | + |
| 58 | +- 추상 메소드(Abstract Method) |
| 59 | +1) 추상 메소드는 객체가 가지고 있는 메소드를 설명한 것 (어떤 매개값이 필요한지, 리턴값이 무엇인지만 알려줌) |
| 60 | +2) 실제 실행은 객체가 가진다. |
| 61 | +- 디폴트 메소드(Default Method) |
| 62 | +1) 인터페이스에 선언되지만, 사실은 객체가 가지고 있는 인스턴스 메소드라고 생각하면된다 |
| 63 | +2) 인터페이스 구현한 객체A,B가 있다고 가정할 때, 인터페이스에 디폴트 메소드를 둠으로서 A,B 둘다 수정할 필요가 없어짐 |
| 64 | +- 정적 메소드(Static Method) |
| 65 | +1) 디폴트 메소드와 달리 객체가 없이 인터페이스만으로 호출 가능 |
| 66 | + |
| 67 | +## 상수 필드 선언 |
| 68 | +- 상수는 public static final로 선언하는데, 인터페이스의 필드는 모두 public static final이기에 안붙여도 자동적으로 붙게 된다. |
| 69 | +``` |
| 70 | +interface 인터페이스 명{ |
| 71 | +public static final MAX_VALUE = 값; |
| 72 | +} |
| 73 | + ``` |
| 74 | + - 상수명은 대문자로, 서로 다른 단어로 구성된 경우 언더바로 연결하는 것이 관례 |
| 75 | + |
| 76 | + ``` |
| 77 | +public interface RemoteControl{ |
| 78 | + // static final을 안붙여도 인터페이스의 필드는 상수이다. |
| 79 | + public static final int MAX_VOLUME = 10; |
| 80 | + public int MIN_VOLUME = 0; |
| 81 | +} |
| 82 | + ``` |
| 83 | + |
| 84 | + |
| 85 | +### 추상 메소드 선언 |
| 86 | +인터페이스를 통해 호출되는 메소드는, 최종적으로 객체에서 실행된다 -> 인터페이스 메소드에는 실행블록이 없다. |
| 87 | +### 디폴트 메소드 선언 |
| 88 | +default 키워드가 리턴 타입 앞에 붙는다. 생략해도 컴파일 과정에 붙음 |
| 89 | +### 정적 메소드 선언 |
| 90 | +클래스의 정적 메소드 선언과 동일 |
| 91 | + |
| 92 | + |
| 93 | + ``` |
| 94 | + // 상수 |
| 95 | + int MAX_VOLUME = 10; |
| 96 | + int MIN_VOLUME = 0; |
| 97 | + |
| 98 | + // 추상 메소드 |
| 99 | + void turnOff(); |
| 100 | + void turnOn(); |
| 101 | + void setVolume(int volume); |
| 102 | + |
| 103 | + //디폴트 메소드 |
| 104 | + default void setMute(boolean mute){ |
| 105 | + if(mute){ |
| 106 | + sout("무음처리"); |
| 107 | + } |
| 108 | + else{ |
| 109 | + soutv("무음 해제"); |
| 110 | + } |
| 111 | + } |
| 112 | + //정적 메소드 |
| 113 | + static void changeBattery(){ |
| 114 | + sout("건전지를 교체합니다."); |
| 115 | + } |
| 116 | + ``` |
| 117 | + |
| 118 | +## 인터페이스 구현 |
| 119 | +개발 코드가 인터페이스를 호출하면, 인터페이스는 객체의 메소드 호출 |
| 120 | +객체는 정의된 추상 메소드와 동일한 메소드 이름,매개타입,리턴타입을 가진 실체메소드를 가지고 있어야 한다. |
| 121 | +구현 객체를 생성하는 클래스를 구현 클래스라고 한다. |
| 122 | + |
| 123 | +### 구현클래스 |
| 124 | + |
| 125 | + ``` |
| 126 | + public class Television implements RemoteControl{ |
| 127 | + //필드 |
| 128 | + private int volume; |
| 129 | + |
| 130 | + //turnOn() 추상메소드의 실체 메소드 |
| 131 | + public void turnOn(){ |
| 132 | + sout("티비를 켭니다"); |
| 133 | + } |
| 134 | + //Keep implements... |
| 135 | +} |
| 136 | + ``` |
| 137 | + - 인터페이스의 모든 메소드는 기본적으로 public 접근 제한을 갖기 때문에 public보다 더 낮은 접근 제한으로 작성할 수 없다. |
| 138 | +- 만약 인터페이스에 선언된 추상 메소드에 대응하는 실체 메소드를 구현 클래스가 작성하지 않으면 구현 클래스는 자동적으로 추상 클래스가 된다. -> abstract키워드를 추가해야 한다. |
| 139 | + |
| 140 | +### 익명 구현 객체 |
| 141 | +구현 클래스를 만들어 사용하는 것이 일반적이고, 클래스 재사용성 때문에 편리하지만, 일회성 구현 객체를 만들기 위해 소스파일과 클래스를 선언하는 것은 비효율적이다. |
| 142 | +이를 위해 익명 구현 객체가 존재한다. |
| 143 | +람다식은 인터페이스의 익명 구현 객체를 만든다 -> |
| 144 | + ``` |
| 145 | +인터페이스 변수 = new 인터페이스(){ |
| 146 | + //인터페이스에 선언된 추상 메소드의 실체 메소드 구현 |
| 147 | +}; |
| 148 | +
|
| 149 | + ``` |
| 150 | +### 다중 인터페이스 implements |
| 151 | +-  |
| 152 | + ``` |
| 153 | +public class 구현클래스명 implements 인터페이스A, 인터페이스B{ |
| 154 | + //인터페이스A에 선언된 추상 메소드의 실체 메소드 선언 |
| 155 | + //인터페이스B에 선언된 추상 메소드의 실체 메소드 선언 |
| 156 | +} |
| 157 | +
|
| 158 | + ``` |
| 159 | +## 인터페이스 사용 |
| 160 | +- 인터페이스로 구현 객체를 사용하려면, 인터페이스 변수에 구현 객체를 대입한다. |
| 161 | +- 인터페이스 변수는 참조 타입이기에, 구현 객체의 번지를 저장한다. |
| 162 | +- 개발 코드에서 인터페이스는 클래스의 필드, 생성자 또는 메소드의 매개 변수, 생성자 또는 메소드의 로컬 변수로 선언될 수 있다. |
| 163 | + ``` |
| 164 | +public class MyClass{ |
| 165 | + //필드 |
| 166 | + RemoteControl rc = new Television(); |
| 167 | + |
| 168 | + //생성자 |
| 169 | + MyClass(RemoteControl rc){ |
| 170 | + this.rc = rc; |
| 171 | + } |
| 172 | + |
| 173 | + //메소드 |
| 174 | + void methodA(){ |
| 175 | + RemoteControl rc = new Audio(); |
| 176 | + } |
| 177 | + |
| 178 | + void methodB(RemoteControl rc){...} |
| 179 | + //... |
| 180 | + |
| 181 | + mc.methodB(new Audio()); |
| 182 | + |
| 183 | +} |
| 184 | + ``` |
| 185 | +## 타입변환과 다형성 |
| 186 | +상속은 같은 종류의 하위 클래스를 만드는 기술 , 인터페이스는 사용 방법이 동일한 클래스를 만드는 기술이다. |
| 187 | +둘의 개념적 차이가 존재하지만, 둘 다 다형성을 구현한다. 다형성 다형성 신나는 노래🥳 |
| 188 | +- 인터페이스의 다형성이란? |
| 189 | +: 프로그램 소스는 변함이 없는데, 구현 객체를 교체함으로써 프로그램의 실행 결과가 다양해 진다. 당연히 유지보수에 좋다. |
| 190 | +- 구현 객체가 인터페이스 타입으로 자동 변환하면, 인터페이스 메소드만 사용 가능하다. 경우에 따라, 구현 클래스에 선언된 필드/메소드를 사용해야 할 경우도 있다. 이때 강제 타입 변환으로 다시 구현 클래스타입으로 변환 후, 구현 클래스의 필드/메소드를 사용할 수 있다. -> instacneof 를 사용하여 객체 타입 확인하기~ |
| 191 | + |
| 192 | + ``` |
| 193 | +public void dirve(Vehicle vehicle){ |
| 194 | + if(vehicle instanceof Bus){ |
| 195 | + Bus bus = (Bus) vehicle; |
| 196 | + } |
| 197 | +} |
| 198 | + ``` |
| 199 | + |
| 200 | +## 인터페이스 상속 |
| 201 | +- 인터페이스는 인터페이스를 상속할 수 있다. |
| 202 | +- 인터페이스는 다중 상속이 가능하다. |
| 203 | + |
| 204 | + ``` |
| 205 | + public class Television implements RemoteControl{ |
| 206 | + //필드 |
| 207 | + private int volume; |
| 208 | + |
| 209 | + //turnOn() 추상메소드의 실체 메소드 |
| 210 | + public void turnOn(){ |
| 211 | + sout("티비를 켭니다"); |
| 212 | + } |
| 213 | + //Keep implements... |
| 214 | +} |
| 215 | + ``` |
| 216 | + - 인터페이스의 모든 메소드는 기본적으로 public 접근 제한을 갖기 때문에 public보다 더 낮은 접근 제한으로 작성할 수 없다. |
| 217 | +- 만약 인터페이스에 선언된 추상 메소드에 대응하는 실체 메소드를 구현 클래스가 작성하지 않으면 구현 클래스는 자동적으로 추상 클래스가 된다. -> abstract키워드를 추가해야 한다. |
| 218 | + |
| 219 | +### 익명 구현 객체 |
| 220 | +구현 클래스를 만들어 사용하는 것이 일반적이고, 클래스 재사용성 때문에 편리하지만, 일회성 구현 객체를 만들기 위해 소스파일과 클래스를 선언하는 것은 비효율적이다. |
| 221 | +이를 위해 익명 구현 객체가 존재한다. |
| 222 | +람다식은 인터페이스의 익명 구현 객체를 만든다 -> |
| 223 | + ``` |
| 224 | +인터페이스 변수 = new 인터페이스(){ |
| 225 | + //인터페이스에 선언된 추상 메소드의 실체 메소드 구현 |
| 226 | +}; |
| 227 | +
|
| 228 | + ``` |
| 229 | +### 다중 인터페이스 implements |
| 230 | +-  |
| 231 | + ``` |
| 232 | +public class 구현클래스명 implements 인터페이스A, 인터페이스B{ |
| 233 | + //인터페이스A에 선언된 추상 메소드의 실체 메소드 선언 |
| 234 | + //인터페이스B에 선언된 추상 메소드의 실체 메소드 선언 |
| 235 | +} |
| 236 | +
|
| 237 | + ``` |
| 238 | +## 인터페이스 사용 |
| 239 | +- 인터페이스로 구현 객체를 사용하려면, 인터페이스 변수에 구현 객체를 대입한다. |
| 240 | +- 인터페이스 변수는 참조 타입이기에, 구현 객체의 번지를 저장한다. |
| 241 | +- 개발 코드에서 인터페이스는 클래스의 필드, 생성자 또는 메소드의 매개 변수, 생성자 또는 메소드의 로컬 변수로 선언될 수 있다. |
| 242 | + ``` |
| 243 | +public interface 하위인터페이스 extends 상위인터페이스1, 상위인터페이스1 {...} |
| 244 | +} |
| 245 | + ``` |
| 246 | +1) 하위 인터페이스를 구현하는 객체는 하위 메소드 뿐 아니라 상위 인터페이스의 모든 추상 메소드에 대한 실체 메소드를 가지고 있어야 한다. |
| 247 | +2) 하위 인터페이스 타입은 상, 하위 인터페이스 메소드 사용이 가능하다. |
| 248 | +3) 그러나 상위 인터페이스는 상위 메소드만 사용 가능하다. |
| 249 | + |
| 250 | +## 디폴트 메소드와 인터페이스 확장 |
| 251 | +부모 인터페이스에 디폴트 메소드가 정의 되어 있을 경우, 자식 인터페이스에서 디폴트 메소드를 활용하는 방법은 세가지다. |
| 252 | + |
| 253 | +디폴트 메소드를 단순히 상속만 받는다. |
| 254 | +디폴트 메소드를 재정의(Override)해서 실행 내용을 변경한다. |
| 255 | +디폴트 메소드를 추상 메소드로 재선언한다. |
| 256 | + |
0 commit comments