我偶然发现了一段代码,让我想知道为什么它成功编译:
public class Main {
public static void main(String[] args) {
String s = newList(); // why does this line compile?
System.out.println(s);
}
private static <T extends List<Integer>> T newList() {
return (T) new ArrayList<Integer>();
}
}
Run Code Online (Sandbox Code Playgroud)
有趣的是,如果我修改方法的签名newList
与<T extends ArrayList<Integer>>
它不工作了.
注释和响应后更新: 如果我将泛型类型从方法移动到类,则代码不再编译:
public class SomeClass<T extends List<Integer>> {
public void main(String[] args) {
String s = newList(); // this doesn't compile anymore
System.out.println(s);
}
private T newList() {
return (T) new ArrayList<Integer>();
}
}
Run Code Online (Sandbox Code Playgroud) 假设我们有2节课.一个空类Base
,以及该类的子类Derived
.
public class Base {}
public class Derived extends Base {}
Run Code Online (Sandbox Code Playgroud)
然后我们在另一个类中有几个方法:
import java.util.Collection
public class Consumer {
public void test() {
set(new Derived(), new Consumer().get());
}
public <T extends Base> T get() {
return (T) new Derived();
}
public void set(Base i, Derived b) {
System.out.println("base");
}
public void set(Derived d, Collection<? extends Consumer> o) {
System.out.println("object");
}
}
Run Code Online (Sandbox Code Playgroud)
这在Java 7中成功编译并运行,但不能在Java 8中编译.错误:
Error:(8, 9) java: reference to set is ambiguous
both method set(Base,Derived) in Consumer …
Run Code Online (Sandbox Code Playgroud) 有人可以向我解释以下行为吗?
我有一个列表X
并使用该addAll()
方法添加元素.这些元素由使用泛型类型的方法返回.方法getA()
返回< T extends A >
与A
作为一类.方法getI()
返回< T extends I >
与I
作为一个接口(见下面的代码).
差异:listX.addAll(getA())
我得到编译错误(如预期的那样),但是listX.addAll(getI())
编译(当元素被强制转换时抛出运行时错误X
).
简化代码:
interface I {}
class A implements I {}
class X {}
public void test() {
List<X> listX = new ArrayList<>();
listX.addAll(getA());
listX.addAll(getI());
for (X x : listX) {}
}
public <T extends A> List<T> getA() {
return new ArrayList<>();
}
public <T extends I> List<T> getI() …
Run Code Online (Sandbox Code Playgroud) 为什么下面的代码片段会编译?OtherInterface
没有扩展,Concrete
所以我打赌肾脏,这将无法编译.但确实如此.
public class Test {
public static interface SomeInterface {}
public static interface OtherInterface{}
public static class Concrete implements SomeInterface {
public <T extends Concrete> T getConcrete() {
return null;
}
}
public static void doStuff() {
Concrete c = new Concrete();
OtherInterface iCompile = c.getConcrete();
}
}
Run Code Online (Sandbox Code Playgroud)
另一方面,下一个片段不能编译,这是我所期望的.
public class Test {
public static interface SomeInterface {}
public static class UnrelatedClass{}
public static class Concrete implements SomeInterface {
public <T extends Concrete> T getConcrete() { …
Run Code Online (Sandbox Code Playgroud) 我知道之前已经发布了类似的类型推断问题(Java编译器选择了错误的重载或为什么Java 8泛型类型推断选择了这个重载?)但我认为我们在这里选择了一个更有趣的案例.
public class TemplateMethod {
public static void main(String[] args) {
System.out.println(System.getProperty("java.version"));
method("a", "b");
method("a", 5);
method("a", new B().get());
}
public static void method(String s, String cause) {
System.out.println("String");
}
public static void method(String s, Object parameters) {
System.out.println("Object");
}
public static interface Base {
String methodToImplement();
}
public static class Impl implements Base {
public String methodToImplement() {
return "Impl.methodToImplement";
}
}
public static class B {
public <T extends Base> T get() { …
Run Code Online (Sandbox Code Playgroud) 我正在尝试将Java 7代码迁移到Java 8,所以我的代码类似于:
package tests;
import java.util.Arrays;
import java.util.Map;
public class Tests {
private static interface ComparableMap<K,V> extends Map<K,V>, Comparable {}
public static void main(String[] args) {
func(getString());
}
private static void func(Comparable...input){
System.out.println(Arrays.toString(input));
}
private static void func(ComparableMap <?,?> m){
System.out.println(m);
}
private static <T extends Comparable> T getString(){
return (T) "aaa";
}
}
Run Code Online (Sandbox Code Playgroud)
在java 7中它正常工作,在Java 8中我得到:
java.lang.ClassCastException:java.lang.String无法强制转换为tests.Tests $ ComparableMap
如果我将一个函数定义更改为:
private static <T> T getString(){
return (T) "aaa";
}
Run Code Online (Sandbox Code Playgroud)
编译将失败:错误:
对func的引用含糊不清
为什么Java 8编译器在第一种情况下没有失败?(看起来对我来说是错误的)是否可以更改第二个重载函数,以便在不更改调用本身的情况下使用varargs参数调用第一个函数?
以下代码工作正常,而不应该compile
.
我不知道为什么一个分配List
给String
被允许的.
它只发生在List
接口上.Array List
按预期更改为工作正常,不再编译.
public class Test {
public static <T extends List<Number>> T newList() {
return null;
}
public static void main(String[] args) {
String s = newList();
}
}
Run Code Online (Sandbox Code Playgroud)
请帮我理解这个行为.
有这样的方法吗?
public <P, T extends List<P>> T getAwesomeList() {
// ...
}
Run Code Online (Sandbox Code Playgroud)
怎么编译没有任何警告?
Set<String> test = getAwesomeList();
Run Code Online (Sandbox Code Playgroud)
我认为这与通用擦除有关,但不确定编译器是怎么回事.这种情况发生在Java 7上,8时你会收到编译错误.
J8上有什么变化让这个不能编译?
更新:
经过仔细检查后,它还可以在Java 8上编译.
我最近被以下 Java 代码惊呆了:
interface Common {}
interface A extends Common {}
static class B implements Common {}
static class Impl {
private A a;
public <T extends A> T translate() {
return (T) a;
}
}
static class Usage {
public void use() {
Impl impl = new Impl();
B b = impl.translate(); // Why does this compile?
}
}
Run Code Online (Sandbox Code Playgroud)
我本来期望的是在类型约束Impl.translate
不会允许将结果存储在类型B
由编译器所接受,考虑到B
不延长A
。代码UncheckedCastException
在运行时抛出一个,而不是编译器错误。
这仅在方法返回类型时发生T
;如果它是方法参数:
public <T extends A> …
Run Code Online (Sandbox Code Playgroud) 我有一些遗留代码Box
用于将Serializable
数据放入并获取数据Map
,Oracle JRE 1.8 Update 102
在编译时运行正常Oracle JDK 1.7 Update 80
.但是当我编译它时,它无法正常运行Oracle JDK 1.8 Updater 102
.我在泛型get
函数方面遇到了一些问题.
SSCCE Box
使用有问题的通用get
函数从实例输出格式化日期:
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
public class Box implements Serializable{
private HashMap<String, Serializable> values = new HashMap<String, Serializable>();
public <T extends Serializable> T get(String key){
return (T) this.values.get(key);
}
public void put(String key,
Serializable value){
this.values.put(key,
value);
}
public static void main(String[] args){
Box box = new …
Run Code Online (Sandbox Code Playgroud) 拥有一组抽象对象: Set<Foo> foes;
我想要一个像这样的方法:
List<? extends Foo> getFoesByType(TypeEnum type);
Run Code Online (Sandbox Code Playgroud)
我试过了:
List<? extends Foo> result = new ArrayList<>();
for(Foo f : foes) {
if(f.getType() == type) {
switch(type) {
case TYPE1:
f = (FooType1) f;
break;
case TYPE2:
/*...*/
}
result.add(f);
/*The method add(capture#1-of ?) in the type
List<capture#1-of ?> is not applicable for the arguments (Foo)*/
}
}
return result;
Run Code Online (Sandbox Code Playgroud)
但是我收到了一个错误.
我希望能够做到这一点:List<FooType1> foesType1 = getFooesByType(TypeEnum.TYPE1);
哪种方法是正确的?