我想在java中创建一个Generics Type对象.请建议我如何实现同样的目标.
注意:这似乎是一个微不足道的泛型问题.但我敢打赌......事实并非如此.:)
假设我有类声明:
public class Abc<T> {
public T getInstanceOfT() {
// I want to create an instance of T and return the same.
}
}
Run Code Online (Sandbox Code Playgroud)
Jen*_*der 69
public class Abc<T> {
public T getInstanceOfT(Class<T> aClass) {
return aClass.newInstance();
}
}
Run Code Online (Sandbox Code Playgroud)
您必须添加异常处理.
您必须在运行时传递实际类型,因为它不是编译后字节代码的一部分,因此没有明确提供它就无法知道它.
Mar*_*tin 26
在您发布的代码中,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
}
}
Run Code Online (Sandbox Code Playgroud)
当然,如果您有一个引用Class<T>
并且T
具有默认构造函数,则可以调用newInstance()
该Class
对象.
如果你是子类,Abc<T>
你甚至可以解决类型擦除问题,并且不必传递任何Class<T>
引用:
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>
{
}
Run Code Online (Sandbox Code Playgroud)
Jac*_*ack 14
你写的内容没有任何意义,Java中的泛型旨在将参数多态的功能添加到对象中.
这是什么意思?这意味着您希望保持类的某些类型变量未定,以便能够使用具有许多不同类型的类.
但是你的类型变量 T
是一个在运行时解析的属性,Java编译器将编译你的类证明类型安全而不试图知道什么类型的对象,T
所以它不可能让你在静态方法中使用一个类型变量.该类型与对象的运行时实例public void static main(..)
相关联,而与类定义相关联,并且该范围T
并不意味着什么.
如果要在静态方法中使用类型变量,则必须将该方法声明为泛型(这是因为,如解释的模板类的类型变量与其运行时实例相关),而不是类:
class SandBox
{
public static <T> void myMethod()
{
T foobar;
}
}
Run Code Online (Sandbox Code Playgroud)
这是有效的,但当然不是用main
方法,因为没有办法以通用方式调用它.
编辑:问题是因为类型擦除只编译一个泛型类并传递给JVM.类型检查器只是检查代码是否安全,然后因为它证明了它被丢弃了所有类型的通用信息.
要实例化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());
}
}
Run Code Online (Sandbox Code Playgroud)
当然这意味着您要实例化的类型:
要与不同类型的构造函数一起操作,您必须深入挖掘反射.
您需要静态获取类型信息.试试这个:
public class Abc<T> {
private Class<T> clazz;
public Abc(Class<T> clazz) {
this.clazz = clazz;
}
public T getInstanceOfT()
throws InstantiationException, IllegalAccessException {
return clazz.newInstance();
}
}
Run Code Online (Sandbox Code Playgroud)
使用它如下:
Abc<String> abc = new Abc<String>(String.class);
abc.getInstanceOfT();
Run Code Online (Sandbox Code Playgroud)
根据您的需要,您可能希望Class<? extends T>
改用.
The only way to get it to work is to use Reified Generics. And this is not supported in Java (yet? it was planned for Java 7, but has been postponed). In C# for example it is supported assuming that T
has a default constructor. You can even get the runtime type by typeof(T)
and get the constructors by Type.GetConstructor()
. I don't do C# so the syntax may be invalid, but it roughly look like this:
public class Foo<T> where T:new() {
public void foo() {
T t = new T();
}
}
Run Code Online (Sandbox Code Playgroud)
The best "workaround" for this in Java is to pass a Class<T>
as method argument instead as several answers already pointed out.