Ограничение членов родительского класса только на его непосредственный дочерний класс

Предположим, что у меня есть четыре класса в java с заданной иерархией.

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

В соответствии с моим пониманием все доступные поля класса A будут доступны для всех его дочерних классов через наследование. Теперь, если я хочу, чтобы несколько полей класса A были доступны только классу B.

Есть ли какой-либо способ в java, чтобы я мог ограничивать определенные поля родительского класса только своим непосредственным дочерним классом?

Ответ 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
    ...

Ответ 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
}

Теперь, если вы объявите Class C and D в package com.secondpackage; и extends их из Class B, тогда эти два класса (Class C and D) не являются прямыми дочерними элементами Class A и, конечно, не в том же пакет, в котором реализована Class A. Таким образом, члены данных класса A недоступны в Class C and D.

Ответ 3

Это неправильный дизайн класса, но если вы действительно хотите это сделать, вы можете управлять этим сценарием.

Например, вы хотите ограничить членов родительского класса другим, кроме непосредственного дочернего класса, вы можете использовать модификатор доступа protected и поместить другой класс в другой package.

В соответствии с вашим примером

Class A и Class B будут в одном пакете, а Class C,D будет другим пакетом. Модификатор защищенного доступа можно использовать для члена Class A.

Ответ 4

Вы можете настроить все свои атрибуты как частные, так и получить доступ к ним с помощью геттеров. Затем вы можете контролировать видимость и переопределять ее.

Пример с 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 может получить доступ к атрибуту A с помощью super.getTest() C не может получить доступ к тесту.

Это гораздо более чистый подход, чем проверка типа класса.

Ответ 5

Обходной путь для достижения цели может быть рефакторингом.
Определение интерфейса или абстрактного класса Класс, реализованный/подклассифицированный A и B, с переменными и общепринятыми методами между двумя классами.
C и D расширяют A, наследуя методы implemetend в А.
Выбор между использованием интерфейса/абстрактного класса для класса продиктован необходимостью повторного использования общих полей и методов в и B или нет.