Справка для понимания проблемы с защищенным методом

Я читаю Sybex Полный апрель 2005 Java 2 Учебника Сертификации (ISBN0782144195). Эта книга для Java-разработчиков, кто хочет передать сертификацию Java.

После главы о модификаторах доступа (наряду с другими модификаторами) я нашел следующий вопрос (#17):

TRUE или FALSE: Если класс Y расширяет класс X, эти два класса находятся в различных пакетах, и класс X имеет защищенный метод, названный abby (), то любой экземпляр Y может назвать abby () методом любого другого экземпляра Y.

Этот вопрос смутил меня немного.

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

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

Но вопросы ничего не говорят о типе переменной, только о типе экземпляра.

Я был смущен немного и ответил "верный".

Ответ в книге

Ложь. Объект, который наследовал защищенный метод от суперкласса в другом пакете, может назвать тот метод на себе, но не на других экземплярах того же класса.

Нет ничего здесь о типе переменной, только о типе экземпляра.

Это очень странно, я не понимаю это.

Кто-либо может объяснить, что продолжается здесь?

9
задан Mark Elliot 12 February 2010 в 09:29
поделиться

6 ответов

Истинно или ложно: Если класс Y расширяет класс X, эти два класса находятся в разных пакетах, а класс X имеет защищенный метод abby(), то любой экземпляр Y может вызвать метод abby() любого другого экземпляра Y.

"Ложь. Объект, который наследует защищенный метод от суперкласса из другого пакета, может вызывать этот метод на себе, но не на других экземплярах того же класса".

Давайте запишем это, как это сделал BalusC, и добавим к Y метод, который вызывает abby() любого другого экземпляра Y:

package one;
public class X {
    protected void abby() {
    }
}

package other;
import one.X;
public class Y extends X {
    public void callAbbyOf(Y anyOther) {
        anyOther.abby();
    }
}

Для Y возможно вызвать метод abby() любого экземпляра Y на который у него есть ссылка. Таким образом, ответ в книге вопиюще неверен. Java не имеет специфичных для экземпляра областей видимости (в отличие, например, от Scala, у которой есть область видимости instance-private).

Если попытаться быть милосердным, возможно, вопрос подразумевал, говоря "любой другой экземпляр Y", что он может получить доступ к методу любого экземпляра Y, который находится в памяти - что невозможно, потому что Java не имеет прямого доступа к памяти. Но в таком случае вопрос настолько плохо сформулирован, что вы даже можете ответить: "Ложь. Вы не можете вызывать методы на экземплярах, которые находятся на другой JVM, или на экземплярах, которые были собраны в мусор, или на экземплярах на JVM, которая умерла год назад и т.д."

.
2
ответ дан 3 November 2019 в 08:20
поделиться

Верно или неверно: если класс Y расширяет класс X, два класса находятся в разных пакетах, а класс X имеет защищенный метод abby (), тогда любой экземпляр Y может вызвать метод abby () любого другого экземпляра. Ю.

Изобразим это.

Класс X:

package one;
public class X {
    protected void abby() {}
}

Класс Y:

package other;
public class Y extends X {}

Тестовый пример:

public static void main(String[] args) {
    Y y1 = new Y();
    Y y2 = new Y();
    Y y3 = new Y();
    // ...
}

Теперь перечитайте вопрос: может ли y1 вызвать abby () на y2 ], y3 и т. Д.? Будет ли вызов abby () на y1 также вызывать вызовы y2 , y3 и т. Д.?

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

0
ответ дан 3 November 2019 в 08:20
поделиться

Потому что тип переменной здесь не имеет значения, пока он не станет «разумным» в контексте вопроса. Поскольку метод abby () принадлежит X Y наследует его), не имеет значения, с какой переменной типа объявляется ссылка на экземпляр Y: это может быть либо X , либо Y . Чтобы быть доступным abby () , мы могли бы вызвать его через обе переменные:

X myY1 = new Y();
myY1.abby();

Y myY2 = new Y();
myY2.abby();
0
ответ дан 3 November 2019 в 08:20
поделиться

Из Спецификация языка Java :

6.6.2.1 Доступ к защищенному члену

Пусть C будет классом в который объявлен защищенным членом m. Доступ разрешен только в теле подкласса S класса C. Кроме того, если Id обозначает поле экземпляра или метод экземпляра, то:

  • Если доступ осуществляется по квалифицированному имени Q.Id, где Q - это ExpressionName, тогда доступ разрешен тогда и только тогда, когда тип выражения Q - S или подкласс S.
  • Если доступ осуществляется с помощью выражения доступа к полю E.Id, где E - это первичное выражение, или с помощью метода выражение вызова E.Id (...), где E - это первичное выражение, тогда доступ разрешен тогда и только тогда, когда тип E - S или подкласс S.

Таким образом, защищенный член доступен во всех экземпляров S, и ответ в вашей книге просто неверен.

1
ответ дан 3 November 2019 в 08:20
поделиться

Этот вопрос кажется плохо сформулированным - и спрашивает о очень редкий крайний случай (я даже не уверен, что он покрыт тестом SCJP). Его формулировка делает ваш ответ правильным, а данный ответ - неправильным. Кодирование аналогичной конструкции и ее запуск легко доказывают это ...

package inside;

public class Base {

    private String name;

    public Base(String name)  {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    protected String abby(String name) {
        String old = this.name;
        this.name = name;
        return old;
    }
}




package outside;
import inside.Base;

public class Another extends Base {

    public Another(String name) {
        super(name);
    }

    public String setAnother(Another another, String hack) {
        return another.abby(hack);
    }

    public static void doCrazyStuff() {
        Another one = new Another("one");
        Another two = new Another("two");

        one.abby("Hi one"); 
        two.abby("Hi two");
        one.setAnother(two, "Hi two from one");

        System.out.println("one = " + one.getName());
        System.out.println("two = " + two.getName());

    }

    public static void main(String[] args) {
        Another.doCrazyStuff();
    }
}
0
ответ дан 3 November 2019 в 08:20
поделиться

Я почти уверен, что вопрос имел в виду:

«любой экземпляр Y может вызывать метод abbey () любого другого экземпляра X "(не Y).

В этом случае он действительно потерпит неудачу. Чтобы позаимствовать пример из другого ответа, приведенного выше, следующее:

package one;
public class X {
    protected void abby() {
    }
}

package other;
import one.X;
public class Y extends X {
    public void callAbbyOf(X anyOther) {
        anyOther.abby();
    }
}

не скомпилируется.

Спецификация языка Java объясняет, почему здесь: http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.6.2

6.6.2.1 Доступ к protected Member

Пусть C будет классом, в котором объявлен защищенный член m. Доступ разрешен только в теле подкласса S класса C. Кроме того, если Id обозначает поле экземпляра или метод экземпляра , то: Если доступ осуществляется по квалифицированному имени Q.Id, где Q - это ExpressionName, тогда доступ разрешен тогда и только тогда, когда тип выражение Q является S или подклассом S. Если доступ осуществляется посредством выражения E.Id доступа к полю, где E является первичным выражением, или посредством вызова метода выражение E.Id (...), Где E - это первичное выражение, тогда доступ разрешен тогда и только тогда, когда тип E {{ 1}} - это S или подкласс S. (выделено мной).

0
ответ дан 3 November 2019 в 08:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: