Day37 Java프로그래밍 기초(메서드 레퍼런스)
메서드 레퍼런스
1. 메소드 레퍼런스의 개념
- 메서드를 참조해서 매개변수의 정보 및 리턴 타입을 알아내 람다식을 간소화 하는 것을 목적으로 사용한다.
- 정적 메소드는 클래스 이름 뒤에 ::기호를 붙인다. ```java 클래스::메서드 ```
- 인스턴스 메서드는 객체를 생성하여 레퍼런스를 만들고 ::기호를 붙인다. ```java 레퍼런스::메서드 ```
2. 스태틱 메서드 레퍼런스
1) 스태틱 메서드 레퍼런스 구현
- 기존 람다식 구현하는 방법에 ::기호를 추가한다.
- 기존 람다식 구현하는 방법
- 일반클래스로 만든다.
- 익명클래스로 만든다.
- 람다식으로 만든다.
- 메서드레퍼런스로 변경한다.
- 다음과 같이 인터페이스와 static 클래스를 구성한다. ```java static class My{ public static int plus(int a, int b){ return a + b; } } interface Cal{ int compute(int x, int y); } ```
- 일반클래스 구현 ```java public class Test{ public static void main(String[] args){ class CalPlus implements Cal{ @Override public int compute(int x, int y){ return My.plus(x,y); } } Cal c1 = new CalPlus(); System.out.println(c1.compute(100,200)); //300 출력 } } ```
- 익명클래스 구현 ```java public class Test{ public static void main(String[] args){ Cal c2 = new Cal{ @Override public int compute(int x, int y){ return My.plus(x,y); } }; System.out.println(c2.compute(100,200)); //300 출력 } } ```
- 람다클래스 구현 ```java public class Test{ public static void main(String[] args){ Cal c3 = (x, y) -> My.plus(x,y); System.out.println(c3.compute(100,200)); //300 출력 } } ```
- 메서드 레퍼런스 ```java public class Test{ public static void main(String[] args){ Cal c4 = My::plus System.out.println(c4.compute(100,200)); //300 출력 } } ```
2) 스태틱 메서드 레퍼런스 원리
- 메서드 레퍼런스는 다음과 같이 구현한다. ```java static class My{ public static int plus(int a, int b){ return a + b; } } interface Cal{ int compute(int x, int y); } public class Test{ public static void main(String[] args){ Cal c4 = Plus::Cal } } ```
- 컴파일 단계에서 My::plus는 익명 클래스로 전환된다
- 컴파일 단계
- Cal인터페이스를 구현는 클래스를 하나 만든다.
- Cal인터페이스의 compute(int,int)를 오버라이딩한다.
- static class My에 있는 메서드 plus를 호출한다.
3) 스태틱 메서드 레퍼런스 특징
- 메서드 레퍼런스의 특징은 추상메서드에 의해 생긴다.
- 매개변수 : 추상메서드의 매개변수와 동일해야 사용가능하다.
예제코드 접기/펼치기
```java 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; public static int power(int a) return a * 2; } interface Calculator { int compute(int a, int b); } public static void main(String[] args){ //인터페이스의 매개변수 (int,int) // -> 메서드 레퍼런스의 매개변수 (int,int) Calculator c01 = MyCalculator::plus; //OK Calculator c02 = MyCalculator::minus; //OK Calculator c03 = MyCalculator::multiple; //OK Calculator c04 = MyCalculator::divide; //OK //Calculator c05 = MyCalculator::power; //NG } ``` - 반환값 : 추상메서드의 반환값을 반환 할 수 있는 메서드만 가능하다.
예제코드 접기/펼치기
```java static class MyCalculator { public static int plus(int a, int b) { return a + b; } } interface Calculator1 {double compute(int a, int b);} interface Calculator2 {float compute(int a, int b);} interface Calculator3 {short compute(int a, int b);} interface Calculator4 {void compute(int a, int b);} interface Calculator5 {Object compute(int a, int b);} interface Calculator6 {String compute(int a, int b);} public static void main(String[] args) { // 리턴 타입 int ===> double Calculator1 c1 = MyCalculator::plus; // OK! // 리턴 타입 int ===> float Calculator2 c2 = MyCalculator::plus; // OK! // 리턴 타입 int ===> short // Calculator3 c3 = MyCalculator::plus; // 컴파일 오류! // 리턴 타입 int ===> void Calculator4 c4 = MyCalculator::plus; // OK! // 리턴 타입 int ===> Object Calculator5 c5 = MyCalculator::plus; // OK! // 리턴 타입 int ===> String // Calculator6 c6 = MyCalculator::plus; // 컴파일 오류! } ```
3. 인스턴스 메서드 레퍼런스
1) 인스턴스 메서드 레퍼런스 구현
- FunctionalInterface를 기존 인스턴스 매서드를 활용하여 구현체로 만들 수 있다.
- 단, 스태틱 메서드 레퍼런스와 마찬가지로 추상메서드의 특징을 만족해야한다.
- 추상매서드의 매개변수의 개수와 인스턴스 매서드의 개수는 동일
- 추상매서드의 매개변수 타입보다 큰 범위의 인스턴스 매서드의 매개변수 타입
- 추상매서드의 리턴값보다 작은 범위의 인스턴스 매서드의 리턴값
- 인스턴스 매서드를 만드는 방법은 동일하다.
- 다만 인스턴스 매서드의 래퍼런스를 먼저 생성해야한다.
예제코드 접기/펼치기
```java public class Test { static class Calculator { double rate; public Calculator(double rate) {this.rate = rate;} public double year(int money) {return money * rate / 100;} public double month(int money) {return money * rate / 100 / 12;} public double day(int money) {return money * rate / 100 / 365;} public double bonus() {return 100000;} } static interface Interest {double compute(int money);} public static void main(String[] args) { //인스턴스 객체 생성 Calculator 보통예금 = new Calculator(0.5); // 인터페이스 레퍼런스 = 객체::인스턴스매서드 Interest i1 = 보통예금::year; // 람다 문법으로 표현하면: // Interest i1 = money -> 보통예금.year(money); System.out.printf("년 이자: %.1f\n", i1.compute(10_0000_0000)); i1 = 보통예금::month; System.out.printf("월 이자: %.1f\n", i1.compute(10_0000_0000)); i1 = 보통예금::day; System.out.printf("일 이자: %.1f\n", i1.compute(10_0000_0000)); } } ```
4. 생성자 레퍼런스
1) 생성자 래퍼런스의 구현
- 인터페이스의 추상메서드가 생성자의 형식과 일치 한다면 생성자 래퍼런스를 구현 할 수 있다.
- ```java public class Test { static class Message { String name; public Message() { this.name = "이름없음"; } public Message(String name) { this.name = name; } public void print() { System.out.printf("%s님 반갑습니다!\n", name); } } static interface Factory1 { Message get(); } static interface Factory2 { Message get(String name); } public static void main(String[] args) { Factory1 f1 = Message::new; Message m1 = f1.get(); m1.print(); //이름없음님 반갑습니다! Factory2 f2 = Message::new; Message m2 = f2.get("홍"); m2.print(); //홍님 반갑습니다! } } ```
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.