是列表<;狗>;List的一个子类<;动物>;?为什么Java泛型不是隐式多态的?
我对Java泛型如何处理继承/多态性有点困惑 假设以下层次结构- 动物(父母) 狗-猫(儿童) 因此,假设我有一个方法是列表<;狗>;List的一个子类<;动物>;?为什么Java泛型不是隐式多态的?,java,generics,inheritance,polymorphism,Java,Generics,Inheritance,Polymorphism,我对Java泛型如何处理继承/多态性有点困惑 假设以下层次结构- 动物(父母) 狗-猫(儿童) 因此,假设我有一个方法doSomething(列出动物)。根据继承和多态性的所有规则,我假设列表是列表,列表是列表,因此任何一个都可以传递给这个方法。不是这样。如果我想实现这种行为,我必须通过说doSomething来明确告诉方法接受动物任何子类的列表(列表< P>不,一个代码>清单不是列表>代码>考虑你可以用列表>代码>你可以添加任何动物……包括一只猫。现在,你能在逻辑上向一窝小狗添加一只猫吗?绝对
doSomething(列出动物)
。根据继承和多态性的所有规则,我假设列表
是列表
,列表
是列表
,因此任何一个都可以传递给这个方法。不是这样。如果我想实现这种行为,我必须通过说doSomething来明确告诉方法接受动物任何子类的列表(列表< P>不,一个代码>清单<代码>不是<代码>列表>代码>考虑你可以用<代码>列表>代码>你可以添加任何动物……包括一只猫。现在,你能在逻辑上向一窝小狗添加一只猫吗?绝对不会。
// Illegal code - because otherwise life would be Bad
List<Dog> dogs = new ArrayList<Dog>(); // ArrayList implements List
List<Animal> animals = dogs; // Awooga awooga
animals.add(new Cat());
Dog dog = dogs.get(0); // This should be safe, right?
//非法代码-否则生活会很糟糕
List dogs=new ArrayList();//ArrayList实现列表
列出动物=狗;//Awooga Awooga
添加(新的Cat());
Dog Dog=dogs.get(0);//这应该是安全的,对吗?
突然你有一只非常困惑的猫
现在,你不能将<代码> CAT/CUT>添加到<代码>列表> P>不,<代码>列表>代码>不是<代码>列表>代码>考虑你可以用<代码>列表>代码>你可以添加任何动物……包括一只猫。现在,你能在逻辑上向一窝小狗添加一只猫吗?绝对不会。< / P>
// Illegal code - because otherwise life would be Bad
List<Dog> dogs = new ArrayList<Dog>(); // ArrayList implements List
List<Animal> animals = dogs; // Awooga awooga
animals.add(new Cat());
Dog dog = dogs.get(0); // This should be safe, right?
//非法代码-否则生活会很糟糕
List dogs=new ArrayList();//ArrayList实现列表
列出动物=狗;//Awooga Awooga
添加(新的Cat());
Dog Dog=dogs.get(0);//这应该是安全的,对吗?
突然你有一只非常困惑的猫
现在,您不能将Cat
添加到列表中,您要查找的是所谓的参数。这意味着,如果一种类型的对象可以在方法中替换为另一种类型的对象(例如,Animal
可以替换为Dog
),则使用这些对象的表达式也是如此(因此,List
可以替换为List
)。问题是,通常情况下,协方差对于可变列表是不安全的。假设您有一个列表
,并且它被用作列表
。当您尝试将一个Cat添加到该列表
(实际上是一个列表
)时会发生什么?自动允许类型参数协方差会破坏类型系统
添加语法以允许将类型参数指定为协变,这将有助于避免方法声明中的?extends Foo
,但这确实增加了额外的复杂性。您要查找的是参数。这意味着如果一种类型的对象可以在方法中替换为另一种类型的对象(例如,Animal
可以替换为Dog
),这同样适用于使用这些对象的表达式(因此List
可以替换为List
)。问题是,通常情况下,协方差对于可变列表是不安全的。假设您有一个列表
,并且它被用作列表
。当您尝试将一个Cat添加到该列表
(实际上是一个列表
)时会发生什么?自动允许类型参数协方差会破坏类型系统
添加语法以允许将类型参数指定为协变,这将有助于避免方法声明中的?extends Foo
,但这确实增加了额外的复杂性。原因是列表不是列表,并且对于为什么有些东西是或不是polymor有一个非常好的、深入的解释PH/IC或允许使用泛型。<代码>列表不是一个<代码>列表,它有一个非常好的、深入的解释,说明为什么有些事物不是多态的或允许泛型的。协方差类型:
Object[] objects = new String[10];
objects[0] = Boolean.FALSE;
这段代码可以很好地编译,但会引发运行时错误(java.lang.ArrayStoreException:java.lang.Boolean
,在第二行)。它不是类型安全的。泛型的要点是添加编译时类型安全性,否则您可以只使用没有泛型的普通类
现在有些时候,您需要更加灵活,这就是?超级类
和?扩展类
的用途。前者是您需要插入类型集合
(例如)当你需要从一个类型安全的方式读取它的时候,但是同时做这两种方法的唯一方法是有一个特定的类型。 我想说泛型的全部要点是它不允许。考虑数组的情况,允许协方差类型:
Object[] objects = new String[10];
objects[0] = Boolean.FALSE;
这段代码可以很好地编译,但会引发运行时错误(java.lang.ArrayStoreException:java.lang.Boolean
,在第二行)。它不是类型安全的。泛型的要点是添加编译时类型安全性,否则您可以只使用没有泛型的普通类
现在有些时候,您需要更加灵活,这就是?超级类
和?扩展类
的用途。前者是您需要插入类型集合
(例如),后者是在您需要以类型安全的方式从中读取时使用的。但同时执行这两项操作的唯一方法是使用特定的类型。这种行为的基本逻辑是泛型
遵循类型擦除机制。因此,在运行时,您无法识别集合
的类型de>数组
中没有这样的擦除过程。所以回到您的问题
非常好
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class DownCastCollection<E> extends AbstractCollection<E> implements Collection<E> {
private Collection<? extends E> delegate;
public DownCastCollection(Collection<? extends E> delegate) {
super();
this.delegate = delegate;
}
@Override
public int size() {
return delegate ==null ? 0 : delegate.size();
}
@Override
public boolean isEmpty() {
return delegate==null || delegate.isEmpty();
}
@Override
public boolean contains(Object o) {
if(isEmpty()) return false;
return delegate.contains(o);
}
private class MyIterator implements Iterator<E>{
Iterator<? extends E> delegateIterator;
protected MyIterator() {
super();
this.delegateIterator = delegate == null ? null :delegate.iterator();
}
@Override
public boolean hasNext() {
return delegateIterator != null && delegateIterator.hasNext();
}
@Override
public E next() {
if(!hasNext()) throw new NoSuchElementException("The iterator is empty");
return delegateIterator.next();
}
@Override
public void remove() {
delegateIterator.remove();
}
}
@Override
public Iterator<E> iterator() {
return new MyIterator();
}
@Override
public boolean add(E e) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
if(delegate == null) return false;
return delegate.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
if(delegate==null) return false;
return delegate.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends E> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection<?> c) {
if(delegate == null) return false;
return delegate.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
if(delegate == null) return false;
return delegate.retainAll(c);
}
@Override
public void clear() {
if(delegate == null) return;
delegate.clear();
}
public void passOn(Consumer<Animal> consumer, Supplier<Animal> supplier) {
consumer.accept(supplier.get());
}
public <A extends Animal> void passOn(Consumer<A> consumer, Supplier<? extends A> supplier) {
consumer.accept(supplier.get());
}
public <A extends Animal> void passOn(Consumer<? super A> consumer, Supplier<A> supplier) {
consumer.accept(supplier.get());
}
public <A extends Animal> void passOn(Consumer<? super A> consumer, Supplier<? extends A> supplier) {
consumer.accept(supplier.get());
}
public interface Animal {
String getName();
String getVoice();
}
public class Dog implements Animal{
@Override
String getName(){return "Dog";}
@Override
String getVoice(){return "woof!";}
List <Animal> animalGroup = new ArrayList<Animal>();
animalGroup.add(new Dog());
(List<Animal>) (List<?>) dogs
public abstract class Shape {
public abstract void draw(Canvas c);
}
public class Circle extends Shape {
private int x, y, radius;
public void draw(Canvas c) {
...
}
}
public class Rectangle extends Shape {
private int x, y, width, height;
public void draw(Canvas c) {
...
}
}
// drawAll method call
drawAll(circleList);
public void drawAll(List<Shape> shapes) {
shapes.add(new Rectangle());
}
// All compiles but throws ArrayStoreException at runtime at last line
Dog[] dogs = new Dog[10];
Animal[] animals = dogs; // compiles
animals[0] = new Cat(); // throws ArrayStoreException at runtime
List<Dog> dogs = new ArrayList<>();
List<Animal> animals = dogs; // compile-time error, otherwise heap pollution
animals.add(new Cat());
<T extends Animal> void doSomething<List<T> animals) {
}
List<Dog> dogs = new ArrayList<Dog>(1);
List<Animal> animals = dogs;
animals.add(new Cat()); // compile-time error
Dog dog = dogs.get(0);
Dog[] dogs = new Dog[1];
Object[] animals = dogs;
animals[0] = new Cat(); // run-time error
Dog dog = dogs[0];
import java.util.ArrayList;
import java.util.List;
public class Demonstration {
public void normal() {
List normal = new ArrayList(1);
normal.add("lorem ipsum");
}
public void parameterized() {
List<String> parameterized = new ArrayList<>(1);
parameterized.add("lorem ipsum");
}
}
Compiled from "Demonstration.java"
public class Demonstration {
public Demonstration();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void normal();
Code:
0: new #2 // class java/util/ArrayList
3: dup
4: iconst_1
5: invokespecial #3 // Method java/util/ArrayList."<init>":(I)V
8: astore_1
9: aload_1
10: ldc #4 // String lorem ipsum
12: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
17: pop
18: return
public void parameterized();
Code:
0: new #2 // class java/util/ArrayList
3: dup
4: iconst_1
5: invokespecial #3 // Method java/util/ArrayList."<init>":(I)V
8: astore_1
9: aload_1
10: ldc #4 // String lorem ipsum
12: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
17: pop
18: return
}
List<Dog> dogs = new ArrayList<Dog>();
List<Animal> animals = new ArrayList<Animal>(dogs);
animals.add(new Cat());
// Illegal code - because otherwise life would be Bad
List<Dog> dogs = new ArrayList<Dog>(); // ArrayList implements List
List<Animal> animals = dogs; // Awooga awooga
animals.add(new Cat());
Dog dog = dogs.get(0); // This should be safe, right?
// This code is fine
List<Dog> dogs = new ArrayList<Dog>();
dogs.add(new Dog());
List<Animal> animals = new ArrayList<>(dogs); // Copy list
animals.add(new Cat());
Dog dog = dogs.get(0); // This is fine now, because it does not return the Cat
// These are both illegal
dogs = animals;
cats = animals;
abstract class Animal {
void eat() {
System.out.println("animal eating");
}
}
class Dog extends Animal {
void bark() { }
}
class Cat extends Animal {
void meow() { }
}
class TestAnimals {
public static void main(String[] args) {
Animal[] animals = {new Dog(), new Cat(), new Dog()};
Dog[] dogs = {new Dog(), new Dog(), new Dog()};
takeAnimals(animals);
takeAnimals(dogs);
}
public void takeAnimals(Animal[] animals) {
for(Animal a : animals) {
System.out.println(a.eat());
}
}
}
animal eating
animal eating
animal eating
animal eating
animal eating
animal eating
class TestAnimals {
public static void main(String[] args) {
ArrayList<Animal> animals = new ArrayList<Animal>();
animals.add(new Dog());
animals.add(new Cat());
animals.add(new Dog());
takeAnimals(animals);
}
public void takeAnimals(ArrayList<Animal> animals) {
for(Animal a : animals) {
System.out.println(a.eat());
}
}
}
animal eating
animal eating
animal eating
animal eating
animal eating
animal eating
class TestAnimals {
public static void main(String[] args) {
ArrayList<Animal> animals = new ArrayList<Animal>();
animals.add(new Dog());
animals.add(new Cat());
animals.add(new Dog());
ArrayList<Dog> dogs = new ArrayList<Dog>();
takeAnimals(animals);
takeAnimals(dogs);
}
public void takeAnimals(ArrayList<Animal> animals) {
for(Animal a : animals) {
System.out.println(a.eat());
}
}
}
animals.add(new Cat());