Java 如何比较对象的类型';将实例转换为泛型类型?

Java 如何比较对象的类型';将实例转换为泛型类型?,java,generics,reflection,Java,Generics,Reflection,如何用java编写此代码 public class ComponentsManager { private List<IComponent> list = new ArrayList<IComponent>(); public <U extends IComponent> U GetComponent() { for (IComponent component : list) {

如何用java编写此代码

public class ComponentsManager 
    {
        private List<IComponent> list = new ArrayList<IComponent>();

        public <U extends IComponent> U GetComponent() {

            for (IComponent component : list) {

                if(component instanceof U)
                {
                    return component;
                }
            }
        }
}
公共类组件管理器
{
私有列表=新的ArrayList();
公共U GetComponent(){
对于(IComponent组件:列表){
if(U的组件实例)
{
返回组件;
}
}
}
}
但是我不能在泛型类型上执行instanceof。我该怎么做?
谢谢。

据我所知,你不能。您必须将
对象作为参数:

public <U extends IComponent> U getComponent(Class<U> clazz) {
    // ...
    if (component.getClass() == clazz) {
        return (U) component;
    }
}

基本上你不能这样做,因为类型擦除。通常的解决方法是将
对象作为参数传递;e、 g

    public <U extends IComponent> U GetComponent(Class<U> clazz) {
        for (IComponent component : list) {
            if (clazz.isInstance(component)) {
                return clazz.cast(component);
            }
        }
    }
公共组件(类clazz){
对于(IComponent组件:列表){
if(类别指示器(组件)){
返回层铸件(组件);
}
}
}

您还可以使用
if(clazz.equals(component.getClass())){…
但这是一个精确的类型匹配…这不是
instanceof
操作符所做的。
instanceof
操作符和
类.instanceof
方法都测试值的类型是否与赋值兼容。

java的一般规则-如果泛型类需要知道其泛型类型,则必须传递提示。解决此问题的常用方法是使用构造函数:

public class ComponentsManager<U extends IComponent> {
  private Class<U extends IComponentManeger> genericType = null;
  public ComponentsManager<U extends IComponent>(
                       Class<U extends IComponent> genericType) {
    this.genericType = genericType;
  }

}
公共类组件管理器{
私有类genericType=null;
公共组件管理器(
类(genericType){
this.genericType=genericType;
}
}

现在,类知道它是泛型类型类,您可以使用泛型类型类实例验证集合中的组件是否与类泛型类型匹配。

您可以尝试添加两个“测试”方法:

private static <U extends IComponent> boolean testComponent(U u) {
  return true;
}

private static boolean testComponent(Object o) {
  return false;
}
输出:

import java.util.*;

class IComponent {
}

class T1 extends IComponent {
}

public class Test {

  public static <U extends IComponent> boolean testComponent(U u) {
    return true;
  }

  public static boolean testComponent(Object o) {
    return false;
  }

  public static void main(String[] args) {
    T1 t = new T1();
    System.out.println("hm? " + (testComponent(t) ? "true" : "false"));
  }
}

hm?true

确切地说,泛型类型不能被视为代码中的普通变量,这使得直接比较很困难。但是反射类,
ParameterizedType
,可以帮助您获得表示参数化类型的实例,这基本上是可行的对象

Type genericSuperType = object.getClass().getGenericSuperclass()
Type[] actualTypeParams = ((ParameterizedType) genericSuperType).getActualTypeArguments()
if (actualTypeParams[0] instanceof Class) {
    ((Class) actualTypeParams[0]).isInstance(testingObj);
}

有关
ParameterizedType
和相应的
TypeVariable
的用法的详细信息,可以引用内部的util类。

你说得对@Stephen。我忘了强制转换结果。谢谢你指出它。这也不会编译。试试看。@Stephen:我试过了,效果很好(至少在使用JDK 6的Eclipse中是这样)。它使用“未经检查的强制转换”进行编译警告,但它很好。你犯了什么错误?这就是我的意思。大多数人认为这是诅咒。问题是,虽然它在实践中是安全的,但一个小的改变会导致它不安全。因此,忽视或抑制它是一个坏主意。相反,你应该把它当作一个硬编译错误来修复它。”史提芬。C:你愿意对我的答案发表评论吗?每个人都说“不能”,但我的小演示仍然有效。为什么Oracle/Java不添加泛型类型访问.class字段(/method/identifier)的可能性?我是否正确地假设原因与编译时与运行时的情况有关?根本原因是类型擦除。类型擦除的根本原因是,为了与早期版本的Java兼容,需要将泛型类型实现为编译时机制(在Java 5中)。名称为“clazz”这个参数有点让我奇怪。但似乎几乎每个例子都使用了完全相同的名称。尝试使用
class
,看看会发生什么。(然后关闭“古怪感测器”。(因为@sje397让我评论…):这将“起作用”,但您必须在
GetComponent
方法中执行不安全的类型转换…或将其更改为非泛型方法。此外,您通过添加自己的ersatz类型检查来复制Java的类型检查。这很麻烦,最终解决方案比使用真正Java类型检查的解决方案更脆弱。即使给定tephen的评论,这很有用。哦,等等,这似乎不是编译“同类型擦除”。@sje397:这对你有用吗?显然你必须在每个类中包含方法?那就没那么有用了。所有这些“答案”问题是,一旦你使用了该方法,类型擦除意味着你不知道它是一个“U”,因此你不能基于“U”进行任何推理,而“U”正是解决这个问题所需要的。方法“testComponent”中所知道的一切,表示“u”是一个i组件。更好的测试是通过两个参数“u”和“i组件其他”,然后显示您可以确定“其他”是否是一个“u”.但在这一点上,最好传入所需的类。或者换一种方式:它当然返回true,这只是重载的一种演示;带有参数IComponent的非泛型方法将具有完全相同的行为。现在证明“u扩展IComponent”我不认为这会给你带来任何好处,但即使我错了,通过一门课也会是一种更干净的方式来达到目的。
Type genericSuperType = object.getClass().getGenericSuperclass()
Type[] actualTypeParams = ((ParameterizedType) genericSuperType).getActualTypeArguments()
if (actualTypeParams[0] instanceof Class) {
    ((Class) actualTypeParams[0]).isInstance(testingObj);
}