我今天看到这样的代码:
public class GenClass<T> { ... }
//in some other class
GenClass g = new GenClass<>();
<>
在这里完成任何事情吗?通常<>
会告诉编译器根据上下文确定通用参数,但在这种情况下,没有上下文。但显然它是合法的。这与以下之间有什么区别吗?
GenClass g = new GenClass();
答案 0 :(得分:3)
钻石正在做它一直做的事情 - 从上下文推断泛型类型,并保证构造函数调用不会影响类型安全。
考虑这个例子:
public class GenClass<T> {
GenClass(T t, List<T> list) {}
public static void main(String[] args) {
GenClass m = new GenClass<>(1, new ArrayList<String>()); // Doesn't compile
}
}
此示例无法编译,因为无法推断出适当的类型。如果删除菱形,它会编译,因为构造函数参数的类型是已擦除的版本(Object
和List
)。
在你的情况下,构造函数不带参数,所以没有什么可以检查。但是,使用钻石是一个很好的习惯,即使您选择将构造函数调用的结果分配给Object
或原始类型(不是您应该使用原始类型)。
答案 1 :(得分:-2)
我只是从this blog复制/粘贴它。它不是我的,只是发现它与答案相关。
ZdeněkTroníček的实际帖子
如您所知,即将推出的Java 7的新功能之一将是钻石运营商。菱形运算符的目的是简化泛型类的实例化。例如,而不是
List<Integer> p = new ArrayList<Integer>();
使用菱形运算符我们只能写
List<Integer> p = new ArrayList<>();
让编译器推断出type参数的值。很好的简化。但我们真的需要写<>
吗? new ArrayList()
不够吗?在本文中,我将描述<>
支持者的论点,并解释为什么我认为这些论点不是很强。但是,我还描述了为什么我们需要<>
。
在Java 1.4中,我们只有原始类型:
List p = new ArrayList();
Java 5引入了泛型:
List<Integer> p = new ArrayList<Integer>();
Java API中的许多类型都是通用的,即使我们仍然可以使用泛型类型作为原始类型,但在Java 5或更新版本中没有理由这样做。引入泛型时,允许原始类型向后兼容,以便我们可以逐步和顺利地采用泛型。例如,Java 1.4中的代码可以与新的通用代码组合,因为原始类型和泛型类型可以一起使用。这也在JLS(4.8原始类型)中表达:
“原始类型的使用仅允许作为对遗留代码兼容性的让步。强烈建议不要在将通用性引入Java编程语言后编写代码中使用原始类型。有可能未来版本的Java编程语言将禁止使用原始类型。“
现在让我们回到钻石运营商再次询问:“我们真的需要&lt;&gt;?”。 &lt;&gt;的支持者语法说我们需要&lt;&gt;保持向后兼容性。让我们看一下来自coin-dev会议的example:
class Foo<X> {
Foo(X x) { }
Foo<X> get(X x) { return this; }
}
class Test {
void test() {
Foo<?> f1 = new Foo(1).get(""); //ok - can pass String where Object is expected
Foo<?> f2 = new Foo<>(1).get(""); //fail - cannot pass String where Integer is expected
}
}
这显示了新Foo(1)和新Foo&lt;&gt;(1)之间的区别。显然,这两者是不同的,如果我们改变了新Foo(1)的语义,它将破坏向后兼容性。可是等等。向后兼容什么?不是行
Foo<?> f1 = new Foo(1).get("");
有点可疑吗?它在左侧部分使用泛型类型,在右侧部分使用原始类型。虽然这是合法的,但可能是遗漏或不当行为。它的合法性可能只是“对遗留代码兼容性做出让步”的副作用。
让我们进一步看看硬币开发会议中的另一个example。它显示了原始类型和参数化类型与钻石之间的区别:
public class X<T> {
public X(T t) { }
public T get() { return null; }
public static int f(String s) { return 1; }
public static int f(Object o) { return 2; }
public static void main(String[] args) {
System.out.println(f(new X<>("").get()));
System.out.println(f(new X("").get()));
}
}
让我们稍微玩一下代码吧。我们假设有一个带有X类的库:
public class X {
public X(Object o) { }
public Object get() { return null; }
}
以及针对此库编译的一些代码:
public class Client {
static int f(String s) { return 1; }
static int f(Object o) { return 2; }
public static void main(String[] args) {
System.out.println(f(new X("").get()));
}
}
然后,图书馆被广泛化了:
public class X<T> {
public X(T t) { }
public T get() { return null; }
}
我们针对通用版本编译了客户端项目。现在,如果我们使用菱形语法将new X("")
的语义更改为新X<String>("")
(或new X<>("")
),则代码的行为会有所不同。因此,标题问题的答案是'是'。如果我们希望保持向后兼容,我们需要<>
,我们不能将new X("")
在语义上等同于新X<>("")
。
其他问题是Java可以发展多长时间并保持与兼容性的让步兼容,以及Java的新手是否会欣赏这一点。