首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java -通过构造函数将泛型列表传递到类中

Java -通过构造函数将泛型列表传递到类中
EN

Stack Overflow用户
提问于 2014-12-24 04:13:32
回答 6查看 6.5K关注 0票数 4

我一直在玩泛型和多态。我遇到了一个问题,我想不起来了。

说我有

代码语言:javascript
复制
public abstract class Animal {
    private age;
    private weight;

    public Animal(){}

    public void Move(){
        //stuff
    }

    public void Eat(){
        //stuff
    }

    //Getters and setters
}

然后

代码语言:javascript
复制
public Cat extends Animal {
    //Constructors
}

public Snake extends Animal {
    //Constructors
    public void ShedSkin(){
        //stuff
    }
}

我也有自己的课"MyAbstractClass“。就在这里,我似乎解决不了问题。

代码语言:javascript
复制
public abstract class MyAbstractClass {
    private List<Animal> myAnimalList;

    public MyAbstractClass(){}

    public MyAbstractClass(List<? extends Animal> animalList) {
        this.myAnimalList = animalList;
    }

    public List<Animal> getAnimalList() {
        return myAnimalList;
    }

    //Stuff which DOES NOT add to the list
}

我想做的是:

代码语言:javascript
复制
public class MyCatClass extends MyAbstractClass {
    public MyCatClass(List<Cat> catList) {
        super(catList);
    }
}

public class MySnakeClass extends MyAbstractClass {
    public MySnakeClass(List<Snake> snakeList) {
        super(snakeList);
    }

    public ShedSkin(){
        (Snake)getAnimalList().get(0).ShedSkin(); //Dont worry about indexing
    }
}

然后

代码语言:javascript
复制
public static void main(string[] args) {
    //Make list of cats
    //Make list of snakes

    MyCatClass cats = new MyCatClass(catList);
    MySnakeClass snakes = new MySnakeClass(snakeList);

    snakes.ShedSkin();
}

这对我不起作用。它无法在public MyAbstractClass(List<? extends Animal> animalList)上编译。这有点超出了我的java经验,非常希望得到一些指导。我希望示例类足够清楚,以理解我的意图。

编译器告诉我:java.util.List<Animal> in MyAbstractClass cannot be applied to java.util.List<capture<? extends Animal>>谢谢。

编辑:看来我得把我想要做的事情说出来。我有一个动物列表,这些动物可能比超类有更多的字段和方法,也可能没有,但它们都扩展了超类。我还想要一个类,它接受一个单一类型动物的列表,并对列表中的每个元素调用方法。我不会在列表中添加任何内容,这样就不会有问题了。我之所以这样分手,是因为动物之间有很多相似之处,但有些动物有自己的特点。接受列表的班级需要能够处理这些特殊性。因此,让worker类扩展一个超类并实现额外的方法。

EDIT2:算出来了!

代码语言:javascript
复制
public abstract class MyAbstractClass {
        private List<? extends Animal> myAnimalList;

        public MyAbstractClass(){}

        public MyAbstractClass(List<? extends Animal> animalList) {
            this.myAnimalList = animalList;
        }

        public List<Animal> getAnimalList() {
            return myAnimalList;
        }

        //Stuff which DOES NOT add to the list
    }

字段和构造函数都需要是List<? extends Animal> foobar。有建设性的头脑风暴会议!

EDIT3:迪马的方法更好。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2014-12-24 04:55:20

您不能将List<? extends Animal>分配给List<Animal>,因为列表不是协变量的:前者不是后者的子类。

您需要将基类成员的声明(以及getAnimalList()的返回类型)更改为List<? extends Animal>。您在其中一个注释中提到,这样做会在MyCatClass中给出某种其他错误,但您肯定弄错了,如果基类中的所有内容都声明正确(不是List<Animal>,而是List<? extends Animal>),那么该类应该是可以的。

这句话:(Snake)getAnimalList().get(0).ShedSkin()可能是给你带来麻烦的那个人。首先,您需要在蛇周围加上一对括号:((Snake) getAnimalList().get(0)).ShedSkin(),其次,您不能将List<Animal>转换为List<Snake>,请确保声明了getAnimalList()以返回List<? extends Animal>,然后所有内容都应该编译。

我认为,在您的情况下,另一个更好的选择是将基类参数化:

代码语言:javascript
复制
public abstract class MyAbstractClass<T extends Animal> {
    private List<T> myAnimalList;
    public MyAbstractClass(List<T> animals) { myAnimalList = animals; }
    public List<T> getAnimalList() { return myAnimalList; }
    //etc.
}

public class MyCatClass extends MyAbstractClass<Cat> {
     public MyCatClass(List<Cat> cats) { super(cats); }
}
public class MySnakeClass extends MyAbstractClass<Snake> {
     public MySnakeClass(List<Snake> snakes) { super(snakes); }
     public ShedSkin() { getAnimalList().get(0).ShedSkin(); }
}

这样你就不需要在任何地方进行铸造了,因为列表的类型总是很清楚的。

票数 6
EN

Stack Overflow用户

发布于 2014-12-24 05:16:42

您必须改变这一点:私有List<Animal> myAnimalList to private List<? extedns Animal> myAnimalList

代码语言:javascript
复制
public List<Animal> getAnimalList() {
        return myAnimalList;
    } to
 public List<?extends Animal> getAnimalList() {
            return myAnimalList;
        }

主要原因是猫扩展了动物,而List<Cat>没有扩展List<Animal>。java泛型不允许List<Cat>List<Animal>。示例:您不能这样做:List<Animal> animalList= new ArrayList<Cat>(); java不允许这样做。因为否则蛇可以添加animalList,其中含糊不清。但是您可以像这样进行转换:List<? extends Animal> animalList= new ArrayList<Cat>();,在这个转换中,您只能调用动物类的函数。因此,您可以在animalList中添加任何类型的动物。

票数 1
EN

Stack Overflow用户

发布于 2014-12-24 05:34:51

实际上,MyAbstractClass构造函数正文中只有一行代码需要更改。基本上,您有两个选项:转换传入的列表或制作列表的(防御)副本。

如果您只保留对传入列表的引用,那么在代码之外对该列表所做的所有更改都将反映在MyAbstractClass中。这可能是你想要的,也可能不是你想要的。相反,对MyAbstractClass中的列表所做的任何更改也会影响代码的调用方。这通常是相当出乎意料的。如果要添加到列表中,转换传入列表的解决方案是危险的,因为您不知道传递给构造函数的列表元素的实际类型(调用方可能已经将列表强制转换到List<Cat>,即使它实际上是一个List<BigCat>) --这不是类型安全操作,但不是禁止的。构造函数中的类型转换也不安全,因此应该避免。不过,下面是具有强制转换的构造函数:

代码语言:javascript
复制
public MyAbstractClass(List<? extends Animal> animalList) {
    this.myAnimalList = (List)animalList;
}

如果MyAbstractClass想要控制Animal的列表,则需要制作列表的副本。请注意,复制列表并不会自动克隆列表的元素,因此对动物的更改仍然会出现在MyAbstractClass中。这里有两种复制列表的方法,顺便说一句,它也解决了编译问题(因为CatSnake的每个列表也都是Animal的列表,创建List<Animal类型的副本是可以的--副本只保证其所有元素都是Animal类型的,仅此而已):

代码语言:javascript
复制
public MyAbstractClass(Collection<? extends Animal> animalList) {
    this.myAnimalList = new ArrayList<>(animalList);
}

您还应该更改动物列表的访问器,除非每个调用方都可以修改动物列表:

代码语言:javascript
复制
public List<Animal> getAnimalList() 
    return Collections.unmodifiableList(myAnimalList);
}

如果动物列表从未改变,那么还有一种替代解决方案,使用谷歌番石榴库中的ImmutableList

代码语言:javascript
复制
public abstract class MyAbstractClass {
   private List<Animal> myAnimalList;

    public MyAbstractClass(){
        this(ImmutableList.of());
    }

    public MyAbstractClass(Collection<? extends Animal> animalList) {
        this.myAnimalList = ImmutableList.copyOf(animalList);
    }

    public List<Animal> getAnimalList() {
        return myAnimalList;
    }

    //Stuff which DOES NOT add to the list
}

使此解决方案更好的是:(a)列表确实是不可变的(与简单包装可变列表的Collections.unmodifiableList相比)和(b) ImmutableList.copyOf()足够聪明,可以知道当它接收到的列表是ImmutableList时,它不需要被复制。由于(a),getAnimalList()可以简单地返回列表。

顺便说一句:方法名称的Java约定是以小写开始,例如shedSkin(),而不是ShedSkin(),后者是C#约定。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27631374

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档