Just confused on how to following answer is correct.
class Cat {
public void isClawedBy(Cat c){
System.out.println("Clawed by a cat");
}
}
class Kitten extends Cat{
public void isClawedBy(Kitten c){
System.out.println("Clawed by a Kit");
}
}
If the following is called
Cat g = new Cat();
Cat s = new Kitten();
Kitten t = new Kitten();
g.isClawedBy(t);
s.isClawedBy(t);
t.isClawedBy(t);
How is the answer:
Clawed by Cat
Clawed by Cat
Clawed by Kitten
I'm confused on why s.isClawedBy(t) = Clawed by Cat.
Since the dynamic type of s is a kitten, and t is a kitten.
Is it because the arguments are different, so it doesn't override it?
Another part I am confused on. //Note the arguments have been swapped.
class Cat {
public void isClawedBy(Kitten c){
System.out.println("Clawed by a cat");
}
}
class Kitten extends Cat{
public void isClawedBy(Cat c){
System.out.println("Clawed by a Kit");
}
}
If the following is called
Cat g = new Cat();
Cat s = new Kitten();
Kitten t = new Kitten();
g.isClawedBy(t);
s.isClawedBy(t);
t.isClawedBy(t);
The output is:
Clawed by Cat
Clawed by Cat
Clawed by Cat
How does it work for when t is called?
About the second query : t.isClawedBy(t) giving the output of Clawed by Cat.
Since t is a Kitten and the argument passed in the method t.isClawedBy(t) is also Kitten , the method from the superclass Cat will be called because it matches the arguments perfectly.
Class Kitten does not override isClawedBy(Cat c). It adds a new method isClawedBy(Kitten c). The runtime sees s referenced as a Cat at the time s.isClawedBy(t) is called, and it ends up calling the Cat method.
If you change Kitten to:
class Kitten extends Cat{
#Override
public void isClawedBy(Cat c){
System.out.println("Clawed by a Kit");
}
}
Then you will see the output you desire. Even more interesting, you can do:
((Kitten) s).isClawedBy(t); and you will see the proper method called.
I'm confused on why s.isClawedBy(t) = Clawed by Cat. Since the dynamic type of s is a kitten, and t is a kitten.
s has reference type Cat but holds a Kitten object. t has reference type Kitten and holds an object Kitten. When the method is run at run-time it is first checked if the reference type has such a method and then the most specific version of the method is called. Since the subclass doesn't override the method (different types in the parameter) the method in the reference type is called.
For your second part it is the exact same thing happening, there is no overload and a Kitten can indeed be passed as a Cat to the method in the reference type so again this method is the most specific one in the hierarchy and it is called.
As for the first question;
Overriding resolution is done at runtime, but overloading resolution is done at compile time.
Since the signature of your methods are not identical (different parameter types. It doesn't matter that one's the subclass of another), they're overloading.
Since resolved at compile time, the compiler does not know what the instance type is; only the declared type.
To the compiler, s.isClawedBy(t) is the method isClawedBy(Kitten) of the declared type Cat.
The compiler says "yep, Cat can accept a Kitten in its method, that's what this method is".
So, at runtime, which method that will call has ALREADY been chosen by the compiler. The lookup is NOT performed at runtime.
Thus, at runtime, despite s actually being a Kitten object, the Cat method is called.
Related
I am surprised that the first 2 lines of code in main below are allowed by the compiler. It seems to be trusting me when I say that getIt() will return a Dog even though the signature also allows a Cat to be returned.
public class GenericsAreWeird {
public static void main(String... args){
// This is fine
Dog d = getIt();
d.woof();
// This fails to compile
// getIt().woof();
// This compiles but gives a runtime ClassCastException
Cat c = getIt();
c.meow();
}
private static <T extends Animal> T getIt(){
return (T) new Dog();
}
public static class Animal {}
public static class Cat extends Animal{
public void meow(){}
}
public static class Dog extends Animal{
public void woof(){}
}
}
I generally trust Java generics to protect me from ClassCastExceptions by giving compiler errors, rather than telling me at runtime that something won't work, so allowing this seems broken.
It also seems counter-intuitive that:
Dog d = getIt();
d.woof();
is not exactly equivalent to:
getIt().woof();
the compiler needs the intermediate variable as a 'hint'.
Have generics always worked this way? Can someone point me to (or provide) a decent explanation of any other scenarios where the compiler fails to pick up a class-related error like this?
return (T) new Dog(); for the most part tells the compiler to
"shut up with your type checking, I know better than you that Dog will always be assignable to T"
to which the compiler replies
"okay, go ahead then, then you better take care of not ever calling this method expecting it to return a anything else / aCat"
Then you do call it expecting it to return a Cat and get a deserved ClassCastException. You get a runtime exception because you tell the compiler that you know it better (which you do not).
After type erasure your getIt() method will look very much like this:
private static Animal getIt(){
return new Dog();
}
But before the type erasure happens, the compiler sees, that you use a generic return type T extends Animal for the method! And thus, once it sees the line
Dog d = getIt();
it says: Ok, so T will be Dog in this particular case, so I need to insert a cast to Dog after type erasure like this:
Dog d = (Dog) getIt();
In the same way, for the call Cat c = getIt() it will resolve the type T to be Cat and add an according cast to Cat:
Cat c = (Cat) getIt();
But inside of your method the compiler warns you: Hey, are you sure, that the Dog you create will always be of type T? Remember, this is not guaranteed generally! So if you ignore this warning, you should know, what you are doing, taht's the point.
And finally, of course the call
getIt().woof()
will not compile, because in this case the compiler has no idea how to resolve the type T, so it will be just Animal, the upper limitation of T. It is not able to guess that it is a Dog only based on the call to the woof() method.
The following line:
getIt().woof();
fails because woof() is defined on Dog not Animal and getIt() returns a sub-class of Animal. Hence the compiler is unaware of woof().
You could try:
abstract class Animal { abstract void speak(); }
class Dog extends Animal { void speak() { // Dog specific implementation } }
class Cat extends Animal { void speak() { // Cat specific implementation } }
Then you could use:
getIt().speak();
You get a ClassCastException because the only information about the type returned by getIt() is that it is a sub-class of Animal. Assigning it to a variable of type Cat or Dog is unsafe. This would be true of any similar use of generics.
A common workaround is to define getIt() something like this:
<T extends Animal> T getIt(Class<T> clazz) {
// return an instance of the appropriate type based on clazz
}
You can use it thus:
Dog dog = getIt(Dog.class);
Let's take this simple Java code:
public class Animal {
public void eat() {
System.out.println("Generic Animal Eating Generically");
}
}
public class Horse extends Animal {
public void eat() {
System.out.println("Horse eating hay ");
}
public void eat(String s) {
System.out.println("Horse eating " + s);
}
}
I'm trying to figure out which version of the three eat() methods will run. Now, when I type
Animal a = new Animal();
a.eat();
The output is "Generic Animal Eating Generically", which is completely understandable.
The same thing happens when I type:
Horse h = new Horse();
h.eat();
The output is "Horse eating hay", which is, again, completely logical.
Here's where it gets confusing for me though. When I type:
Animal ah = new Horse();
ah.eat();
I get:
Horse eating hay
I expected the compiler to invoke the eat() method from the Animal class reference, not the Horse object reference.
So my question is, how can I know for sure which method the compiler is going to invoke when I have a generic reference variable
types referring to an object type (like this one: Animal horse = new Horse();
I expected the compiler to invoke the eat() method from the Animal class reference, not the Horse object reference.
Let's correct this statement first. The variable ah is a reference of type Animal and the statement new Horse() creates an instance of type Horse and assigns it to an Animal reference.
Now that the terminologies are clear, this behavior is expected and is termed as runtype-polymorphism or dynamic method dispatch. At compile time, eat() is resolved based on the reference type which is of type Animal, but at runtime, the method that will be called is based on the instance type which is Horse.
how can I know for sure which method the compiler is going to invoke when I have a generic reference variable types referring to an object type
You could follow these simple steps :
Check the method being called. ah.eat() is calling the method eat.
See if a method with the exact same signature (with the exception being return type covariance) is present in both the parent and child class. (method overriden or not?)
Check the reference type. In Animal ah = new Horse(), the reference type is Animal that is the parent class
Check the instance type. In Animal ah = new Horse(), the instance type is Horse which is the child class.
If all the above conditions are satisfied, you are looking at runtype polymorphism and the method from the child class will be called. In any other scenario, the method to be called will be resolved based on the reference type.
It would also pay to understand that a child class inherits methods from its parents. Lets say that you delete the public void eat() method from Horse class, you are no longer Overrding the eat() method; however, the public void eat(String s) method in Horse is still said to Overload the inherited eat method from Animal. Next, lets add a public void eat(String s) method in Animal. With this addition, you are now Overloading the eat method in Animal and Overrding it in Horse class. No matter how you change the code, the 4 steps mentioned above will always help you decide which method will be called.
This is called dynamic binding in Java. The explicite object type is used not the reference type.
It is not possible to call the overriden super method and the overriding method using a single method, see: How to call the overridden method of a superclass. You could add a method to your horse, which delegates the call to the animal like:
public class Horse extends Animal {
public void animalEat() {
super.eat();
}
public void eat() {
System.out.println("Horse eating hay ");
}
}
This is happens because of method overriding. In method overriding, the reference type does not matter, it is the object type that matters. Animal ah is simply a reference to the object and the actual object is of type Horse. So, Horse's method will be called instead of reference type Animal's method.
Ohkay,
new keyword will create instance of given class...
new Horse();
Now Horse class already is a child of Animal. So following will be instantiate.
public void eat() {
System.out.println("Horse eating hay ");
}
Now you are trying to store that object in Animal's object.
It means Object Of Horse is stored in Animal's Object.
Animal ah = new Horse();
So in Animal's object member of Horse is already stored.
That is the reason that compiler is printing child class method values.
This question already has answers here:
A Base Class pointer can point to a derived class object. Why is the vice-versa not true?
(13 answers)
Closed 7 years ago.
This is rather basic question. But I can't understand well the concept of inheritance.
Suppose I have two classes, A and B with both have a test() method that returned 1 and 2 respectively, and B inherited A class. In main method I declare the instance as such;
A a1 = new B();
and call the method a1.test(), it will return 2. This is the concept of polymorphism. But when I have a method test2() in just subclass, I can't call the method using the same instance declaration as above. Why is that happen?
I can't call the method using the same instance declaration as above. Why is that happen?
Because the type of the variable is A, and class A does not have a method test2(). The Java compiler only looks at the type of the variable to check if you can call a method, it does not look at the actual object (which is in this case a B).
This is all easier to understand if you use more concrete and meaningful names for your classes, instead of abstract names such as A and B. Let's call them Animal and Bear instead:
class Animal {
}
class Bear extends Animal {
public void growl() { ... }
}
class Cat extends Animal {
public void meow() { ... }
}
Animal a1 = new Bear();
Animal a2 = new Cat();
// Doesn't work, because not every Animal is a Bear, and not all
// animals can growl.
a1.growl();
// You wouldn't expect this to work, because a2 is a Cat.
a2.growl();
Because variable type is A, and class A does not have a method test2():
Rather you can use:
A a1 = new B(); // upcasting
B b1 = (B)a1; // Downcasting a1 to type B
b1.test2(); // now you can call test2 function
Because, the left side of your condition determines which method's you can call, and right side determines which methods will be called. So in this case class A does't have test2() method.
Imagine A = "TV" and B = "HD_TV".
You can say
TV tv = new HD_TV() // HD TV
and
TV tv = new TV() // ordinary TV
because an HD_TV is a TV.
You can say:
tv.show(movie)
It will show what is on TV, but you will get a better picture with the HDTV.
You cannot say:
tv.showHD(hdMovie) // Compiler error !!!
because in declaring tv as TV, you are saying it might not be an HD TV. Even though you can see that in this case it is, the compiler still respects your declaration that it is just a TV and you can only use methods supported for a TV.
That is because you are declaring the instance a1 as an A. Because B inherits A, you can call all the functions declared in A and they might have a different meaning if they are overloaded in B, but you do not have any access to B-only things.
You can see the first A as some kind of a header file, if you are familiar with that. It declares what A contains, without looking at how the functions are implemented or what the default vars are of everything in A. As a direct consequence, you can only access everything that is declared to literally be in A.
The left-hand side - A in this case - is the declared type, and it doesn't know about anything specific to child classes. The right-hand side - ´B´ in this case - is the actual type, and this provides the behaviour.
So, this will work because the declared type B knows about methods available in the class B.
B b1 = new B();
b1.test2();
If it was possible to have a1.test2(), that would mean every class would have to know about every child it has - including those in other libraries, when projects are assembled!
When B inherits A class and the reference of A is created with object of B like A a1 = new B();.
On Compile time java compiler looks for method availability in class A.
So it allows calling method test() but not the test2().
As test() method is available in class A but test2() is not available in class A.
You can type cast the object created like ((B)a1).test2().
This will work.
Here a1 object is of type A. a1 is pointing to an object of type B.
a1 is a reference of type A to an object of type B.
since a1 is of type A it know only test() which is declared in its class definition already. In case you want to access test2 declared in class B you need to type cast the a1 object back to B
like
B b1 = (B)a1
b1.test2() will be accessible.
This happens because you declare A variable and use B class which is an A. The compiler know it's an A but doesn't know it's a B later in the code. It's easier to use real life objects as example.
For example you have:
class Pet() {
method feed();
}
And a
class Dog() extends Pet {
method feed();
method bark()
}
If you have a code in another class:
So if you have code :
Pet dogPet=new Dog();
You know it's a dog here because you create the instance and you can use:
((Dog)dogPet).bark(); or just declare the variable as a dog instead of pet.
But if you have a method in another class:
void someMethod(Pet aPet){
// Here you don't know if the Pet is a dog or not. So you know only that it
//can be fed but you don't know if it barks. Even if a Dog is supplied to the method
}
In a1 = new B(), the actual type of the object created is B but you reference it as its supertype so you can call a method that accepts A (polymorphism).
So if a method is overridden in subclass, a1.test() is executing subclass's test().
In order to execute test2() you have to do that: ((B) a1).test2();
There is a concept called Up casting and Down casting.Up-casting is casting to a supertype, while downcasting is casting to a subtype. Supercasting is always allowed, but subcasting involves a type check and can throw a ClassCastException.,See the Example Code:
class A{
public int test(){
return 1;
}
}
class B extends A{
public int test(){
return 2;
}
public int test2(){
return 3;
}
}
and
A a1 = new B();
a1.test2();//not possible
Here you can't invoke methods of class B.
What is the difference between up-casting and down-casting with respect to class variable?
For example in the following program class Animal contains only one method but Dog class contains two methods, then how we cast the Dog variable to the Animal Variable.
If casting is done then how can we call the Dog's another method with Animal's variable.
class Animal
{
public void callme()
{
System.out.println("In callme of Animal");
}
}
class Dog extends Animal
{
public void callme()
{
System.out.println("In callme of Dog");
}
public void callme2()
{
System.out.println("In callme2 of Dog");
}
}
public class UseAnimlas
{
public static void main (String [] args)
{
Dog d = new Dog();
Animal a = (Animal)d;
d.callme();
a.callme();
((Dog) a).callme2();
}
}
Upcasting is casting to a supertype, while downcasting is casting to a subtype. Upcasting is always allowed, but downcasting involves a type check and can throw a ClassCastException.
In your case, a cast from a Dog to an Animal is an upcast, because a Dog is-a Animal. In general, you can upcast whenever there is an is-a relationship between two classes.
Downcasting would be something like this:
Animal animal = new Dog();
Dog castedDog = (Dog) animal;
Basically what you're doing is telling the compiler that you know what the runtime type of the object really is. The compiler will allow the conversion, but will still insert a runtime sanity check to make sure that the conversion makes sense. In this case, the cast is possible because at runtime animal is actually a Dog even though the static type of animal is Animal.
However, if you were to do this:
Animal animal = new Animal();
Dog notADog = (Dog) animal;
You'd get a ClassCastException. The reason why is because animal's runtime type is Animal, and so when you tell the runtime to perform the cast it sees that animal isn't really a Dog and so throws a ClassCastException.
To call a superclass's method you can do super.method() or by performing the upcast.
To call a subclass's method you have to do a downcast. As shown above, you normally risk a ClassCastException by doing this; however, you can use the instanceof operator to check the runtime type of the object before performing the cast, which allows you to prevent ClassCastExceptions:
Animal animal = getAnimal(); // Maybe a Dog? Maybe a Cat? Maybe an Animal?
if (animal instanceof Dog) {
// Guaranteed to succeed, barring classloader shenanigans
Dog castedDog = (Dog) animal;
}
Downcasts can be expressed more succinctly starting from Java 16, which introduced pattern matching for instanceof:
Animal animal = getAnimal(); // Maybe a Dog? Maybe a Cat? Maybe an Animal?
if (animal instanceof Dog castedDog) {
// now castedDog is available here as in the example above
}
Down-casting and up-casting was as follows:
Upcasting: When we want to cast a Sub class to Super class, we use Upcasting(or widening). It happens automatically, no need to do anything explicitly.
Downcasting : When we want to cast a Super class to Sub class, we use
Downcasting(or narrowing), and Downcasting is not directly possible in Java, explicitly we have to do.
Dog d = new Dog();
Animal a = (Animal) d; //Explicitly you have done upcasting. Actually no need, we can directly type cast like Animal a = d; compiler now treat Dog as Animal but still it is Dog even after upcasting
d.callme();
a.callme(); // It calls Dog's method even though we use Animal reference.
((Dog) a).callme2(); // Downcasting: Compiler does know Animal it is, In order to use Dog methods, we have to do typecast explicitly.
// Internally if it is not a Dog object it throws ClassCastException
Autoboxing-vs-Casting
Upcasting and downcasting are important part of Java, which allow us to build complicated programs using simple syntax, and gives us great advantages, like Polymorphism or grouping different objects. Java permits an object of a subclass type to be treated as an object of any superclass type. This is called upcasting. Upcasting is done automatically, while downcasting must be manually done by the programmer, and i'm going to give my best to explain why is that so.
Upcasting and downcasting are NOT like casting primitives from one to other, and i believe that's what causes a lot of confusion, when programmer starts to learn casting objects.
Polymorphism: All methods in java are virtual by default. That means that any method can be overridden when used in inheritance, unless that method is declared as final or static.
You can see the example below how getType(); works according to the object(Dog,Pet,Police Dog) type.
Assume you have three dogs
Dog - This is the super Class.
Pet Dog - Pet Dog extends Dog.
Police Dog - Police Dog extends Pet Dog.
public class Dog{
public String getType () {
System.out.println("NormalDog");
return "NormalDog";
}
}
/**
* Pet Dog has an extra method dogName()
*/
public class PetDog extends Dog{
public String getType () {
System.out.println("PetDog");
return "PetDog";
}
public String dogName () {
System.out.println("I don't have Name !!");
return "NO Name";
}
}
/**
* Police Dog has an extra method secretId()
*/
public class PoliceDog extends PetDog{
public String secretId() {
System.out.println("ID");
return "ID";
}
public String getType () {
System.out.println("I am a Police Dog");
return "Police Dog";
}
}
Polymorphism : All methods in java are virtual by default. That means that any method can be overridden when used in inheritance, unless that method is declared as final or static.(Explanation Belongs to Virtual Tables Concept)
Virtual Table / Dispatch Table : An object's dispatch table will contain the addresses of the object's dynamically bound methods. Method calls are performed by fetching the method's address from the object's dispatch table. The dispatch table is the same for all objects belonging to the same class, and is therefore typically shared between them.
public static void main (String[] args) {
/**
* Creating the different objects with super class Reference
*/
Dog obj1 = new Dog();
` /**
* Object of Pet Dog is created with Dog Reference since
* Upcasting is done automatically for us we don't have to worry about it
*
*/
Dog obj2 = new PetDog();
` /**
* Object of Police Dog is created with Dog Reference since
* Upcasting is done automatically for us we don't have to worry
* about it here even though we are extending PoliceDog with PetDog
* since PetDog is extending Dog Java automatically upcast for us
*/
Dog obj3 = new PoliceDog();
}
obj1.getType();
Prints Normal Dog
obj2.getType();
Prints Pet Dog
obj3.getType();
Prints Police Dog
Downcasting need to be done by the programmer manually
When you try to invoke the secretID(); method on obj3 which is PoliceDog object but referenced to Dog which is a super class in the hierarchy it throws error since obj3 don't have access to secretId() method.In order to invoke that method you need to Downcast that obj3 manually to PoliceDog
( (PoliceDog)obj3).secretID();
which prints ID
In the similar way to invoke the dogName();method in PetDog class you need to downcast obj2 to PetDog since obj2 is referenced to Dog and don't have access to dogName(); method
( (PetDog)obj2).dogName();
Why is that so, that upcasting is automatical, but downcasting must be manual? Well, you see, upcasting can never fail.
But if you have a group of different Dogs and want to downcast them all to a to their types, then there's a chance, that some of these Dogs are actually of different types i.e., PetDog, PoliceDog, and process fails, by throwing ClassCastException.
This is the reason you need to downcast your objects manually if you have referenced your objects to the super class type.
Note: Here by referencing means you are not changing the memory address of your ojects when you downcast it it still remains same you are just grouping them to particular type in this case Dog
I know this question asked quite long time ago but for the new users of this question.
Please read this article where contains complete description on upcasting, downcasting and use of instanceof operator
There's no need to upcast manually, it happens on its own:
Mammal m = (Mammal)new Cat(); equals to Mammal m = new Cat();
But downcasting must always be done manually:
Cat c1 = new Cat();
Animal a = c1; //automatic upcasting to Animal
Cat c2 = (Cat) a; //manual downcasting back to a Cat
Why is that so, that upcasting is automatical, but downcasting must be manual? Well, you see, upcasting can never fail. But if you have a group of different Animals and want to downcast them all to a Cat, then there's a chance, that some of these Animals are actually Dogs, and process fails, by throwing ClassCastException.
This is where is should introduce an useful feature called "instanceof", which tests if an object is instance of some Class.
Cat c1 = new Cat();
Animal a = c1; //upcasting to Animal
if(a instanceof Cat){ // testing if the Animal is a Cat
System.out.println("It's a Cat! Now i can safely downcast it to a Cat, without a fear of failure.");
Cat c2 = (Cat)a;
}
For more information please read this article
Better try this method for upcasting, it's easy to understand:
/* upcasting problem */
class Animal
{
public void callme()
{
System.out.println("In callme of Animal");
}
}
class Dog extends Animal
{
public void callme()
{
System.out.println("In callme of Dog");
}
public void callme2()
{
System.out.println("In callme2 of Dog");
}
}
public class Useanimlas
{
public static void main (String [] args)
{
Animal animal = new Animal ();
Dog dog = new Dog();
Animal ref;
ref = animal;
ref.callme();
ref = dog;
ref.callme();
}
}
Maybe this table helps.
Calling the callme() method of class Parent or class Child.
As a principle:
UPCASTING --> Hiding
DOWNCASTING --> Revealing
1.- Upcasting.
Doing an upcasting, you define a tag of some type, that points to an object of a subtype (Type and subtype may be called class and subclass, if you feel more comfortable...).
Animal animalCat = new Cat();
What means that such tag, animalCat, will have the functionality (the methods) of type Animal only, because we've declared it as type Animal, not as type Cat.
We are allowed to do that in a "natural/implicit/automatic" way, at compile-time or at a run-time, mainly because Cat inherits some of its functionality from Animal; for example, move(). (At least, cat is an animal, isn't it?)
2.- Downcasting.
But, what would happen if we need to get the functionality of Cat, from our type Animal tag?.
As we have created the animalCat tag pointing to a Cat object, we need a way to call the Cat object methods, from our animalCat tag in a some smart pretty way.
Such procedure is what we call Downcasting, and we can do it only at the run-time.
Time for some code:
public class Animal {
public String move() {
return "Going to somewhere";
}
}
public class Cat extends Animal{
public String makeNoise() {
return "Meow!";
}
}
public class Test {
public static void main(String[] args) {
//1.- Upcasting
// __Type_____tag________object
Animal animalCat = new Cat();
//Some animal movement
System.out.println(animalCat.move());
//prints "Going to somewhere"
//2.- Downcasting
//Now you wanna make some Animal noise.
//First of all: type Animal hasn't any makeNoise() functionality.
//But Cat can do it!. I wanna be an Animal Cat now!!
//___________________Downcast__tag_____ Cat's method
String animalNoise = ( (Cat) animalCat ).makeNoise();
System.out.println(animalNoise);
//Prints "Meow!", as cats usually done.
//3.- An Animal may be a Cat, but a Dog or a Rhinoceros too.
//All of them have their own noises and own functionalities.
//Uncomment below and read the error in the console:
// __Type_____tag________object
//Cat catAnimal = new Animal();
}
}
upcasting means casting the object to a supertype, while downcasting means casting to a subtype.
In java, upcasting is not necessary as it's done automatically. And it's usually referred as implicit casting. You can specify it to make it clear to others.
Thus, writing
Animal a = (Animal)d;
or
Animal a = d;
leads to exactly the same point and in both cases will be executed the callme() from Dog.
Downcasting is instead necessary because you defined a as object of Animal. Currently you know it's a Dog, but java has no guarantees it's. Actually at runtime it could be different and java will throw a ClassCastException, would that happen. Of course it's not the case of your very sample example. If you wouldn't cast a to Animal, java couldn't even compile the application because Animal doesn't have method callme2().
In your example you cannot reach the code of callme() of Animal from UseAnimlas (because Dog overwrite it) unless the method would be as follow:
class Dog extends Animal
{
public void callme()
{
super.callme();
System.out.println("In callme of Dog");
}
...
}
We can create object to Downcasting. In this type also. : calling the base class methods
Animal a=new Dog();
a.callme();
((Dog)a).callme2();
I asked a similiar question yesterday, but another issue has arisen.
class Cat {
public void isClawedBy(Cat c, Kitten k){
System.out.println("Clawed by a cat");
}
}
class Kitten extends Cat{
public void isClawedBy(Kitten k, Cat c){
System.out.println("Clawed by a Kit");
}
}
Cat g = new Cat();
Cat s = new Kitten();
Kitten t = new Kitten();
g.isClawedBy(s,t);
s.isClawedBy(t,s);
t.isClawedBy(t,t);
The issue i am am confused about is around t.isClawedBy(t,t);. I understand that s.isClawedBy(t,s); will throw an error, because s is of static type cat.
But t.isClawedBy(t,t); is throwing a "The method isClawedBy(Kitten, Cat) is ambiguous for the type Kitten" error. If i change the code to t.isClawedBy(s,t); or t.isClawedBy(t,s); it works, but unsure as to why it doesnt work for (t,t).
Thanks in advance
In Java method calls are resolved dynamically. When you call a method the JVM tries to find a method that matches the signature i.e. method name, parameter types and return types. It does this by looking in the method table of the class used, which will contain the method signatures of super types also.
When checking if a signature in the method table is suitable it will take into account the supertypes of the parameter (and return) types. In the case of t.isClawedBy(t,t) we have two methods that can match as the method defined in Kitten matches and that defined in Cat matches - note that these are different methods as they have different parameter types.
As two different methods match the method call is ambiguous.
For isClawed(s,t) and isClawed(t,s) there is no ambiguity as s is a Kitten and cannot be a Cat.
It is ambiguous because Kittens are Cats.
Thus, given:
Cat isClawedBy(Cat c, Kitten k)
Kitten isClawedBy(Kitten k, Cat c)
For a Kitten, both methods are available. A Kitten is a Cat, so a call to Cat.isClawedBy(Cat, Kitten) with two Kitten arguments fits the signature. Likewise, a call to Kitten.isClawedBy(Kitten, Cat) with two Kittens also matches the signature.
There is no way for the compiler to tell which method was intended.
It is because you didn't override that method.
For t.isClawedBy(t,t);there are two possible methods to execute.The Cat's isclawed method and the Kitten's isclawed method.
To override a method paremeters must be the same.
kitten extends cat, so kitten gets the atributs and methods of cat, so kitten class knows 2 methods
public void isClawedBy(Cat c, Kitten k)
public void isClawedBy(Kitten k, Cat c)
But it dosent know a metoth public void isClawedBy(Kitten k, Kitten k) so it dosent know what to do when u call isClawedBy(t,t);