• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Access Modifiers in base and derived class and changing output

 
shweta patiljadhav
Ranch Hand
Posts: 48
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello,

While using
Y. Daniel Liang
book ,
I came across this code,


even though access modifiers of String getInfo() are private , out put is coming ,
it is Person Person

when I changed access modifier of String getInfo() method in class student to public still output is Person Person , I am not able to debug this code to see flow of execution, so putting this code here,
what is the reason it is giving same out put even though method in student is public?

Thanks is advance
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
shweta patiljadhav wrote:when I changed access modifier of String getInfo() method in class student to public still output is Person Person , I am not able to debug this code to see flow of execution, so putting this code here,
what is the reason it is giving same out put even though method in student is public?

And what happens if you remove the private access modifier of the getInfo() method in both Person and Student classes?
 
shweta patiljadhav
Ranch Hand
Posts: 48
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Roel,
Then it will five output as
Person
Student

because then access modifier will be default
 
Steffe Wilson
Ranch Hand
Posts: 165
12
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I believe the key point here is that a private method cannot be overridden.

So in your original code:

the inherited printPerson() method invokes its local Person version of getInfo() not the Student version.

(I'm learning this stuff too so hopefully Roel or someone else will confirm?)
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
shweta patiljadhav wrote:Then it will five output as
Person
Student

Exactly! And can you explain why changing the access modifier of both methods changes the output?
 
Paweł Baczyński
Bartender
Posts: 1879
35
Firefox Browser IntelliJ IDE Java Linux Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Welcome to the Ranch, Steffe!
 
shweta patiljadhav
Ranch Hand
Posts: 48
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Roel,

If both methods are private , it still gives output. and it is Person Person....so it gives out put of class person only and not of class student...as private methods can't be overriden(??)
and when both are public, both methods are accessible so it gives out put as Person Student...is it?
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
shweta patiljadhav wrote:If both methods are private , it still gives output. and it is Person Person....so it gives out put of class person only and not of class student...as private methods can't be overriden(??)
and when both are public, both methods are accessible so it gives out put as Person Student...is it?

Exactly! Only methods which are inherited, can be overridden. Let's have a look at this codeBoth getInfo() methods are private and as you know, private methods can not be inherited. So private methods can never be overridden. The printPerson() is public, so this method is inherited by the Student class. So when you execute new Student().printPerson(); it simply executes the printPerson() in the Person class and because the getInfo() method is private in class Person, this method can not be overridden and is always executed. That's why the code prints Person twice.

Now when you make both getInfo() methods package-private (or protected or public) as in this code snippetthe getInfo() method in the Person class is overridden in the Student class. So when you execute new Student().printPerson();, it still executes the printPerson() in the Person class. But because the actual object IS-A Student, the getInfo() method of the Student class is executed (= polymorphism). And that's why the code prints Person and Student this time.

Hope it helps!
Kind regards,
Roel
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Steffe Wilson,

First of all, a warm welcome to CodeRanch!

Steffe Wilson wrote:I believe the key point here is that a private method cannot be overridden.

You are absolutely spot-on!

Steffe Wilson wrote:(I'm learning this stuff too so hopefully Roel or someone else will confirm?)

I just did

Hope it helps!
Kind regards,
Roel
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Now let's see if you have fully understood the above. It's time for one of my famous pop quizzes

What's the result of this code?
 
Steffe Wilson
Ranch Hand
Posts: 165
12
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel, thanks for the welcome and for your help.
I don't want to gatecrash the OP's thread so I shall leave it to shweta respond to your pop quiz.

However just to add to the discussion, and hopefully this may help shweta as well as myself, let's walk through some of the code if we may...

Here's the original code again:

I think we are all fine with understanding the code path for line 3, new Person().printPerson();
So from line 4, we instantiate a Student object and immediately call printPerson().
printPerson() exists in the Student object by virtue of inheritance. Fine.
printPerson now calls getInfo(). This is the hard part!
I understand that the getInfo() method declared by the Student class does not override the Person declaration of getInfo() because the latter is private. Fine.
However BOTH versions of getInfo() still exist in the Student object as far as I understand, so what Java rule dicates that the JVM should give precedence to the Person version of getInfo() instead of the Student version of getInfo() ?
In my earlier post I suggested it might be because the Person version of getInfo() is in the same local scope as printPerson, but to be honest that was a bit of a guess so it would be good to have a proper understanding of this. For instance the JVM might be choosing the Person version of getInfo() because it has to select the most generic (less specialised) version of a method when there is a conflict like this.

TIA.

 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Steffe Wilson wrote:However just to add to the discussion, and hopefully this may help shweta as well as myself, let's walk through some of the code if we may...

No problem! Just have a go...

Steffe Wilson wrote:I understand that the getInfo() method declared by the Student class does not override the Person declaration of getInfo() because the latter is private. Fine.
However BOTH versions of getInfo() still exist in the Student object as far as I understand, so what Java rule dicates that the JVM should give precedence to the Person version of getInfo() instead of the Student version of getInfo() ?

There's a difference between declaring a method and inheriting a method. For example: the Person class defines two methods: getInfo() (private) and printPerson() (public); it inherits a set of methods from the Object class (e.g. toString(), equals() and hashCode()). The Student class defines just one method: getInfo() (private); it inherits the printPerson() method from the Person class and it also inherits the same set of methods from the Object class.

Now if you inherit a method, it only means this method can be invoked; it does not mean that all code required to execute this method is copied into the subclass (aka derived class or child class). And that's probably causing your confusion. So when you invoke new Student().printPerson();, it's the printPerson() defined in the Person class which is executed.

Steffe Wilson wrote:However BOTH versions of getInfo() still exist in the Student object as far as I understand

I know it's the same quote I just have discussed, but it's one of the very, very, very important rules you need to know: a private method can never be inherited. And let's repeat this rule once more: a private method can never be inherited. So the Student class only has one getInfo() method (not 2), the one that's declared in the class declaration returning "Student".

And because third time's a charm, let's repeat that important rule again A private method can never be inherited. Never!

Hope it helps!
Kind regards,
Roel

PS. Do you know the phrase when pigs fly? Java developers could use "when private methods are inherited"
 
Steffe Wilson
Ranch Hand
Posts: 165
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:So the Student class only has one getInfo() method (not 2), the one that's declared in the class declaration returning "Student".

Sure the Student class defines one getInfo() method, but I referred to the Student object.
Does the object have one or two getInfo() methods available to it? And if the answer is one, then which one is it?
I'm trying to narrow this down to try and discover my specific area of misunderstanding.

Thanks!


 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Steffe Wilson wrote:
Roel De Nijs wrote:So the Student class only has one getInfo() method (not 2), the one that's declared in the class declaration returning "Student".

Sure the Student class defines one getInfo() method, but I referred to the Student object.
Does the object have one or two getInfo() methods available to it? And if the answer is one, then which one is it?

You can see the class as the template to create an object (and you can create as many objects as you want). So if your class (template) only has one method, every object will also have only that one method defined in the class (template).

It's like creating donuts: the donut template (class) has one hole in the middle (method), so every donut (object) will have just one hole in the middle (method), not two.
 
Steffe Wilson
Ranch Hand
Posts: 165
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Still something missing ! I'm sure I'll get there though!

You said the class (Student) has only one method getInfo() which returns "Student".
And that class is a template for the student object.
So the student object has only one getInfo() method ... which returns "Student".

So now we instantiate a Student object, we call its (inherited) printPerson() method and printPerson() calls getInfo() and getInfo() returns... "Person".
But we decided above that the only getInfo() method that our student object had was the one that would return "Student"..?

 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Steffe Wilson wrote:So now we instantiate a Student object, we call its (inherited) printPerson() method and printPerson() calls getInfo() and getInfo() returns... "Person".
But we decided above that the only getInfo() method that our student object had was the one that would return "Student"..?

Student does not declare a printPerson() method, so when you invoke the printPerson() of Person. And because getInfo() (in Person) is private, it's impossible this method could be overridden by a subclass, so getInfo() defined in Person is executed. Because the JVM only knows about this getInfo() method, it doesn't know that Student method happens to have a getInfo() method as well. Student could even have no getInfo() method at all and the output would still be the same.
 
shweta patiljadhav
Ranch Hand
Posts: 48
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Roel,

output would be Person Student...as in class person , method is default so it is accessible in same package, so output will be Person....and in class student output will be Student.
even though method is private.
 
Steffe Wilson
Ranch Hand
Posts: 165
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:Student does not declare a printPerson() method, so when you invoke the printPerson() of Person. And because getInfo() (in Person) is private, it's impossible this method could be overridden by a subclass, so getInfo() defined in Person is executed. Because the JVM only knows about this getInfo() method, it doesn't know that Student method happens to have a getInfo() method as well. Student could even have no getInfo() method at all and the output would still be the same.

I have been thinking some more about this problem and I have a different theory now. I now believe the call to getInfo() must be resolved at compile time rather than at runtime.

When javac compiles the Person class it sees that getInfo() is private. As you say, it therefore cannot be overridden. So the compiler knows it can 'hardwire' the getInfo() call within printPerson() to call the Person version of getInfo() because that is the only method of that name that can ever be available for the printPerson() method. It is treated as a local method call... because that is all it is. The fact that there is another method with the same name in the Student class is irrelevant because it is not an override situation, that is an independent method that happens to have the same name. Consequently at runtime there is no decision to be made!

My initial question was how the JVM could choose between the two getInfo()'s - and the answer is it doesn't, the compiler decided at build time.

This explanation makes a lot of sense to me. What do you think?
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
shweta patiljadhav wrote:output would be Person Student...as in class person , method is default so it is accessible in same package, so output will be Person....and in class student output will be Student.
even though method is private.

Wrong! You'll get a compiler error. The overriding method must not have a more restrictive access modifier than the overridden method. So it was a trick question Expect to encounter these questions on the actual exam as well.
 
shweta patiljadhav
Ranch Hand
Posts: 48
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel, oh ! yes , I read this rule that overriding methods should not have more restrictive access modifiers! while implementing it....I was wrong!

Thanks a lot for the question and answer !
 
Venny Ra
Greenhorn
Posts: 15
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:Now let's see if you have fully understood the above. It's time for one of my famous pop quizzes

What's the result of this code?


btw, this won't compile. Cannot reduce the visibility of the inherited method.
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Venny Ra wrote:btw, this won't compile. Cannot reduce the visibility of the inherited method.

True! But you were a little bit too slow
 
Venny Ra
Greenhorn
Posts: 15
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:
Venny Ra wrote:btw, this won't compile. Cannot reduce the visibility of the inherited method.

True! But you were a little bit too slow


Haha. I am happy i could spot the problem. I feel I am ready for the exam now
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Steffe Wilson wrote:This explanation makes a lot of sense to me. What do you think?

Your explanation has a little (but important) flaw. The compiler (javac) has only 1 purpose: validate the written code and make sure every character/statement/line/... is valid. Therefore the compiler has an enormous set of rules and verifies your code against every rule. If the compiler is happy, you get the highly desired .class files (no .class file, no code to run); if the compiler is unhappy, you'll get one (or more) compiler error(s) in your face Once your code is valid and doesn't violate any of the gazillion rules, the compiler provides the .class file(s) and you can run your program. Running your code is the task of the JVM (java). And at that moment, there is no compiler anymore to help the JVM decide which method to invoke.
And here is another very, very, very important rule: The compiler doesn't execute any code! So every compiler error you get, is because the compiler knows something is wrong without executing any line of code. So the compiler doesn't know and care) about the actual objects, the compiler only knows about the types of the reference variables. Consider this code snippetThe compiler only knows that the type of the reference variables p1 and p2 is Person, but it doesn't know that p1 is refering to a Person object and p2 is refering to a Student object. (So that's another reason why the compiler can't "hardwire" the getInfo() method call to the Person object because at compile time objects don't exist, only reference variables (and primitive variables, methods, and so on).

So what's happening at runtime when this code is executedThe JVM checks the Student class for the printPerson() method, but doesn't find this method. Then the JVM goes one level up in the class hierarchy and performs the same check. Student IS-A Person, so the JVM checks the Person class. The JVM finds the printPerson() method and thus executes this method. To be able to invoke the println() method, the JVM requires the return value of the getInfo() method. So the JVM checks the Person class for the getInfo() method. The JVM finds the getInfo() method in the Person class. Then the JVM has a quick glance to the access modifier of this method. Because the getInfo() method is private, the JVM knows there can't be an override of this method (depending on the actual object) and executes the getInfo() method in the Person class.

Hope it helps!
Kind regards,
Roel
 
Steffe Wilson
Ranch Hand
Posts: 165
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:So what's happening at runtime when this code is executedThe JVM checks the Student class for the printPerson() method, but doesn't find this method. Then the JVM goes one level up in the class hierarchy and performs the same check. Student IS-A Person, so the JVM checks the Person class. The JVM finds the printPerson() method and thus executes this method. To be able to invoke the println() method, the JVM requires the return value of the getInfo() method. So the JVM checks the Person class for the getInfo() method. The JVM finds the getInfo() method in the Person class. Then the JVM has a quick glance to the access modifier of this method. Because the getInfo() method is private, the JVM knows there can't be an override of this method (depending on the actual object) and executes the getInfo() method in the Person class.

This helps a lot - thanks Roel for your help and your patience.
 
Roel De Nijs
Sheriff
Posts: 10666
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Let's do the same if the getInfo method is correctly overridden, as shown in this code snippet

So what's happening at runtime when this code is executedThe JVM checks the Student class for the printPerson() method, but doesn't find this method. Then the JVM goes one level up in the class hierarchy and performs the same check. Student IS-A Person, so the JVM checks the Person class. The JVM finds the printPerson() method and thus executes this method. To be able to invoke the println() method, the JVM requires the return value of the getInfo() method. So the JVM checks the Person class for the getInfo() method. The JVM finds the getInfo() method in the Person class. Then the JVM has a quick glance to the access modifier of this method. So until here it's exactly the same as with the private getInfo method, but now it becomes different. Because the getInfo() method is defined with paclage-private access, the JVM knows this method could be overridden. The JVM knows the actual object IS-A Student, so the JVM checks the Student class for the getInfo() method. The JVM finds the getInfo() method and executes the getInfo() method in the Student class.

Also note that the JVM doesn't have to care/check/verify if the getInfo() method in the Student class is a valid override of the getInfo() method in the Person class, because that's already checked/verified by the compiler. And because the override was valid, the compiler was happy and produced the .class files.

So this topic can be summarized in 2 very simple (and hopefully easy to remember) but very, very, very important rules:
  • Which instance variables you can access is determined at compile time based on the reference variable type.
  • Which instance methods you can call/invoke is determined at compile time based on the reference variable type. Which instance method is actually executed is decided at runtime based on the type of the actual object (= polymorphism).


  • Hope it helps!
    Kind regards,
    Roel
     
    • Post Reply
    • Bookmark Topic Watch Topic
    • New Topic