Difference between different ways in instantiating an object in Java - java

I have the code:
class Father{
String name="father";
void f(){System.out.print("father class");}
}
class Son extends Father{
String name = "son";
void f(){System.out.print("son class");}
void f2(){}
}
public class Test {
public static void main(String[] args) {
Father s = new Son();
System.out.println(s.name);// outputs father
s.f();// outputs "son class"
s.f2();// s does not have f2
}
}
My question is, what is the difference between doing Father s = new Father() or, Father s = new Son() or, Son s = new Son()?
As well, why does s.f2 in the example cause an error? Must Father implement f2()?

I think it is easier to explain with an animal example:
class Animal {
void printName() {
System.out.println("Animal");
}
}
class Dog extends Animal{
#Override
void printName() {
System.out.println("Dog");
}
}
class Cat extends Animal{
#Override
void printName() {
System.out.println("Cat");
}
void meow() {
System.out.println("meow");
}
}
When you extend classes, the child class can override parent's methods and can have its own methods. In my Animal example the generic Animal object can only give its name, but the Cat object can give its name and also meow. Obviously, the meow method is specific to Cat as we know that Dogs can't do meow and Animals in general.
When you do
Animal animal = new Cat();
You actually create an instance of the Cat but use it as a general Animal. Thus, your animal instance only has methods which are available in the Animal class but the execution of the methods overridden by Cat class will be delegated to the Cat class.
if you want to execute Cat's specific methods then you need to cast your Animal to the Cat
(Cat) animal.meow();
In your example to call f2() method you need to cast your father object to the son first
(Son)s.f2();

What you're dealing with is reference type (variable type) and object type (what's actually being referred to). The Java compiler needs some kind of guarantee that the object being referred to can run the method you're calling. To do this, it looks to the reference type. When executed, the method run is that of the object type.
Simply put:
Father f = new Father(); //Treated as a Father, behaves like a Father
Son s = new Son(); //Treated as a Son, behaves like a Son
Father q = new Son(); //Treated as a Father, behaves like a Son (sounds like my own father)
If you cast q to a Son by saying (Son)q, it will be treated as a Son by the compiler, unless the object isn't actually a Son, in which case you'll get a ClassCastException.

Let's take a simpler concept, since your hierarchy implies that all Sons are Fathers, but not all Fathers are Sons (which ain't quite true).
Let's take the abstract class Number and any of its children - for brevity, we can use Integer, Float and BigInteger.
Suppose we declare this:
Number num = Float.NaN;
We now have a Float instance which is referenced by a Float. We can do anything we want to that instance, but only in the context of a Number.
There's a useful method for Float called isNan which would allow us to see if our float actually is a number. In the context of Number...that method doesn't exist.
There are advantages to doing it like this - if you don't need the specificity of the child reference, you can refer to everything by its parent class (or interface). This also uncouples you from the child's API should you want to be uncoupled from it (see developing to an interface).

OK I see where is the confusion here.
In java you can override methods but not class variables
keep that rule in mind
So when you did
Father s = new Son();
the object "s" is of type father
and as we said the variables inside it wont be overwritten just the methods
So the the final result is an object that has the member variables from the Father class (the "name" variable) and the method from son class (since father had only 1 method and son overridden it).
and for why the f2 does not work
it is because the object "s" is of type Father not son (it is father object that has 1 method of it overwritten by son class other than that it will keep be father object) and Father does not have f2 method thats why you get the compile error

s.f2() is the syntax error because you told JVM that s is Father, not Son.
In the code, it can't find f2 method in Father class
class Father{
String name="father";
void f(){System.out.print("father class");}
}
But it doesn't mean the code is wrong, just the JVM doesn't like it.
if you change s.f2() to
(Son)s.f2();
It will works

Related

Why does it store or allocate memory for super class variables, in sub class object?

In the following code-
class Mammal {
String name = "furry ";
String makeNoise() {
return "generic noise";
}
}
class Zebra extends Mammal {
String name = "stripes ";
String makeNoise() {
return "bray";
}
}
public class ZooKeeper {
public static void main(String[] args) {
new ZooKeeper().go();
}
void go() {
Mammal m = new Zebra();
System.out.println(m.name + m.makeNoise());
Zebra z = new Zebra();
System.out.println(z.name + z.makeNoise());
}
}
Both objects (m and z), if I see in debug windows of eclipse, contain both values of name variable (furry and stripes).
I do understand that in polymorphism, generic method of super class can be used by sub class as well. But why does sub class object stores values of super class variables as well, even in case of hiding. Is there any use of this?
First: As a general rule, if a class defines a field that a subclass can access, the subclass should not redefine the field. It's just a Really Bad Idea. Primarily what you're seeing is there to make private fields work properly. Redefining non-private fields in a subclass is asking for a world of hurt. (Of course, if Joe writes Mammal and Mary writes Zebra and at some point Joe adds a field to Mammal that happens to conflict with one that Mary used in Zebra, there's nothing Mary can do about that. Which is one reason for making all fields private.)
But why does sub class object stores values of super class variables as well, even in case of hiding.
The key here is to remember that fields are not polymorphic, just methods. So there have to be two name fields in the object (one from Mammal and one from Zebra), because code using a Mammal-typed reference needs to see the Mammal name, whereas code using the Zebra-typed reference needs to see the Zebra name.
That's why your code shows "furry bray" and then "stripes bray". You get "furry bray" via m because accessing name on m (a Mammal-typed variable) accesses Mammal's name (not polymorphic), giving you "furry". But then you call the method makeNoise using m and get back "bray", because the method that gets called is the one on Zebra (polymorphic). Then you do it again with z (a Zebra-typed reference) and see "stripes bray" because z accesses Zebra's name, not Mammal's.
The next question you might have is: If we change makeNoise in both classes to:
String makeNoise() {
return this.name;
}
why does ZooKeeper's code
Mammal m = new Zebra();
System.out.println(m.name + m.makeNoise());
Zebra z = new Zebra();
System.out.println(z.name + z.makeNoise());
give us "furry stripes" from m and stripes stripes from z?
It's the same reason, just a different presentation of it. m.name accesses name from a Mammal-typed reference, and so sees Mammal's name (not polymorphic). m.makeNoise calls Zebra's makeNoise method (polymorphic), and inside Zebra's makeNoise, this has the type Zebra even though we called it from a Mammal-typed m (and so this.name uses Zebra's name). The fact that Zebra's makeNoise is used there, and the fact that this within Zebra code is typed Zebra are both key to polymorphism in Java.
Let's take it further: What if Zebra doesn't define makeNoise at all?
class Mammal {
String name = "furry ";
String makeNoise() {
return this.name;
}
}
class Zebra extends Mammal {
String name = "stripes ";
}
Now we get "furry furry" from m and "stripes furry" from z. And the reason for it is the same as above: The type of the reference determines which field is used, and in Mammal code (makeNoise), this has the type Mammal. So even though we called makeNoise using z, since Zebra has no makeNoise, Mammal's is called, so the reference that looks up name has the type Mammal.
Is there any use of this?
It's crucial to classes working properly, particularly in the case of private fields. Mammal code doesn't have to worry about a subclass coming along and redefining its fields. You could have a 10-deep class hierarchy, with each class defining its own name, and that's fine, each level's code works with the name it defines.

Inheritance concept in Java [duplicate]

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

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();

YAIC (Yet Another Inheritance Confusion)

I am sure this type of question is asked every day, but I am struggling with understanding why the mammal object is instantiated as a cat, and reports its name to be Morris. However, unlike most cats, it does not have 9 lives. If the object is not a cat, why does it report its name to be Morris?
class Mammal {
int temp;
String name = "George";
public Mammal() {
temp = 98;
}
public String getName() {
return name;
}
}
class Cat extends Mammal {
int lives;
String name = "Morris";
public Cat() {
lives = 9;
}
public String getName() {
return name;
}
}
public class Inheritance {
public static void main(String[] args) {
Mammal mm = new Cat();
System.out.println("Mam Temp:" + mm.temp);
//System.out.println("Cat Lives:" + mm.lives); <-- error
System.out.println("Mam Name:" + mm.getName());
}
}
There are two related but concretely separate concepts here.
The runtime type of an object.
The static (and runtime) type of a variable.
The runtime type of the object will determine how it behaves at runtime. It's determined by the constructor you called when you used the new keyword.
The static type of the variable dictates how your code can interact with or reference that variable (and the object it refers to). It's determined by the type you specify when you declare that variable (or field, parameter, etc).
In this case, the static type of the variable is Mammal while the runtime type of the object it points to is Cat. Thus, while it behaves like a Cat at runtime and shows its name as being 'Morris', at compile time the compiler only knows that it is a Mammal, and cannot refer to the lives variable (which is defined in Cat, not Mammal).
Because the variable is of type Mammal which was set in the line Mammal mm = new Cat();. The Mammal class does not contain a variable lives and therefore it throws the error. If you do ((Cat)mm).lives however, you should get the correct result because you are casting the mm variable to the type Cat (which it was initialized as).
EDIT
Also, you overrode the getName() Method in the Cat class which "hides" the one in the Mammal class. You created mm as a Type Mammal but in reality it's a Cat so a call to the getName() method on mm will call the child method getName() which returns "Morris" instead of "George".
You created an instance of Cat but you are treating it as a Mammal. Mammal.lives doesn't exist, which is why you get an error when you try to print mm.lives.
Incidentally, this is a good example of why inheritance can be dangerous and should be used sparingly. Cat and Mammal are tightly coupled by inheritance, so you have to understand both classes and how they interact in order to understand code that deals with Cat.
the object created is that of Cat so the getName method when invoked is on the Cat object and hence its name is reported as "morris". The local variable however is defined as a Mammal so lives can not be accessed unless you explicitly cast it to a cat.

How to downcast a Java object?

I am trying to understand Java's polymorphism, and I have one question about downcasting an object.
Let's say for this example I have two subclasses Dog and Cat that inherit from a superclass Animal
From what I understood, the only way to downcast an object is if this Object is already of the good type, like this:
Animal a = new Dog();
Dog d = (Dog) a;
This works right?
But what if I want to create a regular animal without knowing what it would be, and then cast it when I know, how can I do that?
Animal a = new Animal();
Dog d = (Dog) a;
This will throw a ClassCastException at runtime right?
The only way I found to do that is to create a new Dog constructor that creates a dog from a regular animal:
Animal a = new Animal();
Dog d = new Dog(a);
with
public Class Dog extends Animal{
public Dog(Animal a){
super(a);
}
}
So my question is, how am I supposed to do this?
Am I doing it the best way?
Am I not supposed to do this at all, if I have to it means my program is not well conceived?
Is there a better way I missed?
Thanks a lot!
nbarraille
If you want to create an instance of a type that may vary depending upon non-local conditions, use an Abstract Factory (as described in the Design Patterns book).
In it's simplest form:
interface AnimalFactory {
Animal createAnimal();
}
class DogFactory implements AnimalFactory {
public Dog createAnimal() {
return new Dog();
}
}
Note also there is a difference between the static type of a reference and the dynamic type of the object. Even though you have an Animal reference, if the original object is a Dog, it still behaves like a Dog.
You should only cast to a class that the object really is, so if you have a Dog that extends Animal you can cast it to an Animal (because it is one) but you shouldn't cast an Animal to a Dog because not all Animals are Dogs. The Dog class may well have extra fields that are not implemented by the Animal class and so the cast doesn't make sense (what do you initialise those values to?).
Java is a strongly typed language, and that means you can only cast an object to a type it extends from (either a superclass or an interface).
Even if you "fake it", e.g. copy all a classes methods and fields, you just can't cast an object to a type it doesn't extend.
public class Foo{
public String phleem;
public void bar(){
}
}
public class Bar{
public String phleem;
}
public interface Baz{
public void bar();
}
Given the above code, you can't cast a Foo object to either a Bar or a Baz, although the class structure seems to imply that you could. There is no inheritance involved, so a ClassCastException is thrown.
Here you are talking about downcasting, so in this scenario always superclass should be used as a reference and child object should be pointed by that.
This usd basically in factory patter.

Categories

Resources