Java重载方法

3

我有一个抽象的模板方法:

class abstract MyTemplate
{
    public void something(Object obj)
    {
        doSomething(obj)

     }

    protected void doSomething(Object obj);

}

class MyImpl extends MyTemplate
{

   protected void doSomething(Object obj)
   {
      System.out.println("i am dealing with generic object");
   }

   protected void doSomething(String str)
   {
      System.out.println("I am dealing with string");
   }
}


public static void main(String[] args)
{
   MyImpl impl = new MyImpl();
   impl.something("abc"); // --> this return "i am dealing with generic object"

}

如何在doSomething(Object obj)中打印"I am dealing with string"而不使用instanceof?

谢谢。


1
从面向对象的角度来看,我会认真思考为什么需要这样的结构。类Object的实例没有太多的行为,为什么要将它们作为参数传递呢? - Horst Dehmer
同Horst所说。如果您要定义基类以在其方法签名中使用“Object”类型,则真的不应该假定处理特定类型。我建议使用泛型为MyTemplate定义类层次结构。 - whaley
4个回答

2

0

这是不可能的。MyImpl中的doSomething(Object obj)方法覆盖了MyTemplate中的doSomething方法。

在MyImpl的doSomething(Object obj)方法中使用instanceof运算符。这样做也是更好的代码风格。


1
我认为在一般情况下,使用instanceof可能暗示着违反了Liskov替换原则(LSP)。 - Horst Dehmer
在这种情况下,子类似乎被“优化”用于特定类型的对象,尽管它能够处理所有类型。因此,我们需要一些区分,这可以通过instanceof来实现。但我不喜欢这个原则,因为将某个东西作为子类并使用而不是原始对象是改变程序的好方法。也许我只是没有理解这个原则。 - Daniel
在这些情况下,应优先选择多态性而不是使用instanceof。此外,如果你正在检查(并可能进行强制转换)方法内的特定子类型,则该方法应接受子类型作为参数,而不是超类型(可以通过示例中所提供的泛型来实现)。 - whaley

0
Java编译器使用方法参数的编译时类型来创建方法调用,例如您的示例中是Object而不是String。方法调用忽略了参数的运行时类型。
如果您控制所有输入类,则可以尝试访问者模式,或者使用反射,但这种方法速度慢、复杂且容易出错。

0
简而言之,你不能这样做。其他答案已经解释了原因。另一种选择可能是使用泛型代替,并依赖于特定子类型的抽象类来处理字符串(或其他特定类)。例如:
abstract public class MyTemplate<T> {
    abstract public void doSomething(T t);
}

public class MyTemplateImpl extends MyTemplate<Object> {

    @Override
    public void doSomething(Object o) {
        System.out.println("Dealing with a generic Object");
    }
}

public class MyTemplateImplForStrings extends MyTemplate<String> {
    @Override
    public void doSomething(String s) {
        System.out.println("dealing with a String");
    }
}

这意味着你的调用代码将会是这样:

MyTemplateImplForStrings template = new MyTemplateImplForStrings();
template.doSomething("hello");  //prints ""dealing with a String"

或者

MyTemplate<String> template = new MyTemplateImplForStrings();
template.doSomething("hello");  //prints ""dealing with a String"

注意:除非您将其与String参数化,否则请避免使用抽象基类作为引用类型;否则,您将在运行时留下ClassCastExceptions的可能性,编译器应该会警告您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接