Given the following block of code i would like to understand why and how, emphasis on how, the method print in Subclass is invoked:
class Super {
Super() {
// what happens so that Sub's method print() is invoked
print();
}
public void print() {
System.out.println("in super");
}
}
class Sub extends Super {
Sub() {
super();
}
public void print() {
System.out.println("in sub");
}
}
public class TestClass {
public static void main(String[] args) {
Super s = new Sub(); // "in sub".. not so much expected
s.print(); // "in sub".. as expected
}
}
My understanding is that during compile time, classes will get V-table pointervtblPtrassociated with methods 'belonging' to a class.
Class Super should therefore have reference to it's own implementation of method print().
How come the method print() in Sub is invoked in constructor of Super? What really happens here ?
Here is what Super class looks like for the JVM (actually, that is the human-readable version obtained by javap -c Super)
class Super {
Super();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: invokevirtual #2 // Method print:()V
8: return
public void print();
Code:
0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String in super
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
as you can see, the print inside Super contructor was not resolved at compile time to Super::print. A virtual call means that it is resolved at runtime, with respect to class of this.
My understanding is that during compile time, classes will get V-table pointervtblPtrassociated with methods 'belonging' to a class. Class Super should therefore have reference to it's own implementation of method print().
You have a fundamental misunderstanding about virtual methods and overriding. In Java, every non-static, non-private method is virtual. Every virtual (normal) invocation of a virtual method, from anywhere, will invoke the version associated with the class of the object on which the method is invoked. That version might or might not be inherited, and might or might not override a superclass's method.
That a virtual method invocation is performed implicitly or explicitly on this in no way changes any of that. In particular, the actual class of the object being initialized is visible to every constructor, and provides the context for all their method invocations. In fact, this is why it's rarely a good idea for a constructor to invoke a virtual method provided by its own class. Superclass constructors run before subclass constructors, so if a superclass constructor invokes a method that happens to be overridden by a subclass, then that method will run before the object is fully initialized in the way that method may assume.
Related
Besides that Java inheritance is a fundamental feature of the language, I have some questions.
Here is the source for my testing example:
class MyClass{
public void say(String t){
System.out.println("Hello MyClass "+t);
}
public void print(MyClass t){
System.out.println("MyClass is printed");
}
public void anotherPrint(int i){
System.out.println("MyClass is printed again");
}
}
class MyClass2 extends MyClass{
public void say(String t){
System.out.println("Hello MyClass2 "+t);
}
public void print(MyClass2 t){
System.out.println("MyClass2 is printed");
}
public void anotherPrint(double i){
System.out.println("MyClass2 is printed again");
}
}
public class HelloWorld{
public static void main(String []args){
MyClass klass = new MyClass2();
klass.say("h"); //Question 1 (Prints: "Hello MyClass2 h")
klass.print(new MyClass2()); //Question 2 (Prints: "MyClass is printed")
klass.print(new MyClass()); //Question 3 (Prints: "MyClass is printed")
klass.anotherPrint(1); //Question 4 (Prints: "MyClass is printed again")
klass.anotherPrint(1.0); //Question 5 (Throws Exception!)
}
}
I have the following questions:
1. The klass object is instance of MyClass. Why does it execute the method from the MyClass2 class?
2,3 . At question 1 klass calls the method of the MyClass2 class. Here I used a parameter that fits to each one of the overridden and overloaded (simultaneously) methods. Why klass object always calls the method from the MyClass class?
4. It is normal. No question at all.
5. It is right to throw an exception. The klass object does not have this method with double parameter. But, why it is not called the method from the MyClass2 class, just like it happened at Question 1?
1. The klass object is instance of MyClass.
No it is a reference variable of type MyClass but referring to an object of MyClass2.
2. Why does it execute the method from the MyClass2 class?
Since you are invoking say() on an object of MyClass2, it executes the say() of MyClass2. Expected behavior.
This is called the run time polymorphism in Java. This provides the ability to override functionality already available in the class hierarchy tree. At run time, which version of the method will be invoked is based on the type of actual object stored in that reference variable and not on the type of the reference variable.
3. At question 1 klass calls the method of the Class2 class. Here I used a parameter that fits to each one of the overridden and overloaded (simultaneously) methods. Why klass object always calls the method from the MyClass class?
That is not overridden method. An instance method in a subclass with the same signature (name, plus the number and the type of its parameters) and return type as an instance method in the superclass overrides the superclass's method.An overriding method can also return a subtype of the type returned by the overridden method. This is called a covariant return type.Your method signatures are different. Hence invoking klass.print() where klass is a MyClass reference will always refer to the print() of MyClass.
4. It is right to throw an exception. The klass object does not have this method with double parameter. But, why it is not called the method from the MyClass2 class, just like it happened at Question 1?
Because at compile time, the compiler validates if you can call a method based on the reference type. Here the reference type is MyClass and since MyClass doesn't define anotherPrint(double), the compiler complains.It is a compile time check.In question 1, compiler verified klass.say("hi") and it saw that there exists a method in MyClass which can be invoked this way. At that time, it was not concerned whether klass reference variable will refer to a MyClass object or MyClass2 object at runtime. Hence it worked.
You can refer to these Oracle's tutorials here.
An instance of a class will have the methods of the father(s) plus its own methods. If the signature of one of the child class is the same than the signature of a method in the father, will override it.
In this example, an instance of MyClass2 will have this methods:
public void say(String t) //From MyClass2 (override)
public void print(MyClass2 t)
public void anotherPrint(double i)
public void print(MyClass t) //Inherited from MyClass
public void anotherPrint(int i) //Inherited from MyClass
But you are declaring klass as a MyClass, so it will have available this methods
public void say(String t) //From MyClass
public void print(MyClass t)
public void anotherPrint(int i)
Now, answering your questions
1 - You invoke the method say of a MyClass. But in runtime, actually klass is an object of MyClass2 and MyClass2 overrides this method, so it will invoke the one from MyClass2
2,3 - You invoke the method print of MyClass. In runtime, klass is from MyClass2, but MyClass2 IS NOT OVERRIDING THIS METHOD. The signature is different. So the one to be called is the MyClass. Works fine with a MyClass2 object as parameter since MyClass2 is a MyClass
5 - MyClass has not any method called anotherPrint receiving a double
Question 1:- With the line MyClass klass = new MyClass2(); you have done upcasting, catching the reference id(object) of child class. In case of upcasting, the methods of the child class are called.
Though the compiler checks for the say() function in the parent at comiple time but at run time compiler sees that we have say() function in child also, so it binds it with the child class method and calls it. This is the reason you are getting the output for Question 1 as Hello MyClass2 h
Method overloading and method overriding in Java is two important concept in Java which allows Java programmer to declare method with same name but different behavior. Method overloading and method overriding is based on polymorphism in Java. In case of method overloading, method with same name co-exists in same class but they must have different method signature, while in case of method overriding, method with same name is declared in derived class or sub class.Method overloading is resolved using static binding in Java at compile time while method overriding is resolved using dynamic binding in Java at runtime. In short When you overload a method in Java its method signature got changed while in case of overriding method signature remains same but a method can only be overridden in sub class. Since Java supports polymorphism and resolve object at run-time it is capable to call overridden method in Java
Read more: http://javarevisited.blogspot.com/2011/12/method-overloading-vs-method-overriding.html#ixzz34EEhLp2u
public class PrivateOverride {
private void f() {
System.out.println("private f()");
}
}
public class Derived extends PrivateOverride {
public void f() { //this method is never run.
System.out.println("public f()");
}
}
public static void main(String[] args) {
// instantiate Derived and assign it to
// object po of type PrivateOverride.
PrivateOverride po = new Derived();
// invoke method f of object po. It
// chooses to run the private method of PrivateOveride
// instead of Derived
po.f();
}
}
So, the output of this code is private f(). Now, the question arises to my mind: how can po which is an object of Derived Class call a private method of PrivateOverride which is its base class?
Because you defined the main method in PrivateOverride class. If you put the main method in Derived class, it would not compile, because .f() would not be visible there.
po.f() call in PrivateOverride class is not a polymorphism, because the f() in PrivateOverride class is private, so f() in Derived class is not overriden.
I do not really see the problem. That method is called ""within"" the class, this is pretty much expected.
This method is not overidden at all, instead it is shadowed by another one.
Methods in Java are dispatched depending on the static type of the receiver, which in this case is a PrivateOverride. Do not be confused by the fact that the po variable, by examining the code, can only hold a Derived instance at that line: only the declaration matters when available methods are searched.
And, by the way, the call to f() is not even translated into a virtual call in the final bytecode, because when the compiler looks for the potentially applicable methods in the class PrivateOverride, it only finds Object methods and the f() definition, which is only visible because the main() method is defined in PrivateOverride itself (see JLS 15.12)
I just went through the byte code of the compiled version of the above class and got the invokespecial Opcode. This Opcode was enough to tell the reason why the actual output is obvious. Invokespecial is used in three situations in which an instance method must be invoked based on the type of the reference, not on the class of the object. The three situations are:
1)invocation of instance initialization () methods
2)invocation of private methods
3)invocation of methods using the super keyword
Above example lies within the second scenario where we have invocation of private methods. So the method got invoked based on the the type of reference i.e PrivateOverride rather than type of class i.e Derived
So now the question arises why invokespecial? We have other Opcode like invokevirtual which gets invoked for method on the basis of classtype rather than reference type. So lets discuss why invokespecial Opcode is used for private methods. But we should know the difference between invokevirtual and invokespecial. Invokespecial differs from invokevirtual primarily in that invokespecial selects a method based on the type of the reference rather than the class of the object. In other words, it does static binding instead of dynamic binding. In each of the three situations where invokespecial is used, dynamic binding wouldn't yield the desired result.
When a method is invoked the JVM has to figure out what piece of code to execute: sometimes this is done at runtime (e.g. when overriding methods); sometimes this is done at compile time (e.g. when overloading methods). Once the JVM resolves what bit of code it is executing the actual instance that you are referring to isn't really any more significant than any other parameter.
The example code given sets up a scenario that may look like method overriding but isn't, so the method ends up getting bound at compile time. The private visibility modifier is not violated because the invocation doesn't touch any of Derived's code.
Looking at the bytecode (which the Java code is compiled to via javac) is instructive -
Say we slightly modify the original code to:
public class PrivateOverride {
private void f() {
System.out.println("private f()");
}
public static void main(String[] args) {
PrivateOverride po = new Derived();
po.f();
Derived d = new Derived();
d.f();
}
}
class Derived extends PrivateOverride {
public void f() {
System.out.println("public f()");
}
}
The main method compiles to (edited for brevity):
public static main([Ljava/lang/String;)V
NEW Derived
DUP
INVOKESPECIAL Derived.<init>()V
ASTORE 1
ALOAD 1
INVOKESPECIAL PrivateOverride.f()V
NEW Derived
DUP
INVOKESPECIAL Derived.<init>()V
ASTORE 2
ALOAD 2
INVOKEVIRTUAL Derived.f()V
RETURN
Notice that in each case the method is invoked on the compile time type. Notice also that the second call of f() uses the INVOKEVIRTUAL instruction. This is what tells the JVM to check the runtime type and decide what to call based on that.
It behaves this way because that is how the JVM was defined to behave in those cases.
The hard part is understanding what is going on and why.
You invoked the private method from within the class in which it was private. So the trojan horse is inside the castle, he can fiddle with the private variables. Take the trojan horse out of the castle and the private method is no longer visible.
This example might clear things up, Consider this program:
public class Bicycle {
private void getCost() {
System.out.println("200");
}
public static void main(String[] args) {
Bicycle ACME_bike = new ACME_bike();
ACME_bike.getCost();
Bicycle mybike = new Bicycle();
mybike.getCost();
ACME_bike acme_bike = new ACME_bike();
acme_bike.getCost();
//ACME_bike foobar = new Bicycle(); //Syntax error: Type mismatch:
//cannot convert from
//Bicycle to ACME_bike
}
}
class ACME_bike extends Bicycle {
public void getCost(){
System.out.println("700");
}
}
This program prints:
200
200
700
If you change the access modifier of getCost within Bicycle to public, protected, or package private(no modifier), Then it prints this:
700
200
700
There are four visibility levels in Java, package-level (implied by not using any visibility), public (everyone can call this), private (only I, and internal classes that see my functions as global, can call this), and protected (I, and any subclass, can call this).
You can either make your second class an internal class and then you don't override but simply call the function as if it's global (as far as the internal class is concerned), but then you can't really create instances wherever you want because it's a class that can be used exclusively by the owner (so if you want to use it elsewhere, the owner would need to be a factory and return it as if it's the base class) or you can make the method protected, and then the extending class can call the method.
This question already has answers here:
Can a class have no constructor?
(7 answers)
Closed 7 years ago.
So when a class has a private constructor you can't initialize it, but when it doesn't have a constructor you can. So what is called when you initialize a class without a constructor?
As example, what is called here (new b())??
public class a {
public static void main(String args[]) {
b classB = new b();
}
}
public class b {
public void aMethod() {
}
}
There's no such thing as a "class without a constructor" in Java - if there's no explicit constructor in the source code the compiler automatically adds a default one to the class file:
public ClassName() {
super();
}
This in turn can fail to compile if the superclass doesn't have a public or protected no-argument constructor itself.
It's called the default constructor. It's automatically added when a class doesn't explicitly define any constructors.
Formal specification:
If a class contains no constructor declarations, then a default
constructor that takes no parameters is automatically provided:
If the class being declared is the primordial class Object, then the default
constructor has an empty body.
Otherwise, the default constructor takes no parameters and simply invokes the
superclass constructor with no arguments.
the default no argument constructor is invoked - see here for more information
When in doubt, use javap.
Empty.java:
public class Empty {
public static void main(String[] args) {}
}
Then:
javac Empty.java
javap -v Empty.class
Output excerpt:
public Empty();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
Ha! A constructor got generated. If we try the same for:
public class Empty {
public Empty() {}
public static void main(String[] args) {}
}
we see exactly the same bytecode.
I have asked if this is a Java-only restriction or if it is also present on the bytecode-level at: Is it valid to have a JVM bytecode class without any constructor?
There is an invisible default constructor that looks something like this:
public B() {
super();
}
When you call new B(), this implicit constructor gets called.
One note, in Java we use the convention that class names begin with an uppercase alphabetic character. So I have changed that for you.
Javadoc mentions that Object class has a public no-arg constructor. But Object's source code doesn't have any explicit constructor in it. So obviously the compiler has generated one for it. However, if I see the call stack trace when a constructor is about to return (as shown below), I do not see any call to Object.<init> in that trace.
So the question is, does Object class have a default constructor as the doc says? If yes, why do I not see it in the call stack trace?
public ConTest()
{
new Throwable().printStackTrace();
}
Result:
java.lang.Throwable
at ConTest.<init>(ConTest.java:8)
at ConTest.main(ConTest.java:16)
Super constructors are run before sub/base constructors. In your example Object's constructor has already been run when new Throwable().printStackTrace() is executed.
A more explicit version of your code:
public ConTest()
{
super();
new Throwable().printStackTrace(); // you will not see super() (Object.<init>) in this stack trace.
}
You do not see it in the stack trace, because it was already called. The exception is thrown in your code.
Your code is equivalent to writing:
public ConTest() {
super(); // this will call the Object constructor
new Throwable().printStackTrace();
}
You do not see it in the stack trace because the constructor of the super class is called before your new Throwable().printStackTace() call. What the compiler actually creates is following .
public ConTest()
{
super(); // This is the call to the base class constructor
new Throwable().printStackTrace(); // already back from the base class constructor
}
Yes,Object class have a default constructor as the doc says.
As you know insted of doing that you can check it by using javap -c ConTest in command prompt
you can see it's calling the object class default constructor() in below's code's Line No:1
C:\stackdemo>javap -c ConTest
Compiled from "ConTest.java"
public class ConTest extends java.lang.Object{
public ConTest();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: new #2; //class java/lang/Throwable
7: dup
8: invokespecial #3; //Method java/lang/Throwable."<init>":()V
11: invokevirtual #4; //Method java/lang/Throwable.printStackTrace:()V
14: return
public static void main(java.lang.String[]);
Code:
0: new #5; //class ConTest
3: dup
4: invokespecial #6; //Method "<init>":()V
7: astore_1
8: return
}
Thank you
As Suggested above super() is the first call in the constructor and for method More Information here
When you compile a class, the Java compiler creates an instance initialization method for each constructor you declare in the source code of the class. Although the constructor is not a method, the instance initialization method is. It has a name, <init>, a return type, void, and a set of parameters that match the parameters of the constructor from which it was generated
I'm receiving this error:
java.lang.VerifyError: Bad <init> method call in method FooBar.<init>(I)V at offset 2
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2404)
at java.lang.Class.getConstructor0(Class.java:2714)
at java.lang.Class.getDeclaredConstructor(Class.java:2002)
when attempting to access the constructor of a class that I have modified with ASM 4.0 (using jdk7).
I have checked the bytecode for the initialization method of the class and it is as follows:
aload_0
iload_1
invokespecial com/foo/F/<init>(I)V
return
Decompiling the bytecode produces:
import com.foo.Foo;
public class FooBar extends Foo
{
public FooBar(int i)
{
super(i);
}
}
I'm completely stumped as to why I am receiving this error. I don't know if I've given enough information; please let me know if I can add any more information.
EDIT: Here is the code that is accessing the constructor:
Class fooBarClass = /* define class from class file bytes */;
Constructor fooBarConstructor = fooBarClass.getDeclaredConstructor(int.class);
EDIT2: Here is the code for the class Foo:
public class Foo extends F {
public Foo(int i) {
super(i);
}
}
Try to decompile class Foo and watch for the proper constructor. My bet is constructor Foo(int) does not exist.
The VerifyError is being thrown because the method that is being invoked in the constructor of class FooBar is actually the method of class F and not class Foo.
The constant pool reference to the super method in class FooBar was to the wrong class (i.e. F instead of Foo). Because of this, a VerifyError is thrown with the corresponding message "Bad method call".