检查以下代码示例:
public class Test
{
private void process(Instance1 obj)
{
System.out.println("Process Instance 1");
}
private void process(Instance2 obj)
{
System.out.println("Process Instance 2");
}
/*
COMMENT THIS OUT - I DON'T HAVE THIS CODE IN REAL LIST. Only here to prove point 3 below calls this
private void process(SuperClass obj)
{
System.out.println("Process superclass");
}
*/
/**
* @param args
*/
public static void main(String[] args)
{
Test test = new Test();
Instance1 instance1 = test.new Instance1();
Instance2 instance2 = test.new Instance2();
SuperClass instance3 = test.new Instance1();
// test #1
test.process(instance1);
// test #2
test.process(instance2);
// test #3 (compiler error unless there is a process(SuperClass obj) call)
test.process(instance3);
// test #4
if(instance3 instanceof Instance1)
test.process((Instance1)instance3);
else if(instance3 instanceof Instance2)
test.process((Instance2)instance3);
}
abstract class SuperClass
{
}
class Instance1 extends SuperClass
{
}
class Instance2 extends SuperClass
{
}
}
这给出了输出:
Process Instance 1
Process Instance 2
Process superclass
Process Instance 1
我希望测试#3知道调用正确的函数,但似乎没有。我想这是编译时的事情,而不是运行时的事情。选项#4有效,但很难看,我希望有更好的方法。
更新:澄清问题......我有一个抽象类,其中存在两个具体的实现。我想要的是在另一个类中有两个重载方法(每个具体类一个),并且能够在不执行任何实例的情况下调用它。从我现在所知,这是不可能的,因为这是一个编译时问题,编译器显然不知道当它没有强类型时它是什么具体的类。
答案 0 :(得分:3)
这不是多态性的问题。这是方法重载的问题。
当您将instance3
传递给process()
时,它会调用process(SuperClass obj)
,因为只要JVM知道,instance3
就是SuperClass
,因为那是什么你宣布它为。
如果您想要所需的行为(测试#3打印出“Process Instance 1”),您应该定义process()
方法,如下所示:
private void process(SuperClass obj)
{
System.out.println("Process " + obj.name());
}
你的课程是这样的:
abstract class SuperClass
{
String name() {
return "SuperClass";
}
}
class Instance1 extends SuperClass
{
String name() {
return "Instance 1";
}
}
class Instance2 extends SuperClass
{
String name() {
return "Instance 2";
}
}
这将因动态(或延迟)方法绑定而起作用。
答案 1 :(得分:0)
将其作为层次结构中的虚函数:
abstract class SuperClass
{
public void process() { System.out.println("Process super class"); }
}
class Instance1 extends SuperClass
{
public void process() { System.out.println("Process instance1"); }
}
class Instance2 extends SuperClass
{
public void process() { System.out.println("Process instance2"); }
}
或将various approaches签出到Java本身不支持的多个分派。
答案 2 :(得分:0)
为更清洁地做你正在做的事情提供建议:
选项1:抽象方法
在process()
上定义Superclass
,并在Instance1
和Instance2
上覆盖它:
abstract class SuperClass
{
public void process(String[] args)
{
System.out.println("Process superclass");
}
}
class Instance1 extends SuperClass
{
@Override
public void process(String[] args)
{
System.out.println("Process Instance 1");
}
}
class Instance2 extends SuperClass
{
@Override
public void process(String[] args)
{
System.out.println("Process Instance 2");
}
}
选项2:访客模式
定义执行处理的类,并且是InstanceVisitor
public interface InstanceVisitor
{
public void processSuperclass(Superclass obj, String[] args);
public void processInstance1(Instance1 obj, String[] args);
public void processInstance2(Instance2 obj, String[] args);
}
public class InstanceProcessor implements InstanceVisitor
{
public void processSuperclass(Superclass obj, String[] args)
{
System.out.println("Process superclass");
}
public void processInstance1(Instance1 obj, String[] args)
{
System.out.println("Process Instance 1");
}
public void processInstance2(Instance2 obj, String[] args)
{
System.out.println("Process Instance 2");
}
}
然后每个子类接受一个访问者,并调用正确的方法:
abstract class SuperClass
{
public void accept(InstanceVisitor v, String[] args)
{
v.visitSuperclass(this, args);
}
}
class Instance1 extends SuperClass
{
@Override
public void accept(InstanceVisitor v, String[] args)
{
v.visitInstance1(this, args);
}
}
class Instance2 extends SuperClass
{
@Override
public void accept(InstanceVisitor v, String[] args)
{
v.visitInstance2(this, args);
}
}
答案 3 :(得分:0)
您可以更改SuperClass
和Instance
吗?如果是这样,您应该声明抽象方法SuperClass.process()
并在子类中实现它。
要使测试#3正常工作,您可以添加强制转换:test.process((Instance1)instance3);
。难看。
您还可以定义工厂类,并在其中封装类型切换。
您有ProcessFactory
ProcessObject getInstance(SuperClass obj)
方法可返回类型为ProcessObjectInstance1
或ProcessObjectInstance2
的对象,方法为process()
。 ProcessFactory
与您的测试#4类似。
答案 4 :(得分:0)
这就是我目前正在做的事情。基本上把问题解决了一下。不确定这是否算作访客模式。
基本上我只是在SuperClass中添加了一个executeProcessor(测试测试)抽象函数,具体类隐式知道要调用哪个函数,所以他们可以简单地使用强制转换。
你怎么看?这个代码有异味吗?还是一个简洁的解决方案?public class Test
{
private void process(Instance1 obj)
{
System.out.println("Process Instance 1");
}
private void process(Instance2 obj)
{
System.out.println("Process Instance 2");
}
/**
* @param args
*/
public static void main(String[] args)
{
Test test = new Test();
// Test 1
Instance1 instance1 = test.new Instance1();
instance1.executeProcessor(test);
// Test 2
Instance2 instance2 = test.new Instance2();
instance2.executeProcessor(test);
// Test 3 (note this is not strongly typed)
SuperClass instance3 = test.new Instance1();
instance3.executeProcessor(test);
}
abstract class SuperClass
{
public abstract void executeProcessor(Test test);
}
class Instance1 extends SuperClass
{
@Override
public void executeProcessor(Test test)
{
test.process((Instance1)this);
}
}
class Instance2 extends SuperClass
{
@Override
public void executeProcessor(Test test)
{
test.process((Instance2)this);
}
}
}
答案 5 :(得分:0)
正如其他人所指出的,这不是你在Java中可以做的事情。如果你绝对必须,你可以使用反射来做类似的事情:
private void process(SuperClass obj)
{
try
{
Class<? extends SuperClass> klass = obj.getClass();
Method m = this.getClass().getMethod("process", klass);
m.invoke(this, obj);
}
catch (Exception e)
{
// default behavior
System.out.println("Process superclass");
}
}
我真的会遵循其他建议之一。