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

发布于 2024-08-14 22:01:22 字数 918 浏览 4 评论 0原文

我有一个类结构,我希望基类中的某些方法可以从直接从基类派生的类访问,但不能从派生类派生的类访问。根据 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 {

}

有什么方法可以实现这一点吗?

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

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

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

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

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

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

也许隐藏是错误的表达方式——我真正需要做的是将一些应该是基类私有的功能暴露给层次结构中上一层的类。隐藏可以实现这一点——但我可以看到隐藏将是一个问题。还有其他方法可以做到这一点吗?

I have a class structure where I would like some methods in a base class to be accessible from classes derived directly from the base class, but not classes derived from derived classes. According to the Java Language specification it is possible to override access specifications on inherited methods to make them more public, but not more private. For example, this is the gist of what I need to do, but is illegal:

// 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 {

}

Is there any way to accomplish this?

Edited to explain why I would like to do this:

In this case the class structure is a data handling and import structure. It reads in and parses text files full of tabular data and then stores them in a database.

The base class is the base table class managing the database handling part of it. There is a fair amount of functionality contained in it that is common to all table types - as once they are in the database they become uniform.

The middle class is specific to the kind of table in the file being parsed, and has the table parsing and import logic. It needs access to some of the base class's database access functions.

The top level class is specific to the table and does nothing more than initialize the table's layout in a way the parent classes can understand. Also users of the base class do not need to see or access the database specific functions which the middle class do. In essence, I want to reveal these functions only to one level above the base class and no one else.

I ask because, although the code I posted as an example is illegal, there may be some other means to accomplish the same end. I'm asking if there is.

Perhaps hiding is the wrong way to phrase this - what I really need to do is expose some functionality that should be private to the base class to the class one level up in the hierarchy. Hiding would accomplish this - but I can see how hiding would be a problem. Is there another way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

彩虹直至黑白 2024-08-21 22:01:22

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

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

你说:

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

这可能更清楚,但听起来我们有一个类需要管理数据库连接和常见的数据库操作。遵循单一职责,我想我们已经完成了。您不需要扩展这个类,您需要它交给需要使用其功能的类。

中产阶级是特定于
文件中的表类型是
已解析,并具有表解析和
导入逻辑。它需要访问一些
基类的数据库访问
功能。

这里的“中产阶级”听起来有点像数据映射器。这个类不需要扩展前一个类,它需要拥有对它的引用,可能作为接口注入到构造函数或setter中。

顶级类特定于
表,无非就是
以某种方式初始化表格的布局
家长班都能听懂。
基类的用户也不会
需要查看或访问数据库
中间的具体功能
类做。本质上,我想揭示的是
这些功能仅限于一个级别
高于基类,没有其他人。

我不清楚为什么高级类似乎了解数据库模式(至少这就是短语“初始化表的布局”向我建议的),但同样,如果前两个类之间的关系是< a href="http://blog.platinumsolutions.com/node/129" rel="noreferrer">封装(“has a”/“uses a”)而不是继承(“is a”),我认为这不会成为问题。

I think the very nature of the problem as you've posed it exposes conceptual problems with your object model. You are trying to describe various separate responsibilities as "is a" relationships when actually what you should be doing is describing "has a" or "uses a" relationships. The very fact that you want to hide base class functionality from a child class tells me this problem doesn't actually map onto a three-tiered inheritance tree.

It sounds like you're describing a classic ORM problem. Let's look at this again and see if we can re-map it onto other concepts than strict "is a" inheritance, because I really think your problem isn't technical, it's conceptual:

You said:

The base class is the base table class
managing the database handling part of
it. There is a fair amount of
functionality contained in it that is
common to all table types - as once
they are in the database they become
uniform.

This could be more clear, but it sounds like we have one class that needs to manage the DB connection and common db operations. Following Single Responsibility, I think we're done here. You don't need to extend this class, you need to hand it to a class that needs to use its functionality.

The middle class is specific to the
kind of table in the file being
parsed, and has the table parsing and
import logic. It needs access to some
of the base class's database access
functions.

The "middle class" here sounds a bit like a Data Mapper. This class doesn't need to extend the previous class, it needs to own a reference to it, perhaps injected on the constructor or a setter as an interface.

The top level class is specific to the
table and does nothing more than
initialize the table's layout in a way
the parent classes can understand.
Also users of the base class do not
need to see or access the database
specific functions which the middle
class do. In essence, I want to reveal
these functions only to one level
above the base class and no one else.

I'm not clear why a high-level class seems to have knowledge of the db schema (at least that's what the phrase "initialize the table's layout" suggests to me), but again, if the relationship between the first two classes were encapsulation ("has a"/"uses a") instead of inheritance ("is a"), I don't think this would be a problem.

世界等同你 2024-08-21 22:01:22

不。我不确定你为什么要引用规范,然后询问是否有任何方法可以做与规范所说相反的事情......

也许如果你解释为什么你想这样做,您可以获得一些关于如何的建议。

No. I'm not sure why you'd quote the spec and then ask if there's any way to do the opposite of what the spec says...

Perhaps if you explain why you want to do this, you could get some suggestions on how.

人间☆小暴躁 2024-08-21 22:01:22

重写方法时,您只能使其变得更加公开,而不能使其更加私有。我不知道你为什么使用“一般”这个词

请记住,从最严格到最严格的顺序排列:

public<protected<default<private

是的,“protected”是一个比 default 限制更少的访问修饰符(当未使用修饰符时),因此您可以重写将重写方法标记为 protected 的默认方法,但不能执行相反的操作。

可以:
您可以使用 public 方法覆盖 protected 方法。

不能:
您无法使用 protected 方法覆盖 public 方法。

When overriding a method you can only make it more public, not more private. I don't know why you use the word "general"

Remember that, ordering from least to most restrictive:

public<protected<default<private

Yes, "protected" is a less restrictive access modifier than default (when no modifier is used), so you can override a default method marking the overriding method as protected, but not do the opposite.

Can:
You can override a protected method with a public one.

Can't:
You can't override a public method with a protected one.

_蜘蛛 2024-08-21 22:01:22

如果您这样做,那么从 DerivedTwo 的角度来看,DerivedOne 将不是 Base。相反,您想要的是一个包装类,

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

您无法通过这种方式访问​​基类的受保护方法......

If you did this then DerivedOne would not be a Base, from the DerivedTwo's point of view. Instead what you want is a wrapper class

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

You can't access protected methods of the base though this way...

三寸金莲 2024-08-21 22:01:22

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

如果您从基类继承,则无法控制这可能会引起问题,您可以通过抛出异常来使其他人无法访问该方法,同时通过直接调用 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();
    }

}

编辑:为了回答你的阐述,如果我理解正确的话,你需要在中间类中定义的基类的上下文中指定行为。抽象受保护方法对于从中类派生的类来说是不可见的。

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

该接口将在嵌套在中间类中的(静态?)中实现。我的意思看起来像:

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()
}

What you describe comes close to what the protected access class is for, derived classes can access, all others cannot.

If you inherit from base classes you have no control over this might pose a problem, you can make the method inaccesible to others by throwing an exception while making the inherited code available to your classes by calling super directly, something like:

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

}

Edit: to answer your elaboration, if I understand you correctly you need to specify behaviour in the context of the base class which is defined in the middle class. Abstract protected methods won't be invisible to the classes deriving from the middle class.

One possible approach is to define an interface with the methods you would need to be abstract in the base class, keeping a private final reference in the base class and providing a reference to the implementation when constructing the middle class objects.

The interface would be implemented in a (static?) nested inside the middle class. What I mean looks like:

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()
}
谁对谁错谁最难过 2024-08-21 22:01:22

继承之所以有效,是因为您可以在任何地方使用基类,也可以使用它的子类之一。行为可能不同,但 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()
  }
}

Inheritance works because everywhere you can use the base class, you can also use one of it's subclasses. The behavior may be different, but the API is not. The concept is known as the Liskov substitution principle.

If you were able to restrict access to methods, the resulting class would not have the same API and you would not be able to use substitute an instance of the base class for one of the derived classes, negating the advantage of inheritance.

What you actually want to accomplish can be done with interfaces:

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()
  }
}
谜泪 2024-08-21 22:01:22

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

考虑以下事项:


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...
    }
}

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

It is possible, but requires a bit of package manipulation and may lead to a structure that is a bit more complex than you would like to work with over the long haul.

consider the following:


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...
    }
}

I would recommend being nice to yourself, your co-workers and any other person that ends up having to maintain your code; rethink your classes and interfaces to avoid this.

几味少女 2024-08-21 22:01:22

重写方法时必须将其设为最终方法

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.
}

you have to make method final when override it

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.
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文