Java runtime method overriding rules - java

What are java runtime overriding rules for below 2 scenarios
Scenario 1 :
class A{
void display(Integer i){
sysout("In A Integer");
}
void display(Object obj){
sysout("In A Object");
}
}
class B extends A{
void display(int i){
sysout("In B int");
}
}
PSVM(){
A a=new B();
a.display(2); //In A Integer
a.display(new Integer(2)); //In A Integer
a.display("hello"); //In A Object
a.display(new Object()); //In A Object
a.display(null);
}
Scenario 2 :
class A {
void display(int i){
sysout("In A int");
}
}
class B extends A{
void display(Integer i){
sysout("In B Integer");
}
void display(Object obj){
sysout("In B Object");
}
}
PSVM(){
A a=new B();
a.display(2); //In A int
a.display(new Integer(2)); //In A int
a.display("hello"); // Compilation error
a.display(new Object()); //Compilation error
a.display(null); //Compilation error
}
I have few queries here :
1. How does general runtime override methods evaluation happens: Any reference available ?
2. Why in Scenario 2, a.display(new Intger(2)) not throwing compilation error ?

First question: you can find the rules for overriding within this tutorial from Oracle. Another good starting point might be that site. Of course, if you are looking for a spec, then only the Java Language Specification does the job.
On your second question:
a.display(new Integer(2)); //In A int
That works because the compiler sees:
a is of class A
A has a method display that takes an int
It knows how to turn an Integer into an int
Therefore it can use display(int) from class A. The compiler does unbox the Integer object into a primitive int value for you behind the covers.
And finally: in your scenario 1, you are not overriding anything. Your display method within B does not override anything in A - as it has different signature. Thus, you are still calling the method from A! You will notice that immediately, when putting #Override on your method in B!

let's say for understanding - JAVA tries to match the closest possible Data type in the parameter (given) to the parameters declared (overriden) by the called method. in both the cases Object being the Broadest Object every Object other than integer is considered as a simple Object. however, Thanks to JAVA's Autoboxing, Integer is first typed into int and therefore passed as an integer instead of an Object.

Related

type checking and method lookup

I'm confused about the functionality of type checking and method lookup in Java.
From what I understand, type checking is done at the compile time and method lookup is done at the run time.
Type checking is based on the declared type of the reference object whereas method lookup is based on the actual type of the reference.
So suppose the class MyInt is a superclass of the class GaussianInt as follows:
class MyInt
{
private int n;
public myInt(int n)
{
this.n = n;
}
public int getval()
{
return n;
}
public void increment(int n)
{
this.n += n;
}
public myInt add(myInt N)
{
return new myInt(this.n + N.getval());
}
public void show()
{
System.out.println(n);
}
}
class GaussInt extends MyInt
{
private int m; //represents the imaginary part
public GaussInt(int x, int y)
{
super(x);
this.m = y;
}
public void show()
{
System.out.println( "realpart is: " + this.getval() +" imagpart is: " + m);
}
public int realpart()
{
return getval();
}
public int imagpart()
{
return m;
}
public GaussInt add(GaussInt z)
{
return new GaussInt(z.realpart() + realpart(), z.imagpart() + imagpart());
}
And suppose in the main method we have the following:
GaussInt z = new GaussInt(3,4);
MyInt b = z;
MyInt d = b.add(b)
System.out.println("the value of d is:"+ d.show());
Which add method would be used in the show statement inside the print statement in the end?
From what I understand, b is declared to be MyInt, but it is, in fact, GuaussInt. The type checker only sees that b is of MyInt type and that it has add(MyInt) so the code makes sense and compiles.
But then in run time, the method lookup sees that b is of type GaussInt and it has two add() methods, so it will use add(GaussInt) method by looking at method signature and it produces a GaussInt. But d is of type MyInt and method lookup will think it won't work, then will it go back to add(Myint)?
How does the mechanism behind compiling and running of a program work?
From what I understand, b is declared to be MyInt, but it is, in fact,
GaussInt
You are CORRECT. b's reference type is MyInt but it is pointing to an object of GaussInt type.
But then in run time, the method lookup sees that b is of type
GaussInt and it has two add() methods, so it will use add(GaussInt)
method by looking at method signature and it produces a GaussInt. But
d is of type GaussInt and method lookup will think it won't work, then
will it go back to add(Myint)?
As the add method in GaussInt takes a reference of GaussInt type and not of MyInt type. So b.add(b) will call add method of MyInt type. Since the gaussInt has two add methods one take the argument of type MyInt and other takes the argument GaussInt type. So it will call add method of myInt(superclass).
The thing you are trying to achieve is method overriding. For it to work the method signatures should be same. That is, the parent and child class methods should match in every respect, except that the return type of child class method can be subtype of the return type of parent class method
SO in order to achieve what you have mentioned, that is b.add(b) should call add method of gaussInt, make the argument type of add method in both classes same.
Also what you should learn about is dynamic polynorphism(run time check) and static polymorphism(compile time type check).

Java virtual function calls

From my understanding all function-calls in Java are virtual, and numeral literals have the type int. But why does the Output in the example below differ?
public class A {
public int f(long d) {
return 2;
}
}
public class B extends A {
public int f(int d) {
return 1;
}
}
public class M {
public static void main(String[] args) {
B b = new B();
A ab = b;
System.out.println(b.f(1));
System.out.println(ab.f(1));
}
}
You dont override anything.
The first calling System.out.println(b.f(1)); returns 1, because it works with class B, even the method is named same, but parameters are different (long is not the same as int).
In case when parameters are same (int d), the result would be 1, because it overrides (#Override) the method from the class A.
Now, you know why the second calling System.out.println(ab.f(1)); returns 2. Look from what class it's called from.
Actually the subclass B has inherited the method f(with a long) and has added (overloaded) another method f(with a int).
When you write down a value such as 1 in such a way the compiler, even before assigning it to a typed reference does parse it as an int. More here: Java's L number (long) specification .
When you call the method f using the reference ab (which is A class) it (the reference) says I can only send you to a method f(with a long) and then implicitly cast the type int 1 into a long.
Let's try to change the type of the method in A class to f(short),
then System.out.println(ab.f(1)); will give you this error:
"The method f(short) in the type A is not applicable for the arguments (int)"

Java dynamic, static casting

import javax.swing.*;
public class Toast {
static Object[] objects = { new JButton(),
new String("Example"), new Object() };
public static void main(String[] args) {
System.out.println( new Count(objects) );
for (Object o : objects)
System.out.println(o);
}
}
class Count {
int b, s, o;
public Count(Object[] objects) {
for (int i=0; i<objects.length; i++)
count(objects[i]);
}
public void count(JButton x) { b++; }
public void count(String x) { s++; }
public void count(Object x) { o++; }
public String toString() {
return b + " : " + s + " : " + o + "\n";
}
}
Above is a piece of code that appears in some form or the other in past exam papers for one of my upcoming tests. The idea of the question is to gauge if you fully understand polymorphism, dynamic and static casting. Basic ideas of OO.
I would like to put out what I think is correct and if people would be able to correct me or add points that would be greatly appreciated.
From what I can see in the above code:
Items are upcast to objects in the object array as every class in java technically inherits from the object class. This is why when count is run it will say there are 3 objects not 1 Jbutton, 1 string and 1 object.
When the enhanced for loop is run the toString of that object type e.g. Example from the string and memory address of the object (not sure what the JButton will print). As this is done at runtime this is known as dynamic casting.
I cannot see any other points that would be relevant to the above bit of code.
The idea behind static cast and dynamic cast is related to the moment a type decision needs to be made. If it needs to be made by the compiler then it's static cast. If the compiler postpones the decision to runtime then it's dynamic cast.
So, your first observation is incorrect. The upcast does not explain the count. Objects do not loose they type but the compiler needs to perform a static cast to decide which method to invoke and it chooses count(Object). There is no dynamic dispatch in java which means that the method called is always decided at compile time.
You second observation is also incorrect. What is in use is polymorphism. In Java, methods are always invoked for the type of the instance and not for the type in the code. Also, there is no dynamic casting here. The compiler can verify all the types. It's just that method invocation is always virtual but that's not a cast.
Actually in this example, I don't see a single case of dynamic casting. The compiler can verify all types. You normally only see dynamic casting when down casting and there is no case of that.
Here's what I would take away:
The compiler implicitly upcasts when performing assignments. This includes assigning to array elements during initialization.
The compiler and JVM do not implicitly downcast when selecting method overloads. The static type of the objects array is Object[], so the count(Object) method will always be called.
The JVM does implicitly "downcast" (in a sense) when invoking a virtual method. The println loop will always invoke the toString method of the actual object instance rather than always invoking Object.toString.
In your Count() method, always count(object) will be called as all objects are up casted to object.
To prevent that you can call method instance of and then downcast the object and call the count
public Count(Object[] objects) {
for (int i=0; i<objects.length; i++)
{
if(objects[i] instanceof JButton)
count((JButton) objects[i]);
else if(objects[i] instanceof String)
count((String) objects[i]);
else
count(objects[i]);
}
}

Why can't I have two methods with ArrayList parameters?

Why can't I make two overloaded methods whose parameters are both array lists, but with different data types?
public class test {
public static void main(String[] args){
ArrayList<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
ints.add(3);
ints.add(4);
ints.add(5);
showFirst(ints);
ArrayList<Double> dubs = new ArrayList<Double>();
dubs.add(1.1);
dubs.add(2.2);
dubs.add(3.3);
dubs.add(4.4);
dubs.add(5.5);
showFirst(dubs);
}
public static void showFirst(ArrayList<Integer> a)
{
System.out.println(a.remove(0));
}
public static void showFirst(ArrayList<Double> a)
{
System.out.println(a.remove(0));
}
}
I am in eclipse, and it underlines the problem causing code in red and gives this message: Method showFirst(ArrayList<Integer>) has the same erasure showFirst(ArrayList<E>) as another method in type test
The only way I could get it to work is my adding other parameters, such as , int b after showFirst(ArrayList<Integer> a and , int b after showFirst(ArrayList<Double> a.
Is there any way to make this code work the way I intended? If not, I'd like to know why this is happening.
Running the program generates the following error message:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method showFirst(ArrayList<Integer>) in the type test is not applicable for the arguments (ArrayList<Double>)
at test.test.main(test.java:25)
Edit:
Using or , what if I wanted to do things where I need the data type such as:
public static int[] reverseInArray(ArrayList<Integer> a)
{
int n = a.size();
int[] b = new int[n];
while(n > 0)
{
b[n] = a.remove(0);
n--;
}
return b;
}
public static double[] reverseInArray(ArrayList<Double> a)
{
double n = a.size();
double[] b = new int[n];
while(I > 0)
{
b[n] = a.remove(0);
n--;
}
return b;
}
At run time, every ArrayList<Whatever> will be converted to ArrayList (raw) due to type erasure. So, just have one method that receives List<? extends Number>.
//renamed to show what the method really does
public static void removeFirst(List<? extends Number> a) {
System.out.println(a.remove(0));
}
Note that the method above will work only for Lists (ArrayList, LinkedList and other implementations of List) which declares to hold a class that extends from Number. If you want/need a method to remove the first element from List that holds any type, use List<?> instead:
public static void removeFirst(List<?> a) {
System.out.println(a.remove(0));
}
Remember to always program to interfaces instead of specific class implementation.
Generics are only enforced at compile time. At runtime an ArrayList is an ArrayList.
You can combine the two methods in this particular case, though:
public static void showFirst(ArrayList<? extends Number> a)
{
System.out.println(a.remove(0));
}
Because generics are erased at runtime. In other words, your code doesn't know that the two methods are different. In fact, you have another compiler error that you're not telling us about:
Method showFirst(ArrayList<Integer>) has the same erasure showFirst(ArrayList<E>) as another method in type Main
... because of type erasure, your generic parameters are unknown at runtime, hence your overridden methods share an ambiguous signature.
Have this method only, because, generics are available only in compile, so, both of your methods are compiled to same signature. So it's ambiguous which method to be called
public static void showFirst(ArrayList<? extends Number> a)
{
System.out.println(a.remove(0));
}

Can somebody explain why do I get this when I run the program? (simple Java polymorphism)

So, I have these 3 classes in Java.
When I run the program I get:
20,
15,
10,
My question is, why do I get this instead of:
15,
20 (doesn't public int getX(); in class B get us to 15+5=20?),
10
for example?
Can you please explain to me , step by step, what really happens in this program because I am very confused with the output(and the sequence).
public class A {
private int x = 15;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public void printX() {
System.out.println(this.getX());
}
}
Child:
public class B extends A {
private int x = 5;
#Override
public int getX() {
return super.getX() + x;
}
#Override
public void setX(int x) {
super.setX(x);
super.printX();
}
#Override
public void printX() {
System.out.println(super.getX());
}
}
and
public class C {
public static void main(String[] args) {
A a = new B();
System.out.println(a.getX());
a.setX(10);
a.printX();
}
}
This is happening because you instantiate a as a B object - A a = new B(). It doesn't matter that the explicit type of a is A; it's more generic (abstract) than its real type B (because B inherits from A), therefore polymorphism calls B methods (more specific) in first order. The same applies to fields.
After calling a.getX() class B references to A's getX(), which returns its 15 (superclass method has no reference to the object it was called from in this case), then 5 (B's x) is added, resulting in 20.
The subsequent calls behave in a similar manner.
I have given a basic example similar to your problem go through it you will get your answer. This is the concept of runtime polymorphism
Inheritance creates typecompatibility. It allows a super class reference to refer to the object of sub class. (Reverse is not true).
A super class reference, that refers to object of sub class, can only be used to access the inherited and overrridden methods of sub class. The members newly defined in sub class are not accessible using reference of super class.
class A
{
void f1()//this holds address of object of B
{
System.out.println("A f1");
}
void f2()
{
System.out.println("A f2");
}
}//A
class B extends A
{
void f3()//new method
{
System.out.println("B f3");
}
void f2()//this holds address of object of B
{
System.out.println("B f2 starts");
f3(); //this.f3()
System.out.println("B f2 ends ");
}
}//B
class TypeCmptbl
{
public static void main(String args[])
{
A ref; //reference of A
ref = new B();//Object of B
//ref.inherited() allowed
ref.f1();
//ref.overridden() allowed
ref.f2();
//ref.newMembersOfChild() not allowed
//ref.f3();
}//main
}
Consider the statement
ref.f2();
Here ref is a reference of class A and it has address of object of class B f2() is a overridden method.
When compiler detects such a statement then it doesn't bind the function call with any definition. It only validates the call.
Binding of such calls is left for the runtime environment. At program runtime system identifies the datatype of the object and binds the function call with the function definition provided by the class of object. This type of binding between the function call and function definition is called as "runtime polymorphism" .
Your question is related to the runtime polymorphism in java note that methods are bind at runtime, and the variables are bind at Compile time
In your example
public class C {
public static void main(String[] args) {
A a=new B();
System.out.println(a.getX());
a.setX(10);
a.printX();
}
}
// reference is of A but the object is of B, so at runtime JVM see that memory is of B so the B's method is called, this is runtime Polymorphism
when the below statement is called , the getX() of class B is invoked.
System.out.println(a.getX());
#Override
public int getX() {
return super.getX() + x; // this will add 15 from class A + 5 in this method.
}
the above statement displays 20
when the below statement is called,
a.setX(10);
#Override
public void setX(int x) {
super.setX(x); // observe this method, this prints 15
super.printX(); // this prints 10
}
//super.setX(x); it will call
public void setX(int x) {
this.x=x; // 10 <--- 15 so 15 is displayed
}
here this.x refers the value which is passed through a.setX(10).
A a = new B();
So the concrete type of a is B.
System.out.println(a.getX());
You're calling getX() on an object of type B. So the following method is called, because the concrete type of a is B, and B has overridden the getX() method defined by A:
public int getX() {
return super.getX() + x;
}
It adds B's x (whose value is 5), with the result of super.getX(). This method, in A, is defined as
public int getX() {
return x;
}
So it returns A's x, which is initialized to 15.
The result is thus 5 + 15 = 20.
The rest can be explained the same way. Remember that fields are not accessed in a polymorphic way. Only methods are. So, inside the code of A, when you see x, it always mean "the value of the field x in A". Inside the code of B, when you see x, it always mean "the value of the field x in B".
When you say:
A a = new B();
it means Object of A is instantiated with class B. So, in the memory, a space is reserved for your object 'a' which contains all the methods and properties of class B (not A).
So, when the first print statement is executed, it executes the getX() method of the class B and not the getX() method of class A.
For other methods called by your object 'a', the methods of the class B are called.
This is also known as dynamic binding, as JVM allocates the memory to the object 'a' at the run time and not compile time.
For more details on dynamic binding check these links:
http://www.tutorialspoint.com/java/java_overriding.htm
http://www.tutorialspoint.com/java/java_polymorphism.htm
I also suggest you to instal eclipse on your machine and run your code in the debug mode.
This is the best way you can study your code.

Categories

Resources