3

我有以下代码示例:

class p {
    public void druckauftrag() {
        // ...
        drucke();
    }

    public void drucke() {
        System.out.println("B/W-Printer");
    }
}

class cp extends p {
    public void drucke() {
        System.out.println("Color-Printer");
    }
}

调用以下行:

  cp colorprinter = new cp();
  cp.druckauftrag();

理解为什么“cp.druckauftrag();”没有问题 导致控制台输出“彩色打印机”。

但是当我打电话时:

    p drucker = (p)colorprinter;
    drucker.druckauftrag();

我得到相同的输出 - 为什么?类型转换是否用 colorprinter 中的“drucker”覆盖对象“drucker”的方法“drucker”?

预先感谢您的每一个解释。

4

3 回答 3

4

colorprintercp当您在其上使用强制转换运算符时不会停止作为实例,因此它的实现public void drucke()不会改变

您通过(p)colorprinter转换表达的是您希望对象colorprinter满足的合同(接口)类型,其中包括带有签名的公共方法public void drucke(),但没有任何特定的实现。

drucker而且,顺便说一句,当你声明type时,这个转换已经隐式执行了p,所以(p)p drucker = (p)colorprinter;. p drucker = colorprinter;就足够了。

在这里,您可以了解有关类型转换的更多信息。

请记住,从抽象类或接口扩展并且仅@Override(实现)抽象方法是最佳实践。更好的代码设计是:

abstract class BasePrinter {

    public void druckauftrag() {
        // ...
        drucke();
    }

    public void drucke();

}

class p extends BasePrinter {    
    public void drucke() {
        System.out.println("B/W-Printer");
    }
}

class cp extends BasePrinter {
    public void drucke() {
        System.out.println("Color-Printer");
    }
}

但当然,限制并不总是允许这种重新设计。将基本要求作为参数传递给构造函数(依赖注入)而不是扩展基类也是一个不错的选择:

interface Druckable {
    void drucke();
}

class Druckauftrager {

    Druckable dk;
    Druckauftrager(Drukable dk){
        this.dk = dk;
    }
    public void druckauftrag() {
        // ...
        dk.drucke();
    }

}

class p implements Druckable {    
    public void drucke() {
        System.out.println("B/W-Printer");
    }
}

class cp implements Druckable {
    public void drucke() {
        System.out.println("Color-Printer");
    }
}

现在,如果您想表达打印机需要或可以具有多种打印功能(如彩色和黑白),您只需编写具有尽可能多的额外 Drukable 属性和构造函数参数的类,例如:

class BlackAndWhiteOrColorPrinter {

    p blackAndWhitePrintService;
    cp colorPrintService;

    Druckable selectedPrintService;

    BlackAndWhiteOrColorPrinter (p blackAndWhitePrintService, cp colorPrintService){
        this.blackAndWhitePrintService = blackAndWhitePrintService;
        this.colorPrintService = colorPrintService;
        this.selectedPrintService = blackAndWhitePrintService;
    }

    public void druckauftrag() {
        // ...
        selectedPrintService.drucke();
    }

}

这样,您甚至可以class MultiPrinter使用MultiPrinter(List<Druckable> printServices)构造函数编写 a 并将任意数量的打印模式添加到其打印服务列表中:p、 ,以及将来会出现的任何cp其他实现。如果您想引入单元测试,它也更加实用,因此您可以提供模型对象来强制您想要测试的特定条件,例如抛出 a 。Druckablepublic void drucke()druke()PaperJamException

有关接口、覆盖和继承如何工作的更多信息,请参阅https://docs.oracle.com/javase/tutorial/java/IandI/usinginterface.html

顺便说一句,根据官方java 代码约定指南的最新版本以及事实上的标准,Java 中的类应该使用CamelCase命名约定。您还可以从对所有定义使用语义命名中受益匪浅,例如BlackAndWhitePrinter blackAndWhitePrinterColorPrinter colorPrinter

于 2017-02-05T09:44:26.847 回答
3

colorprinter是 的一个实例cp。即使你将它上载到p,它的drucke()方法仍然是 from cp

不同之处在于,在 upcast 之后colorprinter,您将无法调用cp自己定义的方法。

于 2017-02-05T09:41:08.200 回答
0

使用new运算符创建对象时,内存分配在heap. 方法和字段实际上取决于对象的具体实际类。更改子类会覆盖并修改其超类的行为,调用被覆盖的方法将始终导致修改后的行为。转换仅意味着子类的对象现在由超类型表示,因为对象具有修改的方法行为将始终导致修改的行为。

假设您有以下课程

public class Fruit{
   public void taste(){
     System.out.println("depends upon the actual fruit"); 
   }
}

public class Mango extends Fruit{
   @Override
   public void taste(){
     System.out.println("sweet"); 
   }
   public void wayToExposeSuperMethod(){
     super.taste();
   }
}

换句话说,它就像调用mango一样,fruit但仍然mango存在mango。对于上面的代码

Fruit fruit = new Mango();

fruit.taste(); // <-- this will output : sweet

((Mango)fruit).taste();// <-- this will output : sweet

fruit.wayToExposeSuperMethod(); // <-- this will not compile

((Mango)fruit).wayToExposeSuperMethod(); // <-- this will output : depends upon the actual fruit
于 2017-02-05T09:48:39.133 回答