Как получить доступ к закрытым переменным класса в его подклассе? - PullRequest
19 голосов
/ 13 февраля 2010

Это вопрос, который мне задали в интервью: у меня есть класс A с частными членами, а класс B - с расширением A. Я знаю, что к закрытым членам класса нельзя получить доступ, но вопрос таков: мне нужен доступ к частным членам класс A из класса B, а не создавать переменные с одинаковым значением в классе B.

Ответы [ 28 ]

34 голосов
/ 13 февраля 2010

Интервьюер либо проверял ваши знания о модификаторах доступа, либо ваш подход к изменению существующих классов, либо обоих.

Я бы перечислил их (общедоступные, частные, защищенные, частные пакеты) с объяснением каждого из них. Затем я сказал, что класс A нужно будет изменить, чтобы разрешить доступ к этим членам из класса B, либо добавив сеттеры и геттеры, либо изменив модификаторы доступа членов. Или класс B мог бы использовать отражение. Наконец, поговорим о плюсах и минусах каждого подхода.

11 голосов
/ 13 февраля 2010

Отражение? Пропустив импорт, это должно сработать:

public class A {

    private int ii = 23;

}

public class B extends A {

    private void readPrivateSuperClassField() throws Exception {
        Class<?> clazz = getClass().getSuperclass();
        Field field = clazz.getDeclaredField("ii");
        field.setAccessible(true);
        System.out.println(field.getInt(this));
    }

    public static void main(String[] args) throws Exception {
        new B().readPrivateSuperClassField();
    }

}

Это не будет работать, если вы сделаете что-то подобное до вызова readPrivateSuperClassField();:

System.setSecurityManager(new SecurityManager() {
        @Override
        public void checkMemberAccess(Class<?> clazz, int which) {
            if (clazz.equals(A.class)) {
                throw new SecurityException();
            } else {
                super.checkMemberAccess(clazz, which);    
            }
        }
    });

И есть другие условия, при которых подход отражения не будет работать. См. документы API для SecurityManager и AccessibleObject для получения дополнительной информации. Спасибо CPerkins за указание на это.

Я надеюсь, что они просто проверяли ваши знания, а не искали реального применения этого материала ;-) Хотя я думаю, что такой уродливый хак, как этот, может быть законным в некоторых крайних случаях.

6 голосов
/ 13 февраля 2010

Архитектура нарушена. Частные участники являются частными, потому что вы не хотите, чтобы к ним обращались за пределами класса и друзей.

Вы можете использовать хаки друзей, аксессоры, продвигать участника или #define private public (хех). Но это все краткосрочные решения - вам, вероятно, придется пересмотреть неисправную архитектуру на каком-то этапе.

6 голосов
/ 13 февраля 2010

Используя общедоступные средства доступа (получатели и установщики) рядовых членов А ...

5 голосов
/ 13 февраля 2010

Вы не можете получить доступ к закрытым членам из родительского класса. Вы сделали его защищенным или имеете доступ к защищенному / общедоступному методу.

РЕДАКТИРОВАТЬ : Это правда, что вы можете использовать отражение. Но это не обычно и не очень хорошая идея нарушать инкапсуляцию.

3 голосов
/ 04 января 2014

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

public class SuperClass
{
    private int a = 10;
    public void makeInner()
    {
        SubClass in = new SubClass();
        in.inner();
    }
    class SubClass
    {
        public void inner()
        {
            System.out.println("Super a is " + a);
        }
    }
    public static void main(String[] args)
    {
        SuperClass.SubClass s = new SuperClass().new SubClass();
        s.inner();
    }
}
2 голосов
/ 13 апреля 2014

С JLS & 8;. Объявления полей :

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

Я пишу пример кода:

public class Outer
{
    class InnerA
    {
        private String text;
    }
    class InnerB extends InnerA
    {
        public void setText(String text)
        {
            InnerA innerA = this;
            innerA.text = text;
        }
        public String getText()
        {
            return ((InnerA) this).text;
        }
    }
    public static void main(String[] args)
    {
        final InnerB innerB = new Outer().new InnerB();
        innerB.setText("hello world");
        System.out.println(innerB.getText());
    }
}

Объяснение доступности InnerA.text здесь JLS & sect; 6.6.1. Определение доступности :

В противном случае член или конструктор объявляется закрытым, и доступ разрешается, если и только если он происходит в теле класса верхнего уровня (§7.6), который включает в себя объявление члена или конструктора.

2 голосов
/ 13 февраля 2010

Если я правильно понял вопрос, вы можете изменить private на protected. Защищенные переменные доступны для подклассов, но в противном случае они ведут себя как частные переменные.

2 голосов
/ 05 сентября 2013

Используя сеттеры и геттеры, вы можете получить к нему доступ

1 голос
/ 13 февраля 2010

Думали ли вы сделать их защищенными ? Просто чтобы быть уверенным, что вы знаете об этом варианте, если вы извините меня за то, что я поднял эту мелочь;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...