Java通用类 - 确定类型

时间:2009-06-16 21:25:46

标签: java generics

如果我创建的java类是通用的,例如:

public class Foo<T>

如何在内部确定该类,'T'最终是什么?

public ???? Bar()
{
    //if its type 1
    //    do this
    //if its type 2
    //    do this
    //if its type 3
    //    do this
    //if its type 4
    //    do this
}

我已经开始使用Java API并使用Reflection的东西,instanceof,getClass,.class等,但我似乎无法对它们做出正面或反面。我觉得我很接近,只需要结合一些电话,但不断缩短。

更具体地说,我试图确定该类是否使用3种可能的类型之一进行实例化。

8 个答案:

答案 0 :(得分:58)

我使用了类似的解决方案来解释他在这里解释的一些项目并发现它非常有用。

http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/

它的主旨是使用以下内容:

 public Class returnedClass() {
     ParameterizedType parameterizedType = (ParameterizedType)getClass()
                                                 .getGenericSuperclass();
     return (Class) parameterizedType.getActualTypeArguments()[0];
}

答案 1 :(得分:44)

与.NET相比,Java泛型是通过一种称为“类型擦除”的技术实现的。

这意味着编译器在生成类文件时将使用类型信息,但不会将此信息传递给字节代码。如果您使用javap或类似工具查看已编译的类,您会发现类文件中List<String>是一个简单的ListObject},就像在pre文件中一样-Java-5代码。

编译器将“重写”访问通用List的代码,以包含您必须在早期版本中自己编写的强制转换。实际上,一旦编译器完成了以下两个代码片段,从字节代码的角度来看是相同的:

Java 5:

List<String> stringList = new ArrayList<String>();
stringList.add("Hello World");
String hw = stringList.get(0);

Java 1.4及之前:

List stringList = new ArrayList();
stringList.add("Hello World");
String hw = (String)stringList.get(0);

当从Java 5中的泛型类读取值时,将自动插入对声明的类型参数的必要强制转换。插入时,编译器将检查您尝试放入的值,如果它不是String,则中止错误。

完成所有工作是为了保持旧库和新的通用代码可以互操作,而无需重新编译现有的库。这是.NET方式的一个主要优点,其中泛型类和非泛型类并存,但不能自由互换。

这两种方法都有其优点和缺点,但这就是它在Java中的方式。

回到原来的问题:你将无法在运行时获取类型信息,因为一旦编译器完成其工作,它就不再存在了。这肯定会在某些方面受到限制,并且它周围有一些胡思乱想的方法,通常基于在某处存储类实例,但这不是标准功能。

答案 2 :(得分:12)

由于type erasure,无法直接执行此操作。但是,你可以做的是将Class<T>传递给构造函数并在类中保留它。然后,您可以根据您允许的三种Class类型进行检查。

但是,如果只有三种可能的类型,您可能需要考虑重构为enum

答案 3 :(得分:3)

问题是大多数通用的东西都会在编译过程中消失。

一种常见的解决方案是在创建Object期间保存类型。

对于java的Type Erasure行为的简短介绍,请阅读此page

答案 4 :(得分:1)

如果您知道一些有意义的特定类型,则应该使用实现创建泛型类型的子类。

所以

public class Foo<T>

public ???? Bar()
{
    //else condition goes here
}

然后

public class DateFoo extends Foo<Date>

public ???? Bar()
{
    //Whatever you would have put in if(T == Date) would go here.
}

答案 5 :(得分:0)

泛型类的重点是你不需要知道正在使用的类型....

答案 6 :(得分:0)

看起来你想要的实际上不是Generic类,而是具有许多不同实现的接口。但是,如果你陈述了实际的具体目标,也许会更清楚。

答案 7 :(得分:0)

我同意Visage。泛型用于编译时验证,而不是运行时动态类型。听起来你需要的只是工厂模式。但是如果你的“做到这一点”不是实例化,那么一个简单的Enum可能也会起作用。就像迈克尔所说,如果你有一个更具体的例子,你会得到更好的答案。