Java 这是什么特点?为什么我应该选择访客设计模式这样的双重分派解决方案?
嗨,我有一个基本的代码特性问题,如下所示。当我更改代码时,会得到特殊的输出。下面的程序给出了正确的输出,因为我们知道Java默认情况下不支持双重分派。请您查看下面的代码并查看输出。之后,我修改了代码,得到了奇怪的输出Java 这是什么特点?为什么我应该选择访客设计模式这样的双重分派解决方案?,java,oop,core,dispatch,Java,Oop,Core,Dispatch,嗨,我有一个基本的代码特性问题,如下所示。当我更改代码时,会得到特殊的输出。下面的程序给出了正确的输出,因为我们知道Java默认情况下不支持双重分派。请您查看下面的代码并查看输出。之后,我修改了代码,得到了奇怪的输出 import java.util.ArrayList; import java.util.List; class SavingAccount { } class DematAccount extends SavingAccount { } class Bank {
import java.util.ArrayList;
import java.util.List;
class SavingAccount {
}
class DematAccount extends SavingAccount {
}
class Bank {
public void open(SavingAccount act ) {
System.out.println("... Opening Saving Account ...");
}
public void open(DematAccount act ) {
System.out.println("... Opening Demat Account ...");
}
}
public class Test {
public static void main(String[] args) {
List<SavingAccount> actList = new ArrayList<SavingAccount>();
Bank bank = new Bank();
actList.add( new SavingAccount());
actList.add( new DematAccount());
for( SavingAccount act : actList ) {
bank.open(act);
}
}
}
import java.util.ArrayList;
导入java.util.List;
阶级储蓄帐户{
}
类DematAccount扩展了SavingAccount{
}
班级银行{
公开作废(储蓄账户法){
System.out.println(“…开立储蓄账户…”);
}
公开无效(DematAccount法案){
System.out.println(“…开立Demat账户…”);
}
}
公开课考试{
公共静态void main(字符串[]args){
List actList=新建ArrayList();
银行=新银行();
添加(新的SavingAccount());
add(new DematAccount());
对于(储蓄账户法案:actList){
银行公开(act);
}
}
}
下面给出了输出。
。。。开立储蓄帐户。。。
... 开立储蓄账户…
现在让我修改代码并查看下面的输出
import java.util.ArrayList;
import java.util.List;
class SavingAccount {
public void open() {
System.out.println("... Opened Saving Account Successfully ...");
}
}
class DematAccount extends SavingAccount {
public void open() {
System.out.println("... Opened Demat Account Successfully ...");
}
}
class Bank {
public void open(SavingAccount act ) {
System.out.println("... Opening Saving Account ...");
act.open();
}
public void open(DematAccount act ) {
System.out.println("... Opening Demat Account ...");
act.open();
}
}
public class Test {
public static void main(String[] args) {
List<SavingAccount> actList = new ArrayList<SavingAccount>();
Bank bank = new Bank();
actList.add( new SavingAccount());
actList.add( new DematAccount());
for( SavingAccount act : actList ) {
bank.open(act);
}
}
}
import java.util.ArrayList;
导入java.util.List;
阶级储蓄帐户{
公开作废{
System.out.println(“…已成功开户…”);
}
}
类DematAccount扩展了SavingAccount{
公开作废{
System.out.println(“…已成功打开Demat帐户…”);
}
}
班级银行{
公开作废(储蓄账户法){
System.out.println(“…开立储蓄账户…”);
打开()的动作;
}
公开无效(DematAccount法案){
System.out.println(“…开立Demat账户…”);
打开()的动作;
}
}
公开课考试{
公共静态void main(字符串[]args){
List actList=新建ArrayList();
银行=新银行();
添加(新的SavingAccount());
add(new DematAccount());
对于(储蓄账户法案:actList){
银行公开(act);
}
}
}
这里是输出
... 开立储蓄帐户。。。
... 已成功打开储蓄帐户。。。
... 开立储蓄帐户。。。
... 已成功打开Demat帐户
现在我的问题是,我得到了我期望的结果,为什么我要在上面的代码中选择访问者模式,即使它显示“Saving Account”,但它正确地执行了“Demat Account code”部分
请给我解释一下,问题出在哪里?
提前感谢。简短回答:Java没有运行时参数多态性(根据运行时的参数类型选择方法) 编译器将多态地调用对象上的子类方法,因此
act.open()
将调用DematAccount的实现,如果act是DematAccount。但是,Java的多态性对参数不起作用,因此bank.open(act)
将始终调用open(SavingAccount)
如果act是SavingAccount类型的变量,而不管其运行时类型如何
编译器在调用站点知道的相关信息是,act是一个SavingAccount,bank有一个方法open(SavingAccount)作为最接近的逆变匹配:
for(SavingAccount act : actList ) {
bank.open(act);
}
您可以使用instanceof执行类型大小写,并将act强制转换到子类以解决此问题,也可以在Bank类中执行该类型大小写
for(SavingAccount act : actList ) {
if (act instanceof DematAccount) {
bank.open((DematAccount) act);
} else {
bank.open(act);
}
}
这有点难看,意味着将此代码耦合到各种帐户,并在每次更改时进行更改
在银行操作系统内部更好地更改它,因为银行已经承担了了解所有储蓄账户子类的责任
class Bank {
public void open(SavingAccount act ) {
if (act instanceof DematAccount) {
open((DematAccount) act);
} else {
System.out.println("... Opening Saving Account ...");
act.open();
}
}
public void open(DematAccount act ) {
System.out.println("... Opening Demat Account ...");
act.open();
}
}
在这种情况下,Bank仅在控制台输出上不同,您可以轻松地将该控制台输出移动到SavingAccount和DematAccount,并从Bank中删除open(DematAccount),问题在于您没有使用双重分派/访问者。从内部
DematAccount
它需要调用一个类型为DematAccount
的方法。当你呼叫银行时,打开(act)代码>在循环中,您使用的是SavingAccount
版本,因为这是您在循环中使用的类型。我没有使用访问者模式,请查看代码的第一部分,其中它提供了不同的结果,但在第二部分中,我得到了其他内容。如果我有问题,我将应用访问者模式,但在这里,一切似乎都很好。我的问题是为什么我们会得到一些不同的结果。这并不是真的不同。它会打印相同的“期初储蓄账户”消息,但随后您会调用一个实现方式不同的方法,并成功打印Demat或Save opened。方法调用是在编译时确定的,编译时是运行时类的实现。嗨,阿兰,如果是这种情况,那么它为什么要在“act.open()”方法中调用运行时类型?@Sambit ah。这是因为Java的调用在对象上是多态的act.open()
可以调用子类方法,因为运行时有要调用它的对象,但是bank.open(act)
不能调用带有子类参数的方法,因为bank是决定不执行多态性的对象,bank有一个open()方法用于SavingAccount,所以必须调用它。