Java继承和方法解析顺序



我有以下代码示例:

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.duckauftrag();"会导致控制台输出"彩色打印机"是没有问题的。

但当我打电话给时

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

我得到了同样的输出——为什么?typecast是否用colorprinter中的"drucke"覆盖对象"drucker"的方法"druck"?

提前感谢您的每一个解释。

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

您用(p)colorprinter强制转换表达的是您希望对象colorprinter满足的约定(接口)类型,其中包括一个具有签名public void drucke()的公共方法,但没有任何特定的实现。

顺便说一句,当您声明类型为pdrucker时,这个强制转换已经隐式执行了,所以(p)p drucker = (p)colorprinter;中是多余的。CCD_ 11就足够了。

在这里你可以了解更多关于打字的信息。

请记住,最好是从抽象类或接口进行扩展,并且仅使用@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");
}
}

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

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<Druckable> printServices)构造函数编写一个class MultiPrinter,并将任意数量的打印模式添加到其打印服务列表中:pcp,以及将来Druckable及其public void drucke()的任何其他实现。如果您想引入单元测试,那么它也是非常实用的,因此您可以提供实体模型对象来强制您想要测试的特定条件,例如druke()抛出PaperJamException

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

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

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

不同的是,在升级colorprinter之后,将无法调用cp自己定义的方法。

使用new运算符创建对象时,内存分配在heap中。方法和字段实际上是存在的,这取决于对象的具体实际类。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();
}
}

换句话说,它类似于将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

相关内容

  • 没有找到相关文章

最新更新