注意:这可能看起来是一个微不足道的泛型问题。但我敢打赌…它并不是。 :)
假设我有以下类声明:
public class Abc<T> {
public T getInstanceOfT() {
// I want to create an instance of T and return the same.
}
}
public class Abc<T> {
public T getInstanceOfT() {
// I want to create an instance of T and return the same.
}
}
public class Abc<T> {
public T getInstanceOfT(Class<T> aClass) {
return aClass.newInstance();
}
}
您需要添加异常处理。
在运行时,您必须传递实际类型,因为它不是编译后的字节码的一部分,所以没有办法在不显式提供的情况下知道它。
T newT = this.getInstance(T.class)
无法编译。 - SMBiggsaClass.newInstance();
- Valeria Khusnulinaclazz.newInstance()
已经被弃用,可以使用clazz.getDeclaredConstructor().newInstance()
代替。 - Gerold BroserT
是什么类型,因此无法创建T
的实例:public class Abc<T>
{
public T getInstanceOfT()
{
// There is no way to create an instance of T here
// since we don't know its type
}
}
import java.lang.reflect.ParameterizedType;
public class Abc<T>
{
T getInstanceOfT()
{
ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass();
Class<T> type = (Class<T>) superClass.getActualTypeArguments()[0];
try
{
return type.newInstance();
}
catch (Exception e)
{
// Oops, no default constructor
throw new RuntimeException(e);
}
}
public static void main(String[] args)
{
String instance = new SubClass().getInstanceOfT();
System.out.println(instance.getClass());
}
}
class SubClass
extends Abc<String>
{
}
Class<T>
,但在这里我们可以创建一个实例。 - Konrad RudolphT
的类型(通过Class<T>
)并且该类型具有默认构造函数,则可以实例化T
。但是,在最初发布的代码中并非如此。 - Martinclazz.newInstance()
已在Java 9中被弃用:可以使用clazz.getDeclaredConstructor().newInstance()
来替代。 - Gerold Broserclass SandBox
{
public static <T> void myMethod()
{
T foobar;
}
}
main
方法了。T
,你需要知道T
的类型,但它可以同时是许多类型,所以一种仅需要最少量反射的解决方案是使用Class<T>
来实例化新对象:public class SandBox<T>
{
Class<T> reference;
SandBox(Class<T> classRef)
{
reference = classRef;
}
public T getNewInstance()
{
try
{
return reference.newInstance();
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public static void main(String[] args)
{
SandBox<String> t = new SandBox<String>(String.class);
System.out.println(t.getNewInstance().getClass().getName());
}
}
default(T);
或Activator.CreateInstance(typeof(T));
。 - FelypeArrayList
创建T实例,只需存储先前分配的T引用即可。 - JackType genericType = typeof(T)
是完全有意义的,这将在运行时解析,并且编译器不会对该行代码产生任何影响。 现在根据我在这里调试的内容,似乎 Java 甚至在运行时也不知道 T 代表什么,就是完全一无所知。 - Felype您需要静态获取类型信息。请尝试以下方法:
public class Abc<T> {
private Class<T> clazz;
public Abc(Class<T> clazz) {
this.clazz = clazz;
}
public T getInstanceOfT()
throws throws InstantiationException,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException,
NoSuchMethodException,
SecurityException {
return clazz.getDeclaredConstructor().newInstance();
}
}
使用方法如下:
Abc<String> abc = new Abc<String>(String.class);
abc.getInstanceOfT();
根据您的需求,您可能希望使用 Class<? extends T>
。
clazz.newInstance()
已在Java 9中被弃用:可以使用clazz.getDeclaredConstructor().newInstance()
来替代。 - Gerold BroserT
有一个默认构造函数,就支持此功能。你甚至可以通过typeof(T)
获取运行时类型,并通过Type.GetConstructor()
获取构造函数。我不熟悉C#语法,但它大致如下:public class Foo<T> where T:new() {
public void foo() {
T t = new T();
}
}
Class<T>
作为方法参数传递,而不是像其他答案已经指出的那样。首先,在静态的main方法中无法访问类型参数T
,只能在非静态类成员中访问(在这种情况下)。
其次,你无法实例化T
,因为Java使用类型擦除实现泛型。几乎所有的泛型信息都在编译时被擦除了。
基本上,你不能这样做:
T member = new T();
这是一个关于泛型的好教程。
当你真的必须这样做时,有一些变通的方法。
以下是一个我发现非常有用的转换方法的示例;它提供了一种确定泛型具体类的方法。
此方法接受对象集合作为输入,并返回一个数组,其中每个元素是在输入集合中调用字段getter的结果。例如,假设您有一个 List<People>
,并且您想要一个包含所有人姓氏的 String[]
。
getter返回的字段值类型由泛型 E
指定,我需要实例化类型为 E[]
的数组以存储返回值。
该方法本身有点丑陋,但使用它的代码可以更加简洁。
请注意,此技术仅在输入参数中的某个对象的类型与返回类型匹配,并且您可以确定地找出它时才起作用。如果您的输入参数(或其子对象)的具体类无法告诉您有关泛型的信息,则此技术将无法正常工作。
public <E> E[] array (Collection c) {
if (c == null) return null;
if (c.isEmpty()) return (E[]) EMPTY_OBJECT_ARRAY;
final List<E> collect = (List<E>) CollectionUtils.collect(c, this);
final Class<E> elementType = (Class<E>) ReflectionUtil.getterType(c.iterator().next(), field);
return collect.toArray((E[]) Array.newInstance(elementType, collect.size()));
}
public class Abc<T>
{
T someGenericThing;
public Abc(){}
public T getSomeGenericThing()
{
return someGenericThing;
}
public static void main(String[] args)
{
// create an instance of "Abc of String"
Abc<String> stringAbc = new Abc<String>();
String test = stringAbc.getSomeGenericThing();
}
}
我是用以下方法来实现相同的功能的。
public class Abc<T>
{
T myvar;
public T getInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException
{
return clazz.newInstance();
}
}
我试图找到更好的方法来实现同样的目标。
这不可能吗?
clazz
(请查看我的答案)。如果您在方法中执行此操作,则几乎没有意义,因为它只是调用someObject.getClass().newInstance()
的快捷方式,似乎并没有什么作用。即使您决定以这种方式执行此操作,也不需要泛型类;静态泛型方法就足够了。 - Hosam Alyclazz.newInstance()
已在Java 9中被弃用:可以使用clazz.getDeclaredConstructor().newInstance()
来替代。 - Gerold Broser受到@martin的回答的启发,我编写了一个帮助类,使我能够解决类型擦除问题。使用这个类(和一些不太优美的技巧),我能够创建一个模板类型的新实例:
public abstract class C_TestClass<T > {
T createTemplateInstance() {
return C_GenericsHelper.createTemplateInstance( this, 0 );
}
public static void main( String[] args ) {
ArrayList<String > list =
new C_TestClass<ArrayList<String > >(){}.createTemplateInstance();
}
}
abstract
,以便类的使用者被迫对其进行子类型化。在这里,我通过在调用构造函数后附加 {}
来对它进行了子类化。这定义了一个新的匿名类并创建了它的实例。public class C_GenericsHelper {
/**
* @param object instance of a class that is a subclass of a generic class
* @param index index of the generic type that should be instantiated
* @return new instance of T (created by calling the default constructor)
* @throws RuntimeException if T has no accessible default constructor
*/
@SuppressWarnings( "unchecked" )
public static <T> T createTemplateInstance( Object object, int index ) {
ParameterizedType superClass =
(ParameterizedType )object.getClass().getGenericSuperclass();
Type type = superClass.getActualTypeArguments()[ index ];
Class<T > instanceType;
if( type instanceof ParameterizedType ) {
instanceType = (Class<T > )( (ParameterizedType )type ).getRawType();
}
else {
instanceType = (Class<T > )type;
}
try {
return instanceType.newInstance();
}
catch( Exception e ) {
throw new RuntimeException( e );
}
}
}
clazz.newInstance()
已在Java 9中被弃用:可以使用clazz.getDeclaredConstructor().newInstance()
来替代。 - Gerold Broser