java - 泛型:如何让编译器控制我放入构造函数中的类型

标签 java generics

这个例子取自Thinking in Java。

public class Automobile {
}

public class Holder<T> {
    private T a;
    public Holder(T a){
        this.a = a;
    }
    public void set(T a){
        this.a = a;
    }

    public T get(){
        return a;
    }

    public static void main(String[] args){
        Holder<Automobile> h = new Holder<Automobile>(new Automobile());
        Automobile a = (Automobile)h.get();
    }
}

然后是解释:您必须使用与 main() 中看到的相同的尖括号语法来指定要放入其中的类型。

呃,我什么都听不懂。我理解,如果违反此规则,则必须将其视为可能的编译时错误。

但这有效:

    Holder<Automobile> h = new Holder(new Automobile());
    Automobile a = h.get();

这有效:

Holder h = new Holder(new Automobile());
Automobile a = (Automobile)h.get();

因此,正如我所看到的,编译器不会控制我放入 Holder 对象中的内容。好吧,那么我根本就不懂泛型。我有两个问题:

  1. 使用它们的原因是什么?只是为了在将对象转换回汽车时节省一些精力?

  2. 有没有办法让编译器控制我,让我真的把 Automobile 放入 Holder 中?

最佳答案

这里的转换是不必要的:

    Holder<Automobile> h = new Holder<Automobile>(new Automobile());
    Automobile a = (Automobile)h.get();

但这里有必要:

Holder h = new Holder(new Automobile());
Automobile a = (Automobile)h.get();

这是自 java 1.5 及更高版本以来最好的做事方式:

Holder<Automobile> h = new Holder<Automobile>(new Automobile()); //specify the generic parameter on both static and dynamic type
Automobile a = h.get(); //no casting is necessary

或者为简单起见,java 1.7 以上:

Holder<Automobile> h = new Holder<>(new Automobile()); //diamond operator so you don't need to respecify the same thing
Automobile a = h.get();



以这种方式使用泛型很有用的原因是您不能执行以下操作:

Integer a = new Integer(6);
List list = new ArrayList();
list.add(a);
list.add("5");
for(int i = 0; i < list.size(); i++)
{
    Integer integer = (Integer)list.get(i); //crashes at "5" which is String at runtime
    System.out.println(integer);
}

正如你所看到的,如果你可以无限制地将 Object 的任何子类放入列表中,那么你需要显式转换,如果你将任何不是你期望的东西放入列表中,那么它就会崩溃。请注意,如果没有泛型,您也不会被告知您应该将什么类型放入列表中,这意味着您需要跟踪列表应该包含的内容,当您尝试这样做时,这真的很糟糕逻辑如下:Java generics and casting to a primitive type

我什至不确定如果没有泛型,这是否可能: Is it possible to cast Map<Field, Value> to Map<Mirror, Mirror> when it is known that Field and Value extend Mirror?

因此,从技术上讲,泛型可以实现额外的功能,同时也鼓励类型安全,从而实现无错误的代码,这总是好的。

Integer a = new Integer(6);
List<Integer> list = new ArrayList<Integer>();
list.add(a);
list.add("5"); //this will not compile -> you won't need to wait until runtime to see that things are incorrect!

关于java - 泛型:如何让编译器控制我放入构造函数中的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24660622/

相关文章:

java - 当滚动 Pane 包裹文本 Pane 时,如何防止 JScrollPane 箭头键处理移动插入符

java - 无法初始化代理 - 无 session 异常

c# - 可观察对象/动态接口(interface)?

swift - 在 Swift 中执行 map 时跳过项目?

java - map <字符串,? super Number> 用于添加和 Map<String, ?用于打印的扩展 Number> 会产生错误

java - 无法在 eclipse galileo 中安装 egit 插件

java - Spring 批处理中的重写 Bean 问题

java - 为什么使用另一个按钮后文件没有被删除

c# - 通用链表

java - 在java中创建一个通用数组