Core java - class and object [duplicate] - java

When I was analyzing a simple java code related with overloading and inheritance I expected to recieve an output that overloads matching the argument's data types. But it doesn't work that way.
Code:
class A {
public int calc (double num){
System.out.println("calc A");
return (int)(num+1);}
}
class B extends A{
public int calc (long num){
System.out.println("calc B");
return (int)(num+2);}
}
class C extends B{
public int calc (int num){
System.out.println("calc C");
return num+3;}
}
class D extends C{
public int calc (float num){
System.out.println("calc D");
return (int)(num+4);}
}
class Program{
public static void main(String[] args){
int num1=10;
long num2 = num1;
Object o1 = num1;
System.out.println("num1 Type: "+o1.getClass().getName());
Object o2 = num2;
System.out.println("num2 Type: "+o2.getClass().getName());
A a1=new D();
A a2=new D();
System.out.println("a1 Type: "+a1.getClass().getName());
System.out.println("a2 Type: "+a2.getClass().getName());
int result = a1.calc(num1)+a2.calc(num2);
System.out.println("Number: "+result);
}
}
Output:
num1 Type: java.lang.Integer
num2 Type: java.lang.Long
a1 Type: D
a2 Type: D
calc A
calc A
Number: 22
I was testing the code here:
ideone

Your main question seems to be about why the type outputs don't match with the formal types. This is entirely intentional, and it's what makes object oriented programming so powerful.
When a method is invoked on an instance, the runtime system looks at the actual type of the instance, and looks up the method to call based on its actual type, rather than on its formal type.
If this weren't the case, you wouldn't be able to get anything useful done. You want to be able to declare an abstract class A, with concrete classes B and C hanging off it that implement the details in different ways. But you also want to be able to declare variables of type A, without caring where they've come from, and whether they're actually of type B or type C. You can then invoke methods that are part of the contract of A, and it'll do the right thing: something that's really a B will invoke B's implementation, and likewise for C.
As for why you end up invoking A's calc method rather than D's, this is again because of the way polymorphism works. The formal type of the variables is A; so when you invoke .calc(), the type system will:
find the most appropriate method in class A to match the call at compile time;
see whether that has been overridden between A and the actual type at runtime;
call the overridden version if there is one, or A's version if not.
But you haven't overridden the calc() method at all: you've supplied methods with different signatures. So in step 1 (at compile time) the type system finds A.calc(double); in step 2 (at runtime) it discovers that this hasn't been overridden further down the class hierarchy; in step 3 (runtime) it therefore invokes A's version.
Overloads are resolved at compile time based on formal types; overrides are resolved at runtime based on actual types.

This is because those methods are overloads, not overrides of the original calc method. Therefore, if you are using a reference of type A, all that can be seen are methods that originally belonged to A. All the other methods are hidden in the object, just as if you had written them with new names.
So when the compiler has to decide which method to call for each calculation, it doesn't have all the options that you think it has. It just has the original calc(double), so it compiles the call as "convert the value to double and call calc(double)". At compile time, it doesn't know that the actual class is not A. It can't compile into code that says "check at runtime if there is a method called calc(int), if so, use it, if not, convert to double and use calc(double). It needs to know what instructions to put there at compile time. And at that time, all it knows about this reference is that it's an A.
EDIT in response to comments:
The compiler always chooses which method is going to be invoked using the contract of the reference's type. That is, the type of your variable, which is A in this case.
This happens whether or not the actual object has an overriding method. At this point the compiler doesn't know about it. What it does is tell the runtime environment: "When you get to this point, take the actual object, and run the method with this signature: calc(double)".
So, if at runtime, the actual object has also calc(int) and calc(long) and other methods named calc, it doesn't matter, because the compiler said "use calc(double)".
Now, if the runtime object has an overriding calc(double), the runtime environment will take that instead of the original calc(double) because that's the nature of overriding.
To sum up:
The compiler only knows about method signatures that exist in the reference type - your variable, in this case.
The compiler puts instructions that mean "use the method with this specific signature or any override (with the same signature).
The runtime environment looks at the actual object, and checks what kind of calc(double) it has. If it has an override, it will use that. If it has only the original, it will use that.

Related

Java inheritance casting runtime error vs compiler error

The Problem
Consider the code below. B inherits from A, and none of them inherit from String.
I'd like to know the answers to the following questions:
why does the first first cast, B b1 = (B) a1;, produce a runtime error?
why does the first second cast, String b1 = (String) a1;, produce a compilation error?
Why is there a difference? Why doesn't the compiler see the problem in the first case?
The Code
public class Main {
public static void main(String[] args) {
A a1 = new A();
B b1 = (B) a1;
String b1 = (String) a1;
}
}
with class A:
public class A {}
and class B:
public class B extends A {}
A variable of type A could have been assigned an instance of B, because a B is an A. Eg a Dog is an Animal, so a box labelled “Animal” could contain a dog.
But a variable of type A cannot have been assigned a String. Eg A box labelled “Animal” will not contain a Brick.
You may be asking yourself why the compiler doesn’t complain when we can see that the code will clearly fail - there’s no way the variable is a B; it’s an A!
The compiler looks only at the type of the variable when making its checks. It doesn’t examine what code came before. Although your example is simple, checking what a variable actually contains would be an impossible task in the general case.
why does the first first cast, B b1 = (B) a1;, produce a runtime error?
Variables of type A can store instances of B. However, not all instances of A are instances of B.
An A is not a B, but a B is an A. (Like, not all animals are dogs, but dogs are animals).
why does the first second cast, String b1 = (String) a1;, produce a compilation error?
A is not a supertype of String, and String is not a supertype of B.
Why is there a difference? Why doesn't the compiler see the problem in the first case?
Because variables of type A can store instances of B; but variables of type A can never store instances of String.
A variable of type A could in fact be of type B as B extends A. But a variable of type A can never be of type String. That's why the compiler can catch the cast to String, but not the cast to B.
why does the first first cast, B b1 = (B) a1;, produce a runtime error?
Because a1 is an instance of A, but is not compatible with B. Specifically, new A() creates an object that is not compatible with subclasses of A. If the runtime class (i.e., the class with which new was called) of the object is not the same as or a subclass of the target class, casting to that target class will fail at runtime. This is simply because the child class has nothing to do with that object.
why does the first second cast, String b1 = (String) a1;, produce a compilation error?
Even if the actual casting happens at runtime, the compiler performs type checks and prevents pointless operations like this. For this scenario, casting an A object to String is nonsense and the compiler can detect it: there is no relationship between String and A, and the compiler knows what class is a child of what other class. The compiler knows that there is no way in Java for a1 to be an instance of String or of a subclass of String, and that's because String is not a parent of A, the declared type of a1. There are exceptions to this, such as when the cast is begin made to an interface.
Why is there a difference? Why doesn't the compiler see the problem in the first case?
The compiler only validates type casts based on static types (the type of the variable or of the expression). It doesn't look at the runtime class, which of course isn't available until runtime when the object is actually created. When it can determine with certainty that the cast can't possibly be valid (such as in the second case), it will fail. In the first case, casting from A to B passes compilation because the declared types are compatible (i.e., an A object can possibly be an instance of B, and the compiler leaves it for the runtime to check the actual object). In the second case, the compiler knows that an A object can never be an instance of String (because String is nowhere in A's type hierarchy, and this won't change at runtime)
The class hierarchy diagram for the class A would be:
Object -> A -> B (Note that every class extends Object)
B b1 = (B) a1;
The above line compiles because B extends A and hence the compiler sees it as a valid downcast. The java compiler only checks whether it is possible for an object of type A to be of type B, by checking the class hierarchy of B (whether B extends A directly or indirectly). It doesn't check the actual type of the object A at this point. It wasn't implemented this way since it would add a lot of complexity in the compiler. Also if an object is being downcast (to call some specific sub class method perhaps), then the responsibility is on the programmer to be aware of the specific type of the object. In this example since a1 can't be cast to type B, it will be detected by the JVM at runtime.
String b1 = (String) a1;
In this case, the class String is nowhere in the class hierarchy diagram of A. Therefore it can be detected at compile time that this is an invalid cast.

Why does Java compiler decide whether you can call a method based on the “reference” type and not on actual “object” type?

I was just wondering why does Java compiler decide whether you can call a method based on the "reference" type and not on actual "object" type? To explain I would like to quote an example:
class A {
void methA() {
System.out.println("Method of Class A.");
}
}
class B extends A {
void methB() {
System.out.println("Method of Class B.");
}
public static void main(String arg[]) {
A ob = new B();
ob.methB(); // Compile Time Error
}
}
This will produce a Compile Time Error that method methB() not found in class A, although Object Reference "ob" contains an object of class B which consists of method methB(). Reason for this is that Java Compiler checks for the method in Class A (the reference type) not in Class B (the actual object type). So, I want to know whats the reason behind this. Why does Java Compiler looks for the method in Class A why not in Class B(the actual object type)?
Assume that you have an Animal class and a Dog class which extends Animal. Now, if Animal defines a method named speak() and Dog defines a method named bark(). If you do something like this :
Animal a = new Dog();
It means you are pointing to a Dog and saying that it is an Animal. When you look at a Dog as an Animal (and not as a Dog), you can only call methods which are defined for an Animal, not for a Dog.
During compilation, the compiler checks if a method being called is defined in the reference type.
By declaring the variable to be of type A you essentially hide the fact that it actually is a subtype. Not seeing the methods of type B is standard behavior which is essential in (strictly typed) object orientation.
Quite simply, the compiler has no idea about the type of the variable. Unlike the scenario you described above, it's usually not that obvious what the actual "object" type is. That's why the "object" type is the runtime type: it's known at runtime.
Imagine a method like this:
public static void process(A ob) {
ob.methB(); //how do you know if this is valid?
}
public static void main(String[] args) {
process(new B()); //would make the above call valid
process(new A()); //would make the above call invalid
}
Simply put, you allow the variable to have a runtime type that would make your call invalid. It might be valid, but if you rely on methB(), you have to take a B as parameter.
Back to your code example, this example doesn't make any sense:
A ob = new B();
//why would you declare ob as A if you are storing a B inside it
//this is only useful if you want to store different types of objects in it at some point
//however, that's not the case, because in the next line:
ob.methB(); //you're calling methB()
Your doubt is fine but its a one type of oops. You are assigning one sub class object to super class so i will expose only super class's method to caller.
Simply you assume that A class as interface which have 2 methods and B is implementation class which have ten methods inside it. But if you try to create object for that class with interface A it will expose only 2 methods. The same logic is applied in your case.

Java: Casting to an Interface and Inheritance

I've been trying to understand casting in Java and how it affects the references. I've come up on this particular example:
public interface A1{
public void foo();
};
public class A2{
public void bar();
public static void main( String[] args )
{
A2 a = new B();
A1 c = (A1)a;
c.foo();
}
};
public class B extends A2 implements A1{
public void foo(){ System.out.println("This is B"); }
}
It prints "This is B", but i'm not sure why. This is how I understand this currently: a is a reference to an object of type A2, but during runtime, it points to a heap object which has the properties of B, but a only "sees" the properties of A2. But the types are already determined during compilation, so the cast tries to cast A2 to A1, which it can't do. Obviously I'm wrong, but I can't figure out why. Any help will be appreciated.
Casting conceptually has two components,
At runtime the JVM ensures that the object is of that type, and
will error with a ClassCastException if it is not
At compile time, it tells the compiler to allow use of the methods/fields of
that class. Note that if the object turns out to not be of that type at runtime, then it will error at runtime.
What casting does not do, is change the type of the actual object at runtime.
In your example you called new B(); that means after casting a reference from B to A1, then the object is still an instance of B. Given that foo() is declared on A1, and B extends foo then the compiler is happy (it passes 2 above). At runtime the JVM will scan B looking for the method of foo, it checks B before A1 because the object was created as type B. It did not change its type since new was called.
Casting checks are always made at runtime (see caveat in next paragraph), your reference points to an object of type B, therefore when you get to the casting bit, the VM will see a reference to an object of B, which can be safely cast. Note that casting doesn't actually change the object, it just ensures that the rest of the code calls methods which are available in the original object.
The caveat is that if it can be seen at compile time that the cast is definitely NOT possible, you do get a compile error.
String foo = "x";
Integer i = (Integer)foo; //throws a compile time error because `String` is final and `Integer` isn't its supertype.
But:
Object foo = "x";
Integer i = (Integer)foo; //this will only throw a runtime exception because from the compiler's point of view, `foo` may or may not be an integer.
The type of the variable that holds the reference has nothing to do with what the method implementations resolve to. In Java, all methods are implicitly virtual, meaning that they get looked up by the actual type of the object (instead of the type of the referring variable) every time. Since c actually points to an instance of B, it's B.foo() that gets called.
Note that this doesn't necessarily hold true for all languages - in C#, for example, methods are only virtual if you explicitly declare them as such and so i its default behavior would match what you were thinking. Java, however, is always virtual.
Reference comes into picture only during compile time or in case of static methods or behaviors.
When you are creating an object, method or behavior will depend on the whose object you have created rather than whose reference you have used.This is called polymorphism.
For example lets take an example of real life entities ---
When you rent a house, you ask a broker to find a house for you, which is your reference.but the person whom house belong, the land-lord is the actual object whom you are requesting. so it is the land-lord who gives you house on rent and not the broker.

Why upcasting does not show runtime polymorphism?

I wrote a code to understand runtime polymorphism...
class S{
int i=1;
void m(){
System.out.println("sssssssssssssssssssss");
}
}
public class A extends S{
int i=2;
void m(){
System.out.println("aaaaaaaaaaaaaaaaaaaaaaaa");
}
public static void main(String[] args) {
S a=(S)new A();
System.out.println(a.i);
a.m();
}
}
Instance variable are subject to compile time binding, but why down casting of object of A does not meaning here? Means it's invoking A's method not S's method?
S a = (S)new A();
Let's see what you have here:
variable a, of the reference type S;
an instance creation expression yielding an object of type A, where A extends S;
a reference upcast expression, upcasting the above expression into type S;
the assignment of the result of 3. into the variable a.
What you must keep clear in your mind when reading Java is the distinction between:
the type of the object: an object can never change its type. In your example, the object is of type A;
the type of the reference: in your example, you converted a reference initially of type A into a reference of type S. You assigned that reference to a.
When you invoke a method on an object, the actual method invoked does not at all depend on the type of the reference, but only on the type of the object itself. The type of your object is A therefore the method in type A is invoked.
On the other hand, when you access an instance variable, polymorphism does not apply and the type of the reference becomes essential. With a.i you access i declared in the supertype S, and with ((A)a).i you access i from A. Note that the class A posseses two instance variables, both named i, and you can refer to each individually.
A note on terminology
The term "type of a reference" is actually a shorthand for the more correct "type of the expression yielding the reference." It is a purely compile-time artifact: there is no type information associated with a reference at runtime, it's just a bit pattern. Contrast this with the type of the object, which is a purely runtime artifact: the compiler doesn't in general know the type of the object involved in an expression, it only makes assertions about it. When such an assertion fails at runtime, the result is a ClassCastException.
The variable a is a reference of type S to an object whose class is A. When you call m() on that object, you'll always get the version of m() in class A being called, because that's the class of the object, no matter what type of variable is referencing it. That's what polymorphism is about. The version of m() that gets called depends on the class of the object, not the type of the referring expression.
However, this object actually contains two variables called i - one declared in class A and the other in class S. Which one of these you get depends on the type of the referring expression that you use. Since the variable a is of type S, the expression a.i refers to the one that is declared in class S.

Java: difference between A x = new A() and A x = new B() when B extends A [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
java inheritance - please explain
I'm learning Java and I have two questions:
What is the difference between:
A x = new A();
and
A x = new B();
Considering that:
class A
class B extends A
What's the difference between:
A x = new B();
(A)x.run_function();
Let's say that both A and B have the function run_function, which one will be executed ?
The most important difference is between the static and dynamic types of objects and references to objects.
Say B extends A and C extends B.
The dynamic type of an object (the type used in the new) is its actual runtime type: it defines the actual methods that are present for an object.
The static type of an object reference (a variable) is a compile-time type: it defines, or rather declares, which methods can be called on the object the variable references.
The static type of a variable should always be of the same type or a supertype of the dynamic type of the object it references.
So in our example, a variable with static type A can reference objects with dynamic types A, B and C.
A variable with static type B can reference objects with dynamic types B and C.
A variable with static type C can only reference objects with dynamic type C.
Finally, calling a method on an object reference is a subtle and complex interaction between static and dynamic types. (Read the Java Language Spec on method invocation if you don't believe me.)
If both A and B implement a method f() for example, and the static type is A and the dynamic type involved is C for a method invocation, then B.f() will be invoked:
B extends A, C extends B
public A.f() {}
public B.f() {}
A x = new C(); // static type A, dynamic type C
x.f(); // B.f() invoked
Simplifying greatly: first the static types of both receiver (type A) and arguments (no args) are used to decide the best-matching (most specific) method signature for that particular invocation, and this is done at compile-time. Here, this is clearly A.f().
Then, in a second step at runtime, the dynamic type is used to locate the actual implementation of our method signature. We start with type C, but we don't find an implementation of f(), so we move up to B, and there we have a method B.f() that matches the signature of A.f(). So B.f() is invoked.
In our example we say that method B.f() overrides method A.f(). The mechanism of overriding methods in a type hierarchy is called subtype polymorphism.
1. In
A x = new A();
x is an instantiation of A and of type A.
whereas in
A x = new B();
x is an instantiation of B and of type A.
2. The important thing to note here is that (in the second case) if you call x.someMethod(), the method of B will be called, not the method of A (this is called dynamic binding, as opposed to static binding). Furthermore, casting changes only the type, so
A x = new B();
((A)x).run_function(); // Need extra parenthesis!
will still call B's method.
As I said above, you need to include those extra parenthesis since
(A)x.run_function();
is equivalent to
(A)(x.run_function());
Case 1:
You will see difference when you have a method in B which is NOT in A.
When you try to call that method using reference 'x' it won't be visible.
Case 2:
All method calls will be based on object type not reference type due to polymorphism (except static methods)
A x = new B();
In this case B class run_function will be executed.
A x = new A();
In this case A class run_function will be executed.
Furthermore with:
A x = new B()
You will not be able to execute methods that are defined in B and that are not defined in A. However as indicated previously because of polymorphism in Java if you do execute any methods and B' has overridden these methods then it will use B's implementation.
1.What is the difference between: A x = new A();and A x = new B();
The difference is that in the first case, you are instantiating a class of type A. So you will only be able to call methods defined in A. IN the second case, if the same name method exists in both A and B, then the B implementation will be invoked at runtime.
However, in the second case, using reflection, it will also be possible to invoke methods that are defined in Class B and not in Class A.
A x = new B();
(A)x.run_function();Let's say that both A and B have
the function run_function, which one will be executed ?
Remember - Overriding is decided at runtime whereas overloading is decided at compile time.
So the method in class B will be invoked at runtime based on Dynamic Binding.
There is no real difference. Actually for the second case A olds a B object, but B is an A so thats no problem. B in this case behaves like A.
It will call B's run_function()

Categories