3

Okay so I'm working on this project for the university and I think I'm doing something wrong here, guess I haven't understood java subclassing and class inheritance enough.

I have rewrote my problem in this little form.

    class SuperClass {

        int dunno;

        public SuperClass(int dunno) {
            this.dunno = dunno;
        }
    }

    class SubClass extends SuperClass {

        int duncare;

        public SubClass(int dunno, int duncare) {
            super(dunno);
            this.duncare = duncare;
        }
    }

    class VeryBigClass {

        ArrayList<SuperClass> superList;

        public VeryBigClass(ArrayList<SuperClass> superList) {
            this.superList = superList;
        }
    }

    public void main(String[] args) {

        new VeryBigClass(new ArrayList<SubClass>()); // this is the problematic line

    }

}

In little words I wrote a lot of classes that extend one more general class, and in many places I have made operations with the superclass (the general one), instead of treating each of the subclasses one by one in the same way.

But I can not create the instance of the class I need, since the constructor takes as argument the superclass. I don't even know how to cast it since new VeryBigClass(new (ArrayList<SuperClass>)ArrayList<SubClass>()); is obviously wrong. Plus, the construction of these instances will be handled by a json library at some point so I'd rather not do such fancy stuff...

3 Answers3

7

If you use generics, it should work just fine, is not the same a list of Superclass than a list of Subclass, but the generic solve this:

class VeryBigClass<T extends SuperClass> {

    ArrayList<T> superList;

    public VeryBigClass(ArrayList<T> superList) {
        this.superList = superList;
    }
}
developer_hatch
  • 15,898
  • 3
  • 42
  • 75
5

The Java Tutorial explains this in http://docs.oracle.com/javase/tutorial/java/generics/inheritance.html

Bottom line, if you have types with an inheritance relationship, like Sub extends Super as generics, they do not confer an inheritance relationship in the classes that hold them: Foo<Sub> is not a subtype of Foo<Super>.

The reason is that it would violate the promise of what type the generic type contains, breaking the Liskov Substitution principle. If List<Sub> extended List<Super>, it would be legal to do this:

List<Sub> subs = new ArrayList<Sub>();
List<Super> supers = subs;

Super super = new Super();
supers.add(super);

Whoa! Now subs has an element of type Super, completely illegal!

Because ArrayList<Sub> is not a subtype of List<Super>, when you invoked

new VeryBigClass(new ArrayList<SubClass>());

you passed an argument to the constructor that was not legal.

Lew Bloch
  • 3,364
  • 1
  • 16
  • 10
3

You can also use the wildcard ? extends super That is, any class that extends super.

Example:

class VeryBigClass {

    ArrayList<? extends SuperClass> superList;

    public VeryBigClass(ArrayList<? extends SuperClass> superList) {
        this.superList = superList;
    }
}
Michael Markidis
  • 4,163
  • 1
  • 14
  • 21
  • Wildcards for declared types get a little dicey. They are good for method arguments and return types, because those feed types with better declarations, but as a variable type they provide too little information. It's better to follow the advice given earlier to make `VeryBig` a generic class. – Lew Bloch May 27 '17 at 22:03
  • Oh, didn't know one could do this! It will be helpful for sure, thanks :) – Andrei Scutariu May 27 '17 at 22:14