How are java.lang.Object's protected methods protected from subclasses? - java

The keyword protected grants access to classes in the same package and subclasses (http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html).
Now, every class has java.lang.Object as superclass (http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html).
Hence I conclude that every class may access java.lang.Object's methods even if they are protected.
Take a look at the following example:
public class Testclass {
public Object getOne() throws CloneNotSupportedException {
return this.clone();
}
public Object getTwo() throws CloneNotSupportedException {
return ((Object) this).clone();
}
}
While getOne() compiles fine, getTwo() gives
Testclass.java:6: clone() has protected access in java.lang.Object
return ((Object) this).clone();
I neither understand why getTwo() doesn't compile nor what's the difference (regarding the access of java.lang.Objects members) with getOne().

You can only access protected members of a type in a different package if the compile-time type of the expression you're referencing it through is either your own class or a subclass. (Where "your" class is the class containing the code.) Your own class has to be a subclass of the type which originally declares the method, too.
Here's an example; assume that Base is in a different package to all the other classes:
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 {}
In other words, it's letting you have access to the protected members of "objects which are a like you".
Details are in section 6.6.2 of the Java Language Specification:
A protected member or constructor of
an object may be accessed from outside
the package in which it is declared
only by code that is responsible for
the implementation of that object.
6.6.2.1 Access to a protected Member
Let C be the class in which a
protected member m is declared. Access
is permitted only within the body of a
subclass S of C. In addition, if Id
denotes an instance field or instance
method, then: If the access is by a
qualified name Q.Id, where Q is an
ExpressionName, then the access is
permitted if and only if the type of
the expression Q is S or a subclass of
S. If the access is by a field access
expression E.Id, where E is a Primary
expression, or by a method invocation
expression E.Id(. . .), where E is a
Primary expression, then the access is
permitted if and only if the type of E
is S or a subclass of S.

When you said "((Object) this).clone()", you accessed your own object via its superclass Object. You performed a widening conversion to an Object. The code then attempts to call clone on Object.
But, as you've noted, clone is a protected method, meaning that only if your object was in the same package of java.lang would it be able to access the OBJECT's clone method.
When you say this.clone, your class extended Object and thus had access to override or use clone directly through the protected class modifier because of inheritance. But that doesn't change the Object implementation.
By saying ((Object) yourObject), you get something that is only accessible through the Object class. Only public methods of the Object class are accessible ouside of the package java.lang, so you get the compile-time exception, because the compiler knows this.
By saying this.clone(), you are invoking your object's clone method that it got through inheriting through Object, and is now able to be invoked because it becomes a part of your custom subclass.

The difference is how you are accessing Object.clone(). clone is only accessible when accessed via a sub class or class in the same package. In the getOne() example you are claling this.clone(). This clearly satisfies access from within a sub class.
In getTwo() though you are acessing Object.clone() and not TestClass.clone(). In order for this to work you must have package level access to Object which you don't and hence the error.

Related

range of protected method "subclass" means

Suppose "class A2" and p"ublic class A" are in the A.java file,
and class B is in a different package than A.java.
This is Class B
public class B {
protected void protectedMethod() {
}
}
And below is A.java File
class A2 extends B {
void tFunc() {
protectedMethod();
}
public class A extends A2 {
void tFunc1() {
protectedMethod(); // OK
A2 a2 = new A2();
a2.protectedMethod(); // Compile Error
why can a2.protectedMethod() not compile??
I understand protected can be called if it is an inheritance relationship,
but why does a compilation error occur when A inherits A2 and A2 inherits B?
Because the language spec says so.
See 6.6.2.1. Access to a protected Member
Let C be the class in which a protected member is declared. Access is permitted only within the body of a subclass S of C.
A subclass S is regarded as being responsible for the implementation of objects of class C. Depending on C's accessibility, S may be declared in the same package as C, or in different package of the same module as C, or in a package of a different module entirely.
In addition, access to an instance field or instance method is permitted based on the form of the qualified name, field access expression (§15.11), method invocation expression (§15.12), or method reference expression (§15.13):
If the access is by (i) a qualified name of the form ExpressionName.Id or TypeName.Id, or (ii) a field access expression of the form Primary.Id, then access to the instance field Id is permitted if and only if the qualifying type is S or a subclass of S.
The qualifying type is the type of the ExpressionName or Primary, or the type denoted by TypeName.
See also:
The True Meaning of private and protected if you find standardese hard to read:
Inside a package, the true meaning of the protected keyword is quite simple. To classes in the same package, protected access looks just like package access. Any class can access any protected member of another class declared in the same package.
When you have subclasses in other packages, however, the true meaning of protected becomes more complex. Take a look at the inheritance hierarchy shown in Figure 5-5. In this hierarchy, class Cup, which is declared in the com.artima.vcafe.dishes package, declares a protected instance method named getSize(). This method is accessible to any subclasses declared anywhere, including those shown declared in package com.artima.other. Any objects whose class descends from Cup--instances of class CoffeeCup, CoffeeMug, EspressoCup, or TeaCup-- can invoke getSize() on themselves. Whether they can invoke getSize() on a reference to another object, however, depends upon where that other object sits in the inheritance hierarchy.
package A;
public class Cup {}
package B;
public class TeaCup extends Cup {}
public class CoffeeCup extends Cup {}
public class CoffeeMug extends CoffeeCup {}
public class EspressoCup extends CoffeeCup {}
If a protected instance variable or instance method is accessible to a class, that class can access the protected member through a reference only if the reference type is the class or one of its subclasses. For example, for code in the CoffeeCup class to invoke getSize() on a reference to another object, that reference must be of type CoffeeCup or one of its subclasses. A CoffeeCup object could therefore invoke getSize() on a CoffeeCup reference, a CoffeeMug reference, or an EspressoCup reference. A CoffeeCup object could not, however, invoke getSize() on a Cup reference or a TeaCup reference.
If class has a protected variable or method that is static, the rules are different. Take as an example the protected static method getCupsInUse() declared in class Cup as shown in Figure 5-5. Any code in a subclass of Cup can access a getCupsInUse() by invoking it on itself or invoking it on a reference of type Cup or any of its subclasses. Code in the EspressoCup class could invoke getCupsInUse() on itself or on a reference of type Cup, CoffeeCup, CoffeeMug, EspressoCup, or TeaCup.
Protected method can be used in context Class A by writing
super.protectedMethod()
Creating new instance of A2 in A class breaches the rule that protected methods cannot be accessed from different packages.

Implicit conversion of super keyword in toString() method to super.toString() not happening

I have the following two classes as shown below. For the sake of simplicity,
only toString overridden method is shown .
public class Circle {
#Override
public String toString() {
return "Circle";
}
}
public class Cylinder extends Circle {
#Override
public String toString() {
// return "Cylinder"+this; // runs without explicitly calling toString() on this keyword
// return "Cylinder"+super; // throws error, asks to delete super token
return "Cylinder["+super.toString(); // runs without error after adding .toString() with super keyword
}
}
The issue i am having is in my understanding of super keyword . The toString() of super keyword should be invoked implicitly as is in the case of this keyword .In fact most of the tutorials and books refer to super keyword as a kind of an object reference to a super class and so it must behave same as this keyword when used with "+" concatenation operator inside toString(). Please help me in understanding this.
The super keyword in Java is not an object reference, unlike this.
this is used as a reference to the calling object.
But, There's no reference-id which can be stored in super
super is a keyword which is used to RESOLVE the parent CLASS, its methods and data members.
So, you can't print the value of super keyword. You can only access methods and members of parent class using super keyword.
this
super
Expressions
In Java, super keyword is used in two places.
The constructor of a subclass.
In a overridden method of a subclass.
When used in the constructor, super() must be called on the first line. If you are calling another constructor overload, you must call this() on the first line of that constructor as well.
A constructor without parameter (i.e. default constructor) does not need to call super() if the parent also has a default constructor. This is because the compiler actually does it for you, so it's still there.
When used in an overridden method, you are calling the parent implementation of the method. You cannot call super() because that is for parent constructor; you call via super.foo(). Unlike super(), you must explicitly call this. If you override a method and have empty implementation, then that method does nothing.
Furthermore, super.foo() can be used not only in an overridden method. Also, you need not call the same method as the method you are overriding. For example, this is allowed:
public void foo() {
System.out.println(super.toString());
}
Although this is allowed, it is more common to call this.toString() in this case. This can be used if your class has overridden toString() and you do want the original implementation.
Lastly, super keyword cannot be used on its own. It is always in a form super() or super.method().
Example:
public class Base {
#Override public String toString() {
return "Base";
}
}
public class Sub extends Base {
public void foo() {
System.out.println(super.toString());
System.out.println(this.toString());
}
#Override public String toString() {
return "Sub";
}
}
public class Test {
public static void main(String[] args) {
Sub sub = new Sub();
sub.foo();
}
}
Output:
Base
Sub
As Louis mentioned in the comment super is not a normal object. It is a special case.
According to java spec
The forms using the keyword super are valid only in an instance method, instance initializer, or constructor, or in the initializer of an instance variable of a class. If they appear anywhere else, a compile-time error occurs.
According to the Java Language Specification §15.11.2 and §15.12.1,
Accessing Superclass Members using super
The form super.Identifier refers to the field named Identifier of the
current object, but with the current object viewed as an instance of
the superclass of the current class.
The form T.super.Identifier refers to the field named Identifier of
the lexically enclosing instance corresponding to T, but with that
instance viewed as an instance of the superclass of T.
...
Compile-Time Step 1: Determine Class or Interface to Search (in a method invocation expression)
If the form is super.[TypeArguments]Identifier, then the class to search is the superclass of the class whose declaration contains the method invocation.
It only mentions two forms of the super expression - either super.Identifier or T.super.Identifier. You are using neither of these forms. You are using super as if it were this, as if it were some kind of variable that you can use on its own. This is not true, super behaves very differently from this.
If you compare how the spec describes this:
§15.8.3 this
The keyword this may be used only in the following contexts:
in the body of an instance method or default method (§8.4.7, §9.4.3)
in the body of a constructor of a class (§8.8.7)
in an instance initializer of a class (§8.6)
in the initializer of an instance variable of a class (§8.3.2)
to denote a receiver parameter (§8.4.1)
As you can see, this means that this can be used on its own. super cannot.
In addition, an expression like "Cylinder"+super is less readable than "Cylinder"+suer.toString(). Don't you think? And by the way, return "Cylinder"+this; will probably cause infinite recursion.

Inheritance Java private members

i have been going through Inheritance in java. My question is if private members are not inherited how come they end up in memory. Is there something going on internally to resolve this issue or they are just hidden/un accesible wihout public member function of the parent class.
here is java doc
"A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.
A nested class has access to all the private members of its enclosing class—both fields and methods. Therefore, a public or protected nested class inherited by a subclass has indirect access to all of the private members of the superclass."
They are in memory, but you don't have access to them.
Example:
class A
{
private int foo;
public int getFoo( ) { return foo; }
...
}
class B extends A
{
...
}
Every instance of class B does, in fact, contain an integer foo under the hood.
But, you cannot access it directly, because it is declared private. You can access it indirectly, via the getFoo method, because that one is public.
Your object has Class reference in it. Your object's Class had parent Class reference in it. That's why private methods are still in memory - they're referenced by parent class.
They are just inaccessible normally, you can access them with e.g. Method.setAccessible(). You can get Method's by reflection on parent Class.

Interfaces and Abstract Classes in Java

Does interfaces and abstract classes in Java extend base Object class? Logical answer which I can think of is no, but if interface does not extend Object class, then can please someone explain me the below code:
interface A {
#Override
public int hashCode();
#Override
public String toString();
}
In above case, A interface is the new interface declared. Yet, no class is implementing it. Then how come the methods from Object class visible in the interface?
If it doesn't extend Object class, then why I can't declare following method in the interface:
public Class getClass();
When I tried to declare this method in the interface, it says that it can't override this method, inherited from Object class, as it is declared as final method in Object class.
Interface could only extend some other interface and no - there is no some root interface. Abstract class, as any other class in Java, has Object as its ancestor - while it may not be a direct parent.
Methods, marked as final, could not be overriden in successor classes. As your class has Object as its ancestor - this rule also applies here.
The reason this is can be found in JLS $9.2
If an interface has no direct superinterfaces, then the interface implicitly declares a public abstract member method m with signature s, return type r, and throws clause t corresponding to each public instance method m with signature s, return type r, and throws clause t declared in Object, unless a method with the same signature, same return type, and a compatible throws clause is explicitly declared by the interface.
It is a compile-time error if the interface explicitly declares such a method m in the case where m is declared to be final in Object.
And as seen in Object#getClass:
public final Class<?> getClass()
Interfaces do not inherit from Object, but they do mimick the methods available by implicitly adding them. Likewise here, a final method in that base interface can't be overridden in your self-defined interface.

Why do interfaces extend Object, according to the class file format?

Why does the JVM specification state that interfaces must have a super_class of java/lang/Object, even though interfaces do not extend java/lang/Object?
I'm specifically referring to §4.1 of the JVM spec, where it says:
For an interface, the value of the super_class item must always be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure representing the class Object.
yet in §9.2 of the JLS, it says that interfaces do not extend Object. Instead a implicitly created abstract method is declared which matches each public method in the Object class:
If an interface has no direct superinterfaces, then the interface implicitly declares a public abstract member method m with signature s, return type r, and throws clause t corresponding to each public instance method m with signature s, return type r, and throws clause t declared in Object, unless a method with the same signature, same return type, and a compatible throws clause is explicitly declared by the interface.
As mentioned in §9.2 :
If an interface has no direct superinterfaces, then the interface
implicitly declares a public abstract member method m with signature
s, return type r, and throws clause t corresponding to each public
instance method m with signature s, return type r, and throws clause t
declared in Object, unless a method with the same signature, same
return type, and a compatible throws clause is explicitly declared by
the interface.
Hence , we see that , Although an interface having no direct superinterface doesn't explicitly extends Object but still it has a link with Object class internally as it is used by the compiler to insert abstract methods with same signature and return type and throws clause as that of public methods in Object class, within the interface. That's why For an interface, the value of the super_class item must always be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure representing the class Object. This is the reason that an interface reference variable can successfully call public instance methods for example toString() method of Object . For example, consider the code given below:
interface MyInterface
{}
public class InterfaceTest implements MyInterface
{
public static void main(String[] args)
{
MyInterface mInterface = new InterfaceTest();
System.out.println(mInterface.toString());//Compiles successfully. Although toString() is not declared within MyInterface
}
}
The above code compiles successfully even though toString() method (Which is the method of Object) is not declared within MyInterface. Above code is providing following output on my System:
InterfaceTest#1ba34f2
The output may vary from system to system..
What you see in the JVM spec is basically the concrete implementation of the behavior specified by the JLS - just like classes implement interfaces and have implementation details.

Categories

Resources