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.
Related
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.
I am new in programing and i am watching youtube tutorial (10:05-10:47)
https://www.youtube.com/watch?v=ssAt_qrQpi0&index=31&list=PLsyeobzWxl7rooJFZhc3qPLwVROovGCfh
and I do not understand why we could need reference of class A and an object of class B?
Kotlin example from that video:
var h: Human = Alien()
Java example from that video
Human h = new Alien()
reference of human and object of alien
The usage of "Human" and "Alien" is terrible here. Instead of "Human", think "Animal". Instead of "Alien", think "Dog".
The terminology isn't great either. The "Object" is the literal object itself: the physical Dog <-> the bits associated with it in memory. The "Reference" is the variable, h. It references the object Dog. h is not a "reference of Animal and object of Dog", as the video says with Human/Alien. It's a "reference to a Dog object". However, the variable "h" itself, it not forced to reference only Dogs. In fact, it can reference any Animal.
For example, I can write the code:
Animal mypet = new Dog();
mypet = new Cat();
If I wrote the line Dog mypet, then I would be forced to only write mypet = new Dog() or mypet = getDogFromShelter(myNeighborhoodShelter). It would not let me write mypet = new Cat().
Cats are cool, so that would be terrible. Hence, we write Animal mypet to allow the variable mypet reference any animal. Dog, Cat, Elephant will all be available. However, because of this restriction, I am not allowed to do any Dog-specific things to mypet.
mypet.bark() will not work if mypet is an Animal. Not all Animals can bark. mypet.eat(Food) will work, since all Animals can eat. If I want my pet to Bark, because I know it is a Dog right now, then I can do
((Dog)mypet)).bark();
// Will throw run-time error if mypet is not a Dog!
// This is best to avoid, so just make mypet a Dog type if it must bark.
// If you must make an Animal bark, use if (!(mypet instanceof Dog)) to handle the error propely.
This above code will check to make sure mypet is a dog before letting it bark.
This can be implemented in code by writing
class Animal {
int health = 100;
void eat(Food f) {
health += f.value;
}
}
class Dog extends Animal { // States that "All Dogs are Animals"
// The word "extends" allows you to write Animal a = new Dog();
// "extends" also lets you do "Dog a = new Dog(); a.eat()"
int health = 150; // Dogs are strong
void bark() {
scareNearbyAnimals();
}
}
class Poodle extends Dog {
// Both of these will work:
// Dog mydog = new Poodle();
// Animal mypet = new Poodle();
int glamor = 50; // glamorous
}
The video mixed up Object vs Reference, so I'll make it more explicit with the following code
Dog a = new Dog();
b = a;
a and b both reference the same object in this instance. If Dog uses a lot of memory, then b = a does not cause more memory to be allocated.
b.hasEaten(); // False
a.eat();
b.hasEaten(); // True
b = new Dog(); // Now they are different. a does not affect b
a.eat() allowed the object to eat. The bits in memory have changed: the hunger value has been reset. b.hasEaten() checks the hunger value of the same Dog that a used when it was eating. b = new Dog() will separate them, so that a and b reference distinct dog objects. They will then no longer coupled as they were before.
Ok let me explain you.
We want to create an object "man" of class Human assuming that "man" is a human.
We give the human class some functions that human can do. Let's say walk, run, sit.
Each function tells the object (man) what to do.
In the other hand, we want to create a class for Aliens to create another object. We'll name it "alien". Assume that alien is a humanoid so it can do whatever human can, plus some other special abilities that human cannot. For example "fly".
In order to prevent it to write the exact same functions (walk, run, sit) to class Alien. we inherit the class Human so we can get the functions (walk, run, sit) from Human class.
So let's say:
Human h -> the object "h" is a human(oid)
But "h" is actually an alien so we have to define it so there comes the code:
Human h = new Alien();
In other words. Imagine that you have a structure like this:
Human (functions: walk, run, sit)
-- Alien (functions: (inherit: walk, run, sit), fly)
Please correct me if I'm wrong.
I hope that helps.
class Animal{
public void findAnimal(){
System.out.println("Animal class");
}
public void sayBye(){
System.out.println("Good bye");
}
}
class Dog extends Animal{
public void findAnimal(){
System.out.println("Dog class");
}
}
Given the inheritance above ,it is understood that a reference of Animal can refer to an object of Dog
Animal animal=new Dog();
As a Dog object can perform everything an Animal can do like in above case a Dog also have sayBye and findAnimal methods.
But why it is allowed to downcast an Animal object to a Dog object which serves no purpose and fails at runtime.
Dog dog=(Dog)new Animal(); // fails at runtime but complies.
Dog dog=(Dog)animal;
The above statement look logical as the animal reference is pointing to a Dog object.
This sort of casting is allowed for situations when you get an object of a superclass from outside code, e.g. as a parameter to your method, and then you need to call methods specific to a subclass.
This is not a good practice, but in some rare situations you are forced to do things like that, so the language allows it:
void sound(Animal animal) {
if (animal instanceof Dog) {
Dog dog = (Dog)animal();
dog.bark();
}
if (animal instanceof Cat) {
Cat cat = (Cat)animal();
cat.meow();
}
}
why it is allowed to compile Dog dog=(Dog) new Animal()
Because compiler designers decided to not detect this error at compile time. They verified that the expression being cast to Dog is of type that is a superclass of Dog, and allowed the expression to compile. They could go further and check that the expression will always result in an exception, but that would require an additional effort for very little improvement in user experience with the language.
Because you need it sometimes.
Especially when Java did not yet have generics (Java 1.4 and older), you almost always needed to cast when you got for example an object out of a collection.
// No generics, you don't know what kinds of objects are in this list
List list = new ArrayList();
list.add(new Dog());
// Need to cast because the return type of list.get() is Object
Dog dog = (Dog)list.get(0);
Since we have generics since Java 5, the need for casting is greatly reduced.
You should try to avoid casting in your code as much as possible. A cast is a way to deliberately switch off the compiler's type checking - in general you don't want to do that, you want to make use of the compiler's checking instead of circumventing it. So, if you have code where you need to cast, think a bit further to see if you can write it without the cast.
You need that capability to access an earlier cast object as its original type.
For example, if you cast a Dog to an Animal to pass it to a generic processor, you may later need to cast it back to a Dog to perform specific methods.
The developer is responsible to make sure the type is compatible - and when it is there will be no error. Some pseudo code:
public void example(Animal foo){
if( ...condition... ) ((Dog)foo).bark();
else if( ...other condition... ) ((Cat)foo).meow();
}
Since the introduction of generics, this is less commonly used, but there are still cases for it. The developer is solely responsible for guaranteeing the type is right if you don't want an error.
case 1 -
Here we use loose coupling.
Animal animal = getSomeDog(),
Dog dog = (Dog) animal; // this is allowed because animal could reference a dog
case 2
Here we you use tight coupling.
Animal animal = new Animal();
Dog dog = (Dog) animal; // this will fail at runtime, because animal doesn't reference a Dog
We use Downcasting when there is possibility to succeed at run time
so case 1 has possibility to succeed at runtime over case 2
Down casting is considered as a bad Object Oriented practice. It must be avoided to as much extent as possible.
Java still has it and your question is a good question as why Java allows Down-casting.
Suppose a case below.
public interface List{
public boolean add(Object e);
public boolean remove(Object o);
}
public class ArrayList implements List{
// Extra method present in the ArrayList and not in the parent Interface
public Object[] toArray() {
// returns array of the objects
return Arrays.copyOf(elementData, size);
}
#Override
public boolean add(Object e){
// add e to the ArrayList Underlying array
}
#Override
public boolean remove(Object o){
// remove o from the ArrayList Underlying array
}
}
A good Object oriented practice is to Code for Interfaces. But often there are methods defined in the concrete implementations which we need to call. I read an comment from some one and I quote it in my words.
Know the Rules, in case you need to break them Do break them Knowingly and take care so as to prevent from any adverse effect.
Below is an example where we need to do the Down-casting. The example of down-casting in your question is to teach what is down-casting, below is real life example.
public void processList(List items){
items.add( new Object() );
items.add( new Object() );
processAsPerTypeOfList(items);
}
public void processAsPerTypeOfList( List items ){
if( items instanceof ArrayList){
Object[] itemArray = ((ArrayList)items).toArray();// DOWNCASTING
// Process itemArray
}
}
For more reference you can also see a related question : Why Java needs explicit downcasting?
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 sure this is incredibly common with as OOP centered as Java is. In java is there a way to make a base type variable that accepts all inherited subtypes? Like if I have;
class Mammal {...}
class Dog extends Mammal {...}
class Cat extends Mammal {...}
class ABC {
private Mammal x;
ABC() {
this.x = new Dog();
-or-
this.x = new Cat();
}
}
I need the variable to be able to accept any extended version too, but not in specific one extended kind.
There are some ways that I know, but don't want to use. I could make an attribute for each subtype, then only have the one attribute actually used. Make an array and shove it in there.
Any other ideas or a way to get a "base class" type variable?
Ok since I know using polymorphic duck typing isn't a great idea in Java, but since I don't think I can avoid it. Is the only way to use subclass methods dynamically to re assign a casted version of the varible ie, I get an error with this;
Mammal x;
x = new Dog();
System.out.println(x.getClass());
x.breath();
if (x instanceof Dog) {
x.bark();
} else if (x instanceof Cat) {
x.meow();
}
Saying symbol not found, however this works;
Mammal x;
x = new Dog();
System.out.println(x.getClass());
x.breath();
if (x instanceof Dog) {
Dog d = (Dog) x;
d.bark();
} else if (x instanceof Cat) {
Cat c = (Cat) x;
c.meow();
}
That last one the only way to do it?
If you have the following:
class Mammal {...}
class Dog extends Mammal {...}
class Cat extends Mammal {...}
Then Dog is a subtype of Mammal. Cat is also a subtype of Mammal. This type polymorphism does in fact allow you to do the following:
Mammal x;
x = new Dog(); // fine!
x = new Cat(); // also fine!
If in fact later there's the following:
class Platypus extends Mammal {...} // yes it's true!
Then you can also do:
x = new Platypus(); // fine!
This polymorphic subtyping relationship is one of the basic tenets of object-oriented programming.
See also
Java Tutorials/Object-Oriented Programming Concepts
Wikipedia/Polymorphism in object-oriented programming
Subtype polymorphism, almost universally called just polymorphism in the context of object-oriented programming, is the ability of one type, A, to appear as and be used like another type, B
On instanceof type comparison operator
Suppose we have the following:
class Mammal { void lactate(); }
class Dog extends Mammal { void bark(); }
class Cat extends Mammal { void meow(); }
Then you can use instanceof type comparison operator (§15.20.2) to do something like this:
Mammal x = ...;
if (x instanceof Dog) {
Dog d = (Dog) x;
d.bark();
} else if (x instanceof Cat) {
Cat c = (Cat) x;
c.meow();
}
if (x != null) {
x.lactate();
}
There are also ways to do this without if-else; this is just given as a simple example.
Note that with appropriate design, you may be able to avoid some of these kinds of subtype differentiation logic. If Mammal has a makeSomeNoise() method, for example, you can simply call x.makeSomeNoise().
Related questions
When should I use the Visitor Design Pattern? - sometimes used to simulate double dispatch
On reflection
If you must deal with new types not known at compile-time, then you can resort to reflection. Note that for general applications, there are almost always much better alternatives than reflection.
See also
Java Technical Articles/Advanced Language Topics/Reflection
Effective Java 2nd Edition, Item 53: Prefer interfaces to reflection