Type dependency in Java, Part 1-1
Covariance and contravariance for array types, generic types, and the wildcard element
원문 : http://www.javaworld.com/article/3172592/java-language/type-dependency-in-java-part-1.html
유형 호환성을 이해하는 것은 좋은 Java 프로그램을 작성하는 기본이지만 Java 언어 요소 간의 차이점은 초급자에게는 매우 학술적으로 보일 수 있습니다. 이 기사는 도전 과제를 해결할 준비가 된 소프트웨어 개발자를위한 것입니다! Part 1에서는 배열 유형과 제네릭 유형과 같은 더 단순한 요소와 특수 Java 언어 요소 인 와일드 카드 간의 공변 관계와 반 행위 관계를 보여줍니다. Part 2에서는 일반적인 API 예제와 람다 식에서 형식 종속성과 분산을 살펴 본다.
개념 및 용어
다양한 자바 언어 요소들 사이의 공분산과 반공립 관계에 들어가기 전에, 개념적 틀을 공유해야합니다.
적합성
객체 지향 프로그래밍에서 호환성 은 유형 간 직접 관계를 나타냅니다 (그림 1 참조).
유형의 변수 간에 데이터를 전송할 수있는 경우 Java에서 두 유형이 호환 가능하다고합니다. 데이터 전송은 컴파일러가이를 수락하고 할당 또는 매개 변수 전달을 통해 수행되는 경우 가능합니다. 예를 들어, 할당 이 가능 short
하기 int
때문에 호환 intVariable = shortVariable;
가능합니다. 그러나 할당 이 불가능 boolean
하기 int
때문에 호환 intVariable = booleanVariable;
되지 않습니다. 컴파일러는 그것을 받아들이지 않을 것이다.
호환성이 감독 관계이기 때문에, 때로는 호환됩니다 만 에 호환되지 않습니다 , 여부를 같은 방법으로한다. 우리는 명시 적 또는 암시 적 호환성을 논의 할 때이 점을 더 알 수 있습니다. T1
T2
T2
T1
중요한 것은 참조 유형 간의 호환성 은 유형 계층 구조 내 에서만 가능 하다는 것입니다. 모든 클래스 유형은 Object
예를 들어 모든 클래스가에서 암시 적으로 상속되기 때문에 호환됩니다 Object
. 그러나 Integer
수퍼 클래스가 Float
아니기 때문에 Float
호환되지 않습니다 Integer
. Integer
이다 호환 Number
때문에, Number
의 (추상) 슈퍼 클래스입니다 Integer
. 동일한 유형 계층 구조에 있기 때문에 컴파일러는 할당을 승인합니다 numberReference = integerReference;
.
호환성 여부를 명시 적으로 표시할지 여부 에 따라 암시 적 또는 명시 적 호환성 에 대해 설명 합니다. 예를 들어, short는 암시 적으로 int
(위의 그림과) 호환되지만 반대 shortVariable = intVariable;
는 가능하지 않습니다. 할당 이 불가능합니다. 그러나 할당 이 가능 하기 때문에 short는 명시 적으로 호환됩니다 . 여기서 유형 변환이라고도 하는 캐스팅을 통한 호환성을 표시해야합니다 .int
shortVariable = (short)intVariable;
유사하게, 참조 유형들 중 : 수용 할 수 integerReference = numberReference;
없는 것만 integerReference = (Integer) numberReference;
이 받아 들여질 것이다. 따라서, Integer
이다 암시 적으로 호환 Number
만 Number
아니라 명시 적으로 호환 Integer
.
의존
유형은 다른 유형에 따라 달라질 수 있습니다. 예를 들어, 배열 유형 int[]
은 기본 유형에 따라 다릅니다 int
. 마찬가지로 제네릭 형식 ArrayList<Customer>
은 형식에 따라 다릅니다 Customer
. 메소드는 매개 변수의 유형에 따라 유형 종속적 일 수도 있습니다. 예를 들어, 메소드 void increment(Integer i)
; 유형에 따라 다릅니다 Integer
. 일부 메소드 (일부 일반 유형과 같은)는 두 개 이상의 유형 (예 : 둘 이상의 매개 변수가있는 메소드)에 따라 달라집니다.
공분산과 반 차분
공분산과 반항은 유형에 따라 호환성을 결정합니다. 두 경우 모두 분산은 직접 관계입니다. 공분산 "동일한 방향으로 상이한"로 번역 또는 수 와 다른- 반면 contravariance는 수단 "는 반대 방향에 서로 다른"또는 대 - 다른 . 공역 및 반동 유형은 동일하지 않지만 두 유형 간에는 상관 관계가 있습니다. 이름은 상관 관계의 방향을 의미합니다.
따라서 공분산 이란 두 가지 유형의 호환성이 해당 유형에 대한 유형의 호환성을 의미한다는 것을 의미합니다. 유형 호환성을 감안할 때, 종속 유형은 그림 2와 같이 공변 (covariant)하다고 가정합니다.
의 호환성은 to ) 의 호환성 을 의미합니다 . 종속 유형 을 공변 (covariant )이라고 합니다 . 또는 더 정확하게 )는)에 공변이다 . T1
T2
A(T1
A(T2
A(T)
A(T1
A(T2
다른 예를 들면 : 할당 numberArray = integerArray;
이 가능 하기 때문에 (적어도 Java에서는) 배열 유형 Integer[]
과 Number[]
는 공변입니다. 그래서, 우리 Integer[]
는 그것이 암묵적 으로 공변량 이라고 말할 수 있습니다 Number[]
. 그리고 반대는 사실이 아니지만 - 할당 integerArray = numberArray;
이 불가능합니다 - 형식 casting ( integerArray = (Integer[])numberArray;
)을 사용한 할당 이 가능합니다. 따라서 우리는 말 Number[]
이며 명시 적으로 공변 에 Integer[]
.
요약하면 : Integer
암시 적으로 호환 Number
되므로, Integer[]
암시 적 공변입니다 Number[]
, 그리고 Number[]
명시 적으로 공변입니다 Integer[]
. 그림 3이 설명합니다.
일반적으로 말해서 배열 유형은 Java에서 공변 (covariant)이라고 말할 수 있습니다. 우리는이 기사 뒷부분에있는 일반적인 유형들 사이의 공분산의 예를 살펴볼 것입니다.
반공립
공분산과 마찬가지로, 반항은 직접적인 관계입니다. 공분산을 의미하는 동안 함께-다른 , contravariance 의미 에 대해-다른 . 앞서 언급했듯이 이름은 상관 관계의 방향을 나타냅니다 . 또한 분산은 일반적으로 유형의 속성이 아니라 종속 유형 (예 : 배열 및 제네릭 유형 및 제 2 부에서 설명 할 메소드) 의 속성이라는 점에 유의해야 합니다.
같은 종속 유형 A(T)
이라고 contravariant 의 호환성 경우 에이 의 호환성을 의미 )에을 ). 그림 4에 나와 있습니다. T1
T2
A(T2
A(T1
에 A(T)
의존 하는 언어 요소 (유형 또는 메소드) T
는 공변 (covariant) 인 경우의 호환성은 to ) 의 호환성 을 의미합니다 . 의 호환성 경우 에이 의 호환성 의미 로)를 ), 다음 유형 이다 contravariant . 의 호환성 경우 와는 어떤 사이의 호환성을 의미하지 않는다 )과 ), 다음 입니다 불변 .T1
T2
A(T1
A(T2
T1
T2
A(T2
A(T1
A(T)
T1
T2
A(T1
A(T2
A(T)
Java의 배열 유형은 암시 적 으로 반 변형 적이 지 않지만 일반적인 유형과 마찬가지로 명시 적 으로 반 변형 할 수 있습니다 . 이 기사의 뒷부분에서 몇 가지 예를 제공 할 것입니다.
유형 종속 요소 : 메소드 및 유형
Java에서 메소드, 배열 유형 및 일반 (매개 변수화 된) 유형은 유형 종속 요소입니다. 메소드는 매개 변수의 유형에 따라 다릅니다. 배열 유형 T[]
은 요소의 유형에 따라 다릅니다 T
. 제네릭 형식 G<T>
은 해당 형식 매개 변수에 종속 T
됩니다. 그림 5에 나와 있습니다.
대부분이 기사에서는 유형 호환성에 초점을 맞추고 있지만 Part 2의 마지막 부분에있는 메소드 들간의 호환성에 대해 언급 할 것입니다.
암시 적 및 명시 적 유형 호환성
앞에서 는 암시 적으로 (또는 명시 적으로 ) 호환 되는 유형을 보았습니다 . 이것은 유형 의 변수에 유형 변수에 대입이 태그 지정없이 (또는 함께) 허용되는 경우에만 해당됩니다 . 캐스팅은 명시 적 호환성을 태그 지정하는 가장 일반적인 방법입니다. T1
T2
T1
T2
예를 들어, int
암시 적으로 호환 long
및 명시 적으로 호환 short
:
암시 적 및 명시 적 호환성은 배정뿐만 아니라 메서드 호출에서 메서드 정의로 매개 변수를 전달할 때도 마찬가지입니다. 입력 매개 변수와 함께 이것은 출력 매개 변수로 수행 할 함수 결과를 전달하는 것을 의미합니다.
그주의 boolean
다른 유형에 호환되지 않으며, 기본 및 참조 유형은 이제까지 호환 될 수 있습니다.
A (참조) 부속 유형은 내재적으로 상위 유형과 호환 가능하며 상위 유형은 부속 유형과 명시 적으로 호환 가능합니다. 이것은 참조 유형이 계층 구조 분기 내에서만 호환 가능하다는 것을 의미합니다. 암시 적으로 또는 아래쪽으로 명시 적으로 상향됩니다.
Java 컴파일러는 일반적으로 다른 유형 사이의 런타임에 정보를 잃을 위험이없는 경우 에만 할당에 대한 암시 적 호환성을 허용 합니다. 그러나이 규칙은 from int
에서 float 로의 할당과 같이 정밀도를 잃는 데 유효하지 않습니다 . 예를 들어, 변수가 모든 값을 보유하고 있기 때문에 int
암시 적으로 호환됩니다 . 반대로 변수는 어떤 값도 보유하지 않습니다 . 따라서 이들 요소간에 명시 적 호환성 만 허용됩니다. long
long
int
short
int
그림 6의 암시 적 호환성이 관계를 가정합니다 전이 : short
호환됩니다 long
.
그림 6에서 보았 듯이 하위 유형 int
의 참조에 상위 유형 의 참조를 지정할 수 있습니다. ClassCastException
그러나 다른 방향의 동일한 할당은 a를 던질 수 있으므로 Java 컴파일러는 유형 캐스팅에서만이를 허용합니다.
배열 유형에 대한 공분산 및 반공립
Java에서 일부 배열 유형은 공 변 (covariant) 또는 반 변형 (contravariant)입니다. 공분산의 경우이 경우는 것을 의미 T
로 호환 가능 U
하고 T[]
또한 호환이다 U[]
. contravariance의 경우에, 그것은 U[]
호환되는 것을 의미합니다 T[]
. Java에서는 원시적 형의 배열이 불변입니다.
참조 유형의 배열은 암묵적으로 공변량을 가지며 명시 적 으로 반 변형입니다 .
그림 7. 배열에 대한 암시 적 공분산
이것이 의미하는 바는 실질적으로 배열 구성 요소의 할당이 ArrayStoreException
런타임에 발생할 수 있다는 것 입니다. 배열 참조에 SuperType
배열 객체가있는 경우 해당 구성 요소 SubType
중 하나가 객체에 할당 SuperType
되면 다음 을 수행 합니다.
이를 종종 공분산 문제 라고합니다 . 진정한 문제는 예외 (프로그래밍 분야에서는 피할 수 있음)가 아니지만 런타임에 배열 요소의 모든 할당을 가상 시스템이 검사해야한다는 것입니다. 따라서 공분산이없는 언어 (배열 참조에 대한 호환 할당이 금지 된 언어) 나 스칼라 (Scala) 같은 공용어가없는 언어에 대해서는 Java가 효율적으로 불리한 위치에 놓이게됩니다.
공분산의 예
간단한 예에서 배열 참조는 유형 Object[]
이지만 배열 객체와 요소는 다른 클래스입니다.
공분산으로 인해 컴파일러는 배열 요소에 대한 마지막 할당의 정확성을 검사 할 수 없습니다. JVM은이를 수행하며 상당한 비용이 듭니다. 그러나 배열 유형간에 유형 호환성을 사용하지 않으면 컴파일러가 비용을 최적화 할 수 있습니다.
Java에서, 상위 유형의 오브젝트를 참조하는 일부 유형의 참조 변수는 금지되어 있습니다 : 그림 8의 화살표를 위로 향하게해서는 안됩니다.
제네릭 유형의 분산 및 와일드 카드
일반 (매개 변수화) 유형은 암시 적으로 불변 제네릭 형식의 다른 인스턴스화가 서로 간의 호환되지 않는 것을 의미 자바. 타입 캐스팅으로도 호환성이 발생하지 않습니다.
유형 오류가 발생하더라도 subGeneric.getClass() == superGeneric.getClass()
. 문제는 메서드 getClass()
가 원시 형식을 결정 한다는 것 입니다. 이것이 형식 매개 변수가 메서드의 서명에 속하지 않는 이유입니다. 따라서 두 메소드 선언
인터페이스 (또는 추상 클래스) 정의에서 함께 나타나서는 안됩니다.
'DevOps' 카테고리의 다른 글
Java의 유형 종속성, 2-2 (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 |
Memcached를 이용한 php - 설치와 예제 (0) | 2014.03.07 |
Html Css @media quary for Smart phones (0) | 2011.04.16 |
Python + Django + Oracle (0) | 2009.11.12 |
java + python 연결 [ jython ] Accessing Jython from Java Without Using jythonc (0) | 2009.11.12 |