请在这件事上给予我帮助:
如果Lion IS-A Animal给定Cage<T>:
Cage<? extends Animal> c = new Cage<Lion>(); // ok,
Run Code Online (Sandbox Code Playgroud)
但
Set<Cage<? extends Animal>> cc = new HashSet<Cage<Lion>>(); // not ok
Run Code Online (Sandbox Code Playgroud)
我在这里看不到什么?
谁能解释一下这个?
我有几个班:
abstract class Animal {
public void eat() {
System.out.println("Animal is eating");
}
}
class Dog extends Animal {
public void woof() {
System.out.println("woof");
}
}
class Cat extends Animal {
public void meow() {
System.out.println("meow");
}
}
Run Code Online (Sandbox Code Playgroud)
这就是行动:
import java.util.ArrayList;
import java.util.List;
public class TestClass {
public static void main(String[] args) {
new TestClass().go();
}
public void go() {
List<Dog> animals = new ArrayList<Dog>();
animals.add(new Dog());
animals.add(new Dog());
doAction(animals);
}
public <T extends Animal> void doAction(List<T> animals) { …Run Code Online (Sandbox Code Playgroud) 我正在关注定义这个静态方法的Java中的泛型教程:
public static <T extends Comparable<T>> T min(T a) { ... }
Run Code Online (Sandbox Code Playgroud)
并说
min(new GregorianCalendar());
Run Code Online (Sandbox Code Playgroud)
不能编译,因为GregorianCalendar extends Calendar并Calendar implements Comparable<Calendar>因此暗示GregorianCalendar implements Comparable<Calendar>和NOT Comparable<GregorianCalendar>.所以为了编译签名必须改成:
public static <T extends Comparable<? super T>> T min(T a) { ... }
Run Code Online (Sandbox Code Playgroud)
这完全可以理解.该方法的第一个版本有效地无法在java-5中编译,但它在java-8中编译!(我试过5到8)
为什么java-8现在允许?(因为它现在让它更加混乱).那背后的新"规则"是什么?
Java要求将有界类型参数实例化到其上界类以进行强制转换,例如:
<T extends Integer> void passVal (T t) {
Integer number = 5;
t = (T) number; // Without cast a compile error is issued
}
Run Code Online (Sandbox Code Playgroud)
T在声明时已经被限制Integer为其子类之一(我知道,没有子类),而且在我看来,任何有界类型参数都只能实例化为其上界类或其子类之一,因此为什么需要演员表?
另外,我知道如果不是通过此方法之外的调用实例化该参数,则不是这种情况,因此请不要提供它作为答案;该问题特定于在其声明的类/方法中实例化的有界类型参数。
我有这门课
public class Tree<T> {
//List of branches for this tree
private List<Tree<? super T>> branch = new ArrayList<Tree<? super T>>();
public Tree(T t){ this.t = t; }
public void addBranch(Tree< ? super T> src){ branch.add(src); }
public Tree<? extends T> getBranch(int branchNum){
return (Tree<? extends T>) branch.get(branchNum);
}
private T t;
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用此类创建一个变量
public static void main(String[] args){
Tree<? super Number> num2 = new Tree<? super Number>(2);
}
Run Code Online (Sandbox Code Playgroud)
它给了我这个错误
Cannot instantiate the type Tree<? super Number>
Run Code Online (Sandbox Code Playgroud) 为什么Java可以推断多个上限类型的共同祖先,而不是下限类型的共同祖先?
更具体地说,请考虑以下示例:
static class Test {
static <T> T pick(T one, T two) {
return two;
}
static void testUpperBound() {
List<? extends Integer> extendsInteger = new ArrayList<>();
// List<? extends Integer> is treated as a subclass of List<? extends Number>
List<? extends Number> extendsNumber = extendsInteger;
// List<? extends Number> is inferred as the common superclass
extendsNumber = pick(extendsInteger, extendsNumber);
}
static void testLowerBound() {
List<? super Number> superNumber = new ArrayList<>();
// List<? super Number> is treated as …Run Code Online (Sandbox Code Playgroud) 为什么以下代码无法编译?
interface Iface<T> { }
class Impl<T> implements Iface<T> { }
class TestCase {
static Class<? extends Iface<?>> clazz = Impl.class;
}
Run Code Online (Sandbox Code Playgroud)
错误是
java:不兼容的类型:
java.lang.Class<Impl>无法转换为java.lang.Class<? extends Iface<?>>
但我不明白为什么通配符不能捕获.
以下签名在Scala中有效且常用:
trait Collection[A] {
def reduceLeft [B >: A] (f: (B, A) => B): B
}
Run Code Online (Sandbox Code Playgroud)
但是,由于Java中>:的Scala是等效的super,我转换此签名的第一个想法(用函数类型替换BiFunction并使用Use-Site variance annotations aka Bounded Wildcards)将是
interface Collection<A> {
<B super A> B reduceLeft(BiFunction<? super B, ? super A, ? extends B> mapper)
}
Run Code Online (Sandbox Code Playgroud)
但是哦,不!编译器抱怨super令牌,<B super A>因为你不能有低边界的类型变量!现在,如何在Java代码中编写此方法而不必回顾Java世界中不存在泛型的时间?
是的,我知道你认为我可以使用B extends A,但这不是一回事,正如我的实现所示:
public <R extends E> R reduceLeft(BiFunction<? super R, ? super E, ? extends R> mapper)
{
if (this.isEmpty())
{
return …Run Code Online (Sandbox Code Playgroud) 考虑这种情况:
class A {}
class B<T extends A, E extends T> {
B<?, A> b;
B<?, ? extends A> b2;
}
Run Code Online (Sandbox Code Playgroud)
据我所知,类型界限,在这种情况下,两者的有效上限T和E是class A.所以问题是:为什么javac在字段声明中不接受A类作为参数b,但wildcard ? extends A在字段声明中接受b2?
Collections.fill方法具有以下标头:
public static <T> void fill(List<? super T> list, T obj)
Run Code Online (Sandbox Code Playgroud)
为什么需要通配符?下面的标题似乎也同样有效:
public static <T> void fill(List<T> list, T obj)
Run Code Online (Sandbox Code Playgroud)
我看不出为什么需要通配符;如下代码适用于第二个标头和第一个标头:
List<Number> nums = new ArrayList<>();
Integer i = 43;
fill(nums, i); //fill method written using second header
Run Code Online (Sandbox Code Playgroud)
我的问题是:第一个标头可以工作但第二个标头不能工作的具体调用是什么?fill如果没有这样的调用,为什么要包含通配符?在这种情况下,通配符不会使方法更简洁,也不会增加可读性(在我看来)。
bounded-wildcard ×10
java ×9
generics ×8
collections ×2
java-8 ×1
scala ×1
typechecking ×1
wildcard ×1