> Java > java지도 시간 > Java의 제네릭에 대한 자세한 설명

Java의 제네릭에 대한 자세한 설명

高洛峰
풀어 주다: 2017-01-18 10:54:11
원래의
1414명이 탐색했습니다.

소위 제네릭: 클래스와 인터페이스를 정의할 때 유형 매개변수를 지정할 수 있습니다. 이 유형 매개변수는 변수를 선언하고 객체를 생성할 때 결정됩니다(즉, 유형이라고도 할 수 있는 실제 유형 매개변수를 전달합니다). 인수)

일반 클래스 또는 인터페이스

"다이아몬드" 구문

//定义
 
public interface List<E> extends Collection<E>  
 
public class HashMap<K,V> extends AbstractMap<K,V>  implements Map<K,V>, Cloneable, Serializable 
//使用
 
List<String> list = new ArrayList();
 
//Java7以后可以省略后面尖括号的类型参数
 
List<String> list = new ArrayList<>();
로그인 후 복사

일반 클래스에서 하위 클래스 파생

//方式1
 
public class App extends GenericType<String>
 
//方式2
 
public class App<T> extends GenericType<T>
 
//方式3
 
public class App extends GenericType
로그인 후 복사

의사 일반

실제 일반 클래스는 없습니다. 일반 클래스는 Java 가상 머신에 투명합니다. 즉, JVM은 일반 클래스와 다르지 않게 일반 클래스를 처리합니다. 정적 메서드, 정적 초기화 블록 및 정적 변수에서는 허용되지 않습니다.
- 다음 메소드가 잘못되었습니다.

private static T data;
 
static{
 
    T f;
 
}
 
public static void func(){
 
    T name = 1;
 
}
로그인 후 복사

다음 예는 제네릭 클래스가 없는 것을 측면에서 확인할 수 있습니다

public static void main(String[] args){
 
        List<String> a1 = new ArrayList<>();
        List<Integer> a2 = new ArrayList<>();  
    System.out.println(a1.getClass() == a2.getClass());
 
    System.out.println(a1.getClass());
 
    System.out.println(a2.getClass());
 
}
로그인 후 복사

Output

true
 
class java.util.ArrayList
 
class java.util.ArrayList
로그인 후 복사

와일드카드 입력

먼저 Foo가 Bar의 부모 클래스이지만 List가 List의 부모 클래스가 아닌 경우 Java는 "? " 일반 제네릭을 나타냅니다. 일치. 즉, List는 다양한 제네릭 목록의 상위 클래스를 나타냅니다. 이 와일드카드가 있는 목록 제네릭은 요소를 설정(설정)할 수 없고 요소를 가져오는(가져오기)만 할 수 있습니다. 프로그램은 목록의 유형을 결정할 수 없기 때문에 개체를 추가할 수 없습니다. 그러나 얻은 객체는 Object 유형이어야 합니다.

다음 방법은 컴파일 오류를 발생시킵니다.

List<?> list = new ArrayList<>();
 
list.add(new Object());
로그인 후 복사

몇 가지 아이디어:

1. List 개체는 List 개체로 사용할 수 없습니다. 즉, List 클래스는 List 클래스의 하위 클래스가 아닙니다.

2. 배열과 제네릭은 다릅니다. Foo가 Bar의 하위 유형(하위 클래스 또는 하위 인터페이스)이라고 가정하면 Foo[]는 여전히 Bar[]의 하위 유형이지만 G< ;바>.

3. 다양한 일반 목록의 상위 클래스를 나타내려면 유형 와일드카드를 사용해야 합니다. 물음표(?)를 목록 컬렉션에 전달하세요. , 쓰기: List< ?> (알 수 없는 유형의 요소 목록을 의미) 이 물음표(?)를 와일드카드 문자라고 하며 해당 요소 유형은 모든 유형과 일치할 수 있습니다.

와일드카드 문자의 상한

List은 모든 SuperType 일반 목록 또는 그 자체의 상위 클래스를 나타냅니다. 와일드카드 상한이 있는 제네릭은 set 메소드를 가질 수 없으며 get 메소드만 가질 수 있습니다.

와일드카드 상한을 설정하면 다음 문제를 해결할 수 있습니다. Dog는 Animal 하위 클래스이고, 들어오는 목록 수를 가져오는 getSize 메서드가 있습니다. 코드는 다음과 같습니다.

abstract class Animal {
    public abstract void run();
}
class Dog extends Animal {
    public void run() {
        System.out.println("Dog run");
    }
}
public class App {
    public static void getSize(List<Animal> list) {
        System.out.println(list.size());
    }
    public static void main(String[] args) {
        List<Dog> list = new ArrayList<>();
        getSize(list); // 这里编译报错
    }
}
로그인 후 복사

여기서 프로그래밍 오류가 발생하는 이유는 List이 List의 상위 클래스가 아니기 때문입니다. 첫 번째 해결책은 getSize 메소드의 형식 매개변수 List을 List로 변경하는 것인데, 이 경우 객체를 얻을 때마다 강제 유형 변환이 필요하므로 더 번거롭다. 와일드카드 상한을 사용하면 이 문제가 매우 잘 해결됩니다. List을 List로 변경할 수 있으며 유형 변환이 필요하지 않습니다.


와일드카드 문자의 하한

List< super SubType>은 SubType 일반 목록의 하한을 나타냅니다. 와일드카드 상한이 있는 제네릭은 get 메서드를 가질 수 없고 set 메서드만 가질 수 있습니다.

일반 메소드

유형 매개변수를 사용하지 않고 클래스와 인터페이스를 정의하지만 메소드를 정의할 때 유형 매개변수를 직접 정의하려는 경우 JDK1.5에서도 일반 유형 메소드 지원이 가능합니다. . 일반 메소드의 메소드 시그니처에는 일반 메소드의 메소드 시그니처보다 더 많은 유형 매개변수 선언이 있습니다. 유형 매개변수 선언은 쉼표(,)로 구분됩니다. 메소드 수정자 및 메소드 반환 값 유형 구문 형식은 다음과 같습니다.

修饰符 返回值类型 方法名(类形列表){
 
//方法体
 
}
로그인 후 복사

일반 메소드를 사용하면 유형 매개변수를 사용하여 메소드의 하나 이상의 매개변수 간 유형 종속성을 표현하거나 반환 간의 메소드 유형 종속성을 표현할 수 있습니다. 값과 매개변수. 이러한 유형 종속성이 없으면 일반 메서드를 사용하면 안 됩니다. 컬렉션의 복사 방법은 일반 방법인

 public static <T> void copy(List<? super T> dest, List<? extends T> src){ ...}
로그인 후 복사

를 사용합니다. 이 방법을 사용하려면 src 유형이 dest 유형 또는 그 자체의 하위 클래스여야 합니다.

삭제 및 변환

엄격한 일반 코드에서 일반 선언이 있는 클래스는 항상 유형 매개변수를 전달해야 합니다. 그러나 이전 Java 코드와 일관성을 유지하기 위해 유형 매개변수를 지정하지 않고 일반 선언이 있는 클래스를 사용할 수도 있습니다. 이 제네릭 클래스에 대해 유형 매개변수가 지정되지 않은 경우 유형 매개변수는 원시 유형이라고 하며 매개변수가 선언될 때 지정된 첫 번째 상한 유형이 기본값입니다.

일반 정보가 있는 객체가 일반 정보가 없는 다른 변수에 할당되면 꺾쇠 괄호 사이의 모든 유형 정보가 버려집니다. 예를 들어 List 유형이 List로 변환되면 List의 컬렉션 요소에 대한 유형 확인이 유형 변수(즉, Object)의 상한이 됩니다.

예제

class Apple<T extends Number>
 
{
 
 T size;
 
 public Apple()
 
 {
 
 }
 
 public Apple(T size)
 
 {
 
  this.size = size;
 
 }
 
 public void setSize(T size)
 
 {
 
  this.size = size;
 
 }
 
 public T getSize()
 
 {
 
  return this.size;
 
 }
 
}
 
public class ErasureTest
 
{
 
 public static void main(String[] args)
 
 {
 
  Apple<Integer> a = new Apple<>(6);    // ①
 
  // a的getSize方法返回Integer对象
 
  Integer as = a.getSize();
 
  // 把a对象赋给Apple变量,丢失尖括号里的类型信息
 
  Apple b = a;      // ②
 
  // b只知道size的类型是Number
 
  Number size1 = b.getSize();
 
  // 下面代码引起编译错误
 
  Integer size2 = b.getSize();  // ③
 
 }
 
}
로그인 후 복사

Java의 제네릭에 대한 자세한 설명과 관련된 더 많은 글은 PHP 중국어 홈페이지를 주목해주세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿