Type dependency in Java, Part 2
Using covariance and contravariance in your Java programs
원 문 : http://www.itworld.com/article/3197118/learn-java/type-dependency-in-java-part-2.html?page=2
메소드는 매개 변수의 유형에 따라 다릅니다. 입력 매개 변수와 함께 메서드의 반환 유형도 출력 매개 변수로 간주합니다. 그러나 리턴 유형은 메소드의 특성에 속하지 않으며 입력 (원시) 매개 변수 유형에만 속합니다.
이름이 다르거 나 매개 변수 수가 다른 메서드는 호환되지 않습니다. 호환성 의 문제 는 동일한 이름과 동일한 수의 매개 변수를 가진 메소드에서만 발생합니다.
메소드 선언과 정의의 호환성
클래스의 본문에있는 메서드 호출은 메서드 정의 (클래스)와 선언 (추상 클래스 및 인터페이스)과 호환되거나 호환되지 않을 수 있습니다. 메서드 선언의 경우 질문은 다른 선언과의 호환성입니다.이 정보는 메서드를 재정의 하거나 과부하 할 것인지 결정하는 데 도움이 됩니다.
Java 선언 및 정의 중 서명과 관련된 차이는 없습니다. 메소드가 다른 메소드를 겹쳐 쓰면 서명이 동일해야합니다. 그러나 결과 유형 에 대한 공분산이 있습니다 .
서명과 관련한 Java의 엄격한 규칙을 준수 procedure()
하면이 경우 오버로드되지 않으며 오버라이드되지 않습니다. 주석 @Override
을 추가하면 두 인터페이스 에 SubType.procedure()
대해 매개 변수 유형이 같지 않기 때문에 컴파일러에 오류 메시지가 표시됩니다 procedure()
.
호출이 선언 또는 정의와 호환되는지 여부는 서명을 기반으로 결정됩니다. 여기에는 공분산이 있습니다. 매개 변수의 상위 호환성은 호출의 호환성을 의미합니다. 그러나 우리가 호출 대상 객체에 관심이 있다면, 우리는 분산 에 대해서가 아니라 다형성 에 대해서 말합니다 :
서명과 관련하여 선언 및 정의에 대한 호출은 공 변 (covariant)입니다. 아래의 마지막 것은 불변입니다.
함수의 차이
Java의 메소드 선언 및 정의는 결과 유형과 관련하여 공 변합니다. 매개 변수와 달리 함수 의 결과 유형은 서명에 속하지 않습니다. 결과 형식은 다른 방식으로는 변경할 수 없지만 재정의 된 버전에서 위쪽으로 확장 될 수 있습니다.
함수 결과를 호출 할 때 분산을 찾지는 않지만 대신 상향 호환성을 찾습니다.
그러나 위의 코드에서 나타난 상향 호환성은 공분산 형태로 간주 될 수 있습니다.
함수 결과와 마찬가지로, 액세스 보호 ( private
, public
등) 및 예외 스펙 ( throws
)은 서명에 속하지 않습니다. (그러나 메서드가 재정의 된 경우 위쪽으로 확장 될 수 있습니다.) Appending final
은 다음과 같이 오버라이드를 더 이상 방지 합니다 .
대체로 메소드 편차는 간단합니다. 메소드 서명의 선언과 정의는 서로 불변합니다. 결과 유형, 예외 스펙 및 선언 및 정의에 대한 호출과 같은 다른 모든 요소는 공 변 (covariant)입니다. 표 2는 방법 차이를 요약 한 것이다.
표 2. 방법 차이
선언 정의 | 요구 | |
서명 | 불변량 | 공변량 |
결과 형 | 공변량 | 공변량 |
람다 식에서의 분산 사용 람다 식은 익명 메서드입니다. 모든 익명의 언어 요소 (클래스 및 객체 포함)와 마찬가지로, 이들은 일회용으로 가장 적합합니다. Lambda는 코드 가독성의 원칙을 충족시켜 소프트웨어 품질을 만족시킵니다. 우리는 그 원칙을 다음과 같이 요약 할 수 있습니다. 정의가 사용법에 가까울수록 좋을 것 입니다.
람다 표현식을 사용하면 익명의 프로그램 요소가 사용되는 것처럼 정의 할 수 있습니다. 이렇게 :
이 코드는 다음 선언을 가정합니다.
Java 8 이전에는 호출 procedure()
이 더 복잡해 보였습니다.
익명의 클래스와 객체로 구현 된 다소 간단한 예제 :
Java 8 이전에는 콜백이 다음과 같이 구현되었습니다.
전통적인 콜백 프로 시저에서 메서드 a 는 b 를 호출하는 동안 매개 변수 로 메서드 c 를 전달 하므로 b 가 c를 호출 합니다. b 프로그래밍 을하는 경우 그림 2의 빨간색 원으로 표시된 위치에서 메소드를 호출하지만 호출 할 메소드를 알지 못합니다.
Lambda는 콜백을 구현하는 훨씬 간단한 방법을 제공합니다.
람다 (lambdas)로 통화 단순화
함수를 통합하기위한 알고리즘을 프로그래밍하려는 경우 어떤 함수 (예 : 사인 ) 를 통합할지 모른 채 작성해야합니다 . 그림 3은 사인의 적분을 계산하는 알고리즘을 보여줍니다.
그런 다음 알고리즘을 호출 할 때 통합 알고리즘 사용자가 해당 함수를 ( a 및 b 와 함께 ) 전달합니다. 아래에서, 0 과 π 사이 의 사인 의 적분을 계산하는 데 사용 된 알고리즘을 보았습니다.이 값 은 1.0 입니다.
Java에서 콜백의 좋은 예는 리스너입니다.
수업을 프로그래밍한다고 가정 해보십시오 Button
. 버튼 누름에 반응하도록 버튼을 프로그래밍해야하지만 동작은 정의되지 않습니다. 클래스의 사용자 만 응용 프로그램이 요구하는 정확한 작업을 알 수 있습니다 (이 경우 해당 작업이 수행됩니다 System.out.println()
).
제네릭 단추를 개발하려면 ActionListener
개체를 만들고 이를 Button
호출 하여 개체에 전달합니다 addActionListener()
. 그런 다음 작업이 프로그래밍되는 ActionListener
메서드 actionPerformed()
를 구현합니다. (더 복잡한 예제에서는 ActionEvent
매개 변수도 사용할 수 있습니다 .) Button
버튼을 누르면 사용자 메서드가 클래스 에 의해 "콜백"됩니다 .
lambdas를 도입하면이 프로그램이 간단 해집니다.
즉시 사용할 수있는 메서드 참조를 사용하면 System
더욱 간단하게 처리 할 수 있습니다.
Math
메서드 참조를 내보내 므로 sin
호출 할 때이 메서드 를 사용할 수도 있습니다 integral()
.
그럼 당신은 선언 했음에 틀림 없습니다.
여기서 Function
두 가지 유형 매개 변수가있는 일반 인터페이스가 있습니다.
기능 인터페이스의 Lambdas
당신은 선언 후 람다 표현식을 사용할 수 있습니다 기능 인터페이스를 . 정확히 하나의 (추상적 인) 비 제네릭 메소드를 선언하는 한, 모든 인터페이스를 사용할 수 있습니다. 컴파일러는 인터페이스가 주석으로 표시되어 있으면 이러한 기준을 확인합니다 @FunctionalInterface
.
파라미터의 타입 Button.addActionListener()
, 즉 java.awt.event.ActionListener
, 기준이 만족; 따라서 매개 변수로 람다 식을 사용하여 호출 할 수 있습니다. 람다 표현식은 하나 개의 파라미터와 익명 방식 (이하 '람다의 값 ")을 나타내고, e
화살표 전에 ->
, 그리고 이후에있어서 본체 (A 블록).
Java 8에서 람다 식은 객체처럼 동작하며 매개 변수로 전달 될 수 있습니다. 이 개체는 "람다 형식"으로 간주됩니다. 예제의 경우 객체는 ActionListener
기능 인터페이스 유형 입니다.
람다 식에 대한 참조를 정의 할 수도 있습니다.
통화에서 나중에 사용하십시오.
동일한 청취자를 둘 이상의 단추에 지정하려는 경우 유용 할 수 있습니다.
또 다른 예는 Runnable
다음과 같습니다.
이 호출은 람다 표현식을 사용하면 훨씬 간단 해집니다.
람다 식은 해당 기능 인터페이스 유형을 갖습니다. 다음 예에서 우리는 유형 (지정할 수 있습니다 String
두 개의 매개 변수)를 left
하고 right
있지만, 컴파일러는 추론에 의한 유형을 확인할 수 있습니다 :
이 참조에서는 다음과 같이 람다 값 (메서드 본문)을 호출합니다.
전화를 단순화하는 것이 람다의 유일한 장점은 아닙니다. 람다 표현식은 객체 지향 프로그래밍과 기능 스타일 프로그래밍을 혼합하여 Java에서 새로운 프로그래밍 패러다임을 가능하게합니다. 람다를 사용하여 많은 알고리즘을보다 간결하고 더 읽기 쉽게 작성할 수 있으며 많은 경우 프로그램의 정확성을 향상시키는 데 도움이됩니다.
람다 표현의 공분산
람다는 일반적이어서는 안됩니다. 그러므로 그들은 편차를위한 여지가 거의 없다. 종종 컴파일러의 추론 알고리즘이 람다 식의 유형을 결정하는 것은 어렵습니다. 따라서 람다 식의 매개 변수 유형은 기능 인터페이스의 유형에 정확히 맞아야합니다. 메서드 매개 변수에 대한 일반적인 호환성 규칙이 적용됩니다.
컴파일러는 SuperType
마지막 행에서 적합하지 않은 객체를 수락 하지만 본문의 형 변환 은 런타임에 contravariantProcedure()
a ClassCastException
를 발생시킵니다 . 따라서 람다 표현식 (메소드 호출과 마찬가지로)은 그들의 서명과 관련하여 공변 적이라고 말할 수 있습니다.
Lambda는 결과 유형 및 예외 사양과 관련하여 메소드처럼 작동합니다. 이 경우 그들은 공변이다 :
위의 마지막 두 줄에있는 주물이 a ClassCastException
. 주조는 명백한 반공 변이 없기 때문에 도움이되지 않습니다. 그러나, (단지 방법 등) 람다 표현되는 내재적 공변 그들의 함수 결과 예외 사양의 종류에 대하여 (상기 코드의 셋째 줄 참조).
여기, 우리의 람다 식을 통과 한 SubType
의 매개 변수 SuperType
. 이것은 람다 (lambda)를위한 특별한 경우이다 : superFunction
매개 변수 유형은 SuperInterface
이다; 일반적으로이 호출은 매개 변수를 취할 것이며이 매개 변수 는 하위 유형 SubInterface
이 아닙니다 . 그러나 람다는 암묵적으로 공변 적이므로 작동합니다.
추론은 속임수입니다. 두 가지 버전의 function()
구별 가능한 서명 (서로 다른 유형의 매개 변수를 사용하는 의미)을 정의하고 전통적으로 구현하면 SubInterface
매개 function()
변수 유형을 명시 적으로 지정해야합니다 . 그러나 람다 표현식에 매개 변수 유형이 지정되지 않은 경우 컴파일러는 가장 적합한 피팅을 찾고 유연합니다.
이 유연성은 추가적인 공분산을 보증 합니다. 람다 표현식은 전통적인 방법이 아닌 경우에도 상향 호환됩니다.
'DevOps' 카테고리의 다른 글
Java 101 : 필수 Java 언어 기능 둘러보기, 1 부-2장 assertions and generics (0) | 2017.06.14 |
---|---|
Java 101 : 필수 Java 언어 기능 둘러보기, 1 부-1장 assertions and generics (0) | 2017.06.14 |
Java의 유형 종속성, 2-3 (Collections API, 제네릭, 람다식 활용) (0) | 2017.06.14 |
Java의 유형 종속성, 2-1 (Collections API, 제네릭, 람다식 활용) (0) | 2017.06.14 |
Java에서 유형 종속성, Part 1-2 (array, generic, wildcard) (0) | 2017.06.14 |
Java에서 유형 종속성, Part 1-1 (array, generic, wildcard) (0) | 2017.06.14 |
Memcached를 이용한 php - 설치와 예제 (0) | 2014.03.07 |