【问题标题】:How To Ensure the Validity of Parameterized Types Prior to Object Instantiation如何在对象实例化之前确保参数化类型的有效性
【发布时间】:2014-10-07 06:34:13
【问题描述】:

在研究 Effective Java 2nd Edition 的第 23 条时,我决定尝试使用构造函数来实例化对象,该构造函数具有原始集合和混合对象的参数列表。我假设编译器会发现我试图将原始类型传递给构造函数。但是,编译器仅提供未经检查的异常警告,“在调用者处,而不是被调用者处”。

该类编译良好,进一步支持 Josh Bloch 的声明,即不在新代码中使用原始类型。这个编译的事实让我有点不安。

问?如何在实例化对象之前确保类的类型安全,而不必在构造函数中手动检查对象的有效性?以下仅提供了来自“调用者... in main”的未经检查的分配警告,一个防御性的程序如何针对此进行编程。

public class RawType {

    private final Collection<Example> example;

    public RawType( Collection<Example> example ) {
        this.example = example;
    }

    public Collection<Example> getExample() {
        return example;
    }

    public static void main( String[] args ) {

        Collection unsafe = new ArrayList();

        unsafe.add( new Example() );
        unsafe.add( new Corruption() );
        unsafe.add( new Example() );

        RawType rawType = new RawType( unsafe ); // Corruption

        for(Object type : rawType.getExample()) {
            System.out.println(type.getClass().getName()); // Mixed Classes...
        }

    }

    static class Corruption {}

    static class Example{}

}

【问题讨论】:

  • 不要忽略警告以避免这种情况。
  • 警告不在“被调用者”(构造函数),因为它没有任何问题。问题出在调用者处,您使用的是原始类型,而您应该使用正确的泛型类型。为了使警告也出现在被调用方,它必须说“这个构造函数/方法在其他地方没有正确使用”,这没有任何意义。
  • 我明确指出,“调用者。在 main 中”考虑您正在构建一个 API 并且有人发送一个原始类型......如果没有手动验证,您如何防御性地对其进行编程。这就是问题所在。
  • 我不应该担心它。每个 Java 程序员都应该知道,使用原始类型需要自担风险,如果他们的程序因此而无法运行,那是他们的错,而不是你的错。另请注意,绝大多数类/API 也不能防止原始参数。
  • “许多 API 也不能防止原始参数”......从来没有想过......很有趣。

标签: java generics type-safety raw-types


【解决方案1】:

以下行编译但也会生成警告。

Collection unsafe = new ArrayList(); // RAW type
unsafe.add(1);                       // no compile time error (just warning)

Collection<String> example = unsafe; // assign RAW type to parametrized type
example.add(1);                      // compile time error

最好使用通用集合来避免这种情况,然后在其中添加值。 从不混合RAW 和参数化类型。


看看下面的代码:

Collection<Integer> unsafe = new ArrayList<Integer>();
unsafe.add(1);
Collection<String> example = unsafe; // compile time error

Read more...


如果无法避免 RAW 类型,请在构造函数中使用以下代码:

Collection unsafe = new ArrayList(); 
unsafe.add(1);                       
unsafe.add("hello");

// in the constructor, just add String values from the unsafe collection
Collection<String> example = new ArrayList<String>(); 
for(Object value:unsafe){
    if(value instanceof String){
        example.add((String)value);
    }
}

【讨论】:

  • 我想了解的是,如何确保“调用者”不会在参数中发送外来类型?如果没有验证实现,似乎不可能强制合规。
  • 你为什么使用RAW类型?你能避免吗?
  • 泛型仅适用于编译时检查。所有通用类型信息在运行时都会丢失。
  • 是的,这不是生产...这是对Item 23 Effective Java的评论不要使用原始类型...
【解决方案2】:

为了使 java 泛型与引入之前编写的代码兼容,您可以在需要类型化集合的任何地方使用无类型化集合。因此,可以将 Collection(没有类型参数)传递给期望 Collection 的构造函数。

因此,在回答您的集合时,只有在将对象添加到无类型集合时要小心,才能确保安全。如果您希望运行时安全,您可以在从集合中检索对象时手动验证对象的类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    • 1970-01-01
    • 2010-11-02
    • 2021-01-18
    • 2013-12-11
    • 1970-01-01
    相关资源
    最近更新 更多