【问题标题】:Using instanceof and casting with generics使用 instanceof 并使用泛型进行强制转换
【发布时间】:2021-02-15 06:04:37
【问题描述】:

我正在尝试创建一个函数,该函数接收具有一个类型参数 T 的参数化类的实例,然后使用反射查看其封装类的字段,检查这些字段是否属于 T 类型,然后如果他们是的话,就会对他们进行强制转换并做一些事情。到目前为止,这是我所拥有的:

 private <T> void someFunction(SomeClass<T> instance) throws IllegalAccessException {
            for(Field field : this.getClass().getDeclaredFields()){
                Object obj = field.get(this);
                // TODO: get parameter T from instance and store it in a variable named 'myClass'
                if(myClass.isInstance(obj)){
                    doSomething(instance, myClass.cast(obj))
                }
            }
        }

据我了解,为了在运行时执行此操作,您需要声明一个 Class 类型的变量并将 T 的类存储在其中,以便您可以使用 isInstance() 和 cast() 函数,但我是不确定如何正确执行此操作。

【问题讨论】:

  • to do this at runtime you need to declare a variable of type Class and store the class of T in there so you can then use the isInstance() and cast() functions 你需要澄清一下,因为这太模糊了。您有该声明的来源吗?
  • T 是一个类型参数。没有“T 级”。 T 的实际参数可能类似于 ? extends Comparable&amp;CharSequence。没有Class 对象可以代表这个。
  • @Holger 哦,这有道理,但是看看另一个post,在答案中我发现了这个代码sn-p:ParameterizedType pt = (ParameterizedType)this.getClass().getGenericSuperclass(); clazz = (Class&lt;?&gt;)pt.getActualTypeArguments()[0]; 虽然当我尝试这样做时,我得到了错误java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class。是否可以做类似的事情来从类型参数中获取单个类?
  • Type 在某些情况下可能是Class,但在其他情况下则不是。当你有一个class Sub&lt;T&gt; extends Super&lt;T&gt; 形式的类时,那么getGenericSuperclass().getActualTypeArguments()[0] 不能是Class,因为Super 的类型参数是TSub 声明的类型变量,而不是具体的类.由于someFunction 是通用的,该函数的调用者将决定使用哪个类型的参数。 SomeClass 中的任何内容都无法告诉您 someFunction 的直接调用者做了什么。

标签: java generics java-8 casting instanceof


【解决方案1】:

短篇小说 -- 缺失的部分

private <T extends SomeClass> void someFunction(SomeClass<T> instance) throws IllegalAccessException {
    for (Field field : this.getClass().getDeclaredFields()) {
        Object obj = field.get(this);

        Class<?> objClass = obj.getClass();
        if (objClass.isInstance(instance))
            doSomething(instance, (T) obj);
    }
  • 我们从 Object 获取和存储 Class 的位置,然后根据我们想要匹配的实例检查它。
  • 我们使用the wildcard ? 来表示未知类型,这样我们就不必弄清楚或指定类型。
  • 然后我们保证doSomething 方法接受相同的泛型类型参数以允许类似的工作
    • 因此我们只需要转换为 T

作为一个整体,以动物为例

(是的,这是减少 :))

以动物类为基础

public abstract class Animal {

    protected Object color;

    protected Animal(Object color) {
        this.color = color;
    }

    protected Animal() {}

}

各种颜色的动物(简化)

无色动物(幽灵?!)
public class NoColorAnimal extends Animal {

    // A null color
    public NoColorAnimal() {}

}
单色动物
public class SingleColorAnimal extends Animal {

    // A single String of color
    public SingleColorAnimal(String color) {
        super(color);
    }

}
多彩多姿的动物
public class MultiColorAnimal extends Animal {

    // An Array of colors
    public MultiColorAnimal(String... colors) {
        super(colors);
    }

}

以可视动物为封闭类的动物园

public class ZooAnimals {

    public MultiColorAnimal tiger = new MultiColorAnimal("black", "orange");
    public SingleColorAnimal dolphin = new SingleColorAnimal("grey");


    public <T extends Animal> void viewAnimalIfPresent(Animal<T> animal) throws IllegalAccessException {
        for (Field field : this.getClass().getDeclaredFields()) {
            Object obj = field.get(this);

            Class<?> objClass = obj.getClass();
            if (objClass.isInstance(animal))
                view(animal, (T) obj, field.getName());
        }
    }

    private <T extends Animal> void view(Animal<T> animal, T obj, String name) {
        // TODO - Do something useful with these, but simply log them for now :)
        System.out.printf("Viewed a %s; the %s%n", obj.getClass().getSimpleName(), name);
    }

}

一个简单的测试

ZooAnimals zoo = new ZooAnimals();

    @Test
    public void test() throws IllegalAccessException {
        zoo.viewAnimalIfPresent(zoo.tiger);
        zoo.viewAnimalIfPresent(zoo.dolphin);
        zoo.viewAnimalIfPresent(new NoColorAnimal());
    }

测试结果

显示正确类型转换的测试控制台输出
Viewed a MultiColorAnimal; the tiger
Viewed a SingleColorAnimal; the dolphin

没有字段匹配无色动物,因此没有打印任何内容。

【讨论】:

  • Animal 类的类型参数与您发布的代码无关。您永远不会检查对象是否与 T 的实际类型匹配,这只是巧合,类总是声明实际类型参数是匹配的。我可以轻松地为T 添加另一个与其类型参数不匹配的类,并且测试不会检测到它们不匹配,但无论如何它没有任何后果。
  • 公平点。我想添加它来演示如何直接利用超类中的子类,但只做了到这个阶段,以免让它过于复杂,然后留下评论。因此,您是对的,尽管它没有显示/影响任何内容,但它不会增加任何内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多