在Java中将方法委托给子类

在Java中将方法委托给子类,java,inheritance,Java,Inheritance,我有一个超类形状,和类三角形,正方形等扩展形状。我现在有两个问题: 我的方法三角形延伸形状不编译。它必须返回一个形状,而不是三角形。 我想隐藏这个方法。它应该只能从Shape超类调用。 公共阶级形态{ 公共静态形状createShapeFromXMLString xml{ 字符串类型=parsexml; if type.equalsTriangle{ Triangle.createShapeFromXMLxml; }否则如果{ // ... } } } 公共类三角形扩展形状{ 公共静态三角形cr

我有一个超类形状,和类三角形,正方形等扩展形状。我现在有两个问题:

我的方法三角形延伸形状不编译。它必须返回一个形状,而不是三角形。 我想隐藏这个方法。它应该只能从Shape超类调用。 公共阶级形态{ 公共静态形状createShapeFromXMLString xml{ 字符串类型=parsexml; if type.equalsTriangle{ Triangle.createShapeFromXMLxml; }否则如果{ // ... } } } 公共类三角形扩展形状{ 公共静态三角形createShapeFromXMLString xml{ .... } } 公共静态无效字符串[]args{ 字符串xml=。。。 Shape s=Shape.createShapeFromXMLxml; }
如何解决这些问题?

为什么不在超类中保留一个静态方法,并让它返回相应的Shape子类?签名将保持不变,因为三角形与形状之间存在is-a关系

您可以将超类上的方法设置为私有,以获得所需的访问限制

另一种方法是使用该模式。你可以有一个ShapeFactory。。。
这是一个好主意,因为创建xml解析与Shape类无关。分开你的顾虑。wikipedia链接擅长描述模式,但您可能需要一个更简单的示例。请参阅。

为什么不在超类中保留一个静态方法,并让它返回适当的Shape子类?签名将保持不变,因为三角形与形状之间存在is-a关系

您可以将超类上的方法设置为私有,以获得所需的访问限制

另一种方法是使用该模式。你可以有一个ShapeFactory。。。
这是一个好主意,因为创建xml解析与Shape类无关。分开你的顾虑。wikipedia链接擅长描述模式,但您可能需要一个更简单的示例。请参阅。

要使代码编译,您需要在Triangle类中声明公共静态形状createShapeFromXMLString xml


public class Shape {

    public static void main(String[] args) {
            String xml = "Triangle";
            Shape s = Shape.createShapeFromXML(xml);
            System.out.println(s.toString());
    }

    public static Shape createShapeFromXML(String xml) {
       Shape aShape = null;

       if (xml.equals("Triangle")) {
         aShape = Triangle.createShapeFromXML(xml);
       }
       return aShape;
     }
 }

class Triangle extends Shape {

    public static Shape createShapeFromXML(String xml) {
         return new Triangle();
    }

    @Override
    public String toString() {
       return "Triangle";
    }
 }


System.out.printlns.toString;在主方法输出三角形中,这证明正在创建三角形形状

要使代码编译,需要在Triangle类中声明公共静态形状createShapeFromXMLString xml


public class Shape {

    public static void main(String[] args) {
            String xml = "Triangle";
            Shape s = Shape.createShapeFromXML(xml);
            System.out.println(s.toString());
    }

    public static Shape createShapeFromXML(String xml) {
       Shape aShape = null;

       if (xml.equals("Triangle")) {
         aShape = Triangle.createShapeFromXML(xml);
       }
       return aShape;
     }
 }

class Triangle extends Shape {

    public static Shape createShapeFromXML(String xml) {
         return new Triangle();
    }

    @Override
    public String toString() {
       return "Triangle";
    }
 }

System.out.printlns.toString;在主方法输出三角形中,这证明正在创建三角形形状

//二,。我想隐藏这个方法。它应该只能从超类形状调用

您可以将Shape方法设置为final,以锁定实现。即使是在示例中返回子类类型三角形的重载方法也会被编译器标记

public static final Shape createShapeFromXML(String xml) { ... }
编辑:

针对评论中的对话,我提供以下证据:

public class Shape {
   public static final Shape createShapeFromXML(String xml) {
      if (xml.equals("Triangle")) {//removed parse for demo compliation
         return Triangle.createShapeFromXML(xml);
      } else {
         return new Shape();
      }
   }
}

public class Triangle extends Shape{
   public static Triangle createShapeFromXML(String xml) {
      return new Triangle();
   }
} 
尝试编译上述内容将导致编译器错误:

mybox:src akf$ javac Triangle.java
Triangle.java:3: createShapeFromXML(java.lang.String) in Triangle cannot override createShapeFromXML(java.lang.String) in Shape; overridden method is static final
     public static Triangle createShapeFromXML(String xml) {
                                ^
1 error
这可以通过参考以下两个部分来解释:

从8.4.6.2通过类方法隐藏:

如果一个类声明了一个静态方法,那么该方法的声明被认为隐藏了该类的超类和超接口中具有相同签名的任何和所有方法,否则该类中的代码将可以访问这些方法

然后从8.4.3.3最终方法:

方法可以声明为final,以防止子类重写或隐藏它。试图重写或隐藏最终方法是编译时错误

将两者结合在一起,在静态方法的签名中添加final将保护该方法不被子类隐藏。它将强制执行编译时检查

//二,。我想隐藏这个方法。它应该只能从超类形状调用

您可以将Shape方法设置为final,以锁定实现。即使是在示例中返回子类类型三角形的重载方法也会被编译器标记

public static final Shape createShapeFromXML(String xml) { ... }
编辑:

针对评论中的对话,我提供以下证据:

public class Shape {
   public static final Shape createShapeFromXML(String xml) {
      if (xml.equals("Triangle")) {//removed parse for demo compliation
         return Triangle.createShapeFromXML(xml);
      } else {
         return new Shape();
      }
   }
}

public class Triangle extends Shape{
   public static Triangle createShapeFromXML(String xml) {
      return new Triangle();
   }
} 
尝试编译上述内容将导致编译器错误:

mybox:src akf$ javac Triangle.java
Triangle.java:3: createShapeFromXML(java.lang.String) in Triangle cannot override createShapeFromXML(java.lang.String) in Shape; overridden method is static final
     public static Triangle createShapeFromXML(String xml) {
                                ^
1 error
这可以通过参考以下两个部分来解释:

从8.4.6.2通过类方法隐藏:

如果一个类声明了一个静态方法,那么该方法的声明被认为隐藏了该类的超类和超接口中具有相同签名的任何和所有方法,否则该类中的代码将可以访问这些方法

然后从8.4.3.3最终方法:

方法可以声明为final,以防止子类重写或隐藏它。试图重写或隐藏最终方法是编译时错误

将两者结合在一起,在静态方法的签名中添加final将保护该方法不被子类隐藏。它将强制执行编译时检查。

特别是,
我认为这是一个抽象工厂的例子。我真的不知道为什么GoF把它们分为两种不同的模式。这不是形状类责任fopr对象creation@Karl:FactoryMethod和AbstractFactory之间的基本区别在于FactoryMethod是从类层次结构内部调用抽象基类的,而AbstractFactory是从外部使用的。GoFBook试图暗示这一事实,它说FactoryMethod是基于类的,而AbstractFactory是基于对象的。-来自JavaRanch常见问题解答。谢谢,我将看一看工厂。+1这种关注点分离是工厂的具体含义,我认为这符合抽象工厂的示例。我真的不知道为什么GoF把它们分为两种不同的模式。这不是形状类责任fopr对象creation@Karl:FactoryMethod和AbstractFactory之间的基本区别在于FactoryMethod是从类层次结构内部调用抽象基类的,而AbstractFactory是从外部使用的。GoFBook试图暗示这一事实,它说FactoryMethod是基于类的,而AbstractFactory是基于对象的。-来自JavaRanch常见问题解答。谢谢,我来看看工厂。+1这种关注点分离是工厂的意思,因为静态方法不能被重写,所以final实际上什么都不做。它是合法的,也许“隐藏”比重写更好。因为final禁止在子类中实现具有相同签名的方法,所以编译器也会将该方法标记为隐藏。@akf:Yes。final阻止重写子类中的方法,但正如我所说。。。静态方法不能被重写,所以final对它们来说毫无意义。@akf:Hm,我在尝试这个方法时似乎做错了什么。。。你说得对!静态方法不能被重写,所以final实际上什么都不做。它是合法的,也许“隐藏”比重写更好。因为final禁止在子类中实现具有相同签名的方法,所以编译器也会将该方法标记为隐藏。@akf:Yes。final阻止重写子类中的方法,但正如我所说。。。静态方法不能被重写,所以final对它们来说毫无意义。@akf:Hm,我在尝试这个方法时似乎做错了什么。。。你说得对!