Actually my question was kind of answered already but I can't understand it properly. here is a 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");}
}
It prints out : "from Superclass"
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.
As far as I can imagine the method calling works this way: (maybe I am totally wrong about this):
The instances of an object store only the data in themselves and when I call an instance method Java takes a look at the type of the reference variable and calls the method from the class of that type.
(It seems logical to me and explains why the code above prints "from Superclass")
But changing the access modifier in the first doSomething() method to protected confuses me, because I can't understand how Java knows there is an overriding if the reference type is the SuperClass and not the SubClass. Does overriding change the method in the Superclass as well?
Or am I totally wrong about how method calling and overriding works?
I would really appreciate If someone could help me out and explain what I am missing.
Private methods along with static methods and all variables cannot be overridden, they can be hidden. So you would need to change the access modifier of your method from private to any other access modifier.
N.B: There are a few protocols to follow when overriding a method; The access modifier of the method defined in the sub-class must have the same level of access if not more accessible than the method that is being overridden. Return types must be covariant etc...
The functionality of overriding a method is simply defining another way to execute the same method using inheritance.
No, overriding doesn't change at all the super class (unless you're doing some weird things with reflection, but that's another story).
The private keyword is used when only the class itself can "see" the method. On the other hand, the protected keyword is used exactly for inheritance: the class and it's childs can see the method. That's why you can only override protected methods.
Since you have defined "doSomething" as private method, your override did not work. Change it to public or protected and then see output.
To understand it better, move Subclass in another java file. Now tell me, can you make a private method call from an object handle?
Related
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 a child cannot reduce the visibility of a non-static method and I understand why it is so.
I've read however that "static method can be hidden through its redeclaration". I however do not understand how this could be achieved in Java.
Is this really possible? If yes, how to do that (code example) and why was it introduced (it seems to contradict the principle of non-reducing the visibility of the interface)?
The short answer is: no, it is not possible. You have mixed up some terminology. Hiding has nothing to do with accessibility (which is what you are really asking about, not visibility, which is related to scope and shadowing and is discussed in Chapter 6 of the Java Language Specification (JLS)).
Now for the longer answer. The term overriding applies to instance methods, while the term hiding applies to class (static) methods. From the Java Tutorial topic Overriding and Hiding Methods:
The distinction between hiding a static method and overriding an instance method has important implications:
The version of the overridden instance method that gets invoked is the one in the subclass.
The version of the hidden static method that gets invoked depends on whether it is invoked from the superclass or the subclass.
Some of the other answers here provide incorrect examples about method hiding, so let's go back to the JLS, this time to §8.4.8:
Methods are overridden or hidden on a signature-by-signature basis.
That is, to override or hide a method in the parent class, the subclass must define a method with the same signature—basically, the same number and type of arguments (although generics and type erasure makes the rules a little more complicated than that). There are also rules about return types and throws clauses, but those seem irrelevant to this question.
Note that you can define a method in a subclass with the same name as a method in the parent class (or in an implemented interface) but with different number or type of arguments. In that case, you are overloading the method name and neither overriding nor hiding anything; the subclass method is a new method, pretty much independent of the inherited method(s). (There is an interaction when the compiler has to match methods to method calls, but that's about it.)
Now to your question: the terms accessibility and hiding (as well as visibility) are independent concepts in Java. There is, as you put it, a "principle" that there is simply no way for a subclass to reduce the accessibility of an inherited method. This applies regardless of whether you are overriding an instance method or hiding a class method. From the JLS §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, 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.
In summary, the fact that a static method can be hidden has nothing to do with changing the accessibility of the method.
Based on hagubear's valuable comments, it seems that the author of a statement meant hiding a method through overloading it with a method having the same declaration.
Quoting this link:
We can declare static methods with same signature in subclass, but it
is not considered overriding as there won’t be any run-time
polymorphism. (...) If a derived class defines a
static method with same signature as a static method in base class,
the method in the derived class hides the method in the base class.
Thus, defining a method in a child class having exact same declaration effectively hides the original method in child. However, as in case of fields, casting to the parent will restore the original access.
Sample code:
public class Test {
public static void main( String[] args ) {
B b = new B();
A a = b;
b.f(); // "Access somewhat denied"
a.f(); // "f()"
}
}
class A {
public static void f() {
System.out.println("f()");
}
}
class B extends A {
// *must* be public
public static void f() {
System.out.println("Access somewhat denied");
}
}
So I created a trivial test; IntelliJ indeed rejected it... and Yes, I know "it's a tool...but one I trust". In any case, I went to javac, which emitted the same ERROR:
Error:(...) java: ...Concrete.java:5: doSomethingStatic() in
...Concrete cannot override doSomethingStatic() in
...Base; attempting to assign weaker access privileges; was public
Based on this, and our skepticism in general, I suggest the error is in your documentation.
Below is my sample code, fairly definitive I think. It barfs at the protected.
public class Base
{
public static void doSomethingStatic(){}
}
public class Concrete extends Base
{
protected static void doSomethingStatic(){}
}
It can be hidden by an overloaded redeclaration in a derived class:
class Base
{
public static void doSomethingStatic(){}
}
class Derived extends Base
{
public static void doSomethingStatic(String arg){}
}
but only hidden to people who try to access it via the derived class.
I have a super class with a final method
public final void foo(){ ... }
No you cannot do it.
Overriding a method in subclass with its superclass method marked final is not possible
. You can add a method with different signature
The purpose of final keyword applied to a method is that it doesn't allow subclass method to override it.
The main purpose of final is to prevent from overriding.So, you can not override final methods.
Still you can overload final methods.
You can't override the final super method.but you can overload it.
Make a method final only if it has an implementation that should not be changed and it is critical to the consistent state of the object.
You can't. The final keyword is there to prevent this.
See final methods in Java on Wikipedia.
It’s not clear why you have to have the same name. Either it’s intended to be a different method, then it can have a different name without problems or you are trying to do some sort of overriding you claimed not to do.
If your subclass needs an interface implementation which interferes with that method consider an inner class for that interface implementation.
Otherwise a method in the subclass does not override a superclass method with the same name if either:
it has different parameter types
the superclass method is private
the superclass method is package-private and the subclass resides in a different package
I have been studying for my Software Development course and came across the question from a sample:
"Why does it make no sense to have both the static and final modifiers in front of a Java method?"
I have had a bit of a research and everywhere I go it says it is not bad practice and there are good reasons for doing so - for example, this stackoverflow question:
Is it a bad idea to declare a final static method?
So, is this question itself nonsensical or is there a legitimate answer to this question?
(There are no given solutions to this sample paper)
static methods cannot be overriden since they're associated not with an instance of class, but with the class itself. For example, this is how you'd usually call static method:
MyClass.myStaticMethod()
And this is how you call an instance method:
new MyClass().myInstanceMethod()
final modifier is used with methods to disallow their override in extending classes.
Because a static method cannot be overridden. There is therefore no point in marking it final.
Note however that static final variables (which are, oddly, therefore NOT variables because they cannot change) are very useful because their values can be inlined by the compiler.
Static methods can be sort of overridden (though that's not the technical term), since it is resolved at runtime, searching upwards in class chain until it's found. But this "feature" is probably a mistake; people don't use it, people don't know about it, we should pretend it doesn't exist.
From the Java Language Spec:
A class method is always invoked without reference to a particular
object. It is a compile-time error to attempt to reference the current
object using the keyword this or the keyword super.
So you cannot override a static method because it does not belong to an instance. So, the keywords this and super are not avaliable and you cannot use virtual method invocation. And if you cannot use virtual method invocation then the final keyword is of no use.
I like to think that the compiler sees method declarations like this:
public class SomeClass{
// public static classMethod() becomes
public static [final] void classMethod(){
//...
}
// and public void instanceMethod() becomes
public void instanceMethod(SomeClass this, Object super){
//....
}
}
public class SomeOtherClass extends SomeClass{
// overrides
#Override
public void instanceMethod(SomeOtherClass this, SomeClass super){
//...
}
}
And you call SomeClass instance = new SomeOtherClass().instanceMethod(); then its called the instanceMethod() of SomeOtherClass.
So the compiler does not need to copy method bodys and just pass the reference to the current object in the thread. So, when you use virtual method invocation, in fact you are calling the instanceMethod with a reference to the current object (this) and the body method of the current class is what is called.
Let's look at the following code snippet in Java.
package trickyjava;
class A
{
public A(String s)
{
System.out.println(s);
}
}
final class B extends A
{
public B()
{
super(method()); // Calling the following method first.
}
private static String method()
{
return "method invoked";
}
}
final public class Main
{
public static void main(String[] args)
{
B b = new B();
}
}
By convention, the super() constructor in Java must be the first statement in the relevant constructor body. In the above code, we are calling the static method in the super() constructor parameter list itself super(method());.
It means that in the call to super in the constructor B(), a method is being
called BEFORE the call to super is made! This should be forbidden by the compiler but it works nice. This is somewhat equivalent to the following statements.
String s = method();
super(s);
However, it's illegal causing a compile-time error indicating that "call to super must be first statement in constructor". Why? and why it's equivalent super(method()); is valid and the compiler doesn't complain any more?
The key thing here is the static modifier. Static methods are tied to the class, instance methods (normal methods) are tied to an object (class instance). The constructor initializes an object from a class, therefore the class must already have been fully loaded. It is therefore no problem to call a static method as part of the constructor.
The sequence of events to load a class and create an object is like this:
load class
initialize static variables
create object
initialize object <-- with constructor
object is now ready for use
(simplified*)
By the time the object constructor is called, the static methods and variables are available.
Think of the class and its static members as a blueprint for the objects of that class. You can only create the objects when the blueprint is already there.
The constructor is also called the initializer. If you throw an exception from a constructor and print the stack trace, you'll notice it's called <init> in the stack frame. Instance methods can only be called after an object has been constructed. It is not possible to use an instance method as the parameter for the super(...) call in your constructor.
If you create multiple objects of the same class, steps 1 and 2 happen only once.
(*static initializers and instance initializers left out for clarity)
Yep, checking the JVM spec (though admittedly an old one):
In the instance init method, no reference to "this" (including the implicit reference of a return) may occur before a call to either another init method in the same class or an init method in the superclass has occurred.
This is really the only real restriction, so far as I can see.
The aim of requiring the super constructor to be invoked first is to ensure that the "super object" is fully initialized before it is used (It falls short of actually enforcing this because the super constructor can leak this, but that's another matter).
Calling a non-static method on this would allow the method to see uninitialized fields and is therefore forbidden. A static method can only see these fields if it is passed this as argument. Since accessing this and super is illegal in super constructor invocation expressions, and the call to super happens before the declaration of any variables that might point to this, allowing calls to static methods in super constructor invocation expressions is safe.
It is also useful, because it allows to compute the arguments to the super constructor in an arbitrarily complex manner. If calls to static methods weren't allowed, it would be impossible to use control flow statements in such a computation. Something as simple as:
class Sub extends Super {
Sub(Integer... ints) {
super(Arrays.asList(ints));
}
}
would be impossible.
This is one situation where the java syntax hides what's really going on, and C# makes it a bit clearer.
In C# your B would look like
class B : A {
public B() : base(method()) {
}
private static String method() {
return "method invoker";
}
}
Although the java syntax places super(method) within the constructor it's not really called there: All the parent initialization is run before your subclass constructor. The C# code shows this a little more clearly; by placing super(method()) at the first line of the java constructor you're simply telling java to use the parameterized constructor of the super class rather than the parameterless version; this way you can pass variables to the parent constructor and they'll be used in the initialization of the parent level fields before your child's constructor code runs.
The reason that super(method()) is valid (as the first line in a java constructor) is because method() is being loaded with the static elements--before the non-static ones, including the constructors--which allows it to be called not only before B(), but before A(String) as well. By saying
public B() {
String s = method();
super(s);
}
you're telling the java compiler to initialize the super object with the default constructor (because the call to super() isn't the first line) and you're ready to initialize the subclass, but the compiler then becomes confused when it sees that you're trying to initialize with super(String) after super() has already run.
A call to super is a must in java to allow the parent to get initalized before anything with child class starts.
In the case above, if java allows String s= method(); before the call to super, it opens up flood gate of things that can be done before a call to super. that would risk so many things, essentially that allows a half baked class to be used. Which is rightly not allowed. It would allow things like object state (some of which may belong to the parent) being modified before it was properly created.
In case of super(method()); call, we still adhere to the policy of completing parent initialization before child. and we can use a static member only, and static member of child classes are available before any child objects are created anyways. so the method is avilable and can be called.
OK..i think, this one could be relevant that, if we are calling some member with Super, then it first try to invoke in super class and if it doesn't find same one then it'll try to invoke the same in subclass.
PS: correct me if i'm wrong