【问题标题】:Restricting parent class members to its immediate child class only仅将父类成员限制为其直接子类
【发布时间】:2018-05-06 22:59:31
【问题描述】:

假设我在 java 中有四个具有给定层次结构的类。

class A {}
class B extends A {} 
class C extends B {} 
class D extends C {} 

据我了解,A 类的所有可访问字段都将通过继承对其所有子类可用。现在,如果我希望 A 类的少数字段仅对 B 类可用。

在 java 中有什么方法可以将父类的某些字段限制为其直接子类吗?

【问题讨论】:

  • 如果这真的是你想要的,那么你的类设计很可能是错误的。您的问题的真正用例是什么?
  • 我真的不明白面试中这种没有实际生活价值的问题。真的很烂
  • 我不了解您的用例,但请注意违反 Liskov 替换原则
  • 我感觉您有兴趣先阅读this。然后在面试回复中主要是同一行,即使在这种情况下通过反思提供了一些答案。
  • @user8001621 不建议接受那份工作。听起来他们没有像样的设计技能。

标签: java inheritance access-modifiers restriction


【解决方案1】:

并不是说我会在生产中做这样的事情,但是你去吧:

class A {
    private int a = 1;

    public int getA() {
        if (getClass().equals(A.class) || 
            getClass().getSuperclass().equals(A.class)) {
            return a;
        } else {
            throw new UnsupportedOperationException("hahaha");
        }
    }        

    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        C c = new C();
        System.out.println(a.getA());
        System.out.println(b.getA());
        System.out.println(c.getA());
    }
}

class B extends A {}

class C extends B {}

所以基本上你可以使用这个技巧来只允许你想要的类(使用黑名单或白名单方法)——调用getA()

输出:

1
1
Exception in thread "main" java.lang.IllegalStateException: hahaha
    ...

【讨论】:

  • IllegalStateException: 哈哈哈 并不是说​​我会在生产中做这样的事情:D
  • 我更可能使用UnsupportedOperationException 而不是IllegalStateException
  • 或者,更简单更准确地说,if (getClass().getSuperclass().equals(A.class))
  • @Bohemian 也更简洁 :) 你说得对,谢谢!
【解决方案2】:

仅将父类成员限制为其直接子类,为此,

Java 提供protected 访问修饰符,在其中,您可以访问类成员:

1) 班级内

2) 包内和

3) 仅限子类在包外。

如果你想将数据成员限制为直接子类,那么你可以做的是:

如下声明一个类:

package com.firstpackage;

Class A{
 protected int a;
}

现在像这样在另一个包中使用子类:

package com.secondpackage;

Class B extends A{
 //Access data members of class A
}

现在如果你声明,package com.secondpackage;extends 中的Class C and D 来自Class B,那么这两个类(Class C and D)不是Class A 的直接子级,当然也不在同一个实现Class A 的包。所以Class C and D中无法访问A类的数据成员。

【讨论】:

  • 首先,您需要public class A{ protected int a; },因为您需要从com.secondpackage 访问它。然后,您的成员aprotected,因此每个 子类都可以访问它。因此,您需要将其设为私有包:public class A{ int a;}。但随后B 无法访问A.a。您的解决方案永远不会按原样工作。更好的解决方案是将 AB 放在同一个包中,然后 A.a 包私有,然后使用 Java 9 将包设为私有模块化。
  • 这根本不是真的:在您的示例中让类 C 和 D 扩展 B(作为回报,扩展 A)仍然能够访问 A 类中的受保护字段 - 即使它们'重新装在另一个包里!
【解决方案3】:

这不是正确的类设计,但是,如果你真的想这样做,你可以管理这个场景。

例如,您想将父类成员限制为直接子类以外的成员,您可以使用protected 访问修饰符并将其他类放入另一个package

按照你的例子,

Class AClass B 将在同一个包中,Class C,D 将是另一个包。您可以为Class A 的成员使用受保护的访问修饰符。

【讨论】:

  • 还可以让会员private和使用public class A { private int member; public static class B extends A { ... } }
  • Ronak 的回答下面的 cmets 也适用于此。
【解决方案4】:

您可以将所有属性设置为私有并使用 getter 访问它们。 然后你可以控制可见性并覆盖它。

一个有 3 个类的例子:

    class A{
        private String test = "Test123";
        protected String getTest(){return test;};
    }

    class B extends A{
        @Override
        protected String getTest(){return "no";};
    }

    class C extends B{
    } 

在这里,A 类只与 B 共享测试属性。 B 可以使用super.getTest() 访问A 属性 C 无法访问测试。

它比检查类类型更简洁。

【讨论】:

    【解决方案5】:

    实现此目的的解决方法可能是重构。
    定义接口或抽象类 Class ,由 A 和 B 实现/子类化,两个类之间的变量和方法相同。
    C 和 D 扩展 A,继承方法实现在 A.
    Class 使用接口/抽象类的选择取决于是否需要重用 A 和 B 中的公共字段和方法。

    【讨论】:

      【解决方案6】:

      按 OOPS 概念: 在继承概念上,一个类和另一个类的设计行为不能不同。

      要停止将字段继承给子类,请将这些字段设为密封,即私有。如果您要求字段只能由直接子级访问,则将字段标记为受保护。

      如果您需要访问直到最后一个叶节点子类(在本例中是 D 类)之前的字段,则将这些字段标记为公共。

      或者在将类设计到组件中时,您可以通过类级别的 OOPS 访问修饰符来限制一个类从另一个组件的继承。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-10-08
        • 2019-12-19
        • 1970-01-01
        • 2020-12-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多