This question already has answers here:
Do subclasses inherit private fields?
(21 answers)
Closed 4 years ago.
I did a little bit of research to know if private instance fields and methods are inherited by a subclass from its superclass.
Actually, I red on different forums contradictory answers but the most convincing one was that, like the java documentation tells, private fields and methods are never inherited BUT that instances of the subclass allocate some memory for the private fields and methods of the superclass.
However, on my most reliable source of documentation, which is the book "java in a nutshell 6th edition" it is said :
This existence of potentially inaccessible members seems to be in conflict with the statement that the members of a class are always accessible within the body of the class. To clear up this confusion, we define “inherited members” to mean those superclass members that are accessible.
Then the correct statement about member accessibility is: “All inherited members
and all members defined in this class are accessible.” An alternative way of saying
this is:
• A class inherits all instance fields and instance methods (but not constructors)
of its superclass.
• The body of a class can always access all the fields and methods it declares
itself. It can also access the accessible fields and members it inherits from its
superclass.
So according to my understanding I came to the conclusion that a subclass inherits ALL fields and methods (including the private ones) from its superclass, but somehow the body of the subclass cannot access the private (and eventually other invisible) members of the superclass.
If I understood well what the book says, isn't that contradictory with what the java documentation tells - that private members are not even inherited -?
Or did I just missed something while reading the book?
Whether a member is inherited or not is primarily relevant to lookup procedures. If e.g. a class B extends A, when the language specification says that private members are not inherited, what this means is that the private members of A only belong to instances of B while viewing them as an A.
The classic example of this looks something like this:
class B extends A {}
class A {
private void m() {}
public static void main(String[] args) {
B b = new B();
b.m(); // error: "cannot find symbol"
A a = b;
a.m(); // fine: m() is a member of A
}
}
There is indeed a method m() which we can call on the instance of B, but the method lookup procedure fails to find it unless we're viewing the B as an A.
With private fields, the in-memory representation of an object will include the private fields of its superclasses, even though we say they are not inherited in JLS terms.
Some further clarifications here are in §8.2:
Members of a class that are declared private are not inherited by subclasses of that class.
Only members of a class that are declared protected or public are inherited by subclasses declared in a package other than the one in which the class is declared.
As well as in §8.3:
A class inherits from its direct superclass and direct superinterfaces all the non-private fields of the superclass and superinterfaces that are both accessible to code in the class and not hidden by a declaration in the class.
A private field of a superclass might be accessible to a subclass - for example, if both classes are members of the same class. Nevertheless, a private field is never inherited by a subclass.
(§8.4.8 also has similar rules for methods.)
These clarify that inheritance does have something to do with accessibility, but there's not a strict 1:1 correspondence. For example, in the following, the field x is accessible to, but not inherited by class B (per §8.3 above):
class Outer {
static class A {
private int x;
}
static class B extends A {
B() {
super.x = 1; // accessible, but must be qualified
}
}
}
One way to put this is that accessibility is a necessary, but not sufficient, condition for inheritance. (In other words, inheritance requires accessibility, but not vice versa.)
Colloquially, it's probably correct to say that private members are inherited, in the sense that 1) a subclass object stores the private variables of its superclasses and 2) the private methods of the superclasses can be invoked on a subclass instance. This is, however, not how the JLS is using the word.
Consider
class A {
private int x;
public A() {
x = 10;
}
public int foo() {
return x * 2;
}
}
public class B extends A {
public B() {
super(); // Calls A's constructor assigning x.
// anything
}
}
int n = B().foo(); // n == 20
It is apparent that an instance of B does carry the member x, with its value. If B did not do so, it could not run the inherited method foo, because that method's implementation in A needs the value of x.
Indeed, B cannot directly access x. But as long as it has any methods that (transitively) depend on that value, via inheritance from A, it must allocate storage for x.
In other words, B is A with something added. Nothing can be removed by inheritance. It can only be made invisible, it it was private. But it's still there, not gone.
Related
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.
Here's an interesting code snippet:
public class Superclass {
public static void main (String[] args){
Superclass obj = new Subclass();
obj.doSomething(); #prints "from Superclass"
}
private void doSomething(){System.out.println("from Superclass");}
}
class Subclass extends Superclass {
private void doSomething(){System.out.println("from Subclass");}
}
I know that subclasses do not inherit the private members of its parent, but here obj manages to call a method to which it should have no access. At compile time obj is of type Superclass, at runtime of type Subclass.
This probably has something to do with the fact that the call to doSomething() is taking place inside the driver class, which happens to be its own class (and why it's possible to invoke doSomething() in the first place).
So the question boils down to, how does obj have access to a private member of its parent?
Private methods are only for the owner.
Not even for the kids, relatives or friends of the owner.
You answered it yourself. As the private methods are not inherited, a superclass reference calls its own private method.
It works because you are casting to a Superclass from within a method of the Superclass. In that context, Superclass.doSomething is available to the compiler.
If you were to change your super and subclasses to two different arbitrary classes A and B, not related to the class containing the main method, and try the same code, the compiler would complain about not having access to the method.
Superclass obj = new Subclass();
At this point, obj is both things, a Subclass, and a Superclass object. The fact that you use Superclass in the declaration of the variable is just a matter of casting it.
When you do: obj.doSomething(), you are telling the compiler to call the private method doSomething() of obj. Because you are doing it from the main static method inside Superclass, the compiler can call it.
If you would use the main method of Subclass rather than the one in Superclass, you would not be able to access that method because, as you said, it's neither inherited nor a part of your definition of Subclass.
So basically you understood inheritance correctly. The problem was related to the visibility of private methods.
When you used this line:
Superclass obj = new Subclass();
You casted Subclass into a Superclass Object, which uses only the methods of the Superclass and the same data. If you casted it back into a Subclass, you could use the Subclass methods again, like so:
((Subclass)obj).doSomething(); #prints "from Subclass"
Since the reference type of the object obj is SuperClass, a call to doSomething() tries to access the private method defined in SuperClass itself (private methods cannot be overridden).
As doSomething() is accessible within SuperClass, the main method can call doSomething() without giving any error/s.
Hope this helps! :-)
why it's possible to invoke doSomething() in the first place?
Why not? obj is an instance both of Subclass and Superclass, and as doSomething() is declared in Superclass and obj is used in it, so you've access to Superclass.doSomething(), you may try to rename your method (to e.g.: doAnotherThing()) and you'll still have access to it.
how does obj have access to a private member of its parent?
There is no parent/child for a private method, and as obj is also a type of Superclass, so it has access to all private methods/fields declared within it, because obj is used in this class. You will lose this access privilege if you're outside of Superclass or of a class that has Superclass as a member (nested class).
So What?
There is no relation/inheritance between SuperClass's private methods and SubClass's private methods, even they have the same name and signature, from Java Language Specification, Java SE 8 Edition:
A private method and all methods declared immediately within a final
class (§8.1.1.2) behave as if they are final, since it is impossible
to override them.
To understand this question you can relate private method to member variable of super class and sub class.
So we know member variable is not going to be overridden in sub class.
For example:
Class A{
int i = 10;
}
Class B extends A{
int i = 11;
}
Class C extends A {
int i = 12;
}
A a1 = new B();
print(a1.i) // Will print 10
A a2 = new B();
print(a2.i) // Will print 10
Similar way when there is no inheritance reference variable super class is going to be considered.
When we define a private method with the same name in the derived class, it becomes a new method as derived class don't inherit the private members.
Since the private method is not even visible outside the class, we can never call a base class private method from a derived class, it will throw a compilation error:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method aPrivateMethod() from the type Base is not visible
We can use down casting to the parent class reference to call the derived class private method, which can only be accessed in that derived class.
I know that in Java you can access a private member of a superclass in the subclass as long as the superclass provides a public or protected getter method. I also know however that the subclass does not actually inherit the private member. Considering the following scenario....
Class A {
private var = 2;
protected int getVar(){
return var;
}
}
Class B extends A{
public void printVar(){
System.out.println(getVar());
}
}
Class Main{
public static void main(args []){
B b= new B();
b.printVar();
}
}
I want to understand, since we are creating an instance of the subclass B, what exactly and when is that private member allocated to memory, and what is it's scope? How does it even exist since an instance of A was actually never created? It's not a static variable, or final so is it stack dynamic or implicitly heap dynamic? I thought that when you instantiate a subclass from a super class you inherit the members that aren't private and methods as well and then those get instantiated as part of an object instance of the sub class (unless they're overridden etc), so there is only one object allocated as a heap dynamic variable. But if these private members are not inherited then does the compiler simply provide a stack dynamic reference to them in case the inherited getter method is invoked and only in that case?
Your assumption that the private members of the super-class are not inherited by the sub-class is wrong. All members are inherited. The private members of the sub-class are part of the sub-class instance, but they can't be accessed directly by the code of the sub-class.
Having a protected getter in the super-class that returns the value of the private member gives the sub-class a means to access the value of the private member (though it can't modify it, unless you also have a protected or public setter in the super-class).
I also know however that the subclass does not actually inherit the private member.
Yes it does. An instance of B is an instance of A, and it contains all the same fields. You don't have direct access to the private fields anymore, but they still exist.
How does it even exist since an instance of A was actually never created?
When you create B, a constructor in A is called as well, which makes sure that the B instance is correctly initialized as a valid A. Don't think of a subclass as something different than it's superclass. A B is still an A; it just does more.
How can I create a member that should be available only to my sub classes in java ?
static class XX {
private static int p = 10; //p is only accessible to TT
static class TT {
static public int getT() {
return p;
}
}
}
Assuming your child classes are subclasses, any public variable is accessible to them. If you wish to access private variables from a subclass, than you have to change them to protected.
Assuming that when you say "variable", you are talking about a member of some class. E.g.,
class Parent {
SomeType myVariable;
...
}
Assuming that when you say my child classes, you are talking about the extends relationship in Java. E.g.,
class Child extends Parent {
...
}
In that case, you can't have exactly what you ask for, but maybe you can have what you need.
If you declare the member to be protected, then it will be visible in any child class, but it will also be visible in any other class that belongs to the same package, regardless of whether the other class is a child or not.
class Parent {
protected SomeType myVariable;
...
}
IMO, there's not much use for protected. It serves as a suggestion that other programmers should not try to use it in a class that does not inherit from the parent, but so what?
If you see a private member in some class, then you are assured that no code outside of the source file where you see it can possibly depend on it.
If you see a member with default access (i.e., neither public, nor private, nor protected), then you know that any code that depends on it must be declared in the same package. Nothing prevents some other programmer somewhere in the world from declaring his own code in your package, but if he/she does, then she or he is being stupid, and when you release a new version that breaks his/her application, that's not your problem.
If you see a member with public or protected access, then you have to assume that people you don't know, and people you will never meet are depending on you to not change it.
This is a follow-up to the question: "java access modifiers and overriding". The former generally deals with Java methods however. Why the flexibility with Java fields? We can narrow or widen the visibility with their respect in an inherited class whereas can't with an 'overridden' nor 'hidden' method.
You never override fields to start with - you're always hiding them. Fields aren't polymorphic... in other words, if you write:
Superclass x = new Subclass();
System.out.println(x.field);
and both Superclass and Subclass declare a field called field, it will always use the superclass one anyway, because that's all the compiler can "see".
Personally I try to keep my variables private anyway...
why the flexibility with java fields
You cannot make a field in another class go private by extending it. When you make a new field in a sub class you are just hiding the super class field.
class Base {
protected int x;
}
class Ext extends Base {
private int x; // not the same as Base.x
}