The Java compiler doesn't complain when I override a protected method with a public method. What's really happening here? Is it overriding or hiding the parent method since the parent method has lower visibility?
A sub-class can always widen the access modifier, because it is still a valid substitution for the super-class. From the Java specification about Requirements in Overriding and Hiding:
The access modifier (§6.6) of an overriding or hiding method must provide at least as much access as the overridden or hidden method, as follows:
If the overridden or hidden method is public, then the overriding or hiding method must be public; otherwise, a compile-time error occurs.
If the overridden or hidden method is protected, then the overriding or hiding method must be protected or public; otherwise, a compile-time error occurs.
If the overridden or hidden method has default (package) access, then the overriding or hiding method must not be private; otherwise, a compile-time error occurs.
From the point of view of an external class, the public method is just a new method, not an overriding method, since the external class could not access the protected method anyway.
On the other hand, lowering the visibility is not allowed because the external class can always use a reference of the type of a super-class to reference an object of the sub-class and call the same method.
The visibility only affects external accessibility. Being a public method any external class can call it.
Access level of the overriding method doesn't affect visibility of the original method. After override, with any access levels, the original method can only be accessed by calling super in the subclass.
Related
I've been using Java for a while, largely self-taught. But I am a bit confused about access modifiers and it's bugging me because I have the OCA exam later this week and it's the only topic that I'm not very strong with.
If we have a class with a protected method and we extend that class and override that method using public, that's ok. We went from having a protected method to a public method. My question is, in what other cases can the access modifiers be different?
Thanks in advance!
The exact rules are given by JLS 8.4.8.3. Requirements in Overriding and Hiding.
The access modifier of an overriding or hiding method must provide at least as much access as the overridden or hidden method, as follows:
If the overridden or hidden method is public, then the overriding or hiding method must be public; otherwise, a compile-time error occurs.
If the overridden or hidden method is protected, then the overriding or hiding method must be protected or public; otherwise, a compile-time error occurs.
If the overridden or hidden method has package access, then the overriding or hiding method must not be private; otherwise, a compile-time error occurs.
It must be this way. If you could override a method with a more restrictive access, this would violate the Liskov Substitutability Principle (LSP). The LSP says that you should be able to use an instance of a subtype wherever you can use an instance of the supertype.
I have a superclass and subclasses that inherits the superclass. The superclass contains 6 methods but my subclasses only have a different implementation of 1 of the superclass's methods which needs to be overridden. Do I still have to override the remaining 5 methods in the subclass by doing, ie;
#Override
public void someMethod(String someString) {
super.someMethod(someString);
}
I feel like it's redundant to do so but when calling someMethod in the subclass, will it execute the superclass's methods if it's not overridden or will there be an error? I'm not sure what's good programming practice as I'm new to Java.
No, you don't have to override other methods if you do not change their implementation, that's what inheritance means. And this is a good practice of reusing your code to avoid repeating yourself.
when calling someMethod in subclass, will it execute the superclass's
methods if it's not overridden or will there be an error?
Yes, it will. No error will be thrown unless the method you call is visible to subclasses.
As per official Oracle documentation,
The ability of a subclass to override a method allows a class to inherit from a superclass whose behavior is "close enough" and then to modify behavior as needed. The overriding method has the same name, number and type of parameters, and return type as the method that it overrides. An overriding method can also return a subtype of the type returned by the overridden method. This subtype is called a covariant return type.
When overriding a method, you might want to use the #Override
annotation that instructs the compiler that you intend to override a
method in the superclass. If, for some reason, the compiler detects
that the method does not exist in one of the superclasses, then it
will generate an error.
So I would recommend reading the official document.
So I've been curious about something, and it's not necessarily something I need to know, but still a curiosity.
How do you tell a inherited method that it needs to call its parent method?
An example would be say on android:
#Override
public void onResume(){
}
Method throws an error until you place super.onResume(); inside of it.
I know constructors require a super call if the parent has a required constructor, but a method call?
How do you tell your class that it can have inheritable methods, but those inherited methods need to call its parent?
Java does not have a way to require an overridden method to call up to its superclass implementation. Nor (again in contrast to constructors) can you stop it from being called more than once.
How do you tell a inherited method that it needs to call its parent
method?
There's no way for the Java compiler to enforce this, and it's likely that you wouldn't want this feature for the general case.
When a subclass overrides a superclass method, it is free to completely replace that method, if necessary, with one that is more appropriate to its own abstraction. In this case, the subclass method would never want to invoke the superclass method.
Many subclass methods supplement the existing implementation in the superclass. In this case, invoking the superclass method is natural and appropriate.
The bottom line is that the developer is free to invoke, or not invoke, based on the needs of his implementation. Would it be nice if there were a way to force the issue with some kind of method declaration that would cause the compiler to insist that the superclass method be invoked by all subclasses? Maybe...
Such details are usually implementation details and are part of the contract that should always be specified when the superclass is conceived. Such contracts (eg. such as the Object.equals() contract) are extralinguistic specifications that the compiler is not powerful enough to enforce. These contracts can and should always be specified in the superclass documentation so that all implementors know the rules of the road.
On one hand, I have an abstract class with an abstract method.
On the other hand, I have a child class which overrides the abstract method and specifies the "public" access modifier to it.
Is it meaningful at all what visibility I give to my original abstract class' abstract method?
In Java, subclasses are allowed to "increase" the visibility of a method when overriding it, but not "decrease" it. I.e. a protected method can be overridden and made public, but a public method can't be overridden and made protected.
The meaning of keeping a superclass method protected (not necessary to have the superclass or the method abstract here) is that it allows subclasses to override the method and either keep it protected or make it public. If the superclass makes the method public, then that forces any subclass that overrides that method to have that method remain public.
The JLS, Section 8.4.8.3, covers these requirements:
The access modifier (§6.6) of an overriding or hiding method must provide at least as much access as the overridden or hidden method, as follows:
If the overridden or hidden method is public, then the overriding or hiding method must be public; otherwise, a compile-time error occurs.
If the overridden or hidden method is protected, then the overriding or hiding method must be protected or public; otherwise, a compile-time error occurs.
If the overridden or hidden method has package access, then the overriding or hiding method must not be private; otherwise, a compile-time error occurs.
I need to make my inherited instance variables private; is this possible?
IE, Superclass "Entity" has an int instance variable "health".
How can subclass "Zombie" (Extends "Entity") inherit the health variable from Entity, and have it private? I don't want other classes to be able to directly access the health variable, I want set and get methods for it.
Tell me if I wasn't specific enough; any help appreciated.
Simply : you can't.
This would break the contract of the superclass. Your class, being an Entity, exposes, like its superclass, a field named health. If you had the ability to make it private, all code using this field in instances of Entity (including instances of subclasses of Entity) would break with your class...
If you can, change the superclass (ie Entity) to make the field private. That's the common practice.
Make the variable private in the superclass and let all subclasses use accessor methods.
A second choice would be to make it package-private and arrange for those classes to which you want to deny access to be in another package. This would make sense if your Zombie is especially close to Entity (shares many internals) whereas other classes are more loosely coupled to their superclass.
You cannot decrease the visibility of any instance variable or method of the super class in your subclass..
Suppost you have super class with a public method.. And, suppose you were allowed to decrease the visibility to private in sub class..
Then see what's happens when you create object like this, and access that method of super class: -
SuperClass obj = new SubClass();
obj.pubMethod();
Now, at compile time, compiler sees that method pubMethod() is public in SuperClass, it will allow the access.. Note it does not check for the instance type on the RHS..
Now, at runtime, when JVM checks that the instance is of SubClass, then the actual method it would try to invoke will be searched in the SubClass..
But wait.. Did you see what happened when JVM went to search for pubMethod in SubClass that you made private.. BOoooooMMM -- A Crash..
That's why it is not allowed..
So, you cannot make it private..
From JLS Section - 8.4.8.3: -
The access modifier (§6.6) of an overriding or hiding method must
provide at least as much access as the overridden or hidden method, or
a compile-time error occurs. In more detail:
If the overridden or hidden method is public, then the overriding or hiding method must be public; otherwise, a compile-time error
occurs.
If the overridden or hidden method is protected, then the overriding or hiding method must be protected or public; otherwise,
a compile-time error occurs.
If the overridden or hidden method has default (package) access, then the overriding or hiding method must not be private;
otherwise, a compile-time error occurs.
You cannot add restrictions to an instance variable in a subclass, i.e. of health is protected in Enitity it cannot be private in Zombie (you can make it public).
However, you can make health private in Entity and define a protected getter and setter there. Subclasses can use these methods.