在Java中是否可以隐藏或降低对继承方法的访问?

在Java中是否可以隐藏或降低对继承方法的访问?,java,inheritance,overriding,access-specifier,Java,Inheritance,Overriding,Access Specifier,我有一个类结构,我希望基类中的一些方法可以从直接从基类派生的类中访问,但不能从派生类派生的类中访问。根据Java语言规范,可以覆盖继承方法上的访问规范,使它们更公开,但不更私有。例如,这是我需要做的要点,但却是非法的: // Defines myMethod public class Base { protected void myMethod() {} } // Uses myMethod and then hides it. public class DerivedOne exte

我有一个类结构,我希望基类中的一些方法可以从直接从基类派生的类中访问,但不能从派生类派生的类中访问。根据Java语言规范,可以覆盖继承方法上的访问规范,使它们更公开,但不更私有。例如,这是我需要做的要点,但却是非法的:

// Defines myMethod
public class Base {
    protected void myMethod() {}
}

// Uses myMethod and then hides it.
public class DerivedOne extends Base {
    @Override
    private void myMethod();
}

// can't access myMethod.
public class DerivedTwo extends DerivedOne {

}
有没有办法做到这一点

编辑以解释我为什么要这样做:

在这种情况下,类结构是一个数据处理和导入结构。它读入并解析充满表格数据的文本文件,然后将它们存储在数据库中

基类是管理其数据库处理部分的基表类。它包含了相当多的功能,这些功能对于所有表类型都是通用的,因为一旦它们进入数据库,它们就变得统一了

中间类特定于正在解析的文件中的表的类型,并且具有表解析和导入逻辑。它需要访问一些基类的数据库访问函数

顶级类是特定于表的,只不过以父类可以理解的方式初始化表的布局。基类的用户也不需要像中产阶级那样查看或访问特定于数据库的函数。本质上,我只想将这些函数展示到基类之上的一个级别,而不是其他任何级别

我这样问是因为,尽管我作为示例发布的代码是非法的,但可能还有其他方法可以达到同样的目的。我在问是否有


也许隐藏是表达这一点的错误方式——我真正需要做的是将基类私有的一些功能公开给层次结构中上一级的类。隐藏可以做到这一点,但我可以看出隐藏是一个多么大的问题。有没有其他方法可以做到这一点?

没有。我不知道你为什么要引用规范,然后问是否有任何方法可以与规范所说的相反


如果您解释了为什么要这样做,您可能会得到一些关于如何做的建议。

当重写一个方法时,您只能使它更公开,而不是更私密。我不知道你为什么用“将军”这个词

请记住,从最小到最大的顺序:

public<protected<default<private

public如果你这样做了,那么从DerivedOne的角度来看,DerivedOne将不会是一个基础。相反,您需要的是一个包装器类

//Uses myMethod but keeps it hidden
public class HiddenBase {
    private final Base base = new Base();
    private void myMethod();
    public void otherMethod() {base.otherMethod();}
}

通过这种方式,您无法访问受保护的基本方法…

您描述的内容接近受保护的访问类的用途,派生类可以访问,其他所有类都不能

如果您从基类继承,您无法控制这可能会造成问题,您可以通过抛出异常使其他人无法使用该方法,同时通过直接调用super使继承的代码对您的类可用,例如:

// Uses myMethod and then hides it.
public class DerivedOne extends Base {
    @Override
    public void myMethod() {
        throw new IllegalStateException("Illegal access to myMethod");
    }

    private void myPrivateMethod() {
        super.myMethod();
    }

}
<> > >编辑< /强>:为了回答您的详细阐述,如果我正确理解了,您需要指定在中间类中定义的基类上下文中的行为。抽象受保护的方法不会对中产阶级派生的类不可见

一种可能的方法是使用需要在基类中抽象的方法定义接口,在基类中保留私有final引用,并在构造中间类对象时提供对实现的引用

接口将在嵌套在中产阶级内部的(静态?)中实现。我的意思是:

public interface Specific {
    public void doSomething();
}

public class Base {
    private final Specific specificImpl;

    protected Base(Specific s) {
        specificImpl = s;
    }

    public void doAlot() {

         // ...

         specificImpl.doSomething();

         // ...
    }
}

public class Middle extends Base {

    public Middle() {
        super(new Impl());
    }

    private Impl implements Specific {

        public void doSomething() {

            System.out.println("something done");
        }
    }
}

public class Derived extends Middle {

    // Access to doAlot()
    // No access to doSomething()
}

继承之所以有效,是因为在任何可以使用基类的地方,都可以使用它的一个子类。行为可能有所不同,但API并非如此。这个概念被称为

如果您能够限制对方法的访问,则生成的类将不具有相同的API,并且您将无法使用基类的实例替换其中一个派生类,从而否定继承的优势

您真正想要完成的工作可以通过接口完成:

interface IBase1 {
}

class Derived1 implements IBase1 {
  public void myMethod() {
  }
}

class Derived2 implements IBase1 {
}

class UseMe {
  public void foo(IBase1 something) {
     // Can take both Derived1 and Derived2
     // Can not call something.myMethod()
  }
  public void foo(Derived1 something) {
     something.myMethod();
  }
  public void foo(Derived2 something) {
    // not something.myMethod()
  }
}

这是可能的,但是需要一些包操作,并且可能导致一个比您希望长期使用的结构更复杂的结构

考虑以下几点:






我建议对你自己、你的同事和任何其他最终不得不维护你的代码的人都要友善;重新考虑您的类和接口以避免这种情况。

我认为您提出的问题的本质暴露了对象模型的概念问题。您试图将各种不同的责任描述为“是a”关系,而实际上您应该做的是描述“有a”或“使用a”关系。想要对子类隐藏基类功能的事实告诉我,这个问题实际上并没有映射到三层继承树上

听起来你在描述一个典型的ORM问题。让我们再看一次,看看我们是否可以将它重新映射到严格“是”继承之外的其他概念,因为我真的认为您的问题不是技术性的,而是概念性的:

你说:

基类是基表类 管理的数据库处理部分 信息技术有相当数量的 它所包含的功能是 所有表类型通用-一次 它们在它们成为的数据库中 制服

这可能更清楚,但听起来我们有一个类需要管理DB连接和公共DB操作。接下来,我想我们到此结束。您不需要扩展这个类,您需要将它交给需要使用其功能的类

中产阶级是特定于中产阶级的 正在创建的文件中的表的类型 已解析,并且
package a;

public class Base {
    void myMethod() {
        System.out.println("a");
    }
}
package a;

public class DerivedOne extends Base {
    @Override
    void myMethod() {
        System.out.println("b");
    }
}
package b;

public class DerivedTwo extends a.DerivedOne {
    public static void main(String... args) {
        myMethod(); // this does not compile...
    }
}
public class Base {
protected void myMethod() {}
}

// Uses myMethod and then hides it.
public class DerivedOne extends Base {
@Override
final protected void myMethod(); //make the method final
}


public class DerivedTwo extends DerivedOne {
   // can't access myMethod here.
}