Как защищенные методы java.lang.Object защищены от подклассов? - PullRequest
12 голосов
/ 16 января 2009

Ключевое слово protected предоставляет доступ к классам в одном пакете и подклассам (http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html).

Теперь каждый класс имеет java.lang.Object как суперкласс (http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html).

Следовательно, я заключаю, что каждый класс может обращаться к методам java.lang.Object, даже если они protected.

Взгляните на следующий пример:

public class Testclass {
  public Object getOne() throws CloneNotSupportedException {
    return this.clone();
  }
  public Object getTwo() throws CloneNotSupportedException {
    return ((Object) this).clone();
  }
}

В то время как getOne() компилируется нормально, getTwo() дает

Testclass.java:6: clone() has protected access in java.lang.Object
        return ((Object) this).clone();

Я не понимаю, почему getTwo() не компилируется, и в чем разница (относительно доступа java.lang.Object s членов) к getOne().

Ответы [ 3 ]

16 голосов
/ 16 января 2009

Вы можете получить доступ к защищенным членам типа в другом пакете, если тип времени выражения, через которое вы ссылаетесь, это ваш собственный класс или подкласс. (Где «ваш» класс - это класс, содержащий код.) Ваш собственный класс должен быть подклассом типа, который также первоначально объявляет метод.

Вот пример; Предположим, что Base находится в другом пакете для всех других классов:

package first;
public class Base
{
    protected void Foo() {}
}

// Yes, each class is really in its own file normally - but treat
// all the classes below as being in package "second"

package second;
public class Child extends Base
{
    public void OtherMethod(Object x)
    {
        ((Base) x).Foo(); // Invalid: Base is not Child or subclass
        ((Child) x).Foo(); // Valid: Child is Child
        ((GrandChild) x).Foo(); // Valid: GrandChild is subclass of Child
        ((OtherChild) x).Foo(); // Invalid: OtherChild is not Child or subclass
    }
}

public class GrandChild extends Child {}
public class OtherChild extends Base {}

Другими словами, он позволяет вам иметь доступ к защищенным членам «объектов, похожих на вас».

Подробности находятся в разделе 6.6.2 спецификации языка Java :

A protected член или конструктор к объекту можно получить доступ снаружи пакет, в котором он заявлен только по коду, который отвечает за реализация этого объекта.

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

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

5 голосов
/ 16 января 2009

Когда вы сказали "((Object) this).clone()", вы получили доступ к своему собственному объекту через его объект суперкласса. Вы выполнили расширенное преобразование в Объект. Затем код пытается вызвать клон на объекте.

Но, как вы заметили, клон - это защищенный метод, означающий, что только если ваш объект находится в том же пакете java.lang, он сможет получить доступ к методу клонирования OBJECT.

Когда вы говорите this.clone, ваш класс расширяет Object и, таким образом, имеет доступ к переопределению или использованию clone напрямую через модификатор защищенного класса из-за наследования. Но это не меняет реализацию объекта.

Говоря ((Object) yourObject), вы получаете что-то, что доступно только через класс Object. Только открытые методы класса Object доступны вне пакета java.lang, поэтому вы получаете исключение времени компиляции, потому что компилятор знает это.

Говоря this.clone (), вы вызываете метод клона вашего объекта, который он получил посредством наследования через Object, и теперь можете его вызывать, поскольку он становится частью вашего пользовательского подкласса.

1 голос
/ 16 января 2009

Разница в том, как вы обращаетесь к Object.clone (). Клон доступен только при доступе через подкласс или класс в том же пакете. В примере getOne () вы используете clal this.clone (). Это явно удовлетворяет доступ из подкласса.

В getTwo (), хотя вы работаете с Object.clone (), а не TestClass.clone (). Чтобы это работало, у вас должен быть доступ уровня объекта к объекту, который у вас отсутствует, и, следовательно, ошибка.

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