自Java5+;菱形运算符
据我所知,泛型只在编译时有用 因此,可以声明:自Java5+;菱形运算符,java,generics,jakarta-ee,collections,scjp,Java,Generics,Jakarta Ee,Collections,Scjp,据我所知,泛型只在编译时有用 因此,可以声明: private Set set = new HashSet<String>(); private Set=new HashSet(); 然后,在这个字符串hashset中,向该集合添加dogs或任何内容,没有任何问题,因为在运行时没有任何类似于数组的检查(ArrayStoreException…)(但在使用该集合时,可能会遇到类似类转换的问题 所以我想说的是,我们通常以这种方式实例化泛型集合: Set<String> s
private Set set = new HashSet<String>();
private Set=new HashSet();
然后,在这个字符串hashset中,向该集合添加dogs或任何内容,没有任何问题,因为在运行时没有任何类似于数组的检查(ArrayStoreException…)(但在使用该集合时,可能会遇到类似类转换的问题
所以我想说的是,我们通常以这种方式实例化泛型集合:
Set<String> set = new HashSet<String>();
Set Set=newhashset();
我的问题是,既然变量引用的类型才是真正重要的(我认为),为什么我们要设置HashSet的类型呢
我的意思是,我们可以简单地写:
Set<String> set = new HashSet();
Set Set=newhashset();
它也会起同样的作用,对吗?
那么为什么我们通常在实例化过程中编写类型呢?(这不是强制性的)
编辑 我知道用于类型推断的“菱形运算符”,但为什么我们甚至需要它!!!因为类型推断已经开始工作了 以下代码:
Set<String> set = new HashSet();
set.add("Test add a string 1");
set.add("Test add a string 2");
for ( String s : set ) {
System.out.println(s);
}
Set Set=newhashset();
set.add(“测试添加字符串1”);
set.add(“测试添加字符串2”);
for(字符串s:set){
系统输出打印项次;
}
生成输出:
测试添加字符串1
测试添加字符串2
自己测试一下
所以现在您将类型推断作为Java7的一个特性来讨论,但它已经对我起作用了
有了java7,我将不得不替换我的
Set<String> set = new HashSet();
Set Set=newhashset();
借
Set Set=newhashset();
做完全相同的事情还需要另外两个字符否?(除非泛型不仅仅是Java7的编译时?我不知道)您最后的建议是类型推断,并已通过所谓的菱形运算符在Java7中引入:
Set<String> set = new HashSet<>();
Set Set=newhashset();
是的,这可能从一开始就存在,但这是Java,通常需要几十年的时间才能获得新的语言特性的批准(
它的工作原理完全相同,对吗?
运行时:是
编译时:否
您的代码将把一个包含任意对象的集合分配给一个变量,该变量存储一个包含字符串的集合,这是错误的,类型检查器将不支持该集合
当您编写newhashset()
时,您使用的是一个。我指的是这个问题,关于它的含义,以及为什么应该避免它:
一般来说,你可以这样争论:
Set<String> set = new HashSet();
Set Set=newhashset();
不远
HashSet tmp = new HashSet();
...
Set<String> set = tmp;
HashSet tmp = new HashSet();
tmp.add(7);
...
Set<String> set = tmp;
HashSet tmp=newhashset();
...
Set=tmp;
这也离我们不远了
HashSet tmp = new HashSet();
...
Set<String> set = tmp;
HashSet tmp = new HashSet();
tmp.add(7);
...
Set<String> set = tmp;
HashSet tmp=newhashset();
tmp.add(7);
...
Set=tmp;
它仍然可以编译,但有一千个原因是不好的:)
Java7允许您编写
Set<String> set = new HashSet<>();
Set Set=newhashset();
但是,它告诉编译器推断
之间的类型
关于“菱形运算符”的文档:
- (来自oracle.com)
- (来自oracle.com)
有关详细信息:实际上它不是必需的。 如果你打字
Set<String> s = new HashSet();
然后,如果我们尝试添加一个整数值,例如,我们会得到一个编译错误。尽管Java目前删除泛型类型信息,但他们非常小心地设计了语言和库,以便将来可以添加回完整的泛型类型信息(称为具体化)。任何正确编写的泛型代码(即,没有任何javac警告)将在这种语言更改中生存。在您的示例中,菱形版本是未来的证明;原始版本不是-当然它仍然必须编译,但它将在运行时抛出类型转换异常 然而,这种未来的兼容性完全是一种错觉。擦除将永远伴随着我们。如果引入完全物化,可以肯定地说,几乎所有非平凡的通用代码都将崩溃,因为每个人都在编写错误的通用代码 这不是我们的错。Java迫使我们这么做。它给了我们狗屁的擦除,我们别无选择,只能绕过它来实现一些东西。我们的代码完全依赖于擦除的细节知识 JDK是罪魁祸首。JDK API是精心设计的,以在具体化过程中幸存下来;但是实现依赖于擦除。如果Java添加了具体化,这些JDK代码必须重写。如果Java团队指责我们编写了错误的代码,而他们自己却必须做同样的事情,那么他们将极其虚伪 考虑到大量代码在不重写的情况下无法通过具体化,我们可以有把握地说Java永远不会添加具体化,只要它保持向后兼容性的承诺 在这种情况下,是的,不管怎样。
Set=new HashSet()
并没有什么可怕的。就我个人而言,我总是添加
,以避免警告。(实际上,只要可能,我都会尝试证明我的代码具体化,正如我所说的,这是一种妄想行为)
在您的示例中,推理是琐碎的。在更复杂的情况下,
推理不是那么琐碎,它的类型检查会很有帮助,而
class Foo<T>
{
Foo(Class<T> clazz){}
}
Foo<String> foo1 = new Foo(Integer.class); // compiles (wrongly)
Foo<String> foo2 = new Foo<>(Integer.class); // does not compile