考虑以下场景在OO文献中非常常见:
public class Vehicle {
}
public class Car extends Vehicle {
}
public class Bike extends Vehicle {
}
现在,假设我想创建一个总是返回子类类型的函数get()
,这样我就可以得到一个子类实例:
public static void main(String[] args) {
Car car = Car.get();
Bike bike = Bike.get();
car.Start();
bike.Start();
}
可以在超类中实现一个知道其返回类型的public static <T> T get()
,而不将其作为参数传递或从Object
转换?
更新
在第一个版本中,我谈论的是抽象类。现在我删除了抽象,我使用常规类。
答案 0 :(得分:1)
在这种情况下,如果在超类上调用静态方法,Java不知道要返回哪种类型的子类。你提到你想要在不传递参数的情况下这样做,你不能。如果你可以传入一个参数,你可以这样做:
package com.stackexchange.stackoverflow;
public class Question19281170 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Car car = Vehicle.get(Car.class);
Bike bike = Bike.get(Bike.class);
car.start();
bike.start();
}
static abstract class Vehicle {
public void start() {
System.out.println(String.format("Start %s", toString()));
}
public static <T extends Vehicle> T get(Class<T> clazz) throws IllegalAccessException, InstantiationException {
return clazz.newInstance();
}
@Override
public String toString() {
return "Vehicle";
}
}
static class Car extends Vehicle {
@Override
public String toString() {
return "Car";
}
}
static class Bike extends Vehicle {
@Override
public String toString() {
return "Bike";
}
}
}
最佳做法是使用多态:
Vehicle car = new Car();
Vehicle bike = new Bike();
答案 1 :(得分:0)
继承是一个强大的功能,非常适合构建基于类的层次结构,例如JavaFX中的层次结构。
但是设计继承类是一种痛苦,充满了潜在的问题。这是一个常见问题:如果您决定使用HashMap来表示车辆集合,该怎么办?问题是以不破坏equals()和hashcode()的契约的方式为子类编写equals()和hashcode()方法比听起来更难。此外,继承会破坏封装,并使您的子类依赖于超类中的实现细节,这可能会使您的代码变得脆弱或更难以维护。
继承的替代方法是使用基于接口的类型系统,类似于Java Collections API使用的类型。
public interface Vehicle {
public void start();
:
}
public class Car implements Vehicle {
}
public class Bike implements Vehicle {
}
接口用作基本类型,具有几个优点。最重要的是,无论类是什么,任何实现Vehicle接口的类都可以传递给任何要求Vehicle的方法。虽然这看起来类似于继承,但是没有实际的基于类的层次结构。实现细节,封装和equals()合同的所有问题都消失了。
基于接口的类型系统的缺点有几个:
您必须能够使用接口定义以健壮的方式指定基本类型的行为。如果没有这个,作为基类型的界面就变得不方便了。
接口必须由每个使用它的类完全实现(除非您为接口创建抽象骨架实现类,例如Collections API中的AbstractList)。
很难改变界面......但编辑超类通常会有问题。请记住,对超类的更改可能会在其子类中产生副作用,这些副作用依赖于超类中的实现细节。
使用基于接口的类型会使您的情况看起来像这样(使用静态工厂):
Vehicle car = Car.newInstance();
Vehicle bike = Bike.newInstance();
car.start();
bike.start();
TL; DR:基于接口的类型系统可用于解决创建基于类的类型系统的问题(继承中断封装),并且可以成为某些问题的良好替代解决方案。