Java—是否可以用一个类扩展一个类的所有子类?

Java—是否可以用一个类扩展一个类的所有子类?,java,inheritance,Java,Inheritance,Java—是否可以用一个类扩展一个类的所有子类 让我们用一个例子来解释它,实际的代码要复杂得多。我有一个动物类,它有自己的类层次结构。假设它有两个子类:Testarrosa和Viper public class Car { public abstract String getManufacturer(); } public class Testarossa extends Car{ public String getManufacturer(){ retur

Java—是否可以用一个类扩展一个类的所有子类

让我们用一个例子来解释它,实际的代码要复杂得多。我有一个动物类,它有自己的类层次结构。假设它有两个子类:Testarrosa和Viper

public class Car {

    public abstract String getManufacturer();
}

public class Testarossa extends Car{

    public String getManufacturer(){
        return "Ferrari";
    }
}

public class Viper extends Car{

    public String getManufacturer(){
        return "Dodge";
    }
}
我想用RegisteredCar子类扩展所有Car子类

public class RegisteredCar extends Car {

   private String plateNumber;

   public RegisteredCar (String plateNumber){
       this.plateNumber=plateNumber;
   }

   public String getPlateNumber() {
       return plateNumber;
   }
}
在某种程度上,我应该能够创建特定子类的新RegisteredCar。差不多

RegisteredCar c = new RegisteredCar<Viper>("B-3956-AC");
RegisteredCar c=新的RegisteredCar(“B-3956-AC”);
调用c.getManufacturer()获得“道奇”,调用c.getPlateNumber()获得B-3956-AC。显然,我仍然能够创建一辆
Car c=new Viper()


这就是一个例子。如果没有注册,在Car中有一个空值的属性是不够的。

在java中,禁止扩展超过一个类。 例如,您可以构建从类到扩展的链。
解决Java中的多重继承问题→ 使用接口

简而言之,不,这是不可能的。不幸的是,您必须修改对象模型

例如,以这种方式注册
类怎么样:

公共接口注册{
C getCar();
字符串getPlateNumber();
}
通过这种方式,您可以在维护
车型的同时,提取与单个类别中的注册相关的信息

然后可以执行以下帮助器方法:

Registration RegisteredPiper=createRegistration(新Viper(),“B-3956-AC”);

<> >不,它不像C++。多重继承在Java中是不可能的。但是,您可以实现多个接口。

继承无法实现这一点。 最好的选择是将RegisteredCar类型设置为泛型,然后使用一个泛型实例变量来保存所需类型的car:

public class RegisteredCar<T extends Car> {
   private String plateNumber;
   private T car;

   public T getCar() {
       return this.car;
   }
   public T setCar(T car) {
       this.car = car;
   }
   public RegisteredCar (String plateNumber){
       this.plateNumber=plateNumber;
   }
   public String getPlateNumber() {
       return plateNumber;
   }
}
公共类注册卡{
私有字符串编号;
私家车;
公共T getCar(){
归还这辆车;
}
公共T车(T车){
这辆车;
}
公共注册卡(字符串编号){
这个。plateNumber=plateNumber;
}
公共字符串getPlateNumber(){
返回车牌号;
}
}
有了它,您将能够向RegisteredCar传递属于Car子类的任何类型的对象


正如您所注意到的,我已经删除了这个类的
扩展Car
部分,因为它不需要是Car本身的子类。

您应该尽可能避免继承。使用抽象(接口)使代码优雅且可维护。只是谷歌为什么扩展是邪恶的。


正如其他人所说,不,这是不可能的,你的例子可以通过改变你的模型来解决

作为继承的替代方法,您可以使用另一个类包装
Car
实例。
我会制作
Car
一个接口(尽管拥有
RegisteredCar
extend
Car
也应该可以),然后尝试以下伪代码:

class RegisteredCar<T extends Car> implements Car {
   private final  T car

   RegisteredCar(T car) {
     this.car = car;
   }

   ... methods for RegisteredCar
   ... methods from Car delegating to `this.car`
}
类RegisteredCar实现Car{
私家车
登记车辆(T车){
这辆车;
}
…RegisteredCar的方法
…从Car授权到“this.Car”的方法`
}
请原谅我的代码有点糟糕,我没有打开IDE,我总是在没有IDE的情况下搞乱泛型

另一个可能的解决方案是使用AOP,尽管我不知道这是如何流行的,但您所描述的可能是一个跨领域的问题


最后一种选择可能是使用一种允许扩展、特征、协议或其他类型的“混合”的语言,如其他答案中所述,使用通用类方法,您将无法在需要传递
Car
对象的地方使用
RegisteredCar
。e、 假设您需要生成一些发票

Invoice getInvoice(Car c);
在此方法中,您不能使用
RegisteredCar
,因为它不是Car类型。所有需要Car的API都不适用于
RegisteredCar
。在某些情况下,您可能需要车牌号和汽车,在那里您可能需要保持车牌号和汽车的映射。我建议采用以下基于装饰模式的方法,并将所有Car调用委托给传递的Car对象

    public class RegisteredCar extends Car{

    public RegisteredCar(Car c, String plateNumber){

    }        
    @Override
    String getColor(){
       c.getColor();
    }
}

在实际的类中,有没有一个原因是您不能简单地将新特性添加到现有的基类中

public abstract class Car
{
    public abstract String getManufacturer() ;

    protected String plate_number = null ;

    public String getPlateNumber()
    { return this.plate_number ; }

    public boolean isRegistered()
    { return ( this.plate_number != null ) ; }
}

“假设它有两个子类:大猩猩和狼”。。我想你应该坚持你的
汽车
example;)。但是不,这是不可能的。不可能将Viper和Testarossa的基类更改为RegisteredCar吗?我不明白为什么布尔成员“registered”是不够的。未注册的默认行为由假值处理。我想说,以这种方式使用继承确实是一个非常糟糕的设计。我要说的是,将继承用于make同样可怕。啊!几乎和我的答案一样。我只需要让它实现
Car
接口,然后它就可以在使用
Car
的地方使用,只需将实现的方法委托给包装好的
Car
实例即可。这不是多重继承的问题。我不想创建一个从多个类继承的类。这是一个遗传的问题;您不知道要扩展哪个类。类继承一点也不邪恶。您的解决方案迫使程序员在每个子类中实现通用方法。如果您需要公共功能,您可以实现该功能,将其抽象出来,并将该抽象组合到所有需要它的类中。通过这种方式,您将避免对实现的依赖,您将能够更改实现,并且没有人会注意到这一点,因为实现是完全隐藏的。这被称为组合重于继承。小茶
public abstract class Car
{
    public abstract String getManufacturer() ;

    protected String plate_number = null ;

    public String getPlateNumber()
    { return this.plate_number ; }

    public boolean isRegistered()
    { return ( this.plate_number != null ) ; }
}