Java继承和方法解析顺序

Java继承和方法解析顺序,java,inheritance,casting,method-resolution-order,Java,Inheritance,Casting,Method Resolution Order,我有以下代码示例: 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("Co

我有以下代码示例:

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();
我得到相同的输出-为什么? typecast是否用colorprinter中的“drucke”覆盖对象“drucker”的方法“drucke”


提前感谢您的解释。

colorprinter
cp
的一个实例。即使您将其向上转换为
p
,它的
drucke()
方法仍然是
cp
中的方法


不同之处在于,向上投射
colorprinter
后,将无法调用
cp
自行定义的方法

colorprinter
在您对其使用强制转换操作符时,不会停止作为
cp
的实例,因此
public void drucke()
的实现不会改变

您使用
(p)colorprinter
强制转换所表达的是您希望对象
colorprinter
满足的契约(接口),其中包括签名为
public void drucke()
的公共方法,但不包括任何具体实现

顺便说一下,当您声明
p
类型的
drucker
时,该转换已经隐式执行,因此
(p)
p drucker=(p)colorprinter中是多余的<代码>p drucker=彩色打印机就足够了

请记住,最好的做法是从抽象类或接口扩展,而只覆盖(实现)抽象方法。更好的代码设计是:

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");
    }
}
现在,如果要表示打印机需要或可以具有多个打印功能(如颜色和黑白),只需使用所需的多个额外可打印属性和构造函数参数编写类,例如:

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();
    }

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

有关接口、重写和继承如何工作的更多信息,请参见


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

当您使用
new
操作符创建对象时,内存在
堆中分配。方法和字段实际上是存在的,这取决于对象的具体实际类。
Alter子类重写并修改其超类中的行为,调用重写的方法将始终导致修改的行为。强制转换只意味着子类的对象现在由超级类型表示,因为对象具有修改的行为,因为方法将始终导致修改的行为

假设你有以下的课程

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();
   }
}
换句话说,它就像把
芒果
称为
水果
,但是
芒果
仍然是
芒果
。 对于上述代码

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
水果=新芒果();

水果味();//有点挑剔:为了清晰起见,请用大写字母命名类。在命名类、方法等时,不要使用非英语母语。请使用英语camelCase。类类型是“外部用户”(其他类)如何看待对象的定义。方法实现绑定到实例,而类型仅定义其外部约束。