Java 泛型类 - 确定类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1004022/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 22:08:21  来源:igfitidea点击:

Java Generic Class - Determine Type

javagenerics

提问by dreadwail

If I am creating a java class to be generic, such as:

如果我要创建一个通用的 java 类,例如:

public class Foo<T>

How can one determine internally to that class, what 'T' ended up being?

如何在内部确定该类的“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
}

I've poked around the Java API and played with the Reflection stuff, instanceof, getClass, .class, etc, but I can't seem to make heads or tails of them. I feel like I'm close and just need to combine a number of calls, but keep coming up short.

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

To be more specific, I am attempting to determine whether the class was instantiated with one of 3 possible types.

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

采纳答案by jnt30

I've used a similar solution to what he explains here for a few projects and found it pretty useful.

我在几个项目中使用了与他在这里解释的类似的解决方案,发现它非常有用。

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

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

The jist of it is using the following:

它的 jist 使用以下内容:

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

回答by Michael Myers

Because of type erasure, there is no way to do this directly. What you could do, though, is pass a Class<T>into the constructor and hold onto it inside your class. Then you can check it against the three possible Classtypes that you allow.

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

However, if there are only three possible types, you might want to consider refactoring into an enuminstead.

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

回答by PaulJWilliams

The whole point of a generic class is that you dont need to know the type that is being used....

泛型类的全部意义在于您不需要知道正在使用的类型......

回答by Janusz

The Problem is that most of the Generic stuff will disappear during compilation.

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

One common solution is to save the type during the creation of the Object.

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

For a short introduction in the Type Erasure behaviour of java read this page

有关 java 的类型擦除行为的简短介绍,请阅读此页面

回答by Michael Borgwardt

It looks like what you want is in fact not a Generic class, but an interface with a number of different implementations. But maybe it would become clearer if you stated your actual, concrete goal.

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

回答by Daniel Schneller

In contrast to .NET Java generics are implemented by a technique called "type erasure".

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

What this means is that the compiler will use the type information when generating the class files, but not transfer this information to the byte code. If you look at the compiled classes with javap or similar tools, you will find that a List<String>is a simple List(of Object) in the class file, just as it was in pre-Java-5 code.

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

Code accessing the generic List will be "rewritten" by the compiler to include the casts you would have to write yourself in earlier versions. In effect the following two code fragments are identical from a byte code perspective once the compiler is done with them:

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

Java 5:

爪哇 5:

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

Java 1.4 and before:

Java 1.4 及之前:

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

When reading values from a generic class in Java 5 the necessary cast to the declared type parameter is automatically inserted. When inserting, the compiler will check the value you try to put in and abort with an error if it is not a String.

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

The whole thing was done to keep old libraries and new generified code interoperable without any need to recompile the existing libs. This is a major advantage over the .NET way where generic classes and non-generic ones live side-by-side but cannot be interchanged freely.

整个过程是为了保持旧库和新的泛化代码可互操作,而无需重新编译现有库。与 .NET 方式相比,这是一个主要优势,在 .NET 方式中,泛型类和非泛型类并排存在但不能自由互换。

Both approaches have their pros and cons, but that's the way it is in Java.

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

To get back to your original question: You will not be able to get at the type information at runtime, because it simply is not there anymore, once the compiler has done its job. This is surely limiting in some ways and there are some cranky ways around it which are usually based on storing a class-instance somewhere, but this is not a standard feature.

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

回答by aberrant80

I agree with Visage. Generics is for compile-time validation, not runtime dynamic typing. Sounds like what you need is really just the factory pattern. But if your "do this" isn't instantiation, then a simple Enum will probably work just as well. Like what Michael said, if you have a slightly more concrete example, you'll get better answers.

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

回答by Ryan Shillington

If you know a few specific types that are meaningful, you should create subclasses of your generic type with the implementation.

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

So

所以

public class Foo<T>

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

And then

进而

public class DateFoo extends Foo<Date>

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