|
| 1 | +# 익명클래스, 추상클래스, 인터페이스 |
| 2 | + |
| 3 | +Created by: 이재현 |
| 4 | +Created time: 2023년 7월 6일 오후 9:54 |
| 5 | +Tags: JAVA |
| 6 | + |
| 7 | +## 익명 클래스란? |
| 8 | + |
| 9 | +- 말그대로 클래스의 이름을 정하지 않는 것으로, |
| 10 | +한번만 사용되고 버리고자 한다면 사용할 수 있다. |
| 11 | +- 일반적으로 어떤 클래스의 자원을 상속받아 재정의하여 사용하기 위해서는 |
| 12 | +자식이 될 클래스를 만들고 상속받아서 객체 인스턴스 초기화를 해야 한다. |
| 13 | + |
| 14 | +```java |
| 15 | +package week1; |
| 16 | + |
| 17 | +class Animal { |
| 18 | + public void func() { |
| 19 | + System.out.println("Animal! Animal!"); |
| 20 | + } |
| 21 | +} |
| 22 | + |
| 23 | +class Cat extends Animal { |
| 24 | + @Override |
| 25 | + public void func() { |
| 26 | + System.out.println("Meow! Meow!"); |
| 27 | + } |
| 28 | +} |
| 29 | + |
| 30 | +public class ex1 { |
| 31 | + public static void main(String[] args) { |
| 32 | + Animal a = new Cat(); |
| 33 | + a.func(); |
| 34 | + } |
| 35 | +} |
| 36 | +``` |
| 37 | + |
| 38 | + |
| 39 | + |
| 40 | +- 위 예제 코드를 익명 클래스로 바꾸어보자. |
| 41 | + - 따로 클래스를 정의하지 않고도 메소드 내에서 바로 클래스를 생성하여 인스턴스화를 할 수 있으며, 이로부터 클래스의 선언 및 객체의 생성을 동시에 수행하므로 단 한 번만 사용된다. |
| 42 | + - 익명으로 정의된 클래스는 일회용으로 사용되고 버려진다. |
| 43 | + - 그러므로 단 한번만 정의하고 사용하고자 하는 클래스는 익명 클래스로 선언하는 것이 메모리 관점에서 효율적일 수 있다. |
| 44 | + - 생성된 익명 객체는 다른 객체와 마찬가지로, 더이상 사용되지 않는다고 판단되면 GC 에 의해 회수된다. |
| 45 | + |
| 46 | +```java |
| 47 | +package week1; |
| 48 | + |
| 49 | +class Animal { |
| 50 | + public void func() { |
| 51 | + System.out.println("Animal! Animal!"); |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +public class ex1 { |
| 56 | + public static void main(String[] args) { |
| 57 | + Animal a = new Animal(){ |
| 58 | + @Override |
| 59 | + public void func(){ |
| 60 | + System.out.println("Meow! Meow!"); |
| 61 | + } |
| 62 | + }; |
| 63 | + a.func(); |
| 64 | + } |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | + |
| 69 | + |
| 70 | +<aside> |
| 71 | +💡 **재사용하지 않을 클래스를 익명 클래스로 선언하면 코드를 보다 간편하게 줄일 수 있고, 메모리 관점에서 효율적이라고 할 수 있다.** |
| 72 | + |
| 73 | +</aside> |
| 74 | + |
| 75 | +### 일반적으로 인터페이스를 구현할 때 익명 클래스를 자주 사용한다. |
| 76 | + |
| 77 | +- 아래의 예시를 보자. |
| 78 | + |
| 79 | +`Calculator` 클래스의 `int result(Operate op)` 메서드는 전달받는 `Operate` 객체의 `act` 메서드에 의해서 반환값이 달라진다. |
| 80 | + |
| 81 | +```java |
| 82 | +public class Calculator { |
| 83 | + int a; |
| 84 | + int b; |
| 85 | + public Calculator(int a, int b) { |
| 86 | + this.a = a; |
| 87 | + this.b = b; |
| 88 | + } |
| 89 | + public int result(Operate op){ |
| 90 | + return op.act(a, b); |
| 91 | + } |
| 92 | +} |
| 93 | +``` |
| 94 | + |
| 95 | +- `Operate` 는 아래와 같이 `int act(int a, int b)` 를 멤버로 가지는 인터페이스로 구현되어 있다. |
| 96 | + |
| 97 | +```java |
| 98 | +public interface Operate { |
| 99 | + int act(int a, int b); |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +- 따라서 Calculator 가 덧셈기로 동작하도록 하려면, |
| 104 | +Operate 를 구현한 Plus 라는 객체를 만들어서 사용해야 한다. |
| 105 | + |
| 106 | +```java |
| 107 | +public class Plus implements Operate { |
| 108 | + @Override |
| 109 | + public int act(int a, int b) { |
| 110 | + return a + b; |
| 111 | + } |
| 112 | +} |
| 113 | +``` |
| 114 | + |
| 115 | +```java |
| 116 | +public class ex2 { |
| 117 | + public static void main(String[] args) { |
| 118 | + Calculator calc = new Calculator(20, 10); |
| 119 | + Operate op = new Plus(); |
| 120 | + System.out.println(calc.result(op)); |
| 121 | + } |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | + |
| 126 | + |
| 127 | +- 하지만 이렇게 구현하면 문제가 다소 발생한다. |
| 128 | + - 뺄셈 기능을 사용하려면 Minus 라는 객체를 만들어야하고... |
| 129 | + - 나눗셈 기능을 사용하려면 Divide 라는 객체를 만들어야할테고... 🫠 |
| 130 | +- 이러한 상황에서 익명 클래스를 사용하면 매우 효율적이다. |
| 131 | + |
| 132 | +```java |
| 133 | +public class ex2 { |
| 134 | + public static void main(String[] args) { |
| 135 | + Calculator calc = new Calculator(20, 10); |
| 136 | + int result = calc.result(new Operate() { |
| 137 | + @Override |
| 138 | + public int act(int a, int b) { |
| 139 | + return a - b; |
| 140 | + } |
| 141 | + }); |
| 142 | + System.out.println(result); |
| 143 | + } |
| 144 | +} |
| 145 | +``` |
| 146 | + |
| 147 | + |
| 148 | + |
| 149 | +- 람다식을 이용하면 보다 간결하게 작성할 수 있다. |
| 150 | + |
| 151 | +```java |
| 152 | +public class ex2 { |
| 153 | + public static void main(String[] args) { |
| 154 | + Calculator calc = new Calculator(20, 10); |
| 155 | + int result = calc.result((a, b) -> a - b); |
| 156 | + System.out.println(result); |
| 157 | + } |
| 158 | +} |
| 159 | +``` |
| 160 | + |
| 161 | +--- |
| 162 | + |
| 163 | +## 추상 클래스와 인터페이스의 개념과 공통점 |
| 164 | + |
| 165 | +(추상 클래스와 인터페이스의 차이점에 관한 질문이 면접에서 자주 등장한다고 한다.) |
| 166 | + |
| 167 | +- **모 블로그의 면접 후기 🥲🥲** |
| 168 | + |
| 169 | + |
| 170 | + |
| 171 | +- 추상 메서드란 내부가 구현되지 않은 메소드이다. |
| 172 | + |
| 173 | +```java |
| 174 | +public interface Animal{ |
| 175 | + public void sound(); // 추상 메서드 |
| 176 | +} |
| 177 | +``` |
| 178 | + |
| 179 | +- 추상 클래스는 추상 메서드를 포함하고 있는 클래스를 의미한다. |
| 180 | +- 인터페이스는 모든 메서드가 추상 메서드로만 이루어진 클래스이다. |
| 181 | + - 추상 클래스와 인터페이스는 하위 클래스에서 구현을 강제하는 추상 메서드를 포함한다는 공통점이 있다..! |
| 182 | + - 근데 굳이 왜 두 개가 나뉜걸까..?? |
| 183 | + |
| 184 | +--- |
| 185 | + |
| 186 | +## 추상 클래스와 인터페이스의 차이점 |
| 187 | + |
| 188 | +- 핵심 키워드는 `상속` ********************이다. |
| 189 | + - 우선 자바에서는 클래스의 다중 상속을 지원하지 않는다. |
| 190 | + - 아래와 같은 `다이아몬드 상속` 문제를 방지하기 위해 지원하지 않도록 결정했다고 한다. |
| 191 | + |
| 192 | +  |
| 193 | + |
| 194 | + - `ComboDrive` 클래스에서 구현해야 할 `burn()` 은 누구로부터 온것인가?! 🫠 |
| 195 | + - 위와 같이 상위 클래스에서 같은 이름의 메서드가 존재한다면, 하위 클래스에서 그 메서드를 호출했을 때 실제로 어떤 메서드가 호출되어야 할 지 모호해진다. |
| 196 | +- 하지만 인터페이스는 다른 클래스와는 다르게 **다중 상속**이 가능하다! |
| 197 | + - 애초에 모든 메서드가 추상 메서드로 이루어져있기 때문에 다이아몬드 문제는 우려하지 않아도 된다. |
| 198 | + - 다중 상속 받은 하위 클래스는 상속받은 모든 인터페이스를 구현해야 하고, 모든 상위 인터페이스의 구현체로 사용할 수 있다. |
| 199 | + - 하지만 다중상속만이 인터페이스의 존재 이유라고 이야기 할 수는 없다. |
| 200 | + - 인터페이스를 상속받은 클래스는 모든 추상 메서드를 재정의하여야 하므로, 하위 클래스에게 일종의 설계도와 같은 역할을 수행한다. |
| 201 | + - 추상클래스는 조금 다르다. 하위 클래스는 상속받은 추상 클래스의 기존 메서드는 그대로 이용하고, 추상 메서드만 확장하는 역할을 수행한다. |
| 202 | + |
| 203 | +<aside> |
| 204 | +💡 **즉, 추상 클래스는 상속 받은 클래스의 기능을 이용하고 확장하는 것이 주목적이고 인터페이스는 하위 클래스에게 일종의 설계도와 같은 역할을 제공한다는 것이 중요하다!** |
| 205 | + |
| 206 | +</aside> |
| 207 | + |
| 208 | +--- |
0 commit comments