Why cant we declare an instance method in sub Class B which shares the same signature of a static method in parent Class A?
It throws a compile time error if i try to do that.
My question is, since static method of parent class is restricted to parent class, why does instance method of child class does not compile.
Lets see by code:
`
public class A{
static void testStatic(){}
}
public class B extends A{
void testStatic (){}
}
public class Test{
public static void main (String[] args){
A a = new B()
a.testStatic();
}
`
In the above code,since A does not have an instance method by that name, and since Java allows static methods to be accessed by objects, Object a of type 'A' pointing to 'B' can call static method present in it(class A). But complier throws an error "The instance method cannot override a static method" why?
Note: I can understand if a class does not allow same method name for two methods, even if one is instance and other is static. But I fail to understand why it does not allow a sub class to have an instance of same name. Especially considering the fact that static methods cannot be overridden. And yet, Java allows subclass to have same name as parent class static method, which is called information hiding, but not overriding.
The compiler throws an error because those are the rules of the language. From the Java Language Specification §8.4.8.2:
If a class C declares or inherits a static method m, then m is said to hide any method m', where the signature of m is a subsignature (§8.4.2) of the signature of m', in the superclasses and superinterfaces of C that would otherwise be accessible to code in C.
It is a compile-time error if a static method hides an instance method.
(emphasis in the original). The language is dense (as in most places in the JLS) but it matches the situation you are describing. The JLS doesn't provide a rationale for this rule that I could find on first reading. But a little thought about how one might try to make this rule unnecessary shows why it's there.
It's illegal in Java. The call to the static method is allowed on an instance as well, so there'd be no way to distinguish which method to call in some cases:
A a = new A ();
B b = new B ();
A.testStatic (); // ok
B.testStatic (); // ok
a.testStatic (); // ok calling static
b.testStatic (); // undefined. What to call? Based on what?
Last call is the reason why it's not allowed.
Calls to static methods are resolved at compile time itself. So, they cannot be overridden. And by defining another method with the same signature as the static method, the compiler complains.
static method is bound with class whereas instance method is bound with object.
Static belongs to class area and instance belongs to heap area.
I am not hundred percent sure but I guess answer as below.
Static method means it can be used without an instance of the the class in which it is defined. Also static method can access only static variables of the class. Now if we override non static method and create an instance of sub class with reference of the super class, compiler will be confused for above two basic functioning of static method. Please debate if any thing wrong in this.
4 line showing error. so do this
public class B extends A
Related
The following constellation:
public class AccessModifierTest {
private static class Super {
private int n = 3;
private Super() {}
private void setN(int n) {
this.n = n;
}
}
private static class Sub extends Super {
private Sub() {
super(); // invoking private ctor is permitted
// setN(5); but invoking private method is not permitted, why?
// super.setN(5); this is fine too
}
}
public static void main(String[] args) {
Super superInstance = new Sub();
}
}
The private ctor of Sub is allowed to invoke the private ctor of Super.
Why this is ok, is answered here:
scope of private constructor in Nested Class
Because of this, shouldn't it be also fine to invoke the private method setN in the ctor of Sub?
Why is this not legal?
Just like the superclass constructor, setN is perfectly accessible in Sub. This is because, as your linked Q&A explained, private members declared in an inner class are accessible everywhere as long as you are inside the top-level class. So the problem is somewhere else.
If you are using IntelliJ, the error message it gives is "setN has private access...", which is more useful and lets you fix the error immediately (and setN being private also plays a role as you will see). But javac's error message, "cannot find symbol setN", shows that this isn't actually about accessibility, and that the compiler can't actually find setN.
According to the spec, a simple method name like setN
consists of a single UnqualifiedMethodIdentifier which specifies the name of the method to be invoked. The rules of method invocation require that the UnqualifiedMethodIdentifier denotes a method that is in scope at the point of the method invocation.
setN is actually not in scope in the constructor of Sub. The scope of setN is only Super. See also Scope of a Declaration in the spec.
But doesn't Sub inherit setN from Super? Well, it doesn't. private members are not inherited. See this section for the conditions for inheritance.
A class C inherits from its direct superclass type D all concrete
methods m (both static and instance) for which all of the following
are true:
m is a member of D.
m is public, protected, or declared with package access in the same
package as C.
No method declared in C has a signature that is a subsignature
(§8.4.2) of the signature of m as a member of D.
If you use another form (instead of a simple name) to refer to Super.setN, like super.setN(5);, or ((Super)this).setN(5); then it can compile just fine.
For why these work, see the compile-time step 1 of processing a method call, where the compiler determines in which type it should search for a method declaration. If the type to search is Super, then it would compile, because Super actually has the setN method, whereas Sub does not inherit it from Super, so does not have it as a member.
Note that constructor calls and method calls are treated completely separately by the language spec and they have completely different rules. The super(); syntax is essentially "hardcoded" into the language - there is no "scope" or "names" of a constructor or anything like that. The constructor just has to be accessible for you to call it.
Compiler understands the scope of the class Super is within the AccessModifierTest, but compiler does not know a callee method of any class without the reference. This is how oop based languages are designed to work. The main benefit is that compiler can remove the method call ambiguity through this.
So when a private constructor is called within a class scope compiler understands where it is coming from, but any other method requires the object reference to access.
to make your code work you need to use the reference super.setN(5) to make it work.
I'm new to Java Programming and learning polymorphism.
__EDIT__
As per the answers I received from everyone,I have code:
Here I'm typecasting my Derived object (obj) to Base type and then calling method().
public class Tester {
public static void main(String[] args) {
Base obj=(Base)new Derived();
obj.method();
}
}
class Base{
public void method(){
System.out.println("In Base");
}
}
class Derived extends Base{
public void method(){
System.out.println("In Derived");
}
}
Output I'm getting is: "In Derived".
So after typecasting my object should become of type Base referenced by Base type.
But it's not happening? Why?
Does typecast work on child->parent conversion or it has no effect here?
Base obj=new Derived();
In the above statement, the reference part points to type Base. This is how the compiler identifies which class to consider. But your code will create an error. Let me explain the structure of the above statement before explaining why will it show an error.
Structure of the above statement:
Declaration-The reference part is Base obj.
Instantiation: The new keyword is a Java operator that creates the object/allocates space in the memory.
Initialization: The new operator is followed by a call to a constructor, which initializes the new object.
Since, Derived is a sub-class of Base, you are allowed to call the constructor in the Derived class. This is how inheritance and polymorphism works.
Okay, Now let us go back to the error part.
The obj.method() in your code is looking for a function method() in Base class but the method(int a) function in Base class requires an argument of type integer to be passed. So for the code to work, the calling statement has to be something like obj.method(5).This statement works because the calling statement is actually passing 5 to the function.
There is an easy fix for your code:
Derived obj=new Derived();
Have you noticed?
I have relaced the reference to type Derived.
Why does that work?
Because there is method() function in your Derived class which doesn't require an integer argument.
There is one more amazing fact about inheritance in Java:
Everything possessed by a super-class is also possessed by the sub-class but the reverse is not true. And yes, the sub-class has the right to redefine any method/function it has inherited from super-class.
The above statement means the following code will work:
Derived obj=new Derived();
obj.method(5);
You must be wondering-How come this code works even though method() in Derived requires no argument. In fact, Derived has no method(int a).
Well, the answer to this is the amazing fact I have mentioned above.
Yes, method(int a) also belongs to Derived since it's a sub-class of Base.
But How does the code mentioned below work?
Derived obj=new Derived();
obj.method(5);
Simple, the JVM looks for the method(int a) in class Derived and it finds the function since Derived has inherited the function from Base class.
Remember this too, the sub-class also has a privilege to over-ride a method in super class. This means that you can add method(int a) function in class Derived which over-rides the original method inherited from Base.
How inheritance works?
When you call obj.method(5) in the above code, the JVM first looks for any over-ridden method of the same type in Derived. If it does not find any over-ridden method, it moves up in the inheritance hierarchy chain to the super class and looks for the same method. But the reverse is not the true.
how does compiler comes to know which method is to be called & too from which class?
The compiler searches for the method in the class (in this case Base) of the object (in this case obj). If the method is not found in that class, then it looks for the method in the super class (in this case Object). If still not found, it flags an error.
Is it that compiler checks the reference type class & if method to be invoked is not present in reference type class it gives error??
Yes. But, as said before, If the method is not found in that class, then it looks for the method in the super class (in this case Object). If still not found, it flags an error.
Your obj.method() will fail, because Base does not have a method with the signature method() (it has method(int))
If your obj was of type Derived, then both these case will work:
obj.method(); // will call this method from the Derived class
obj.method(1); // will call this method from the Base class
when there are same method names in different classes , the compiler comes to know by:
1-if you are passing any argument , then the type of argument which you are passing will tell the compiler which method to be called
2-if there are two classes , then make the object of that class for which you want to call the method
Given the following classes:
public abstract class Super {
protected static Object staticVar;
protected static void staticMethod() {
System.out.println( staticVar );
}
}
public class Sub extends Super {
static {
staticVar = new Object();
}
// Declaring a method with the same signature here,
// thus hiding Super.staticMethod(), avoids staticVar being null
/*
public static void staticMethod() {
Super.staticMethod();
}
*/
}
public class UserClass {
public static void main( String[] args ) {
new UserClass().method();
}
void method() {
Sub.staticMethod(); // prints "null"
}
}
I'm not targeting at answers like "Because it's specified like this in the JLS.". I know it is, since JLS, 12.4.1 When Initialization Occurs reads just:
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
...
T is a class and a static method declared by T is invoked.
...
I'm interested in whether there is a good reason why there is not a sentence like:
T is a subclass of S and a static method declared by S is invoked on T.
Be careful in your title, static fields and methods are NOT inherited. This means that when you comment staticMethod() in Sub , Sub.staticMethod() actually calls Super.staticMethod() then Sub static initializer is not executed.
However, the question is more interesting than I thought at the first sight : in my point of view, this shouldn't compile without a warning, just like when one calls a static method on an instance of the class.
EDIT: As #GeroldBroser pointed it, the first statement of this answer is wrong. Static methods are inherited as well but never overriden, simply hidden. I'm leaving the answer as is for history.
I think it has to do with this part of the jvm spec:
Each frame (§2.6) contains a reference to the run-time constant pool (§2.5.5) for the type of the current method to support dynamic linking of the method code. The class file code for a method refers to methods to be invoked and variables to be accessed via symbolic references. Dynamic linking translates these symbolic method references into concrete method references, loading classes as necessary to resolve as-yet-undefined symbols, and translates variable accesses into appropriate offsets in storage structures associated with the run-time location of these variables.
This late binding of the methods and variables makes changes in other classes that a method uses less likely to break this code.
In chapter 5 in the jvm spec they also mention:
A class or interface C may be initialized, among other things, as a result of:
The execution of any one of the Java Virtual Machine instructions new, getstatic, putstatic, or invokestatic that references C (§new, §getstatic, §putstatic, §invokestatic). These instructions reference a class or interface directly or indirectly through either a field reference or a method reference.
...
Upon execution of a getstatic, putstatic, or invokestatic instruction, the class or interface that declared the resolved field or method is initialized if it has not been initialized already.
It seems to me the first bit of documentation states that any symbolic reference is simply resolved and invoked without regard as to where it came from. This documentation about method resolution has the following to say about that:
[M]ethod resolution attempts to locate the referenced method in C and its superclasses:
If C declares exactly one method with the name specified by the method reference, and the declaration is a signature polymorphic method (§2.9), then method lookup succeeds. All the class names mentioned in the descriptor are resolved (§5.4.3.1).
The resolved method is the signature polymorphic method declaration. It is not necessary for C to declare a method with the descriptor specified by the method reference.
Otherwise, if C declares a method with the name and descriptor specified by the method reference, method lookup succeeds.
Otherwise, if C has a superclass, step 2 of method resolution is recursively invoked on the direct superclass of C.
So the fact that it's called from a subclass seems to simply be ignored. Why do it this way? In the documentation you provided they say:
The intent is that a class or interface type has a set of initializers that put it in a consistent state, and that this state is the first state that is observed by other classes.
In your example, you alter the state of Super when Sub is statically initialized. If initialization happened when you called Sub.staticMethod you would get different behavior for what the jvm considers the same method. This might be the inconsistency they were talking about avoiding.
Also, here's some of the decompiled class file code that executes staticMethod, showing use of invokestatic:
Constant pool:
...
#2 = Methodref #18.#19 // Sub.staticMethod:()V
...
Code:
stack=0, locals=1, args_size=1
0: invokestatic #2 // Method Sub.staticMethod:()V
3: return
The JLS is specifically allowing the JVM to avoid loading the Sub class, it's in the section quoted in the question:
A reference to a static field (§8.3.1.1) causes initialization of only the class or interface that actually declares it, even though it might be referred to through the name of a subclass, a subinterface, or a class that implements an interface.
The reason is to avoid having the JVM load classes unnecessarily. Initializing static variables is not an issue because they are not getting referenced anyway.
The reason is quite simple: for JVM not to do extra work prematurely (Java is lazy in its nature).
Whether you write Super.staticMethod() or Sub.staticMethod(), the same implementation is called. And this parent's implementation typically does not depend on subclasses. Static methods of Super are not supposed to access members of Sub, so what's the point in initializing Sub then?
Your example seems to be artificial and not well-designed.
Making subclass rewrite static fields of superclass does not sound like a good idea. In this case an outcome of Super's methods will depend on which class is touched first. This also makes hard to have multiple children of Super with their own behavior. To cut it short, static members are not for polymorphism - that's what OOP principles say.
According to this article, when you call static method or use static filed of a class, only that class will be initialized.
Here is the example screen shot.
for some reason jvm think that static block is no good, and its not executed
I believe, it is because you are not using any methods for subclass, so jvm sees no reason to "init" the class itself, the method call is statically bound to parent at compile time - there is late binding for static methods
http://ideone.com/pUyVj4
static {
System.out.println("init");
staticVar = new Object();
}
Add some other method, and call it before the sub
Sub.someOtherMethod();
new UsersClass().method();
or do explicit Class.forName("Sub");
Class.forName("Sub");
new UsersClass().method();
When static block is executed Static Initializers
A static initializer declared in a class is executed when the class is initialized
when you call Sub.staticMethod(); that means class in not initialized.Your are just refernce
When a class is initialized
When a Class is initialized in Java After class loading, initialization of class takes place which means initializing all static members of class. A Class is initialized in Java when :
1) an Instance of class is created using either new() keyword or using reflection using class.forName(), which may throw ClassNotFoundException in Java.
2) an static method of Class is invoked.
3) an static field of Class is assigned.
4) an static field of class is used which is not a constant variable.
5) if Class is a top level class and an assert statement lexically nested within class is executed.
When a class is loaded and initialized in JVM - Java
that's why your getting null(default value of instance variable).
public class Sub extends Super {
static {
staticVar = new Object();
}
public static void staticMethod() {
Super.staticMethod();
}
}
in this case class is initialize and you get hashcode of new object().If you do not override staticMethod() means your referring super class method
and Sub class is not initialized.
Why does not Java support dynamic polymorphism for static methods?
If the answer is "static methods are not supposed to be called on instances and hence method call is not needed to be resolved at runtime", then further question is 'Why does Java allow me to call static methods on instances?'. Why doesn't it simply block the user from calling the method on instances directly by giving some compile time error.
Otherway round, What would have gone wrong if Java would have supported Runtime Polymorphism for static methods?
Why does Java allow me to call static methods on instances?
Your assumption is wrong. It never calls on the instance of the class. It always called on class.
Try below sample code and you will never get NullPointerException
class ABC {
public static void hello() {
System.out.println("Hello");
}
}
ABC abc = null;
abc.hello();
What would have gone wrong if Java would have supported Runtime Polymorphism for static methods?
Polymorphism comes into picture when you override the method in subclass. since static method belong to class hence there is no meaning of overriding static methods. Hence Polymorphism always works for instance methods only that belongs to the instances of the class.
Static methods are resolved based on a variable's type and not the instance's class. This allows for some optimisations, since the exact method to be called is always known at compile time. Allowing polymorphic static methods would prevent this.
A result of allowing static methods to be called on instances is the following.
class A {
static void func() {}
}
class B extends A {
static void func() {}
}
B b = new B();
A a = b;
b.func(); // calls B.func()
a.func(); // same instance, but calls A.func()
Highly confusing, and counter intuitive. Based on how static methods were implemented allowing static methods to be called on instances was a major design flaw and should always be avoided.
By definition static methods do not require an instance to be called. By allowing polymorphic calls you require an instance, and if you require an instance to determine which method to call then why is the method static?
Dynamic Polymorphism can be supported for method overriding. But for static method overriding is not possible because it leads us to method hiding. Hence Dynamic polymorphism is not supported for static methods.
I'm glad I can call a static method through an instance of a class. It lets me call the method from the instance without qualification. And my IDE warns me if I try to (legally but irrationally) call it through an instance.
public static void foo() {
//yadda yadda
}
public void bar() {
foo(); // this is legal
MyClass.foo() // this is also legal, but would be necessary if I couldn't call it through the instance
}
// in some other class:
new MyClass().foo() // this is legal but silly and my IDE warns me about it
I have 2 classes as below
public class statictest {
public void print()
{
System.out.println("first one");
}
}
public class newer extends statictest
{
public void print()
{
System.out.println("second one");
}
}
and in the main function I do
statictest temp = new newer();
newer temp2 = new newer();
temp.print();
temp2.print();
Output is :
second one
second one
But When I make these 2 methods static the output is
firstone
secondone
what happened to late binding in this case?? Can anyone explain
This is called dynamic method invocation. You can look on this JLS.
It states,
The strategy for method lookup depends on the invocation mode.
If the invocation mode is static, no target reference is needed and
overriding is not allowed. Method m of class T is the one to be
invoked.
Otherwise, an instance method is to be invoked and there is a target
reference. If the target reference is null, a NullPointerException is
thrown at this point. Otherwise, the target reference is said to refer
to a target object and will be used as the value of the keyword this
in the invoked method. The other four possibilities for the invocation
mode are then considered.
static methods can not be overridden, they remains hidden if redefined in subclasses.
Ps: they do take part in inheritance. you can access static methods, from subclass name.
It is because static methods are not polymorphic. Static methods will not be Overridden.
Do search on Dynamic method dispatch
Static methods can't be overridden, that is why after making it static you are getting output like this.
static methods can not overridden.
you created object for newer class by using statictest class reference variable temp2 u hold that object by using super class reference variable. At the time of compilation compiler just checks syntax weather that method is available in the statictest class or not.if it is available it complies fine otherwise error will come.your code you declared static print method so it is availble in statictest class compilation done fine but your method is static it can't be override. now coming main method u declared
statictest temp = new newer();
now temp object is created with statictest class features only. it won't contains newer class methods or variables object is created based on the referenced class properties only it won't contains subclass properties(newer class) if super class(statictest) contains any non static values same as sub class(newer class) just it will overrides super class properties. why it overrides? because with the class it will not allow to declare same varibles or same methods