Java 中的重载和隐藏方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2589146/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 21:55:42  来源:igfitidea点击:

Overload and hide methods in Java

javaoopoverloading

提问by Mark

i have an abstract class BaseClass with a public insert()method:

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

public abstract class BaseClass {

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

}

which is extended by many other classes. For some of those classes, however, the insert()method must have additional parameters, so that they instead of overriding it I overload the method of the base class with the parameters required, for example:

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

public class SampleClass extends BaseClass {

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

}

Now, if i instantiate the SampleClass class, i have two insert()methods:

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

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

what i'd like to do is to hide the insert()method defined in the base class, so that just the overload would be visible:

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

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

Could this be done in OOP?

这可以在 OOP 中完成吗?

回答by cletus

There is no way of hidingthe method. You can do this:

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

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

but that's it.

但就是这样。

The base class creates a contract. All subclasses are bound by that contract. Think about it this way:

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

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

How is that code meant to know that it doesn't have an insert(Object)method? It can't.

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

Your problem sounds like a design problem. Either the classes in question shouldn't be inheriting from the base class in question or that base class shouldn't have that method. Perhaps you can take insert()out of that class, move it to a subclass and have classes that need insert(Object)extend it and those that need insert(Object, Object)extend a different subclass of the base object.

您的问题听起来像是设计问题。所讨论的类不应该从所讨论的基类继承,或者该基类不应该具有该方法。也许你可以去掉insert()那个类,把它移到一个子类中,并拥有需要insert(Object)扩展它的类和那些需要insert(Object, Object)扩展基对象的不同子类的类。

回答by Andy White

I don't believe there's a clean way to completely hide an inherited method in Java.

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

In cases like this, if you absolutely can't support that method, I would probably mark that method as @Obsolete in the child class, and have it throw a NotImplementedException (or whatever the equivalent exception is in Java), to discourage people from using it.

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

In the end, if you inherit a method that does not make sense for your child class, it could be that you really shouldn't inherit from that base class at all. It could also be that the base class is poorly designed or encompasses too much behavior, but it might be worth considering your class hierarchy. Another route to look at might be composition, where your class has a private instance of what used to be the base class, and you can choose which methods to expose by wrapping them in your own methods. (Edit: if the base class is abstract, composition might not be an option...)

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

回答by Cowan

As Cletus points out, this is really a design problem, in that you are trying to create a child class that does not obey the contract of its parent class.

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

There are rare circumstances where working around this by e.g. throwing an exception might be desirable (or at least an acceptable compromise -- for example, the Java Collections Framework) but in general it's a sign of poor design.

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

You may wish to read up on the Liskov substitution principle: the idea that (as Wikipedia puts it) "if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program". By overriding a method to throw an exception, or hiding it any other way, you're violating this principle.

您可能希望阅读Liskov 替换原则:这种想法(如维基百科所说)“如果 S 是 T 的子类型,则程序中的 T 类型对象可以替换为 S 类型的对象,而不会改变任何该程序的理想特性”。通过覆盖一个方法来抛出异常,或以任何其他方式隐藏它,你违反了这个原则。

If the contract of the base class' method was "inserts the current object, or throws an exception" (see e.g. the JavaDoc for Collection.add()) then you could argue you're not violating LSP, but if that is unexpected by most callers you may want to rethink your design on these grounds.

如果基类方法的约定是“插入当前对象,或抛出异常”(参见例如JavaDoc for Collection.add()),那么您可以争辩说您没有违反 LSP,但如果这是意外的大多数来电者您可能希望基于这些理由重新考虑您的设计。

回答by Nate

This sounds like a badly designed hierarchy -

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

If no default exists and the user shouldn't call the method at all you can mark the method as @Deprecatedand throw an UnsupportedOperationExceptionas other posters have noted. However- this is really only a runtime check. @Deprecatedonly throws a compiler warning and most IDEs mark it in some way, but there's no compile time prevention of this. It also really sucks because it's possible to get the child class as a parent class reference and call the method on it with no warning that it's "bad" at all. In the example below, there won't be any indication until runtime that anything's wrong.

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

Example:

例子:

// 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;
    }
}

However, if a sensible default exists, you could mark the inherited method as final and provide the default value inside of it. This handles both the bad hierarchy, and it prevents the "unforseen circumstances" of the above example.

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

Example:

例子:

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) {
        // ...
    }
}