There something ambiguous about this idea and I need some clarifications.
My problem is when using this code:
public class B {
private void don() {
System.out.println("hoho private");
}
public static void main(String[] args) {
B t = new A();
t.don();
}
}
class A extends B {
public void don() {
System.out.println("hoho public");
}
}
The output is hoho private.
Is this because the main function is in the same class as the method don, or because of overriding?
I have read this idea in a book, and when I put the main function in another class I get a compiler error.
You cannot override a private method. It isn't visible if you cast A to B. You can override a protected method, but that isn't what you're doing here (and yes, here if you move your main to A then you would get the other method. I would recommend the #Override annotation when you intend to override,
class A extends B {
#Override
public void don() { // <-- will not compile if don is private in B.
System.out.println("hoho public");
}
}
In this case why didn't compiler provide an error for using t.don() which is private?
The Java Tutorials: Predefined Annotation Types says (in part)
While it is not required to use this annotation when overriding a method, it helps to prevent errors. If a method marked with #Override fails to correctly override a method in one of its superclasses, the compiler generates an error.
is this because the main function is in the same class as the method "don"
No, it's because A's don() is unrelated to B's don() method, in spite of having the same name and argument list. private methods are hidden inside their class. They cannot be invoked directly by outside callers, such as main method in your case, because they are encapsulated inside the class. They do not participate in method overrides.
No, a private method cannot be overridden since it is not visible from any other class. You have declared a new method for your subclass that has no relation to the superclass method. One way to look at it is to ask yourself whether it would be legal to write super.func() in the Derived class.
You can't override a private method, but you can introduce one in a derived class without a problem. The derive class can not access the private method on the ancestor.
Since t is a on object of type B, calling don() method will invoque the method defined at B. It doesn't even know that there is a method named also don() at class A
private members aren't visible to any other classes, even children
You can't override a private method, but then again, you can't call it either. You can create an identical method with the same name in the child however.
public class A
{
private int calculate() {return 1;}
public void visibleMethod()
{
System.out.println(calculate());
};
}
public class B extends A
{
private int calculate() {return 2;}
public void visibleMethod()
{
System.out.println(calculate());
};
}
If you call A.visibleMethod() it prints out 1.
If you call B.visibleMethod() it prints 2.
If you don't implement the private calculate() method in B, it won't compile because the public method that calls it can't see the private method in A.
Related
abstract class Base{
protected abstract void a();
}
class Child extends Base{
#Override
public void a(){
//why is this valid
}
}
Why is that we can't reduce the visibility but can increase it?
Also I need to implement Template pattern in which the public methods visible can only be of base class.
Example:
abstract class Base{
public void callA(){
//do some important stuff
a();
}
protected abstract void a();
}
class Child extends Base{
#Override
public void a(){
//why is this valid
}
}
Now if java allows to increase visibility then there are two methods visible publicly??
I know interface is one solution but is there some other way out???
Why decreasing visibility is not allowed is already explained in other responses (it would break the contract of the parent class).
But why it is allowed to increase the visibility of a method? First, it would not break any contract, so there is no reason to not allow it. It can be handy sometimes, when it makes sense in the child class for a method to not be protected.
Second, not allowing it could have the side effect of making impossible sometimes to extend a class and implement an interface at the same time:
interface Interface1 {
public void method();
}
public class Parent {
protected abstract void method();
}
public class Child extends Parent implements Interface1 {
#Override
public void method() {
}
//This would be impossible if the visibility of method() in class Parent could not be increased.
}
About your second question, you can do nothing about it. You have to trust that the person who implements the child class doesn't do anything that breaks your implementation. Even if java wouldn't allow to increase visibility, that would still not fix your problem, because a public method with a different name could be created that calls the abstract method:
class Child extends Base{
#Override
protected void a(){
}
public void a2() {
a(); //This would have the same problems that allowing to increase the visibility.
}
}
If the base class makes a promise regarding visibility, then the subclass cannot break that promise and still satisfy the Liskov substitution principle. You can't use a subclass in any situation where the promised method is exposed if that promise is broken.
The subclass IS-A base class. If the base class exposes a method, so must the subclass.
There's no way out in Java or C++. I'd guess the same is true in C#.
Why is that we can't reduce the visibility but can increase it?
Suppose that it would be possible to reduce the visibility. Then look at the following code:
class Super {
public void method() {
// ...
}
}
class Sub extends Super {
#Override
protected void method() {
// ...
}
}
Suppose that you would have another class, in another package, where you use these classes:
Super a = new Sub();
// Should this be allowed or not?
a.method();
To check whether a method call is allowed or not, the compiler looks at the type of the variable you call it on. The type of the variable a is Super. But the actual object that a refers to is a Sub, and there the method is protected, so you would say it should not be allowed to call the method from an unrelated class outside the package. To solve this strange situation, it's made forbidden to make overridden methods less visible.
Note that the other way around (making a method more visible) doesn't lead to the same problem.
Since Java allows Super class reference to point to sub class object.. So, restriction should not be increased from compile-time to runtime..
Lets see this through an example: -
public class B {
public void meth() {
}
}
class A extends B {
private void meth() { // Decrease visibility.
}
}
Now, you create an object of class A and assign it the reference of class B..
Lets see how: -
B obj = new A(); // Perfectly valid.
obj.meth(); // Compiler only checks the reference class..
// Since meth() method is public in class B, Compiler allows this..
// But at runtime JVM - Crashes..
Now, since compiler only checks the type of the reference variable, and check the visibility of methods in that class (class B), and it doesn't check what kind of object does the reference obj refers to.. So, it is not worried about that.. It is left to JVM at runtime to resolve the appropriate method..
But at runtime, JVM will actually try to invoke the meth method of class A as object is of class A.. But, now what happens... BooooOOMM ---> JVM Crashes.. because meth method is private in class A...
That's why visibility is not allowed to be decreased..
Given the following code:
SuperClass :
package poc.poc;
public class SuperClass {
private void method() {
System.out.println("SuperClass!");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SuperClass s = new SubClass();
s.method();
}
}
SubClass :
package poc.poc;
public class SubClass extends SuperClass {
public void method() {
System.out.println("Subclass!");
}
}
When I run the main method of SuperClass , I would expect to get an exception of some sort, but actually the code in the SuperClass is run, rather than the code in the SubClass, and therefore running an instance method of the superclass type on a subclass instance.
Why does this happen?
EDIT: Doesn't this violate encapsulation?
P.S. When changing to protected rather than private modifier, polymorphism starts to kick in and we're back to something I would call "expected behavior"
There is no way to override a private method. Instead, the subclass is hiding it. That means that when the subclass is used polymorphically, the method is not considered one of the parent's existing methods. It's like a whole new method that's not available through polymorphism.
The private method is not part of the parent's class contract. Polymorphism only applies to methods that are part of the parent's contract. If it wasn't like that, you could cause a class to act differently than its contract, by changing implementation where the author wanted it to be private. If the author wanted you to do that, they would have used protected instead. In effect, a private method is like final.
In this particular main method, because it is defined in the actual parent's class, it is able to see a private method and therefore able to call it. If your main method has been in any other class and tried to call it, it would have failed.
A private method cannot be overrided, that alone explains what you see here. You are able to call the method in your main because the main is in the same class, otherwise it would not be possible.
You correctly analyzed what happens when changing private to protected : the method is now overridable and the "nearest" definition of it is executed when calling it on a subclass instance.
why should we widen the accessibility of overridden methods ? If the super class has a protected method and subclass has same method with public. Why should happen?
It's a different method! Subclasses don't inherit private methods! So you're not "overriding" at all. You are simply DEFINING a method with the same name as the private method in the superclass.
class A
{
private void myMethod() { }
}
class B extends A
{
public void myMethod() { } // a completely different method. Has nothing to do with the above method. It is not an override.
}
Because in an object hierarchy, JVM will always run the Overriden method. If your overriden method is not accessible, then it is useless.
public class A{
void A(){}
}
public class B extends A{
private void A(){} //this makes no sence and its impossible
PSV main(String ..){
A a = new B();
a.A(); //error as JVM cannot call overriden method which is private.
}
}
Methods declared as private or static can not be overridden!
Annotation #Override indicates that a method declaration is intended to override a method declaration in a superclass. If a method is annotated with this annotation type but does not override a superclass method, compilers are required to generate an error message.
Use it every time you override a method for two benefits. This way, if you make a common mistake of misspelling a method name or not correctly matching the parameters, you will be warned that you method does not actually override as you think it does. Secondly, it makes your code easier to understand because it is more obvious when methods are overwritten.
And in Java 1.6 you can use it to mark when a method implements an interface for the same benefits.
Let's say I have a method called mymethod()
and this method overrides the method of the super class method.
What does it mean to override a method?
Does that mean mymethod() ignores everything that is in the method of the superclass, or does that means mymethod() also includes everything in the superclass method?
When overriding a method, can I only override the methods of the same name, or I can override methods of any name?
thanks.
An example:
public class Base {
public void saySomething() {
System.out.println("Hi, I'm a base class");
}
}
public class Child extends Base {
#Override
public void saySomething() {
System.out.println("Hi, I'm a child class");
}
}
Now assume we have a main function somewhere...
public static void main(String [] args) {
Base obj = new Child();
obj.saySomething();
}
When this runs, it will call Child's version of saySomething, because you overrode the parent's version by giving a new version of the function in Child.
The #Override annotation allows other developers (and you, when you forget) to know that this method overrides something in a base class/interface, and it also allows the compiler to yell at you if you're not actually overriding anything in a base class. For example, if you got the number of arguments wrong for a function, the compiler will give you an error saying your #Override is incorrect.
For example:
public class Child extends Base {
#Override
public void saySomething(int x) {
System.out.println("I'm a child and x is: " + x);
}
}
The compiler will yell at you because this version of saySomething takes an argument, but the parent's version doesn't have an argument, so you're #Override-ing something that's not in the parent.
On super
The Child version of saySomething will not invoke the Base version, you have to do it yourself with super.method().
For example:
public class Child extends Base {
#Override
public void saySomething() {
super.saySomething();
System.out.println("I'm also a child");
}
}
If you ran the main and used this Child class, it would print out I'm a base and I'm also a child.
Overriding means that when you call a method on your object, your object's method is called instead of the super class. The #Override annotation is something you use to make sure that you are overriding the correct method of the superclass. If you annotate a method that does not exist in the superclass, the Java compiler will give you an error. This way you can be sure that you are overriding the correct methods. This is especially useful in cases like this:
public class MyClass {
...
public boolean equals(MyClass myClass) {
...
}
}
There is a logic-bug in the code above. You haven't actually overridden the Object class's equals method. If you add the #Override annotation:
public class MyClass {
...
#Override
public boolean equals(MyClass myClass) {
...
}
}
The Java compiler will now complain because there is no corresponding method in the parent class. You'll then know that the correct solution is:
public class MyClass {
...
#Override
public boolean equals(Object o) {
...
}
}
To call the parent class's method, you can call super.overriddenMethod() where overriddenMethod is the name of the method you have overridden. So if you want to do something in addition to what the parent class already does, you can do something like this:
public class MyClass {
...
#Override
public void overriddenMethod() {
super.overriddenMethod();
/* whatever additional stuff you want to do */
}
}
If an inheriting class has on override method of the same name as the parent class it will be called instead of the one in the parent class. This only works if the names are the same, and of course if the signature of the method matches your call to the method.
What does it mean to override a method?
It means you replace the super class definition of the method with your own definition.
does that mean mymethod() ignores everything that is in the method of the super class?
or does that means mymethod() also includes everything in the superclass method?
You can choose whether to include the super class definition within your definition. To include it, you need to call super.mymethod() within mymethod().
and when overriding a method, can I only override the methods of the same name, or I can override methods of any name?
To override a method, you must supply a method in the sub class with the same signature (which means the same name, parameters and return type).
As a side note, the #Override annotation in your question does not actually cause your method to override another method. It causes a compile-time error if a method annotated with it does not have a signature matching a public or protected method of a super class (or interface as of 1.6).
I once had a student come to ask me why his code wasn't working. He had spent several days wondering why he could put something into a collection but was not able to find it. His code was something like:
public int hashcode()
instead of:
public int hashCode()
So the hashCode method never got called.
Adding #Overrides to a method makes it clear that you are overriding the method AND make sure that you really are overriding a method.
When you override a method of the super class, calling that method on your object calls its method instead of that of the super class.
You can call the super class's method (despite having overridden it) using super.methodName(). A common reason for this is when the overridden method would otherwise reimplement the super class method and add additional code specific to the extending class (public void methodName() { super.methodName(); /* more code */ }).
#Override annotation allows you to cause warning at compile time if the method isn't actually overriding anything. It isn't necessary, but these warning are a hit to you that you might have got the signature wrong in the extending class, forgot to implement the method at all in the super class, or some other silly mistake.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why can't you reduce the visibility of a method in a java subclass?
How come I can override a private method in superclass with a public when in a subclass, but I cannot override a public method in the superclass into private method in subclass?
Why?
Thank you in advance.
Overriding a method can't ever reduce the visibility. Allowing that would violate the Liskov Substitution Principle, which states (simplified) that all objects of a derived class B must have the same properties as the base class A. In this case one such "property" would be a public method foo which would be "lost" if B had that same method, but made it protected.
Also, since private methods are not inherited (try calling it from a derived class!) they can't ever be overriden. You can have a public method with the same name as a private one in the base class, but that's not overriding, it's simply a new method with the same name, but not other relation. Calls to the private method in the base class will not call the public method in the superclass, even when executed on objects of the superclass!
In other words: private methods never use runtime polymorphism.
See this sample:
public static class Base {
public void callBoth() {
foo();
bar();
}
private void foo() {
System.out.println("Base.foo");
}
protected void bar() {
System.out.println("Base.bar");
}
}
public static class Sub extends Base {
public void foo() {
System.out.println("Sub.foo");
}
public void bar() {
System.out.println("Sub.bar");
}
}
When executing new Sub().callBoth() the output will be this:
Base.foo
Sub.bar
Because it doesn't break the class contract to make a method more available. If Kitten subclasses Animal, and Animal has a public method feed(), then Kitten must also have a public method feed(), as it must be possible to treat any instance of Kitten like an instance of Animal. Redefining the access level to private would break that.
If the public method became private, then it would not be possible to up cast the instance into its parent class (because one of the methods would be unavailable).
If the private method became public, then it would be possible to up case the instance into its parent class (because then you would just have no way to grab the private / publicly overriden method).
The access level can't be more restrictive than the overridden method.
private-->[default]-->protected-->public
By overriding you're saying that your subclass can be called with the same api but may function differently. Making something public increases the access level - so you're not removing guaranteed functionality.
By making a public method private (if you could actually do this) you'd be removing functionality, so breaking the "contract". It also doesn't make sense in that the method could still be called publicly, it's just that the public call would access the public method in the superclass, which would be counterintuitive.