java - type - 자바 제네릭




List, List<?>, List<T>, List<E> 및 List<Object>의 차이점 (7)

1) 수정

2) 그 중 하나를 "읽기 전용"목록으로 생각할 수 있습니다. 여기서 항목의 유형은 상관하지 않습니다. 예를 들어 목록의 길이를 반환하는 메소드에서 사용할 수 있습니다.

3) T, E, U는 동일하지만 사람들은 유형에 T, 요소에 E, 가치에 V, 열쇠에 K를 사용하는 경향이 있습니다. 컴파일하는 메서드는 특정 형식의 배열을 사용하고 동일한 형식의 배열을 반환한다고 말합니다.

4) 오렌지와 사과는 섞을 수 없습니다. 객체 목록을 예상하는 메서드에 문자열 목록을 전달할 수 있으면 String 목록에 Object를 추가 할 수 있습니다. (그리고 모든 객체가 문자열은 아닙니다)

List , List<?> , List<T> , List<E>List<Object> 의 차이점은 무엇입니까?

이제는 맹목적으로이 질문을하지 않으므로이 스레드를 닫지 마십시오. 먼저 기본 코드를 소개하겠습니다.

private static List<String> names = new ArrayList<String>();
static {
    names.add("Tom");
    names.add("Peter");
    names.add("Michael");
    names.add("Johnson");
    names.add("Vlissides");
}

public static void test(List<String> set){
    System.out.println(set);
}
public static void main(String args[]){
    test(names);
}

나는 그것을 이해한다.

1. List : 원시 형식이므로 typesafe 아닙니다. 형 변환이 나쁜 경우에만 런타임 오류가 생성됩니다. 캐스트가 잘못되었을 때 컴파일 타임 오류가 발생합니다. 사용하지 않는 것이 좋습니다.

2. List<?> : 제한되지 않은 와일드 카드입니다. 그러나 이것이 무엇을위한 것인지 모르겠다. 그래서 test 방법을

public static void test(List<?> set){
    System.out.println(set);
}

여전히 잘 작동합니다. 이 사용법을 설명 할 수 있다면 크게 감사하겠습니다.

편집 : 만약 내가 이렇게 :

public static void test(List<?> set){
    set.add(new Long(2)); //--> Error
    set.add("2");    //--> Error
    System.out.println(set);
}

하지만 내가 이것에 대한 test 를 변경하면 :

public static void test(List<String> set){
    set.add(new Long(2)); //--> Error
    set.add("2");    //--> Work
    System.out.println(set);
}

3. List<T> :

public static void test(List<T> set){   //T cannot be resolved
    System.out.println(set);
}

나는이 구문을 이해하지 못한다고 생각한다. 나는 이런 것을 보았다.

public <T> T[] toArray(T[] a){
    return a;   
}

제발 설명해주세요. 때로는 <T> 또는 <E> 또는 <U> , <T,E> 됩니다. 그들은 모두 같습니까? 아니면 다른 것을 나타낼까요?

4. List<Object>

public static void test(List<Object> set){
    System.out.println(set);
}

그런 다음 The method test(List<Object>) is not application for the argument List<String> 아래 코드의 The method test(List<Object>) is not application for the argument List<String> . 나는 혼란 스럽다. StringObject 의 하위 집합이라고 생각 했나요?

public static void main(String args[]){
    test(names); 
}

편집 : 나는 이것을 시도하면

test((List<Object>)names);

Cannot cast from List<String> to List<Object>


Java puzzlers를 읽는 것이 좋습니다. 선언에서 상속, 제네릭, 추상화 및 와일드 카드를 아주 잘 설명합니다. http://www.javapuzzlers.com/


맞습니다 : String은 Object의 하위 집합입니다. String은 Object보다 정확하기 때문에 이것을 캐스팅하여 System.out.println ()의 인수로 사용해야합니다.


문제 2는 "System.out.println (set);" "System.out.println (set.toString ());"을 의미합니다. set는 List의 인스턴스이므로, complier는 List.toString ()을 호출합니다.

public static void test(List<?> set){
set.add(new Long(2)); //--> Error  
set.add("2");    //--> Error
System.out.println(set);
} 
Element ? will not promise Long and String, so complier will  not accept Long and String Object

public static void test(List<String> set){
set.add(new Long(2)); //--> Error
set.add("2");    //--> Work
System.out.println(set);
}
Element String promise it a String, so complier will accept String Object

문제 3 :이 기호는 동일하지만 다른 기호를 지정할 수 있습니다. 예 :

public <T extends Integer,E extends String> void p(T t, E e) {}

문제 4 : 콜렉션은 유형 매개 변수 공분산을 허용하지 않습니다. 그러나 배열은 공분산을 허용합니다.


자바 역사의 맥락에서 그들에 대해 이야기 해보자.

  1. List :

List는 모든 객체를 포함 할 수 있음을 의미합니다. 목록은 Java 5.0 이전의 릴리스에있었습니다. Java 5.0에서는 하위 호환성을 위해 List가 도입되었습니다.

List list=new  ArrayList();
list.add(anyObject);
  1. List<?> :

? 알 수없는 객체를 의미하지는 않습니다. 와일드 카드 ? 소개는 Generic Type에 의해 구축 된 문제를 해결하기위한 것입니다; wildcards ; 그러나 이것도 또 다른 문제를 일으킨다.

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
  1. List< T> List< E>

프로젝트 Lib에 T 또는 E 유형이 없음을 전제로 한 일반 선언을 의미합니다.

  1. List< Object> 는 일반적인 매개 변수화를 의미합니다.

표기법 List<?> 은 "뭔가의 목록 (그러나 나는 무엇을 말하지 않고있다)"을 의미합니다. test 의 코드는 목록에있는 모든 종류의 객체에서 작동하므로 공식적인 메소드 매개 변수로 작동합니다.

유형 매개 변수 (예 : 3 번 항목)를 사용하려면 type 매개 변수를 선언해야합니다. 이를위한 Java 구문은 함수 앞에 <T> 를 넣는 것입니다. 이것은 메서드 본문에서 이름을 사용하기 전에 메서드에 형식적 매개 변수 이름을 선언하는 것과 완전히 유사합니다.

List<Object>List<String> 받아 들일 수 없다는 것은 StringObject 가 아니기 때문에 의미가 있습니다. Object 의 서브 클래스입니다. 해결 방법은 public static void test(List<? extends Object> set) ... 를 선언하는 public static void test(List<? extends Object> set) ... 입니다. 그러나 모든 클래스가 직접적으로 또는 간접적으로 Object 확장하기 때문에 extends Object 가 중복됩니다.


이론

String[]Object[] 캐스트 될 수 있습니다 Object[]

그러나

List<String>List<Object> 캐스트 할 수 없습니다.

연습

리스트에서는 컴파일 타임 에 메소드에 전달 된 List 매개 변수의 유형이 점검되지 않기 때문에 그보다 더 미묘합니다. 메소드 정의는 List<?> 라고 말할 수 있습니다 - 컴파일러의 관점에서 보면 동등합니다. 이것이 OP의 예 # 2가 런타임 오류가 컴파일 오류가 아닌 이유입니다.

메서드에 전달 된 List<Object> 매개 변수를 처리하여 List<Object> 모든 요소에 대해 유형을 확인하지 않도록하면 List<Object> 사용하여 메서드를 정의 할 수 있지만 사실 List<String> 매개 변수를 호출 코드에서 가져옵니다.

A. 이 코드는 컴파일이나 런타임 오류를주지 않으며 실제로 작동합니다 (그리고 어쩌면 놀랍게도)?

public static void test(List<Object> set) {
    List<Object> params = new List<>();  // This is a List<Object>
    params.addAll(set);       // A String can be added to List<Object>
    params.add(new Long(2));  // A Long can be added to List<Object>
    System.out.println(params);
}

public static void main(String[] args) {
    List<String> argsList = Arrays.asList(args);
    test(argsList);  // The object passed is a List<String>
}

B. 이 코드는 런타임 오류를 발생시킵니다.

public static void test(List<Object> set) {
    List<Object> params = set;  // Surprise!  Runtime error
    set.add(new Long(2));       // Also a runtime error
    System.out.println(set);
}

public static void main(String[] args) {
    List<String> argsList = Arrays.asList(args);
    test(argsList);
}

C. 이 코드는 런타임 오류를 발생시킵니다 ( java.lang.ArrayStoreException: java.util.Collections$UnmodifiableRandomAccessList Object[] ).

public static void test(Object[] set) {
    Object[] params = set;    // This is OK even at runtime
    params[0] = new Long(2);  // Surprise!  Runtime error
    System.out.println(params);
}

public static void main(String[] args) {
    test(args);
}

B에서 매개 변수 set 은 컴파일 타임에 형식화 된 List 이 아닙니다. 컴파일러는이를 List<?> 로 봅니다. 런타임에 setmain() 에서 전달 된 실제 객체가되고 List<String> 이므로 런타임 오류가 발생합니다. List<String>List<Object> 캐스트 할 수 없습니다.

C에서는 매개 변수 setObject[] 가 필요합니다. String[] 객체를 매개 변수로 사용하여 컴파일 오류 및 런타임 오류가 발생하지 않습니다. String[]Object[] 되기 때문입니다. 그러나 test() 의해 수신 된 실제 객체는 여전히 String[] 이며 변경되지 않았습니다. 따라서 params 객체는 String[] 됩니다. 그리고 String[] 의 요소 0은 Long !에 할당 될 수 없습니다.

(바라건대 내가 여기있는 모든 것을 가지고있다. 내 추론이 잘못 되었다면 공동체가 나에게 말할 것이라고 확신한다.)





generics