简体   繁体   中英

Java: Accessing subclass methods from objects in arraylist

I am trying to access methods in the class Car from my arraylist. The class hierarchy is essentially:

class Vehicle {} 
class Car extends Vehicle {} 
class Chevy extends Car {}
class Ford extends Car {}

In this example Car class has a getter called getID()

The main method looks like this:

Ford vehicle1 = new Ford(id, model, etc);
Chevy vehicle2 = new Chevy(id, model, etc);

ArrayList<Vehicle> list = new ArrayList<Vehicle>();
list.add(vehicle1);
list.add(vehicle2);

Through a lot of trial an error I've been able to access the getID() method like so:

System.out.println("Vehicle ID: " + ((Chevy) list.get(1)).getID());

Which works... I just can't imagine I'm doing this the proper way. Is there a better way to access these sub class methods?

For a serious program, your Vechicle interface should define all the behavioral methods common to all vehicles, which should include your getID() method. However, in some cases you might want to have specific method that only applies to a certain type of vehicles; then you need to either do that in subclasses or sub interfaces to Vehicle . Take your above example, you might want to have a NamedVehicle with that getID() method. How to arrange your interfaces and classes is up to you. Refer to bridge design pattern if that helps.

Having said the above, in very occasional places you do want to do the explicit cast.

Adding a subclass objects in the list seems fine, but u would never know which child object would be accessed when iterating over the list.

I would suggest you could have parent reference point to child object in the following way.

Car vehicle1 = new Ford(id, model, etc);
Car vehicle2 = new Chevy(id, model, etc);

And add then to list as seen. When you iterate over the list u would downcast it based on the instanceof check, which would make it more conventional.

ex:

Car c = (Car)list.get(0)).getID();
if(c instanceof Ford){

    Ford f = (Ford)c;
    System.out.println(f.getId());

}

Why vehicle isn't an interface (classes cannot extend interfaces, they implement it)?

As far as I understood Vehicle doesn't have a getId() while Car does, that's why not casting your Vehicle array list object to a subclass which has such method (like Chevy ) causes an error.

If you did:

System.out.println("Vehicle ID: " + ((Car) list.get(1)).getID());

it would have worked.

I suggest you to make Vehicle an interface:

interface Vehicle{
    public int getId();
}

class Car implements Vehicle{ //altough I think this also should be abstract
    int id;

    @Override
    public int getId(){
        return id;
    }
}

With this configuration you can do:

Car vehicle1 = new Ford(id, model, etc);
Car vehicle2 = new Chevy(id, model, etc);

ArrayList<Vehicle> list = new ArrayList<Vehicle>();
list.add(vehicle1);
list.add(vehicle2);

System.out.println("Vehicle ID: " + list.get(1).getID()); //Chevy ID

Since the getId() method is declared in the Car class, then you can only access this method through inheritance ( of cource need to be marked with either of access modifiers protected or public ).

So any subclass of Car will have access to the getId() method and should have the behavior marked in the Car#getId unless that method is overriden in the related subtype thus at runtime the method behavior will be evaluted based on the current object type and not the object reference.

Now coming to one of the most famous OO (Object Oriented) features which is polymorphism (many forms) which let you pass any Car subtype where a car is needed, and return any Car subtype when you expect a Car instance.

So to sumup, you can have any Car subtype in an ArrayList of Car (s): Ford , Chevy and you will be able then to call any Car instance method on any item of the list (whatever real type it is, it does not matter since it is a child of Car ).

The main issue now is that the described behavior can't go in the other side, so a parent reference (in you case Vehicle ) would never know about its descendants behavior (the Car in your case) unless an explicit cast is met under the road.

Then you will need simply put, to instantiante your ArrayList using the Car as a Generic type (that's what you are doing when you say <Vehicle> , <Car> ):

public static void main(String[] args)
{
  Ford vehicle1 = new Ford(id, model, etc);
  Chevy vehicle2 = new Chevy(id, model, etc);

  ArrayList<Car> list = new ArrayList<Car>(); //Use a Car as generic type so you can call all car methods
  list.add(vehicle1);
  list.add(vehicle2);

  for(Car car : list)
  {
    System.out.println(car.getId()); // Iterate over the list and retrieve each element ID
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM