com.eomcs.oop.ex12.Exam0510.java
기존에 있는 메서드를 사용할 수 있다.
인터페이스를 구현할 때 기존의 메서드를 사용하고 싶
익명 클래스로 만들 수도 있음
더하기든 빼기든 앞으로는 compute를 호출하자
인터페이스를 구현해야 됨
그렇다고 처음부터 작성하기는
새 사용법에 맞춰서 새로 만들어야 한다
기존에 작성된 코드를 복붙할 것인가
경력 있는 개발자는 그러진 않을 것이다
메서드를 처음부터 다시 구현하는 게 아니라
기존에 작성한 코드를
처음부터 작성하면 시간도 걸리고.. 버그 검사해야 되고
코드가 중복되면 위험하다는 건 몇 번이나 강조했었음
class CalculatorImpl implements Calculator {
@Override
public int compute(int x, int y) {
return x + y;
}
}
class CalculatorImpl implements Calculator {
@Override
public int compute(int x, int y) {
return MyCalculator.plus(x, y);
}
}
Calculator calc1 = new CalculatorImpl();
Calculator calc2 = new Calculator() {
@Override
public int compute(int x, int y) {
return MyCalculator.plus(x, y);
}
};
인스턴스를 생성하는 문장은 항상 세미콜론으로 끝나야 한다.
람다 문법
Calculator calc3 = (x, y) -> MyCalculator.plus(x, y);
return 지우기
컴파일러 너가 해
inner class에서 컴파일러가 자동으로 만들어 주는 거랑 똑같음
네 번째,
껍데기 너가 만들어
Calculator calc4 = MyCalculator::plus;
System.out.println(calc4.compute(100, 200));
컴파일러가 나 대신 클래스 만들라는 거
Calculator 인터페이스 구현체를 만들라는 거
MyCalculator::plus 이 문장이
익명 클래스 문장으로 바뀐다는 거
독립적인 문법이라기 보다 기존에 있는 문법을 간략하게 표현할 수 있는 일종의 단축 문법
단축 문법이 존재하는데도 불구하고 저렇게 짜면
메서드 레퍼런스라는 껍데기를 자동으로 씌워주는 문법이 존재하는데도 안 쓰면 무식하다는 소리 들음
// 메서드 레퍼런스 - 스태틱 메서드 레퍼런스
package com.eomcs.oop.ex12;
public class Exam0510xx {
static class MyCalculator {
public static int plus(int a, int b) {return a + b;}
public static int minus(int a, int b) {return a - b;}
public static int multiple(int a, int b) {return a * b;}
public static int divide(int a, int b) {return a / b;}
}
interface Calculator {
int compute(int x, int y);
}
public static void main(String[] args) {
// 1) 로컬 클래스
class CalculatorImpl implements Calculator {
@Override
public int compute(int x, int y) {
return MyCalculator.plus(x, y);
}
}
Calculator c1 = new CalculatorImpl();
System.out.println(c1.compute(200, 17));
// 1) 익명 클래스
Calculator c2 = new Calculator() {
@Override
public int compute(int x, int y) {
return MyCalculator.plus(x, y);
}
};
System.out.println(c2.compute(200, 17));
// 3) 람다
Calculator c3 = (x, y) -> MyCalculator.plus(x, y);
System.out.println(c3.compute(200, 17));
// 4) 메서드 레퍼런스
Calculator c4 = MyCalculator::plus;
System.out.println(c4.compute(200, 17));
}
}
com.eomcs.oop.ex12.Exam0520.java
메서드 레퍼런스 - 스태틱 메서드 레퍼런스 구현 원리
Calculator c1 = MyCalculator::plus;
컴파일러에게 기존 메서드를 사용하여
인터페이스 구현체를 만들라는 명령
직접 코딩하지 말고
컴파일러가 대신해서 이런 코드를 작성해준다
new Calculator() {
@Override
public int compute(int x, int y) {
return MyCalculator.plus(x, y);
}
};
단축 문법일 뿐이다
com.eomcs.oop.ex12.Exam0530.java
Calculator c01 = MyCalculator::plus;
Calculator c01 = MyCalculator::minus;
Calculator c01 = MyCalculator::multiple;
Calculator c01 = MyCalculator::divide;
단, 못 만드는 게 있을 거임
해당 메서드를 가지고 구현체를 만들 수 없다.
메서드 레퍼런스가 가능한지 불가능한지
double compute(int a, int b)
↓ call
int plus(int a, int b)
plus에 껍데기를 씌울 수 있는가
파라미터 값이 그대로 전달될 수 있는가 따진다
리턴한 int값을 double로 리턴할 수 있는가
short compute(int a, int b)
↓ call
int plus(int a, int b)
파라미터 받을 수 있는가? O
short로 던질 수 있는가? X. 자동 형변환이 안 된다.
byte, short, char > int > long > float > double
거꾸로는 자동 형변환 안 됨!
void compute(int a, int b)
↓ call
int plus(int a, int b)
안 받고 안 던지는 건 OK
Object compute(int a, int b)
↓ call
int plus(int a, int b)
인터페이스를 자동으로 구현할 수 있는가
int ------> Object (자동 형변환 됨)
오토 박싱
int a = 100;
Integer obj = new Integer(100);
Object obj2 = a; // Integer.valueOf(a);
Object 타입이면 오토 박싱이 일어난다.
String compute(int a, int b)
↓ call
int plus(int a, int b)
com.eomcs.oop.ex12.Exam0540.java
구현체를 만들 수 있냐고
리턴 값을 double로 만들 수 있냐고
인터페이스에 있는 메서드가 byte를 받아서 int에 전달할 수 있는가? O
int compute(long a, long b)
↓ call
int plus(int a, int b)
외부에서 compute를 호출할 때 long 값을 받을 건데
plus 호출해줘 라고 했을 때
자기가 받은 long 값을 전달할 수 있는가? X
Calculator1 c1 = MyCalculator::plus;
내가 준 메서드 가지고 Calculator 구현체 만들어봐
Calculator 구현. 메서드까지 구현.
이게 가능하면 OK
이게 불가능하면 OK가 안 되는 거
메서드 레퍼런스는 여기서 끝내겠다
나중에 익숙해지면 생성자에서 쓰는
com.eomcs.algorithm.data_structure.array2.step1
이걸 지원하는 문법이 바로 제네릭이라는 문법
ArrayList로 받을 항목의 타입
@SuppressWarnings("unchecked")
public itemType get(int index) {
if (index < 0 || index >= size) {
throw new ArrayIndexOutOfBoundsException("인덱스가 유효하지 않습니다.");
}
return (itemType) elementData[index];
}
안 넣어주면 기본이 Object
가능하면 알파벳 대문자 한 개로
https://docs.oracle.com/javase/tutorial/
https://docs.oracle.com/javase/tutorial/java/generics/index.html
E - Element (used extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types
① 특정 타입으로 사용을 제한할 수 없다.
② 값을 꺼낼 때마다 형변환 해야 한다.
개선
IntArrayList
StringArrayList
ScoreArrayList
① 특정 타입을 다루는 클래스 별도 정의
② 형변환이 필요 없다
문제점
타입별로 ArrayList 정의해야 한다
특정 타입을 다루는 클래스
한 개의 클래스로 다양한 타입을 다룰 수 있다.
Object로 하면 특정 타입으로 사용을 제한할 수 없다.
꺼낼 때마다 형변환 해야 된다.
표준 클래스 정의
ArrayList<E>
사용할 때 타입을 지정한다.
ArrayList<integer>
ArrayList<String>
ArrayList<Score>
ArrayList<Member>
한 개의 클래스를 가지고 다양한 타입에 사용할 수 있다.
com.eomcs.generic.ex01
클래스 전체에도 적용할 수 있지만 메서드에 한정해서 적용할 수도 있다.
잘못된 형변환은 컴파일러는 속일 수 있을 지라도, runtime 에서는 오류를 발생시킨다.
JVM이 잡아 낸다
제네릭 문법을 떠나서 알고 있기
// 제네릭 적용 전
static Object[] reverse(Object[] arr) {
for (int i = 0; i < arr.length / 2; i++) {
Object temp = arr[i];
int targetIndex = arr.length - 1 - i;
arr[i] = arr[targetIndex];
arr[targetIndex] = temp;
}
return arr;
}
제네릭 배열
제네릭의 타입 파라미터로 레퍼런스 배열을 생성할 수 없다.
arr = new T[10]; // 컴파일 오류! new 명령어를 사용할 때 제네릭의 타입 파라미터를 사용할 수 없다.
문법적으로 안 된다
타입별로 클래스를 만들 필요가 없다
어떤 타입의 목록을 다루는 ArrayList 타입을 지정하지 않으면 아무거나 다 됨
// => 레퍼런스를 선언할 때 제네릭 타입을 지정하지 않으면
// ArrayList 객체를 생성할 때 지정한 제네릭 타입은 무시된다.
컴파일러도 검사 못 함
파라미터 타입이 정해지지 않았기 때문에
다형적 변수에 입각해서
여기서는 다형적 변수 그런 거 안 따짐.
사용하는 문법을 검사할 때는 다형적 문법을 따진다.
레퍼런스에서 지정한 타입과 인스턴스에서 지정합 타입이 다르다면 모순 발생!
224, 225는 나중에
com.eomcs.generic.ex02.Exam0230.java
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashMap.html
com.eomcs.generic.ex03
com.eomcs.oop.ex12.Exam0630.java
generic.ex01 ~ ex03
com.eomcs.basic.ex03 혼자 공부하기 (반드시 하기)