在Java中充分利用多态性

在Java中充分利用多态性,java,polymorphism,abstract-class,Java,Polymorphism,Abstract Class,我有以下问题: 假设我们有3个类: 一个名为Vehicle 一个名为摩托车的类别扩展了车辆 一个名为Car的类,扩展了Vehicle 这意味着车辆对象可以同时容纳摩托车和汽车对象 我还有一个名为VehicleDatabase的类,它基本上“模拟”了一个数据库(我希望我可以使用数据库,但这是一个大学项目),并持有一个名为db的ArrayList字段,以及一些提供一些基本操作的方法,以便我可以与数据库交互(积垢操作和其他一些) 我想要实现的一种方法是showVehicles()。为了简化并达到我

我有以下问题:

假设我们有3个类:

  • 一个名为
    Vehicle
  • 一个名为
    摩托车
    的类别扩展了
    车辆
  • 一个名为
    Car
    的类,扩展了
    Vehicle
这意味着
车辆
对象可以同时容纳
摩托车
汽车
对象

我还有一个名为
VehicleDatabase
的类,它基本上“模拟”了一个数据库(我希望我可以使用数据库,但这是一个大学项目),并持有一个名为
db
ArrayList
字段,以及一些提供一些基本操作的方法,以便我可以与数据库交互(积垢操作和其他一些)

我想要实现的一种方法是
showVehicles()
。为了简化并达到我问题的要点,假设此方法必须简单地将函数参数指定的所有对象的
.toString()
打印到控制台

示例:

用户界面中将显示一个菜单:

Select which type of vehicles you want to be shown:

1.Motorcycles
2.Cars

Make your choice: 
在此之后,我们的函数
showVehicles
必须采用一个参数,例如
showVehicles(CarSomething)
并打印存储在
db
ArrayList上的所有汽车。我真的找不到更优雅的方法来实现该函数。以下是我当前的实现:

public void showVehicles(Class<?> cls)
{
    for(Vehicle v : db)
    {
        if(v.getClass().equals(cls))
            System.out.println(v.toString());
    }
}
公共车辆(cls类)
{
用于(车辆v:db)
{
如果(v.getClass().equals(cls))
System.out.println(v.toString());
}
}
然后像这样调用它:
showVehicles(Car.class)
showVehicles(Motorcycle.class)


有没有更好的方法可以做到这一点?请给出您的建议。我只是觉得我没有像应该的那样使用多态性。

实际上,这不是面向对象方法通常使用的方式。下面是一个多态方法的示例。“printName”函数是在抽象类中定义的(在这种情况下也可以是接口):

import java.util.ArrayList;
抽象类车辆{
公共抽象void printName();//虚拟函数
}
二等车{
public void printName(){//类Car中的函数实现
System.out.println(“我是一辆车”);
}
}
二等车{
public void printName(){//类中的函数实现
System.out.println(“我是一辆自行车”);
}
}
公共类T1{
ArrayList车辆=新ArrayList();
void create(){
车辆。添加(新车());
车辆。添加(新自行车());
}
作废清单(){
用于(车辆v:车辆)
v、 printName();//在显示时使用该函数
}
公共静态void main(字符串参数[]){
T1=新的T1();
t1.create();
t1.list();
}
}

如果您想使用真实的数据库,则会有很大的不同。后者只能保存java类中的
数据
字段并将其还原到类中。因此,您的应用程序必须在读取时了解这些类,并确保正确的类中填充了正确的数据。在这种情况下,序列化会有所帮助。

这里是一种可能性

我创建了一个
Map,List>inventory=List.stream().collect(
Collectors.groupingBy(Object::getClass));
}
}
这是否是一个合理的方法取决于您(以及其他评论者)。您可能仍然需要一个映射来从用户菜单获得正确的类

  Map<String, Class<?>>  menuMap = new HashMap<>();
  menuMap.put("Car", Car.class);
  menuMap.put("MotorCycle", MotorCycle.class);

  Class<?> lookup = menuMap.get("Car");

  for (Vehicle v : inventory.get(lookup)) {
     System.out.println(v.toString()); 
  }
Map lookup=menuMap.get(“汽车”);
对于(车辆v:库存获取(查找)){
System.out.println(v.toString());
}

好吧……现在你知道为什么没有“对象关系映射器”了。关系数据库存储数据,而对象是关于行为的。在你的小例子中,你仍然能够确定一些
车辆
汽车
还是
摩托车
。这是不正确的(如果不存储其他信息,则至少不存储)如果你使用一个真实的数据库。为了避免这个问题,你是否考虑将它们存储在<代码> map < /COD>其中字符串是实际的车辆类型?@ WJS需要使用<代码> MAP>代码>来存储每个类的多个实例或<代码> MAP>代码>,将类名存储为值,而不是键。ode>Class
-实例,而不是类的名称为
String
@Turing85。我同意。我不会说这会使我的方法更方便,但它确实是实现我尝试的方法的更好方法。到目前为止,最好的答案是,如果没有更好的方法出现,我会接受它。我本来打算做Map(我忘了列表部分)但是@Turing85让我保持诚实,还建议使用
类实例作为键。我看到了评论,也为@Turing85感到荣幸。老实说,我不认为有更好的方法可以做,这通常是关系数据库的工作,而不是Java的。但我认为这会打印ArrayList的每个元素……这不是这不是我所期望的明确的行为。
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

abstract class Vehicle {
}

class MotorCycle extends Vehicle {
   String name;

   MotorCycle(String name) {
      this.name = name;
   }
   public String toString() {
      return name;
   }
}

class Car extends Vehicle {
   String name;

   Car(String name) {
      this.name = name;
   }

   public String toString() {
      return name;
   }
}

public class CarMapper {

   public static void main(String[] args) {
      List<Vehicle> list = new ArrayList<>();
      list.add(new MotorCycle("Honda"));
      list.add(new MotorCycle("Harley-Davidson"));
      list.add(new Car("Ford"));
      list.add(new Car("Chrysler"));

      Map<Class<?>, List<Vehicle>> inventory = list.stream().collect(
            Collectors.groupingBy(Object::getClass));

     }
}

  Map<String, Class<?>>  menuMap = new HashMap<>();
  menuMap.put("Car", Car.class);
  menuMap.put("MotorCycle", MotorCycle.class);

  Class<?> lookup = menuMap.get("Car");

  for (Vehicle v : inventory.get(lookup)) {
     System.out.println(v.toString()); 
  }