2014-10-07 11 views
1

在研究Effective Java 2nd Edition的项目23时,我决定尝试使用具有带混合对象参数列表的原始集合的构造函数实例化对象。我认为编译器会拿起我试图将一个原始类型传递给构造函数。但是,编译器只会提供一个未经检查的异常警告,“在调用者而不是被调用者。”如何在对象实例化之前确保参数化类型的有效性

该类编译得很好,进一步支持Josh Bloch声明不要在新代码中使用原始类型。这个编译的事实对我来说有点令人不安。

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

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{} 

} 
+1

不要忽视警告以避免这种情况。 – Braj 2014-10-07 06:46:38

+0

警告不在“被调用者”(构造函数)处,因为它没有任何问题。问题在于调用者,在那里你使用原始类型,你应该使用适当的泛型类型。对于警告也是在被调用方,它不得不说“这个构造函数/方法在其他地方没有被正确地使用”,并且不会引起注意。 – kajacx 2014-10-07 21:26:50

+0

我明确指出,“主叫”主要考虑你正在建立一个API,并且有人发送一个原始类型......你如何在没有手动验证的情况下防御性地对它进行编程。就是那个问题。 – 2014-10-07 21:30:38

回答

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 

更好地使用通用集合来避免这种情况,然后在其中添加值。 从不 mix 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); 
    } 
} 
+0

我试图理解的是,我如何确保'调用者'不会在参数中发送外部类型?没有验证实施,强制遵守似乎是不可能的。 – 2014-10-07 07:05:54

+0

你为什么使用RAW类型?你能避免吗? – Braj 2014-10-07 07:07:35

+0

泛型只适用于编译时检查。所有通用类型信息在运行时都会丢失。 – Braj 2014-10-07 07:13:28

0

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

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

相关问题