【问题标题】:Overload and hide methods in JavaJava中的重载和隐藏方法
【发布时间】:2010-04-06 23:58:26
【问题描述】:

我有一个带有公共 insert() 方法的抽象类 BaseClass:

public abstract class BaseClass {

 public void insert(Object object) {
  // Do something
 }

}

它被许多其他类扩展。然而,对于其中的一些类,insert() 方法必须有额外的参数,以便它们不会覆盖它,而是使用所需的参数重载基类的方法,例如:

public class SampleClass extends BaseClass {

 public void insert(Object object, Long param){
  // Do Something
 }

}

现在,如果我实例化 SampleClass 类,我有两个 insert() 方法:

SampleClass sampleClass = new SampleClass();
sampleClass.insert(Object object);
sampleClass.insert(Object object, Long param);

我想做的是隐藏基类中定义的insert() 方法,以便只看到重载:

SampleClass sampleClass = new SampleClass();
sampleClass.insert(Object object, Long param);

这可以在 OOP 中完成吗?

【问题讨论】:

    标签: java oop overloading


    【解决方案1】:

    没有办法隐藏该方法。你可以这样做:

    @Override
    public void insert(Object ob) {
      throw new UnsupportedOperationException("not supported");
    }
    

    但就是这样。

    基类创建一个契约。所有子类都受该合同的约束。这样想:

    BaseObject b = new SomeObjectWithoutInsert();
    b.insert(...);
    

    该代码如何知道它没有insert(Object) 方法?不能。

    您的问题听起来像是设计问题。有问题的类不应该从有问题的基类继承,或者该基类不应该具有该方法。也许您可以将insert() 从该类中取出,将其移至子类,并让需要insert(Object) 的类扩展它,而那些需要insert(Object, Object) 的类扩展基本对象的不同子类。

    【讨论】:

    • 您的解决方案的另一个版本:将 @Deprecated 注释添加到应该隐藏的覆盖方法中。为什么?因为当开发者尝试调用这个方法时,他会看到 deprecated 消息,但在运行时没有捕获异常。
    【解决方案2】:

    我不相信有一种干净的方法可以完全隐藏 Java 中的继承方法。

    在这种情况下,如果您绝对不能支持该方法,我可能会在子类中将该方法标记为 @Obsolete,并让它抛出 NotImplementedException(或 Java 中的任何等效异常),以劝阻人们不要使用它。

    最后,如果您继承的方法对您的子类没有意义,那么您可能根本不应该从该基类继承。也可能是基类设计不佳或包含太多行为,但可能值得考虑您的类层次结构。另一种查看方法可能是组合,您的类有一个曾经是基类的私有实例,您可以通过将它们包装在自己的方法中来选择要公开的方法。 (编辑:如果基类是抽象的,组合可能不是一个选项......)

    【讨论】:

      【解决方案3】:

      正如 Cletus 所指出的,这确实是一个设计问题,因为您试图创建一个不遵守其父类契约的子类。

      在极少数情况下可以通过例如解决此问题。抛出异常可能是可取的(或者至少是可接受的折衷方案——例如,Java 集合框架),但一般来说这是设计不佳的标志。

      您可能希望阅读the Liskov substitution principle:“如果 S 是 T 的子类型,则程序中 T 类型的对象可以替换为 S 类型的对象而不改变该程序的任何理想属性”。重写抛出异常的方法,或以任何其他方式隐藏它,都违反了这一原则。

      如果基类方法的约定是“插入当前对象,或引发异常”(参见例如the JavaDoc for Collection.add()),那么您可能会争辩说您没有违反 LSP,但如果大多数调用者都没有想到的话您可能需要基于这些理由重新考虑您的设计。

      【讨论】:

        【解决方案4】:

        这听起来像是一个设计糟糕的层次结构 -

        如果不存在默认值并且用户根本不应该调用该方法,您可以将该方法标记为@Deprecated 并抛出UnsupportedOperationException,正如其他海报所指出的那样。 然而 - 这实际上只是一个运行时检查。 @Deprecated 只会引发编译器警告,并且大多数 IDE 都会以某种方式对其进行标记,但没有编译时预防措施。这也很糟糕,因为可以将子类作为父类引用并在其上调用该方法,而不会警告它是“坏的”。在下面的示例中,直到运行时才会有任何迹象表明有任何问题。

        例子:

        // Abstract base builder class
        public abstract class BaseClassBuilder {
            public final doBuild() {
                BaseClass base = getBase();
                for (Object obj : getObjects() {
                    base.insert(obj);
                }
            }
            protected abstract BaseClass getBase();
            protected abstract Object[] getObjects();
        }
        
        // implementation using SampleClass
        public class SampleClassBuilder extends BaseClassBuilder {
        
            @Override
            protected BaseClass getBase() {
                return new SampleClass();
            }
        
            @Override
            protected Object[] getObjects() {
                Object[] obj = new Object[12];
                // ...
                return obj;
            }
        }
        

        但是,如果存在合理的默认值,您可以将继承的方法标记为 final,并在其中提供默认值。这既可以处理不良的层次结构,又可以防止上述示例的“意外情况”。

        例子:

        public abstract class BaseClass { 
            public void insert(Object object) {
                // ...
            }
        }
        
        public class SampleClass extends BaseClass {
        
            public static final Long DEFAULT_PARAM = 0L;
        
            public final void insert(Object object) {
                this.insert(object, DEFAULT_PARAM);
            }
        
            public void insert(Object object, Long param) {
                // ...
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-29
          • 1970-01-01
          • 1970-01-01
          • 2015-05-31
          • 2013-03-30
          • 2011-01-17
          • 2015-09-18
          • 2015-03-13
          相关资源
          最近更新 更多