Подтвердить что ты не робот

Как защищенные методы java.lang.Object защищены от подклассов?

Ключевое слово 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) с getOne().

4b9b3361

Ответ 1

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

Вот пример; предположим, что 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 - класс, в котором a защищенный член m. доступ разрешается только в теле подкласс S of C. Кроме того, если Id обозначает поле экземпляра или экземпляр метод, то: Если доступ осуществляется посредством квалифицированное имя Q.Id, где Q - ExpressionName, тогда доступ разрешено тогда и только тогда, когда тип выражение Q является S или подклассом S. Если доступ осуществляется путем доступа к полю выражение E.Id, где E является основным выражение или путем вызова метода выражение E.Id(...), где E - Первичное выражение, то доступ разрешено тогда и только тогда, когда тип E является S или подклассом S.

Ответ 2

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

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

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

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

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

Ответ 3

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

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