Java Generics-빠른 가이드
Integer 배열, String 배열 또는 정렬을 지원하는 모든 유형의 배열에서 요소를 정렬 할 수있는 단일 정렬 메서드를 작성할 수 있다면 좋을 것입니다.
프로그래머는 Java Generic 메소드 및 일반 클래스를 사용하여 단일 메소드 선언, 관련 메소드 세트 또는 단일 클래스 선언을 사용하여 관련 유형 세트를 각각 지정할 수 있습니다.
제네릭은 또한 프로그래머가 컴파일 타임에 유효하지 않은 형식을 포착 할 수 있도록 컴파일 타임 형식 안전성을 제공합니다.
Java Generic 개념을 사용하여 객체 배열을 정렬하는 일반 메소드를 작성한 다음 Integer 배열, Double 배열, String 배열 등으로 일반 메소드를 호출하여 배열 요소를 정렬 할 수 있습니다.
지역 환경 설정
JUnit은 Java 용 프레임 워크이므로 가장 먼저 필요한 것은 컴퓨터에 JDK를 설치하는 것입니다.
시스템 요구 사항
JDK | 1.5 이상. |
---|---|
기억 | 최소 요구 사항이 없습니다. |
디스크 공간 | 최소 요구 사항이 없습니다. |
운영 체제 | 최소 요구 사항이 없습니다. |
1 단계 : 시스템에서 Java 설치 확인
먼저 콘솔을 열고 작업중인 운영 체제에 따라 java 명령을 실행하십시오.
OS | 직무 | 명령 |
---|---|---|
윈도우 | 명령 콘솔 열기 | c : \> 자바 버전 |
리눅스 | 명령 터미널 열기 | $ 자바 버전 |
맥 | 터미널 열기 | 기계 : <joseph $ java -version |
모든 운영 체제의 출력을 확인하겠습니다.
OS | 산출 |
---|---|
윈도우 | 자바 버전 "1.6.0_21" Java (TM) SE 런타임 환경 (빌드 1.6.0_21-b07) Java HotSpot (TM) Client VM (빌드 17.0-b17, 혼합 모드, 공유) |
리눅스 | 자바 버전 "1.6.0_21" Java (TM) SE 런타임 환경 (빌드 1.6.0_21-b07) Java HotSpot (TM) Client VM (빌드 17.0-b17, 혼합 모드, 공유) |
맥 | 자바 버전 "1.6.0_21" Java (TM) SE 런타임 환경 (빌드 1.6.0_21-b07) Java HotSpot (TM) 64 비트 서버 VM (빌드 17.0-b17, 혼합 모드, 공유) |
시스템에 Java가 설치되어 있지 않은 경우 다음 링크에서 Java SDK (Software Development Kit)를 다운로드하십시오. https://www.oracle.com. 이 자습서에서는 Java 1.6.0_21을 설치된 버전으로 가정합니다.
2 단계 : JAVA 환경 설정
설정 JAVA_HOME시스템에 Java가 설치된 기본 디렉토리 위치를 가리키는 환경 변수. 예를 들면.
OS | 산출 |
---|---|
윈도우 | 환경 변수 JAVA_HOME을 C : \ Program Files \ Java \ jdk1.6.0_21로 설정합니다. |
리눅스 | 내보내기 JAVA_HOME = / usr / local / java-current |
맥 | export JAVA_HOME = / Library / Java / Home |
시스템 경로에 Java 컴파일러 위치를 추가하십시오.
OS | 산출 |
---|---|
윈도우 | 문자열 추가 C:\Program Files\Java\jdk1.6.0_21\bin 시스템 변수의 끝에서 Path. |
리눅스 | 내보내기 경로 = $PATH:$JAVA_HOME / bin / |
맥 | 필요하지 않음 |
명령을 사용하여 Java 설치 확인 java -version 위에서 설명한대로.
제네릭 클래스 선언은 클래스 이름 뒤에 형식 매개 변수 섹션이 오는 것을 제외하고는 제네릭이 아닌 클래스 선언과 비슷합니다.
제네릭 클래스의 유형 매개 변수 섹션에는 쉼표로 구분 된 하나 이상의 유형 매개 변수가있을 수 있습니다. 이러한 클래스는 하나 이상의 매개 변수를 허용하므로 매개 변수화 된 클래스 또는 매개 변수화 된 유형이라고합니다.
통사론
public class Box<T> {
private T t;
}
어디
Box − Box는 일반 클래스입니다.
T− 제네릭 클래스에 전달 된 제네릭 유형 매개 변수. 어떤 Object도 취할 수 있습니다.
t − 일반 유형 T의 인스턴스.
기술
T는 일반 클래스 Box에 전달되는 유형 매개 변수이며 Box 객체가 생성 될 때 전달되어야합니다.
예
원하는 편집기를 사용하여 다음 Java 프로그램을 만듭니다.
GenericsTester.java
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("Hello World"));
System.out.printf("Integer Value :%d\n", integerBox.get());
System.out.printf("String Value :%s\n", stringBox.get());
}
}
class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
그러면 다음과 같은 결과가 생성됩니다.
산출
Integer Value :10
String Value :Hello World
규칙에 따라 형식 매개 변수 이름은 단일 대문자로 명명되므로 형식 매개 변수는 일반 클래스 또는 인터페이스 이름으로 쉽게 구분할 수 있습니다. 다음은 일반적으로 사용되는 유형 매개 변수 이름의 목록입니다-
E − 요소이며 주로 Java Collections 프레임 워크에서 사용됩니다.
K − 키로, 주로 맵 키의 매개 변수 유형을 나타내는 데 사용됩니다.
V − 값, 주로 맵 값의 매개 변수 유형을 나타내는 데 사용됩니다.
N − 숫자, 주로 숫자를 나타내는 데 사용됩니다.
T − Type이며 주로 첫 번째 제네릭 유형 매개 변수를 나타내는 데 사용됩니다.
S − Type, 주로 두 번째 일반 유형 매개 변수를 나타내는 데 사용됩니다.
U − Type, 주로 세 번째 일반 유형 매개 변수를 나타내는 데 사용됩니다.
V − Type, 주로 네 번째 일반 유형 매개 변수를 나타내는 데 사용됩니다.
다음 예제는 위에서 언급 한 개념을 보여줍니다.
예
원하는 편집기를 사용하여 다음 Java 프로그램을 만듭니다.
GenericsTester.java
package com.tutorialspoint;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GenericsTester {
public static void main(String[] args) {
Box<Integer, String> box = new Box<Integer, String>();
box.add(Integer.valueOf(10),"Hello World");
System.out.printf("Integer Value :%d\n", box.getFirst());
System.out.printf("String Value :%s\n", box.getSecond());
Pair<String, Integer> pair = new Pair<String, Integer>();
pair.addKeyValue("1", Integer.valueOf(10));
System.out.printf("(Pair)Integer Value :%d\n", pair.getValue("1"));
CustomList<Box> list = new CustomList<Box>();
list.addItem(box);
System.out.printf("(CustomList)Integer Value :%d\n", list.getItem(0).getFirst());
}
}
class Box<T, S> {
private T t;
private S s;
public void add(T t, S s) {
this.t = t;
this.s = s;
}
public T getFirst() {
return t;
}
public S getSecond() {
return s;
}
}
class Pair<K,V>{
private Map<K,V> map = new HashMap<K,V>();
public void addKeyValue(K key, V value) {
map.put(key, value);
}
public V getValue(K key) {
return map.get(key);
}
}
class CustomList<E>{
private List<E> list = new ArrayList<E>();
public void addItem(E value) {
list.add(value);
}
public E getItem(int index) {
return list.get(index);
}
}
그러면 다음과 같은 결과가 생성됩니다.
산출
Integer Value :10
String Value :Hello World
(Pair)Integer Value :10
(CustomList)Integer Value :10
유형 추론은 메소드 호출과 유형 인수를 확인하고 결정하기위한 해당 선언을 보는 Java 컴파일러의 기능을 나타냅니다. 추론 알고리즘은 인수 유형을 확인하고 사용 가능한 경우 할당 된 유형이 반환됩니다. 추론 알고리즘은 모든 유형 매개 변수를 채울 수있는 특정 유형을 찾으려고합니다.
컴파일러는 유형 추론이 사용되지 않는 경우 확인되지 않은 변환 경고를 생성합니다.
통사론
Box<Integer> integerBox = new Box<>();
어디
Box − Box는 일반 클래스입니다.
<> − 다이아몬드 연산자는 유형 추론을 나타냅니다.
기술
다이아몬드 연산자를 사용하여 컴파일러는 매개 변수의 유형을 결정합니다. 이 연산자는 Java SE 7 버전부터 사용할 수 있습니다.
예
원하는 편집기를 사용하여 다음 Java 프로그램을 만듭니다.
GenericsTester.java
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args) {
//type inference
Box<Integer> integerBox = new Box<>();
//unchecked conversion warning
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("Hello World"));
System.out.printf("Integer Value :%d\n", integerBox.get());
System.out.printf("String Value :%s\n", stringBox.get());
}
}
class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
그러면 다음과 같은 결과가 생성됩니다.
산출
Integer Value :10
String Value :Hello World
다른 유형의 인수로 호출 할 수있는 단일 제네릭 메서드 선언을 작성할 수 있습니다. 제네릭 메서드에 전달 된 인수 유형에 따라 컴파일러는 각 메서드 호출을 적절하게 처리합니다. 다음은 일반 방법을 정의하는 규칙입니다-
모든 제네릭 메서드 선언에는 메서드의 반환 형식 앞에 꺾쇠 괄호 (<및>)로 구분 된 형식 매개 변수 섹션이 있습니다 (다음 예제에서는 <E>).
각 유형 매개 변수 섹션에는 쉼표로 구분 된 하나 이상의 유형 매개 변수가 있습니다. 유형 변수라고도하는 유형 매개 변수는 일반 유형 이름을 지정하는 식별자입니다.
형식 매개 변수를 사용하여 반환 형식을 선언하고 실제 형식 인수라고하는 제네릭 메서드에 전달 된 인수 형식에 대한 자리 표시 자 역할을 할 수 있습니다.
제네릭 메서드의 본문은 다른 메서드와 마찬가지로 선언됩니다. 유형 매개 변수는 기본 유형 (예 : int, double 및 char)이 아닌 참조 유형 만 나타낼 수 있습니다.
예
다음 예제는 단일 Generic 메서드를 사용하여 다른 유형의 배열을 인쇄하는 방법을 보여줍니다.
public class GenericMethodTest {
// generic method printArray
public static < E > void printArray( E[] inputArray ) {
// Display array elements
for(E element : inputArray) {
System.out.printf("%s ", element);
}
System.out.println();
}
public static void main(String args[]) {
// Create arrays of Integer, Double and Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println("Array integerArray contains:");
printArray(intArray); // pass an Integer array
System.out.println("\nArray doubleArray contains:");
printArray(doubleArray); // pass a Double array
System.out.println("\nArray characterArray contains:");
printArray(charArray); // pass a Character array
}
}
이것은 다음 결과를 생성합니다-
산출
Array integerArray contains:
1 2 3 4 5
Array doubleArray contains:
1.1 2.2 3.3 4.4
Array characterArray contains:
H E L L O
Generic 클래스는 다중 유형 매개 변수를 가질 수 있습니다. 다음 예제는 위에서 언급 한 개념을 보여줍니다.
예
원하는 편집기를 사용하여 다음 Java 프로그램을 만듭니다.
GenericsTester.java
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args) {
Box<Integer, String> box = new Box<Integer, String>();
box.add(Integer.valueOf(10),"Hello World");
System.out.printf("Integer Value :%d\n", box.getFirst());
System.out.printf("String Value :%s\n", box.getSecond());
Box<String, String> box1 = new Box<String, String>();
box1.add("Message","Hello World");
System.out.printf("String Value :%s\n", box1.getFirst());
System.out.printf("String Value :%s\n", box1.getSecond());
}
}
class Box<T, S> {
private T t;
private S s;
public void add(T t, S s) {
this.t = t;
this.s = s;
}
public T getFirst() {
return t;
}
public S getSecond() {
return s;
}
}
그러면 다음과 같은 결과가 생성됩니다.
산출
Integer Value :10
String Value :Hello World
String Value :Message
String Value :Hello World
Generic 클래스는 매개 변수화 된 유형을 가질 수 있으며 여기서 유형 매개 변수는 매개 변수화 된 유형으로 대체 될 수 있습니다. 다음 예제는 위에서 언급 한 개념을 보여줍니다.
예
원하는 편집기를 사용하여 다음 Java 프로그램을 만듭니다.
GenericsTester.java
package com.tutorialspoint;
import java.util.ArrayList;
import java.util.List;
public class GenericsTester {
public static void main(String[] args) {
Box<Integer, List<String>> box
= new Box<Integer, List<String>>();
List<String> messages = new ArrayList<String>();
messages.add("Hi");
messages.add("Hello");
messages.add("Bye");
box.add(Integer.valueOf(10),messages);
System.out.printf("Integer Value :%d\n", box.getFirst());
System.out.printf("String Value :%s\n", box.getSecond());
}
}
class Box<T, S> {
private T t;
private S s;
public void add(T t, S s) {
this.t = t;
this.s = s;
}
public T getFirst() {
return t;
}
public S getSecond() {
return s;
}
}
그러면 다음과 같은 결과가 생성됩니다.
산출
Integer Value :10
String Value :[Hi, Hello, Bye]
원시 유형은 생성 중에 유형 인수가 전달되지 않으면 제네릭 클래스 또는 인터페이스의 객체입니다. 다음 예제는 위에서 언급 한 개념을 보여줍니다.
예
원하는 편집기를 사용하여 다음 Java 프로그램을 만듭니다.
GenericsTester.java
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args) {
Box<Integer> box = new Box<Integer>();
box.set(Integer.valueOf(10));
System.out.printf("Integer Value :%d\n", box.getData());
Box rawBox = new Box();
//No warning
rawBox = box;
System.out.printf("Integer Value :%d\n", rawBox.getData());
//Warning for unchecked invocation to set(T)
rawBox.set(Integer.valueOf(10));
System.out.printf("Integer Value :%d\n", rawBox.getData());
//Warning for unchecked conversion
box = rawBox;
System.out.printf("Integer Value :%d\n", box.getData());
}
}
class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T getData() {
return t;
}
}
그러면 다음과 같은 결과가 생성됩니다.
산출
Integer Value :10
Integer Value :10
Integer Value :10
Integer Value :10
유형 매개 변수에 전달할 수있는 유형의 종류를 제한하려는 경우가있을 수 있습니다. 예를 들어 숫자에 대해 작동하는 메서드는 Number 또는 해당 하위 클래스의 인스턴스 만 허용하려고 할 수 있습니다. 이것이 경계 유형 매개 변수의 용도입니다.
경계 유형 매개 변수를 선언하려면 유형 매개 변수의 이름, extends 키워드, 상위 경계를 차례로 나열하십시오.
예
다음 예제는 "extends"(클래스에서와 같이) 또는 "implements"(인터페이스에서와 같이)를 의미하는 일반적인 의미에서 extends가 사용되는 방법을 보여줍니다. 이 예제는 세 개의 Comparable 객체 중 가장 큰 것을 반환하는 Generic 메서드입니다.
public class MaximumTest {
// determines the largest of three Comparable objects
public static <T extends Comparable<T>> T maximum(T x, T y, T z) {
T max = x; // assume x is initially the largest
if(y.compareTo(max) > 0) {
max = y; // y is the largest so far
}
if(z.compareTo(max) > 0) {
max = z; // z is the largest now
}
return max; // returns the largest object
}
public static void main(String args[]) {
System.out.printf("Max of %d, %d and %d is %d\n\n",
3, 4, 5, maximum( 3, 4, 5 ));
System.out.printf("Max of %.1f,%.1f and %.1f is %.1f\n\n",
6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ));
System.out.printf("Max of %s, %s and %s is %s\n","pear",
"apple", "orange", maximum("pear", "apple", "orange"));
}
}
이것은 다음 결과를 생성합니다-
산출
Max of 3, 4 and 5 is 5
Max of 6.6,8.8 and 7.7 is 8.8
Max of pear, apple and orange is pear
유형 매개 변수는 여러 경계를 가질 수 있습니다.
통사론
public static <T extends Number & Comparable<T>> T maximum(T x, T y, T z)
어디
maximum − 최대 값은 일반적인 방법입니다.
T− 제네릭 메소드에 전달 된 제네릭 유형 매개 변수. 어떤 Object도 취할 수 있습니다.
기술
T는 일반 클래스 Box에 전달되는 유형 매개 변수이며 Number 클래스의 하위 유형이어야하며 Comparable 인터페이스를 구현해야합니다. 클래스가 바운드로 전달되는 경우 인터페이스 전에 먼저 전달되어야합니다. 그렇지 않으면 컴파일 시간 오류가 발생합니다.
예
원하는 편집기를 사용하여 다음 Java 프로그램을 만듭니다.
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args) {
System.out.printf("Max of %d, %d and %d is %d\n\n",
3, 4, 5, maximum( 3, 4, 5 ));
System.out.printf("Max of %.1f,%.1f and %.1f is %.1f\n\n",
6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ));
}
public static <T extends Number
& Comparable<T>> T maximum(T x, T y, T z) {
T max = x;
if(y.compareTo(max) > 0) {
max = y;
}
if(z.compareTo(max) > 0) {
max = z;
}
return max;
}
// Compiler throws error in case of below declaration
/* public static <T extends Comparable<T>
& Number> T maximum1(T x, T y, T z) {
T max = x;
if(y.compareTo(max) > 0) {
max = y;
}
if(z.compareTo(max) > 0) {
max = z;
}
return max;
}*/
}
이것은 다음 결과를 생성합니다-
산출
Max of 3, 4 and 5 is 5
Max of 6.6,8.8 and 7.7 is 8.8
Java는 List 인터페이스에서 일반적인 지원을 제공했습니다.
통사론
List<T> list = new ArrayList<T>();
어디
list − 목록 인터페이스의 객체.
T − 목록 선언 중에 전달 된 일반 유형 매개 변수.
기술
T는 일반 인터페이스 List 및 해당 구현 클래스 ArrayList에 전달되는 형식 매개 변수입니다.
예
원하는 편집기를 사용하여 다음 Java 프로그램을 만듭니다.
package com.tutorialspoint;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GenericsTester {
public static void main(String[] args) {
List<Integer> integerList = new ArrayList<Integer>();
integerList.add(Integer.valueOf(10));
integerList.add(Integer.valueOf(11));
List<String> stringList = new ArrayList<String>();
stringList.add("Hello World");
stringList.add("Hi World");
System.out.printf("Integer Value :%d\n", integerList.get(0));
System.out.printf("String Value :%s\n", stringList.get(0));
for(Integer data: integerList) {
System.out.printf("Integer Value :%d\n", data);
}
Iterator<String> stringIterator = stringList.iterator();
while(stringIterator.hasNext()) {
System.out.printf("String Value :%s\n", stringIterator.next());
}
}
}
이것은 다음 결과를 생성합니다-
산출
Integer Value :10
String Value :Hello World
Integer Value :10
Integer Value :11
String Value :Hello World
String Value :Hi World
Java는 Set 인터페이스에서 일반적인 지원을 제공했습니다.
통사론
Set<T> set = new HashSet<T>();
어디
set − 인터페이스 설정의 대상.
T − 집합 선언 중에 전달 된 일반 유형 매개 변수.
기술
T는 일반 인터페이스 Set 및 구현 클래스 HashSet에 전달되는 유형 매개 변수입니다.
예
원하는 편집기를 사용하여 다음 Java 프로그램을 만듭니다.
package com.tutorialspoint;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class GenericsTester {
public static void main(String[] args) {
Set<Integer> integerSet = new HashSet<Integer>();
integerSet.add(Integer.valueOf(10));
integerSet.add(Integer.valueOf(11));
Set<String> stringSet = new HashSet<String>();
stringSet.add("Hello World");
stringSet.add("Hi World");
for(Integer data: integerSet) {
System.out.printf("Integer Value :%d\n", data);
}
Iterator<String> stringIterator = stringSet.iterator();
while(stringIterator.hasNext()) {
System.out.printf("String Value :%s\n", stringIterator.next());
}
}
}
이것은 다음 결과를 생성합니다-
산출
Integer Value :10
Integer Value :11
String Value :Hello World
String Value :Hi World
Java는 Map 인터페이스에서 일반적인 지원을 제공했습니다.
통사론
Set<T> set = new HashSet<T>();
어디
set − 인터페이스 설정의 대상.
T − 집합 선언 중에 전달 된 일반 유형 매개 변수.
기술
T는 일반 인터페이스 Set 및 구현 클래스 HashSet에 전달되는 유형 매개 변수입니다.
예
원하는 편집기를 사용하여 다음 Java 프로그램을 만듭니다.
package com.tutorialspoint;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class GenericsTester {
public static void main(String[] args) {
Map<Integer,Integer> integerMap
= new HashMap<Integer,Integer>();
integerMap.put(1, 10);
integerMap.put(2, 11);
Map<String,String> stringMap = new HashMap<String,String>();
stringMap.put("1", "Hello World");
stringMap.put("2","Hi World");
System.out.printf("Integer Value :%d\n", integerMap.get(1));
System.out.printf("String Value :%s\n", stringMap.get("1"));
// iterate keys.
Iterator<Integer> integerIterator = integerMap.keySet().iterator();
while(integerIterator.hasNext()) {
System.out.printf("Integer Value :%d\n", integerIterator.next());
}
// iterate values.
Iterator<String> stringIterator = stringMap.values().iterator();
while(stringIterator.hasNext()) {
System.out.printf("String Value :%s\n", stringIterator.next());
}
}
}
이것은 다음 결과를 생성합니다-
산출
Integer Value :10
String Value :Hello World
Integer Value :1
Integer Value :2
String Value :Hello World
String Value :Hi World
물음표 (?)는 와일드 카드를 나타내며 제네릭에서 알 수없는 유형을 나타냅니다. 유형 매개 변수에 전달할 수있는 유형의 종류를 제한하려는 경우가있을 수 있습니다. 예를 들어 숫자에 대해 작동하는 메서드는 Number 또는 해당 하위 클래스의 인스턴스 만 허용하려고 할 수 있습니다.
상한 와일드 카드 매개 변수를 선언하려면?, extends 키워드, 상한을 나열하십시오.
예
다음 예는 extends를 사용하여 상한 와일드 카드를 지정하는 방법을 보여줍니다.
package com.tutorialspoint;
import java.util.Arrays;
import java.util.List;
public class GenericsTester {
public static double sum(List<? extends Number> numberlist) {
double sum = 0.0;
for (Number n : numberlist) sum += n.doubleValue();
return sum;
}
public static void main(String args[]) {
List<Integer> integerList = Arrays.asList(1, 2, 3);
System.out.println("sum = " + sum(integerList));
List<Double> doubleList = Arrays.asList(1.2, 2.3, 3.5);
System.out.println("sum = " + sum(doubleList));
}
}
이것은 다음 결과를 생성합니다-
산출
sum = 6.0
sum = 7.0
물음표 (?)는 와일드 카드를 나타내며 제네릭에서 알 수없는 유형을 나타냅니다. Object 클래스에서 제공하는 기능을 사용하여 메서드를 구현할 수 있거나 코드가 형식 매개 변수와 독립적 인 경우 모든 개체를 사용할 수있는 경우가 있습니다.
Unbounded Wildcard 매개 변수를 선언하려면? 뿐.
예
다음 예제는 확장이 제한되지 않은 와일드 카드를 지정하는 데 사용되는 방법을 보여줍니다.
package com.tutorialspoint;
import java.util.Arrays;
import java.util.List;
public class GenericsTester {
public static void printAll(List<?> list) {
for (Object item : list)
System.out.println(item + " ");
}
public static void main(String args[]) {
List<Integer> integerList = Arrays.asList(1, 2, 3);
printAll(integerList);
List<Double> doubleList = Arrays.asList(1.2, 2.3, 3.5);
printAll(doubleList);
}
}
이것은 다음 결과를 생성합니다-
산출
1
2
3
1.2
2.3
3.5
물음표 (?)는 와일드 카드를 나타내며 제네릭에서 알 수없는 유형을 나타냅니다. 유형 매개 변수에 전달할 수있는 유형의 종류를 제한하려는 경우가있을 수 있습니다. 예를 들어 숫자에 대해 작동하는 메서드는 Integer 또는 Number와 같은 수퍼 클래스의 인스턴스 만 허용하려고 할 수 있습니다.
하한 와일드 카드 매개 변수를 선언하려면?, super 키워드, 하한을 나열하십시오.
예
다음 예제는 super를 사용하여 하한 와일드 카드를 지정하는 방법을 보여줍니다.
package com.tutorialspoint;
import java.util.ArrayList;
import java.util.List;
public class GenericsTester {
public static void addCat(List<? super Cat> catList) {
catList.add(new RedCat());
System.out.println("Cat Added");
}
public static void main(String[] args) {
List<Animal> animalList= new ArrayList<Animal>();
List<Cat> catList= new ArrayList<Cat>();
List<RedCat> redCatList= new ArrayList<RedCat>();
List<Dog> dogList= new ArrayList<Dog>();
//add list of super class Animal of Cat class
addCat(animalList);
//add list of Cat class
addCat(catList);
//compile time error
//can not add list of subclass RedCat of Cat class
//addCat(redCatList);
//compile time error
//can not add list of subclass Dog of Superclass Animal of Cat class
//addCat.addMethod(dogList);
}
}
class Animal {}
class Cat extends Animal {}
class RedCat extends Cat {}
class Dog extends Animal {}
이것은 다음 결과를 생성합니다-
Cat Added
Cat Added
와일드 카드는 세 가지 방법으로 사용할 수 있습니다.
Upper bound Wildcard−? 유형을 확장합니다.
Lower bound Wildcard−? 슈퍼 타입.
Unbounded Wildcard −?
조건에 가장 적합한 와일드 카드 유형을 결정하기 위해 먼저 메소드에 전달되는 매개 변수 유형을 다음과 같이 분류하겠습니다. in 과 out 매개 변수.
in variable− in 변수는 코드에 데이터를 제공합니다. 예를 들어, copy (src, dest). 여기서 src는 복사 할 데이터 인 변수로 작동합니다.
out variable− out 변수는 코드에 의해 업데이트 된 데이터를 보유합니다. 예를 들어, copy (src, dest). 여기서 dest는 데이터를 복사 한 변수처럼 작동합니다.
와일드 카드 지침.
Upper bound wildcard − 변수가 in 범주, 와일드 카드로 키워드를 확장하십시오.
Lower bound wildcard − 변수가 out 범주, 와일드 카드와 함께 수퍼 키워드를 사용하십시오.
Unbounded wildcard − 객체 클래스 방법을 사용하여 변수에 액세스 할 수있는 경우 바인딩되지 않은 와일드 카드를 사용합니다.
No wildcard − 코드가 둘 다에서 변수에 액세스하는 경우 in 과 out 카테고리는 와일드 카드를 사용하지 않습니다.
예
다음 예는 위에서 언급 한 개념을 보여줍니다.
package com.tutorialspoint;
import java.util.ArrayList;
import java.util.List;
public class GenericsTester {
//Upper bound wildcard
//in category
public static void deleteCat(List<? extends Cat> catList, Cat cat) {
catList.remove(cat);
System.out.println("Cat Removed");
}
//Lower bound wildcard
//out category
public static void addCat(List<? super RedCat> catList) {
catList.add(new RedCat("Red Cat"));
System.out.println("Cat Added");
}
//Unbounded wildcard
//Using Object method toString()
public static void printAll(List<?> list) {
for (Object item : list)
System.out.println(item + " ");
}
public static void main(String[] args) {
List<Animal> animalList= new ArrayList<Animal>();
List<RedCat> redCatList= new ArrayList<RedCat>();
//add list of super class Animal of Cat class
addCat(animalList);
//add list of Cat class
addCat(redCatList);
addCat(redCatList);
//print all animals
printAll(animalList);
printAll(redCatList);
Cat cat = redCatList.get(0);
//delete cat
deleteCat(redCatList, cat);
printAll(redCatList);
}
}
class Animal {
String name;
Animal(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
class Cat extends Animal {
Cat(String name) {
super(name);
}
}
class RedCat extends Cat {
RedCat(String name) {
super(name);
}
}
class Dog extends Animal {
Dog(String name) {
super(name);
}
}
이것은 다음 결과를 생성합니다-
Cat Added
Cat Added
Cat Added
Red Cat
Red Cat
Red Cat
Cat Removed
Red Cat
제네릭은 컴파일 타임에 더 엄격한 유형 검사와 제네릭 프로그래밍을 제공하는 데 사용됩니다. 일반적인 동작을 구현하기 위해 Java 컴파일러는 유형 삭제를 적용합니다. 유형 삭제는 컴파일러가 일반 매개 변수를 실제 클래스 또는 브릿지 메소드로 대체하는 프로세스입니다. 유형 삭제에서 컴파일러는 추가 클래스가 생성되지 않고 런타임 오버 헤드가 없는지 확인합니다.
유형 삭제 규칙
바인딩 된 형식 매개 변수가 사용되는 경우 제네릭 형식의 형식 매개 변수를 해당 바인딩으로 바꿉니다.
제한되지 않은 유형 매개 변수가 사용되는 경우 제네릭 유형의 유형 매개 변수를 Object로 바꿉니다.
유형 안전을 유지하기 위해 유형 캐스트를 삽입하십시오.
확장 된 제네릭 유형에서 다형성을 유지하는 브리지 메서드를 생성합니다.
Java 컴파일러는 바인딩 된 유형 매개 변수가 사용되는 경우 제네릭 유형의 유형 매개 변수를 해당 바인딩으로 대체합니다.
예
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<Double> doubleBox = new Box<Double>();
integerBox.add(new Integer(10));
doubleBox.add(new Double(10.0));
System.out.printf("Integer Value :%d\n", integerBox.get());
System.out.printf("Double Value :%s\n", doubleBox.get());
}
}
class Box<T extends Number> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
이 경우 Java 컴파일러는 T를 Number 클래스로 대체하고 유형 삭제 후 컴파일러는 다음 코드에 대한 바이트 코드를 생성합니다.
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args) {
Box integerBox = new Box();
Box doubleBox = new Box();
integerBox.add(new Integer(10));
doubleBox.add(new Double(10.0));
System.out.printf("Integer Value :%d\n", integerBox.get());
System.out.printf("Double Value :%s\n", doubleBox.get());
}
}
class Box {
private Number t;
public void add(Number t) {
this.t = t;
}
public Number get() {
return t;
}
}
두 경우 모두 결과는 동일합니다.
산출
Integer Value :10
Double Value :10.0
Java 컴파일러는 제한되지 않은 유형 매개 변수가 사용되는 경우 일반 유형의 유형 매개 변수를 Object로 대체합니다.
예
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("Hello World"));
System.out.printf("Integer Value :%d\n", integerBox.get());
System.out.printf("String Value :%s\n", stringBox.get());
}
}
class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
이 경우 Java 컴파일러는 T를 Object 클래스로 대체하고 유형 삭제 후 컴파일러는 다음 코드에 대한 바이트 코드를 생성합니다.
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args) {
Box integerBox = new Box();
Box stringBox = new Box();
integerBox.add(new Integer(10));
stringBox.add(new String("Hello World"));
System.out.printf("Integer Value :%d\n", integerBox.get());
System.out.printf("String Value :%s\n", stringBox.get());
}
}
class Box {
private Object t;
public void add(Object t) {
this.t = t;
}
public Object get() {
return t;
}
}
두 경우 모두 결과는 동일합니다.
산출
Integer Value :10
String Value :Hello World
Java 컴파일러는 제한되지 않은 유형 매개 변수가 사용되는 경우 일반 유형의 유형 매개 변수를 Object로, 바인딩 된 매개 변수가 메소드 매개 변수로 사용되는 경우 유형으로 대체합니다.
예
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("Hello World"));
printBox(integerBox);
printBox1(stringBox);
}
private static <T extends Box> void printBox(T box) {
System.out.println("Integer Value :" + box.get());
}
private static <T> void printBox1(T box) {
System.out.println("String Value :" + ((Box)box).get());
}
}
class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
이 경우 Java 컴파일러는 T를 Object 클래스로 대체하고 유형 삭제 후 컴파일러는 다음 코드에 대한 바이트 코드를 생성합니다.
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args) {
Box integerBox = new Box();
Box stringBox = new Box();
integerBox.add(new Integer(10));
stringBox.add(new String("Hello World"));
printBox(integerBox);
printBox1(stringBox);
}
//Bounded Types Erasure
private static void printBox(Box box) {
System.out.println("Integer Value :" + box.get());
}
//Unbounded Types Erasure
private static void printBox1(Object box) {
System.out.println("String Value :" + ((Box)box).get());
}
}
class Box {
private Object t;
public void add(Object t) {
this.t = t;
}
public Object get() {
return t;
}
}
두 경우 모두 결과는 동일합니다.
산출
Integer Value :10
String Value :Hello World
제네릭을 사용하면 기본 유형을 유형 매개 변수로 전달할 수 없습니다. 아래의 예제에서 int 프리미티브 유형을 box 클래스에 전달하면 컴파일러가 불평합니다. 이를 완화하려면 int 프리미티브 유형 대신 Integer 객체를 전달해야합니다.
예
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
//compiler errror
//ReferenceType
//- Syntax error, insert "Dimensions" to complete
ReferenceType
//Box<int> stringBox = new Box<int>();
integerBox.add(new Integer(10));
printBox(integerBox);
}
private static void printBox(Box box) {
System.out.println("Value: " + box.get());
}
}
class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
이것은 다음 결과를 생성합니다-
산출
Value: 10
형식 매개 변수는 메서드 내에서 개체를 인스턴스화하는 데 사용할 수 없습니다.
public static <T> void add(Box<T> box) {
//compiler error
//Cannot instantiate the type T
//T item = new T();
//box.add(item);
}
이러한 기능을 얻으려면 리플렉션을 사용하십시오.
public static <T> void add(Box<T> box, Class<T> clazz)
throws InstantiationException, IllegalAccessException{
T item = clazz.newInstance(); // OK
box.add(item);
System.out.println("Item added.");
}
예
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args)
throws InstantiationException, IllegalAccessException {
Box<String> stringBox = new Box<String>();
add(stringBox, String.class);
}
public static <T> void add(Box<T> box) {
//compiler error
//Cannot instantiate the type T
//T item = new T();
//box.add(item);
}
public static <T> void add(Box<T> box, Class<T> clazz)
throws InstantiationException, IllegalAccessException{
T item = clazz.newInstance(); // OK
box.add(item);
System.out.println("Item added.");
}
}
class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
이것은 다음 결과를 생성합니다-
Item added.
제네릭을 사용하면 유형 매개 변수가 정적 일 수 없습니다. 정적 변수는 객체간에 공유되므로 컴파일러는 사용할 유형을 결정할 수 없습니다. 정적 유형 매개 변수가 허용 된 경우 다음 예제를 고려하십시오.
예
package com.tutorialspoint;
public class GenericsTester {
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
printBox(integerBox);
}
private static void printBox(Box box) {
System.out.println("Value: " + box.get());
}
}
class Box<T> {
//compiler error
private static T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
stringBox와 integerBox는 모두 stared 정적 유형 변수를 가지고 있으므로 유형을 결정할 수 없습니다. 따라서 정적 유형 매개 변수는 허용되지 않습니다.
제한되지 않은 와일드 카드로 매개 변수화되지 않는 한 매개 변수화 된 유형으로의 캐스트는 허용되지 않습니다.
Box<Integer> integerBox = new Box<Integer>();
Box<Number> numberBox = new Box<Number>();
//Compiler Error: Cannot cast from Box<Number> to Box<Integer>
integerBox = (Box<Integer>)numberBox;
동일한 결과를 얻기 위해 제한되지 않은 와일드 카드를 사용할 수 있습니다.
private static void add(Box<?> box) {
Box<Integer> integerBox = (Box<Integer>)box;
}
컴파일러는 유형 삭제를 사용하기 때문에 런타임은 유형 매개 변수를 추적하지 않으므로 런타임시 Box <Integer>와 Box <String> 간의 차이는 instanceOf 연산자를 사용하여 확인할 수 없습니다.
Box<Integer> integerBox = new Box<Integer>();
//Compiler Error:
//Cannot perform instanceof check against
//parameterized type Box<Integer>.
//Use the form Box<?> instead since further
//generic type information will be erased at runtime
if(integerBox instanceof Box<Integer>) { }
매개 변수화 된 유형의 배열은 허용되지 않습니다.
//Cannot create a generic array of Box<Integer>
Box<Integer>[] arrayOfLists = new Box<Integer>[2];
컴파일러는 유형 삭제를 사용하기 때문에 유형 매개 변수는 Object로 대체되고 사용자는 모든 유형의 객체를 배열에 추가 할 수 있습니다. 그리고 런타임에 코드는 ArrayStoreException을 throw 할 수 없습니다.
// compiler error, but if it is allowed
Object[] stringBoxes = new Box<String>[];
// OK
stringBoxes[0] = new Box<String>();
// An ArrayStoreException should be thrown,
//but the runtime can't detect it.
stringBoxes[1] = new Box<Integer>();
제네릭 클래스는 Throwable 클래스를 직접 또는 간접적으로 확장 할 수 없습니다.
//The generic class Box<T> may not subclass java.lang.Throwable
class Box<T> extends Exception {}
//The generic class Box<T> may not subclass java.lang.Throwable
class Box1<T> extends Throwable {}
메소드는 유형 매개 변수의 인스턴스를 포착 할 수 없습니다.
public static <T extends Exception, J>
void execute(List<J> jobs) {
try {
for (J job : jobs) {}
// compile-time error
//Cannot use the type parameter T in a catch block
} catch (T e) {
// ...
}
}
throws 절에서 유형 매개 변수가 허용됩니다.
class Box<T extends Exception> {
private int t;
public void add(int t) throws T {
this.t = t;
}
public int get() {
return t;
}
}
클래스는 유형 삭제 후 동일한 서명을 가질 수있는 두 개의 오버로드 된 메소드를 가질 수 없습니다.
class Box {
//Compiler error
//Erasure of method print(List<String>)
//is the same as another method in type Box
public void print(List<String> stringList) { }
public void print(List<Integer> integerList) { }
}