关于java中虚拟方法的问题

时间:2010-08-26 10:13:10

标签: java casting virtual-functions visitor

简单地说:我想要以下代码来打印“sub”:

Element e = new SubElement();
print(e);
... 

private static void print(Element e) {
    System.out.println("e");
}

private static void print(SubElement e) {
    System.out.println("sub");
}

我不想改变打印(元素e)。所以没有像

private static void print(Element e) {
    if (e instanceof SubElement) {
        print((SubElement) e);
    } else {
        System.out.println("e");
    }
}

我想做的是

print(e.getClass().cast(e));

自动将其转换为真正的子类并强制系统输入print(SubElement e)。这有点可能吗?

5 个答案:

答案 0 :(得分:7)

在编译时选择运行的重载方法,这就是选择Element版本而不是SubElement版本的原因。似乎更合理的是让Element或子类包含应该打印的数据。

class Element {

    public String getName() {
        return "e";
    }
}

class SubElement extends Element {
    public String getName() {
        return "sub";
    }
}

然后在print方法中:

private static void print(Element e) {
    System.out.println(e.getName());
}

这是否有意义将取决于Element类实际上是什么以及打印数据代表什么。

答案 1 :(得分:1)

是。您可以使用Visitor pattern。但是它适用于已建立的明确定义的层次结构,因为您必须定义的Visitor接口需要每种类型的方法。

interface ElementVisitor {
   visit(Element e);
   visit(SubElement se);
}

class ElementerPrinter implements ElementVisitor {
   visit(Element e) { System.out.println("e"); }
   visit(SubElement e) { System.out.println("sub"); }
}

class Element {
  // here's the trick, Element knows that this is Element
  // and childs have to implement it!
  // if the parent-most class is an interface it force you to implement!
  accept(ElementVisitor visitor) { visitor.visit(this); } 
}

class SubElement {
  // here's the trick, Element knows that this is SubElement
  accept(ElementVisitor visitor) { visitor.visit(this); }
}

答案 2 :(得分:1)

print()需要成为Element的实例方法。你试图以一种艰难的方式模仿多态。如果您希望这样做,则无法真正避免从if到函数对象的一系列Class语句映射。为什么要这么麻烦?

答案 3 :(得分:0)

您是否能够将行为差异推向元素类?

Element e = new SubElement();
print(e);
... 

private static void print(Element e) {
    System.out.println(e.getMessageToPrint());
}

// no longer needed
//
//private static void print(SubElement e) {
//    System.out.println("sub");
//}

这样,SubElement可以覆盖getMessageToPrint()方法。

或者更好的是:

Element e = new SubElement();
e.print();

答案 4 :(得分:0)

我会选择不同的方法。

  1. 使用其他人建议的多态,扩展Element以添加print()方法(可以被子类覆盖)或
  2. 定义帮助程序接口并使用策略和工厂模式的组合:
  3. 基类

     public class Element{}
    

    派生类

     public class SubElement extends Element{}
    

    帮助打印元素的界面

    public interface PrintHelper{
        void print(Element element);
    }
    

    出厂以获得给定元素的最佳PrintHelper

    public class PrintHelperFactory{
    
        private final Map<Class<? extends Element>, PrintHelper> registeredHelpers =
            new HashMap<Class<? extends Element>, PrintHelper>();
    
        // Register a PrintHelper for a given Element class.
        public void registerHelper(final Class<? extends Element> clazz,
          final PrintHelper helper){
            this.registeredHelpers.put(clazz, helper);
        }
    
        // Get the most specific PrintHelper for a given Element.
        public PrintHelper getHelperForElement(final Element element){
            Class<? extends Element> clazz = element.getClass();
            while(!Object.class.equals(clazz)){
                if(this.registeredHelpers.containsKey(clazz)){
                    return this.registeredHelpers.get(clazz);
                }
                clazz = (Class<? extends Element>) clazz.getSuperclass();
            }
            return null;
        }
    
    }
    

    客户端测试类,作为Java应用程序运行

    public class Main{
    
        public static void main(final String[] args){
    
            final PrintHelperFactory factory = new PrintHelperFactory();
            factory.registerHelper(Element.class, new PrintHelper(){
                @Override
                public void print(final Element element){
                    System.out.println("Element");
                }
            });
            factory.registerHelper(SubElement.class, new PrintHelper(){
                @Override
                public void print(final Element element){
                    System.out.println("Sub Element");
                }
            });
    
            // test it with an Element  
            final Element elem = new Element();
            factory.getHelperForElement(elem).print(elem);
    
            // test it with a sub class
            final Element sub = new SubElement();
            factory.getHelperForElement(sub).print(sub);
    
        }
    
    }
    

    <强>输出

    Element
    Sub Element