Java:反射、通用类型和未检查的转换

标签 java generics reflection

我的类(class)将获得一个 Object 类(class)。然后我使用反射遍历该类的声明字段并注册一个 ChangeListener在每个字段上使用 Property基类。

原始的“createChangeListener”方法如下所示:

private void createChangeListener(Property property) {
    property.addListener(new ChangeListener() {
        @Override
        public void changed(ObservableValue observable, Object oldValue, Object newValue) {                        
            Foo.this.propertyChanged(observable);
        }
    });
}

但是,这会产生不需要的警告:

warning: [unchecked] unchecked call to addListener(ChangeListener<? super T>) as a member of the raw type ObservableValue
    property.addListener(new ChangeListener() {
        where T is a type-variable:
    T extends Object declared in interface ObservableValue

不要被劝阻,我为我的 Property 提供了一个通用类型参数和 ChangeListener :

private void createChangeListener(Property<Object> property) {
    property.addListener(new ChangeListener<Object>() {
        @Override
        public void changed(ObservableValue observable, Object oldValue, Object newValue) {                        
            Foo.this.propertyChanged(observable);
        }
    });
}

...直到现在才被告知我只是将我的问题转移到反射源。下面的代码现在修改为转换为 Property<Object>从原来的Property没有通用类型:

if (Property.class.isAssignableFrom(field.getType())) {
    createChangeListener((Property<Object>)(field.get(model)));
}

这个以前没有警告的代码现在正在产生头部倾斜:

warning: [unchecked] unchecked cast
    createChangeListener((Property<Object>)(field.get(model)));
required: Property<Object>
found:    Object

问题:

  • ಠ_ಠ
  • 鉴于 Java 的类型删除限制,我可以使用哪些技术来安全地解决这些警告?
  • 在原始的非类型化方法中抑制未经检查的警告是否安全?

最佳答案

将您的字段值转换为 Property<Object>你明确地说 Property通用参数是 Object ,这可能是错误的,编译器无法帮助您。比如字段的真实类型是Property<String>您可以执行以下操作:

Property<Object> p = (Property<Object>)(field.get(model)); // compiler warning, runtime ok
p.setValue(new Object()); // runtime ok, but now you're probably stored incompatible value

// somewhere much later in completely different piece of code
String value = this.propertyField.getValue(); // sudden ClassCastException

因此编译器会警告您转换为 Property<Object>你在做一个编译器无法证明的假设,并且你实际上可能有不同的类型,这可能导致将对象置于不正确的状态,这可能会在以后的某个地方破坏你的程序。

在您的特定情况下,您不想说“我知道通用参数类型是 Object”。你想说的是“我不关心泛型参数类型”。对于这种情况,有一个特殊的结构 <?> .你可以在这里使用它:

void createChangeListener(Property<?> property) {
    property.addListener(new ChangeListener<Object>() {
        @Override
        public void changed(ObservableValue<?> observable, 
                            Object oldValue, Object newValue) {                        
            Foo.this.propertyChanged(observable);
        }
    });
}

并且您可以安全地转换为 Property<?>没有任何警告。但是现在你不能调用 setValue根本不需要,但似乎您根本不​​需要。

关于Java:反射、通用类型和未检查的转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32857360/

相关文章:

Java 小程序没有按应有的方式重印

java - 如何按符号修剪/剪切java中的字符串?

reflection - 如果您可以通过反射来更改私有(private)属性,那么拥有私有(private)属性有什么用?

c# - 循环中的高效反射

java - 遍历 Java 中的枚举类数组,测试每个类的 `parse()` 方法

java - WSO2 和 Java 客户端定期请求

java - 如何自定义泛型?

java - 创建变量中定义的类的 ArrayList

c# - 通用的多个接口(interface)

java - Boolean.FALSE 不等于 false