2012-08-01 57 views
2

我們可以製作class Foo <T>,爲什麼我不能撥打new T()? 我試着瞭解,我知道T是一個類型變量,但沒有得到答案......這是朋友問的,也渴望知道答案......請提前致謝。我們可以讓Foo <T>,爲什麼我不能叫新的T()?

+2

參見[什麼是具體化泛型,他們是如何解決類型擦除問題,爲什麼他們不能沒有大的變化被添加?](http://stackoverflow.com/questions/879855) – McDowell 2012-08-01 12:37:15

回答

2

因爲你不知道T是否可以實例化,它可能有一個私有構造函數。

試想:

class Foo<T> { 

    public Foo() { 
     new T(); 
    } 
} 

class Bar { 
    private Bar() {} 
} 

class FooBar { 
    public FooBar() { 
     Foo<Bar> foo = new Foo<>(); 
    } 
} 
7

這是因爲type erasure。 T的類只在編譯時才知道,而不是在運行時。

有一種解決方法。您可以添加Class<T>類型的其他方法參數,然後在該參數上調用newInstance。確保你閱讀文檔進行反思,並在嘗試之前知道你正在進入的內容。

+0

有一個特殊情況'class Bar擴展Foo ',其中泛型信息在運行時保持不變。 Bar會知道它的類型參數是Baz。通過反射,你可以實例化巴茲。您可能需要Baz有一個零參數構造函數。無論它是否是私人的,反射都可以解決這個問題。問題是你可以編寫在父類Foo上使用反射的代碼。 – 2012-08-01 12:45:35

0

的問題是類型擦除的注意,但Taymon。你可以使用反射和子類來解決它,所以類型信息在運行時保持不變。

請注意,它適用於Bar,但不適用於Qux。請注意,Bar通過使用固定類型參數Baz擴展Foo來指定編譯它的類型參數。實例化也依賴於一個可訪問的零參數構造函數。

import java.lang.reflect.ParameterizedType; 
import java.lang.reflect.Type; 
import java.lang.reflect.TypeVariable; 
import sun.reflect.generics.reflectiveObjects.TypeVariableImpl; 

// Made abstract so we can use getClass().getGenericSuperclass() and rely on subclasses 
// specifying it's type parameter. 
public abstract class Foo<T> { 
    public T instantiateTypeParameter() throws Exception { 
     Type type = getClass().getGenericSuperclass(); 
     if (type instanceof ParameterizedType) { 
      ParameterizedType paramType = (ParameterizedType) type; 

      Type typeArg = paramType.getActualTypeArguments()[0]; // We know it's only one, T 
      if (typeArg instanceof TypeVariableImpl) { 
       // Type is not specified. Can't do anything to retrieve it at runtime 
       TypeVariableImpl typeVar = (TypeVariableImpl) typeArg; 
       for (TypeVariable var : typeVar.getGenericDeclaration().getTypeParameters()) { 
        System.out.println("Type: " + var); 
       } 
       return null; 
      } else { 
       Class<?> clazz = (Class<?>) typeArg; 
       return (T) clazz.getConstructor().newInstance(); 
      } 
     } else { 
      System.out.println("IMPOSSIBRUUU"); 
      return null; 
     } 
    } 
} 

public class Bar extends Foo<Baz> { 
} 

public class Qux<T> extends Foo<T> { 
} 

public static void main(String[] args) throws Exception { 
    Bar bar = new Bar(); 
    Baz baz = bar.instantiateTypeParameter(); // Note that you know that it returns Baz 
    System.out.println("Baz: " + baz); // It works! 

    Qux<Baz> qux = new Qux<Baz>(); 
    Baz baz2 = qux.instantiateTypeParameter(); // Will be null 
    System.out.println("Baz2: " + baz2); 
} 
相關問題