Java Inheritance - java

A class C has a void method m with no parameters. Another class D extends C and overrides m. Each class has a constructor with no parameters. In each of the following, say whether it is legal, and if so, which definition of m will be used.
i) C x = new D();
x.m();
ii) D x = new C();
x.m();
I think i is legal, and ii is not illegal. Not sure how I get my head around this question, any hints are welcome.

The best way to answer the question is to write some code and see what happens. Use System.out.println("method called from C"); in your implementation of m to tell which implementation is called. Having said that, the whole point of overriding a method is so that the new implementation will get used. If you object is of type C then Cs method will get called. If you object is of type D then Ds method will get called regardless of what type the reference is.
The first answer:
C x = new D();
is legal because and object of type D is a C as well (because D extends C).
The second answer:
D x = new C();
is not legal because a reference to D cannot hold an object of its supertype C.

Yes, you are right.
(i) is legal, and it will be D's m method that gets run (this is called polymorphism).
(ii) is illegal, and will not even compile, because D is not a supertype of C (in fact, it's a subtype). We could make it compile by writing it as:
D x = (D) new C(); x.m();
but then it would fail at runtime with a ClassCastException

Try to think of inheritance in terms of "is a" relationships.
If D extends C then that means each D is a C, but does not imply that each C is a D.
To apply that thinking, translate the question into an "is a" question.
C x = new D()
is a statement that requires that a new D() is a C.
In String s = new Object(), ask yourself "is a new Object() a String?" What about vice-versa?
Good luck learning OOP.

i) is legal, ii) is not. It's very easy to see if you use a metaphor, say class C is Animal and class D is Dog, method m() is makeNoise.
Now it's legal to have a variable of class Animal and assign a Dog to it (because a dog "is a" animal), but it's not legal to instantiate an Animal and assign it to Dog since the Dog is more specific than Animal (we can not say an animal "is a" dog).
Now for the method: the method is always called on the runtime type, not on the variable type (all method calls are so-called virtual in Java), so in case i) it calls the m() method of class D, not of class C.

Related

Understanding Type Casting in inheritence

I am preparing for java certification and unable to find any concept or logic behind this.
Can anyone help me understanding the concept of multiple typecasting. I can understand the one level of type casting but I am not getting any information for these conversions.
Here is the sample I am trying to understand.
interface I{
}
class A implements I{
}
class B extends A {
}
class C extends B{
}
A a = new A();
B b = new B();
Now option 1 don't have any error at compile time or runtime, while 2nd option is having error. I run it in eclipse but unable to understand the logic behind this.
1. a = (B)(I)b;
2. b = (B)(I)a;
Your question is a bit vague but I'll see if I can help.
So you have your interface I and classes A, B and C.
You can now do things like these:
I i1 = new A();
I i2 = new B();
I i3 = new C();
This is possible because, by inheritance, all the classes A, B and C implement I.
You can also do
A a1 = new B();
A a2 = new C();
for almost the same reason (difference being they are extending A rather than implementing an interface).
You probably guessed by now that you can also do
B b1 = new C();
What you can't do is something like
B b = new A(); // Type error
C c = new B(); // Type error
B b2 = (B)new A(); // ClassCastException
This is not possible since the type A does not extend from B.
In general you don't need to explicitly type cast in these cases.
I i = (I)new A(); // <- not necessary
It can be necessary in the opposite direction however:
I i = new B();
B b = (B)i; // <- cast is needed.
This works if and only if i is actually of type B (or C). If the object i is not of type B or a type that extends from B you will get ClassCastException.
Now for your question
Both your two options are a bit strange. Double casting is not something you would normally do. the cast to I is unnecessary.
With that said, 1) will work and 2) will not. Your object b cannot be assigned a because A does not extend from B.
Edit
To be clear, when you instantiate an object, for example
A a = new A();
The actual object (I'm going to call it o) is an instance of class A. You also have an object reference called 'a' which is typed as A which refers to the object o.
When you assign other object references, the type of the actual object doesn't change. When assigning a reference, the type of the object must be the same type as the reference or of a type that inherits from the referred type.
For example, you can assign a reference of type I:
I i = a;
This assigns the reference i to the same object that a refers to which is the object o. Note that o is still of type A.
System.out.println(i instanceof A);
will print
true

Java class/object casting when is it applicable

I have a broad question regarding Java casting via classes. Let's say I create 4 classes (well 3 classes and 1 interface), Interface A is the super interface I guess you could say and Class B implements A (meaning that it is the subclass of the interface A) and C extends B and then D extends C.
Let's say that I have a driver class in which I initialize the following like below:
A myA;
B myB = new B();
C myC = new C();
D myD = new D();
//I want to cast now!
myB = (B) myD;
myC = (D) myA;
myD = (C) myB;
When are these fabricated objects actually compilable? I'm having a bit of a difficult time understanding the rules between casting. I do kind of understand Down-casting and how it's not permitted, but I guess class casting is still a concept that sort of confuses me.
The thumb rule is that if an object B is of type A, then it can be casted to A. In you example B implements A so B is of type A. You can cast any B object to A. Since C extends B, C is of type B as well as of type A. So C objects can be cast to A or B.
Wanted to add as comment, but coz of limitation, had to add it as answer:
1) Rule is Child can inherit what father/parent has, but not reverse.
2) Child can be stored as parent, but not reverse.
That makes myD =(C)myAB; uncompilable as myD extends C (which extends B-->A)
So when you create
B myB = new B();
If I try to explain in non technical terms, Then myB knows everything about B and A, but it does not know what is below. It can see and identify itself with anything above it in following hierarchy:
A
B
C
D
So lowest one D can be casted to anything that lies above it.
1) myB = (B) myD;
With rule state above, D is below B and hence can be assigned to B.
2) myC = (D) myA;
Here you have casted interface to D, and hence in compile time, D can be assigned to top level C.
3) Here myB (which in that statement is typecasted to C in compile time) can't be assigned to D at compile time (although it is instance of D which is lower in hierarchy) but when you are compiling, you don't have runtime instance available. So below will fail:
myD = (C) myB;
I assume I have not confused you further here.

Casting "with" Interface [duplicate]

This question already has answers here:
Cast reference of known type to an interface outside of type's hierarchy
(6 answers)
Closed 8 years ago.
interface I{}
class A implements I{}
class B{}
First:
I[] arr = new A[10];
arr[0] = (I) new B(); // will produce ClassCastException at runtime
Second:
wherein if I use concrete class
I[] arr = new A[10];
arr[0] = (A) new B(); // will produce compile-time error
What's the difference if in my first example,(I) new B(), the java compiler should produce compile-error as well?
Isn't it that the java compiler should be able to distinguish that it is also an "inconvertible type"? Especially when the new operator comes immediately?
Is there any instance/chance that it will be possible that creating that new instance of B could produce a
convertible type of type I?
I know at some point, that the Java compiler should not immediately say that it is a compiler error, like when you do this:
I i = (I) getContent(); // wherein getContent() will return a type of Object
Edit:
Let me clarify this question why it is not a possible duplicate of this: Cast reference of known type to an interface outside of type's hierarchy
The intention of this question is not because I am not aware of what will be the result of or what is something wrong with something, etc.
I just want to know a "more detailed explanation in a technical way" of why does the JVM behave that way or why does Java came up with that kind of decision of not making that kind of scenario a compile-time error.
As what we all know, it is always better to find "problematic code" at compile-time rather than at run-time.
Another thing, the answer I am looking for was found here on this thread not on those "duplicates?".
The rules for what casts are compile-time legal only take into account the static types.
When the Java compiler analyzes the expression (I) new B(), it sees that the static type of the expression new B() is B. We can tell that new B() can't possibly be an instance of I, but the compile-time analysis rules can't tell that the object isn't actually an instance of a subclass of B that implements I.
Thus, the compiler has to let it through. Depending on how sophisticated the compiler is, it might detect the oddity and issue some sort of warning, but in the same way 1/0 isn't a compile-time error, this can't be a compile-time error.
The difference in this situation is obviously that I is an interface, which could be implemented. This means, that even though B has nothing to do with I, there could be a subclass of B, that implements the interface I. Will illustrate this with an example:
interface I{}
class A implements I{}
class B{}
class C extends B implements I{}
I[] arr = new A[10]; // valid, cause A implements I
B b = new C(); // Valid because C is a subclass of B
arr[0] = (I) b; // This won't produce ClassCastException at runtime, because b
// contains an object at runtime, which implements I
arr[0] = (I) new B(); // This will compile but will result in a ClassCastException
// at runtime, cause B does not implement I
It's important to distinguish the difference between static and dynamic types. In this case the static type of the variable b is B, but it has the dynamic type (the runtime type) C, where new B() does also have the static type B, but the dynamic type is also B. And as in some cases a cast from B to I won't result in exceptions (as in this scenario), the compiler allows such casts but only to an interface type.
Now take a look at the following scenario:
I[] arr = new A[10];
B b = new C(); // Valid because C is a subclass of B
A a1 = (A) b; // compile time error
A a2 = (A) new B(); // compile time error
Is it possible that a subclass of B will ever extend A and B at the same time? The answer is NO, cause you are limited to only one super class to extend in Java (where in some other OO languages this is not the case), therefore the compiler forbids it, cause there are no possible scenarios, where this will work.
You can cast any object to the desired var, only if you cast it to the var type:
interface I{}
class A implements I{}
class B{}
I var = (I) object; // This is always possible in compile-time, no matter the object type, because object is casted to the var type, I
I var = (A) object; // Not possible in compile-time because of the difference of types
The runtime exception comes when the object cannot be casted, but you can't know it until runtime.
A object = new A();
I var = (I) object;
B anotherObject = new B();
var = (I) anotherObject;
Both of the above will work in compile-time, but only the first one will do it in runtime, because of the implementation of the I interface.
Class inheritance is single inheritance, no future descendant can introduce a new base class, e.g. in your example, no descendent of B can ever be cast to A. But it can introduce a new interface, i.e. a descendent of B could support I.
It's a failing of the compiler that it can't solve your simple case, but it's not a case you would ever see in the wild. Create and cast in one line that is.
Example of why the compiler can't detect this in a more complex case using your classes
void method(B b){
I i = (I) b;
}
class C extends B implements I{} // a descendent of B that introduces support for I
method(new A()); //still compile time error
method(new B()); //runtime exception
method(new C()); //works
I tried four cases:
Casting a class to another class.
Casting a class to an interface.
Casting an interface to a class.
Casting an interface to another interface.
Compile-time error only happens in the first case.
static interface I {}
static interface J {}
static class A {}
static class B {}
Object o = (B) new A(); // compile-time error
Object o = (I) new A(); // runtime error
Object o = (B) ((I) new A()); // runtime error
Object o = (J) ((I) new A()); // runtime error
My guess is that this happens because determining whether the cast will succeed or not relatively easier in the first case, compared to the other three cases. The main reason is that a class can only extend one class, which allows the compiler to reason whether the cast will succeed or not. See these examples:
Suppose, in addition to the above classes and interfaces, I add new class:
static class C extends B implements I, J {}
Example of code that casts a class to an interface (last line):
C c = new C();
B b = (B) c;
I i = (I) b; // This is ok.
Example of code that casts an interface to a class (last line):
C c = new C();
I i = (I) c;
B b = (B) i; // This is ok.
Example of code that casts an interface to another interface (last line):
C c = new C();
I i = (I) c;
J j = (J) i; // This is ok.

Upcasting and Downcasting confusion in java

Okay. So if...
int x=3;
int y=5;
x=y;
That'll make x=5, right?
Okay, so if B is a subclass of A...
A a=new A();
B b=new B();
a=b;
^^^Why is this considered upcasting?
Isn't the "a" supposed to become the "b" and not the other way around? Can someone explain all this to me?
Instead of As and Bs, let's jump to a concrete example.
class Person {
public void greet() {
System.out.println("Hello there!");
}
}
class ComputerScientist extends Person { // Does he, really?
#Override
public void greet() {
System.out.println("Hello there! I work at the Informatics Department.");
}
public void validateAlgorithm(Algorithm a)
throws InvalidAlgorithmException {
// ...
}
}
When you have a ComputerScientist as
ComputerScientist cs = new ComputerScientist();
You can access both greet and validateAlgorithm. You know (s)he is a Person, and can greet him/her as any other person. However, you may also treat him/her specifically as a ComputerScientist.
When you assign this object to a variable of type Person, all you do is saying "I don't care anymore that you are a ComputerScientist. From now on, I will treat you just as any other Person".
Person p = cs;
Which is equivalent to
Person p = (Person) cs;
The object referred by p still knows how to validateAlgorithm, and still tells you that (s)he works at the Informatics Department. However, when accessing it via p, you are telling the compiler that you only want to greet this Person, nothing else.
It is called upcasting because the variable goes up in the hierarchy tree, where up means more general/abstract and down means more specific. You're generalizing a ComputerScientist as a Person.
After a = b;, the variable a (declared with type A) will refer to an object of type B. Thus the assignment involves an implicit upcast: a = (A)b;, converting how Java views b from B to its superclass A. That's an upcast.
A a = new A();
B b = new B();
The flow is as follows:
Object of A is created using new A() and ASSIGNED to refrence variable a
similarly Object of B is created using new B() and ASSIGNED to the refrence variable b
The point to note here is that the evaluation goes from the right side to the left side which is why first the Right side is calculated and the results are assigned to respective variables.
Now coming to your problem which is why a=b is UPCASTING
The above mentioned points apply to this statement as well, first b is evaluated which is a subclass of a. Now since you are assigning a subclass to a superclass an implicit casting takes place from a subtype to a super type which is ofcourse UPCASTING.
This link will make it more clear https://www.youtube.com/watch?v=Wh-WZXCAarY
Hope this helps.
That'll make x=5, right?
Right.
Okay, so if B is a subclass of A...
^^^Why is this considered upcasting?
Because that's what it is.
Isn't the "a" supposed to become the "b" and not the other way around?
Yes, and it does. The reference to B is upcast to a reference to an 'A'.

Abstract superlcass help

A is an abstract superclass of the concrete classes B and C. Constructors of all
three classes do not take parameters. The following variables are defined:
A a;
B b;
C c;
Which one or more of the following assignments will result in an error at
compile time?
(i) a = new C();
(ii) b = new C();
(iii) a = new A();
(iv) b = (B) new A();
Any help is appreciated
A is abstract so ANY attempt to create an A outright will fail. Also, the relationship between B and C is not clearly defined but I am betting the second case will fail as well unless B is a superclass of C.
Because A is an abstract superclass of B and C, A cannot be initialized. However, its subclasses can be stored in an object of the type of the superclass (A), since it shares or defines the methods contained in A.
Should be enough to figure it out.

Categories

Resources