I'm working through a Java book based on JDK 8. In the chapter about inheritance and generalisation the following example is shown:
class A {}
class B extends A {}
class C1 extends B { public void x1() {System.out.println("C1.x1");} }
class C2 extends B { public void x2() {System.out.println("C2.x2");} }
Then, some object variables are declared, all of type A:
A obj1, obj2, obj3, obj4;
These variables are populated with instances of the four classes:
obj1 = new A();
obj2 = new B();
obj3 = new C1();
obj4 = new C2();
Now, obj3.x1() doesn't work because obj3 is of type A, and x1() is not defined in A. In the book, now one can declare a new variable obj5 of type C1 and assign to it the value of obj3:
C1 obj5 = obj3; // then obj5.x1() should work
However on this line I get an Incompatible Types compile error.
Is this different between SDK8 and 10? Or am I missing some error somewhere?
As a side note: casting such as in C1 obj5 = (C1) obj3 works.
By casting, you tell the compiler that in your opinion, the assignment is ok because you consider obj3 to be of type C1. Then the compiler believes you and proceeds.
If you lied on this, you get a runtime exception. If not, all is fine.
You do need to cast, and there is no difference between Java 8 and Java 10 with regard to this. This is easier to understand if you give the classes meaningful names. Suppose that A = Animal, B = Mammal, C1 = Dog, C2 = Cat:
class Animal {}
class Mammal extends Animal {}
class Dog extends Mammal { public void x1() {System.out.println("Woof");}
class Cat extends Mammal { public void x2() {System.out.println("Meow");}
Animal obj1, obj2, obj3, obj4;
obj1 = new Animal();
obj2 = new Mammal();
obj3 = new Dog();
obj4 = new Cat();
When you try to do this assignment:
Dog obj5 = obj3; // obj3 is of type Animal
the cast is necessary because obj3 is of type Animal, but by looking at this line alone the compiler cannot be sure whether it's actually a Dog or something else. You'll have to use a cast to tell the compiler "I know better than you what this is, so I want you to treat this Animal as if it's a Dog".
Note that a runtime check will still be done - if, at runtime, it turns out that obj3 refers to an object that is not a Dog, you'll get a ClassCastException.
Have a look at the following code :
A a = new C1(); //reference variable of *A* class points object of *C1* class
C1 c1 = a; //compile time error, requires casting
C1 c1 = (C1) a; // type casting A to C1
In the above code, typecasting object of C1 class into A class will throw ClassCastExcepiton if a is not an object of the C1 class. If A and C1 class are not related to each other and doesn't part of the same type hierarchy, the cast will throw compile time error e.g. you can not cast String and StringBuffer, as they are not from same type hierarchy.
It’s an error in the book you are quoting. There is no difference between Java 8 and 10 here. Also in Java 8 you need the explicit cast:
C1 obj5 = (C1) obj3;
// then obj5.x1() works:
obj5.x1();
This has been so since Java 1.0, I believe.
Related
I am kinda new to java and I have a question about polymorphism and possible errors.
Assume that we have this:
public interface Animal {
}
public abstract class Cat implements Animal{
}
public abstract class Fish implements Animal {
}
public class Salmon extends Fish{
}
public class Tiger extends Cat{
}
and Assume that we have something like this:
Animal t1 = new Tiger();
Fish f1 = new Salmon();
Tiger t2= new Tiger();
Salmon s1 = new Salmon();
What is The errors in following lines (Compile Time Error, Runtime Error or No Error):
Cat c1 = new Cat();
Cat c2 = (Tiger) t1;
Animal a1 = s1;
Animal a2 = new Animal();
Fish f1 = (Fish) t2;
Animal a3 = (Fish) s1;
Animal a4 = (Cat) new Tiger();
Cat c3 = (Cat) new Salmon();
I've Answered it like bellow but I've thought it's kinda weird that I found no Runtime Error. if all of them is correct can u make an example where we have runtime error (in this polymorphism concept)
My Answer:
a compile error
b no error
c no error
d compile error
e compile error
f no error
g no error
h compile error
Focusing on the part about "how to get to an exception at runtime".
You figured yourself that Cat c3 = (Cat) new Salmon(); is wrong.
And obviously, the compiler can already tell you that.
Why? Because the compiler can "see" that you create a Salmon, and that you then want to treat that as Cat, which isn't meaningful.
The only thing you need to get "past" the compiler is to "hide" that fact, like:
Salmon s1 = new Salmon();
Animal a3 = (Fish) s1;
Cat c3 = (Cat) a3;
As soon as you introduce a3, you are able to "hide" the fact that s1 is actually a Salmon.
Of course: even in my example, a smarter compiler could understand that a3 must be a Salmon, can't be a Cat. But java plays it "simple and conservative" here. The compiler only recognizes the most basic casting violations, and for good or bad, the java language ignores many situations that could be detected at compile time, too. That makes it easier to implement compilers, the traddeoff is that your code is more exposed to such exceptions at runtime.
Since Java only supports single inheritance of classes, it can verify whether casting between classes is potentially valid, because when casting, one of the classes must be an ancestor of the other. You can do up-cast, e.g. Tiger to Cat, or you can do down-cast, e.g. Cat to Tiger.
I'm ignoring the dumb identity cast, e.g. Tiger to Tiger, but it is of course allowed too.
You cannot cast a class to another class that it is not "related" to.
The same cannot be verified by the compiler regarding interfaces, since multiple inheritance is allowed, meaning that at compile-time, casting a class or interface to an interface is always possible, and casting an interface to a class or another interface is also always possible. The cast can only be verified at runtime.
Since you don't have two classes inheriting from the same base class, you cannot setup a runtime error for casting between classes. The compiler will always catch the error.
Since you only have one interface, and all the classes implement that interface, you cannot setup a runtime error for casting to an interface.
Which means that to setup a runtime error, you need to cast from an interface to a class that the real object is not compatible with, e.g. casting from Animal t1 (real object Tiger) to Salmon or Fish would do it:
Salmon s2 = (Salmon) t1; // ClassCastException: class Tiger cannot be cast to class Salmon
Your answers are all correct. A newer compiler should find the cases, where the casts will fail in your example. The runtime exceptions will only be thrown in cases, where the compiler will lose track of the actual type, because the type is downcast:
public Cat catterize(Animal a) {
return (Cat) a; // this line should yield an unsafe typecast warning!
}
...
Salmon salmon = new Salmon();
Cat cat = catterize(salmon); // This is compiletime legal, but will ultimately throw a ClassCastException.
This question already has answers here:
Downcasting in Java
(12 answers)
Closed 8 years ago.
I am getting an exception for the following code.
class A {
void foo() {
System.out.println("Running foo()");
}
}
class B extends A {
void foo() {
System.out.println("Overidden foo()");
}
}
public class Casting {
public static void main(String[] args) {
A obj = new B();
obj.foo();
// B ref = (B) obj;
// ref.foo();
B ref = (B) new A();
ref.foo();
}
}
But if I run
B ref = (B) obj;
ref.foo();
instead of
B ref = (B) new A();
ref.foo();
it works properly.
Can anyone explain what is happening here.?
obj is an instance of B because you created it using the contructor of class B. This is why B ref = (B) obj; works fine.
In B ref = (B) new A(); you are simply casting an object of type A created using the constructor of A (which is the parent class) to a subclass type which will cause a java.lang.ClassCastException. The opposite casting would work, i.e.
A ref = (A) new B();
ref.disp();
in which case you converting an instance of a subclass to its parent which is fine since an object of type B is also an instance of A.
It's pretty easy to explain.
By doing new A() you receive an A-object. Then you tell the JVM it's of type B, but that's obviously wrong and the JVM can't cast from A-type to B-type, how should Java know how to do that? It's not sure that A has the same methods as B. It's just a parent, B could have methods A hasn't. If you could cast from A to B you could have B objects that don't behave like B objects and don't have the B classes methods.
If you have a B-object you can treat it like a A-object because every B-object has at least the same methods, constructors and ivars.
An example using ducks:
Imagine you have got an abstract Duck class (but you didn't declared it as abstract). This class is the parent class of all other duck classes and also including RubberDuck. As reason of that the Duck class just has some basic methods like getSize but no method like walk or eat (a rubber duck can't eat herself).
What would happen if you create a duck object and downcast it to BuffleheadDuck and you would try to invoke the walk method? A BuffleheadDuck duck knows how to walk, but an abstract duck can't walk.
So, I have this:
public class A {
public int a = 0;
public void m(){
System.out.println("A"+a);
}
}
And this:
public class B extends A {
public int a = 5 ;
public void m (){
System.out.println("B"+a);
}
public static void main(String[] args) {
A oa = new A();
B ob = new B();
A oab = ob;
oa.m();
ob.m();
oab.m();
System.out.println("AA"+oa.a);
System.out.println("BB"+ob.a);
System.out.println("AB"+oab.a);
}
}
Output:
A0
B5
B5
AA0
BB5
AB0
I don't understand why oab.m(); output is B5 instead of A0. Can someone explain this to me?
That's the whole point of polymorphism. The concrete type of oab is B (since the object was created with new B()). So the method B.m() is called.
Look at the Animal example in http://en.wikipedia.org/wiki/Polymorphism_%28computer_science%29 to understand why it's useful. When you have an animal, and this animal is a Cat, you expect it to say "Meow!" when you make it talk.
B ob = new B();
A oab = ob;
Similar as
A oab=new B();
I don't understand why oab.m(); output is B5 instead of A0
Because you creating object of B and referencing it to A so m() is being inherited and that's why B's version of m()is being called.
A oa = new A();
B ob = new B();
A oab = ob;
From the code above ob is an instance of class B. It can be stored in a variable of class A as A extends B. But as the stored Object instance is of B and hence it is not aware of A's m() function.
Hence the out put is B5
In inheritance actual method invocation depends on the type of the actual object and not on the type of the reference.
B ob = new B();
A oab = ob;
Here oab is a reference variable of type A but it is pointing to object of type B i.e. ob so at runtime oab.m() will invoke overridden m() method from class B
In Java there is something like late binding (polymorphism). It means that code of method is not linked while compilation time (early binding), but while runtime. While invoking oab.m(); JVM is checking actual type (class) of object from aob reference (in your case B) and based on that info invoking code of method from that class. That is why oab.m(); returns B5.
You also need to know that late binding works only for methods, not fields. For fields value will be determined by reference type, so oab.a will return 0 not 5.
Imagine you had the following:
public class C extends A {
public int a = 7 ;
public void m (){
System.out.println("C"+a);
}
Now if you had this in your Main method...
C oc = new C();
A oac = oc;
oac.m();
...you would want that last call to output the stuff that is specific for the class C.
The point is that B is an A, and C is an A, but each of them have more specific versions of the values that an A contains, and when you ask for those data, the specific versions of them should be returned.
Now you can do this:
// Get an instance of B or C, but you don't
// care which - could be either:
A someVersionOfA = getAnInstanceOfA();
// This works no matter if you've got an instance
// of B or C, but the result should vary accordingly:
someVersionOfA.m();
As someone else mentioned, think of A as "Animal", B as "cat", and C as "Dog". If m() means "Make some noise", then calling m() should result in "Meow" or "Woof!" depending on on the instance getAnInstanceOfA() returned.
You have just copied the internal address of B to A one, and replacing it.
B inherit from A, so no compilation problem.
Finally, the reference to A is destroyed, it is now a copy of reference to B
There are 2 classes A and B, B extends A. What is the difference between
A a = new B();
and
B b = new B()?
Both create the object of class B. What is the difference?
You are right that in both cases an object of class B is created. The difference between the two declarations is in the type of the variable.
It is very important to keep the distinction between variables and objects in mind. For example, the following code defines 3 variables but only 2 objects:
Circle c1 = new Circle(5);
Circle c2 = c1;
Circle c3 = new Circle(5);
When you say
Shape s = new Circle(5);
instead of
Circle s = new Circle(5);
assuming Circle extends Shape then, even though in both cases you did create a circle object, in the former case you can only call shape methods on the circle (through the variable s) whereas in the second case you can you all circle methods (because you will be calling them through the circle variable c). That is a call like s.getArea() will work in both cases but something like s.getRadius() will ONLY be allowed in the second (unless you use an ugly cast).
So why do we often do things like the first case? That is, why do we often define our variables of a more general type than necessary? Usually we do this because we want to restrict the interface for safety. Perhaps we only care about shapes, but in this case the particular shape just happens to be a circle. If you cared about circle specific properties, then we would have used a circle variable. But we should strive to be as general as possible. Coding to the most general interface allows our code to work with shapes other than circles without modification.
Of course, for this to really sink in, you have to experience it firsthand, but hopefully this explanation is a start. There are many books and blog posts and articles that explain this in more detail with useful real-life anecdotes I'm sure.
A a = new B();
has only the attributes and methods of A.
B b = new B();
has the the attributes and methods of B.
If you added some attributes or methods to B, you can't call them with a.
The advantage is
Fruit f = new Mango();
Suppose
consumeFruit(Fruit f);
now you can call
consumeFruit(new Mango());
consumeFruit(new Strawberry());
Note:
For this case you would be only able to call the methods declared in the reference type. and object type's version will get invoked . and you would be only accessing fields from the reference type's class
See Also
Liskov substitution principle
If you say
List a = new ArrayList();
then you reference ArrayList only in one place in your code. That makes it easier to change it later to something else, like LinkedList;
Of course, this does not work if you need methods specific to ArrayList.
In general, you should use the most general type applicable.
This question is on Polymorphism. Following is an extract from Kathy Siera:
public class TestAnimals {
public static void main (String [] args) {
Animal a = new Animal();
Animal b = new Horse(); //Animal ref, but a Horse object
a.eat(); // Runs the Animal version of eat()
b.eat(); // Runs the Horse version of eat()
}
}
class Animal {
public void eat() {
System.out.println("Generic Animal Eating Generically");
}
}
class Horse extends Animal {
private void eat() { // whoa! - it's private!
System.out.println("Horse eating hay, oats, "
+ "and horse treats");
}
}
If this code compiled (which it doesn't), the following would fail at runtime:
Animal b = new Horse(); // Animal ref, but a Horse
// object , so far so good
b.eat(); // Meltdown at runtime!
Suppose this example:
We have class an animal:
public class Animal {
public void eat() {
// each animal can eat
}
}
Now we have another class dog:
public class Dog extends Animal {
public void bark() {
// dogs can bark
}
}
Now we can write this code:
Animal pet = new Dog();
Now we know, that pet can eat, but nothing more. But if we write
Dog pet = new Dog();
Then we know, that our pet can eat and bark.
Also there is safe and unsafe casting. Safe casting is from Dog to an Animal because each dog is animal (extends it)
Dog pet = new Dog();
Animal animal = pet;
But if we want to cast Animal to Dog we have to test if the instance of animal is really dog, because it doesn't have to be.
Animal pet = new Dog();
Dog myDog = null;
if (pet instanceof Dog) {
myDog = (Dog) pet;
}
Usually, declaring a parent class and assigning it an inherited class is useful when the parent class variable may be assigned different objects. For example
Pet p;
if (favoritePet == Pets.CAT) {
p = new Cat();
} else {
p = new Dog();
}
System.out.println(p.someMethodFromPet());
I'm preparing to SCJP and looks like I don't understand class cast principles.
class Dog extends Animal
First way of creating Dog() instance- make instance of Animal and cast it to Dog(upcast):
Animal a = new Dog();
Dog d1 = (Dog)a;
VS
Second way of creating Dog() instance - make it directly:
Dog d2 = new Dog();
what is the difference between d1 and d2 objects this case?
After the cast of a to Dog, there's no difference between d1 and d2. The cast is potentially problematic. If a isn't actually a Dog, you'll get a ClassCastException at runtime. Therefore, you would be better off verifying the runtime type with instanceof:
Animal a = new Dog();
Dog d1 = null;
if(a instanceof Dog)
{
d1 = (Dog)a;
}
The real issue is that if you need a Dog, declare the variable as a Dog, not an Animal. If you're operating on any type of Animal, use the base class.
The type of a variable only specifies what interface you want to use -- whether it's the interface provided by the base class, an implementation of some class, or an actual interface. The type of a variable does not dictate its runtime type.
Animal a = new Dog();// a dog is created but it will be referred by reference of animal as dog is an animal
Dog d1 = (Dog)a;//now we know that this animal is Dog so we are casting it to dog.
Dog d2 = new Dog();// we are creating instance of dog which is referred by reference of Dog
what is the difference between d1 and d2 objects this case?
d1 and d2 are just reference to dog, both will eventually refer to an instance of Dog .
there is no difference
Also See
Polymorphism
The first way is polymorphic because Animal can be a dog, cat, elephant, etc... whereas the latter way is not. Otherwise, there is no much difference between the 2.
There is no difference in instantiation between these snippets: in both cases you instantiate object of type Dog by using new Dog(). Actually, it's about difference between type of object (runtime type) and type of variable (static type).
But in the first case you assign a reference to that object to variable of type Animal, and then assign value of that variable to another variable of type Dog. This requires cast since variable of type Animal may contain references to objects of types other than Dog, but in your case it references object of type Dog, so that cast is successful.
In the second case you assign value of type Dog to variable of type Dog directly.