I'm kind of stuck on the following question:
What two Java language mechanisms allow the type of an object reference variable to be "different" than the type of the object to which it refers? Give specific examples to illustrate. In what sense are they not different at all?
My current answer is that it is "implement" and "extend" right? And they are similar because they both will make a class that at least will posses all of the method signatures of the super class which can be actual, abstract, or an interface. Is this correct? Thanks in advance!
That is more or less correct. The second part of your answer should talk about subtyping. In Java, it is not sufficient for objects to just have the same method signatures. There actually has to be a declared subtyping relationship (via extends / implements).
This is not mere pedantry. In some languages (but not Java), the mere existence of compatible method signatures is sufficient for type compatibility. This is called "duck typing".
Implements
interface Animal {
void attackHuman(); // actually public abstract by default
}
class Horse implements Animal {
public void attackHuman() { }; // must implement
}
// type and reference the same
Horse a1 = new Horse();
// type and reference different
Animal a2 = a1;
Extends
class Animal {
void attackHuman();
}
class Dinosaur extends Animal {
// attackHuman() inherited
}
// type and reference the same
Dinosaur a1 = new Dinosaur();
// type and reference different
Animal a2 = a1;
See this example....
- Here the Animal is the Super-Class, and the Dog and Cat are inherited out of it.
- You can Create a Dog object using an Animal Object Reference Variable.
- This is known as Class Polymorphism.
public class Test {
public static void main(String[] args){
Animal a = new Dog();
new Hospital().treatAnimal(a);
}
}
class Animal {
public void sayIt(){
}
}
class Dog extends Animal{
public void sayIt(){
System.out.println("I am Dog");
}
}
class Cat extends Animal{
public void sayIt(){
System.out.println("I am Cat");
}
}
See the NEXT PAGE for the Remaining Code
class Hospital{
public void treatAnimal(Animal a){
if(a instanceof Dog){
a.sayIt(); // Will output "I am Dog"
}
else{
a.sayIt(); // Will output "I am Cat"
}
}
}
Related
What's definitely the best way to call a different method of a class according to a different object type in a List?
common example:
public class Dog extends Animals{
...
public void say(){
System.out("i'm a dog");
}
public class Cat extends Animals{
...
public void say(){
System.out("i'm a cat");
}
public class OtherClass {
public void route(){
List<Animals> aList = new ArrayList<>();
a.add(new Dog());
a.add(new Cat());
for(Animals a:aList)
methodOverloaded(a); ---> that's the point <---
}
public methodOverloaded(Dog d){
d.say();
}
public methodOverloaded(Cat c){
c.say();
}
}
Of course, the metaphorical goal is print I'm a dog on the first iteration and I'm a cat on second running methodOverloaded().
I tried
Visitor Pattern
instanceOf()
but I'm looking for better solution.
edit : I stricrtly want to call the overloaded methods of example's OtherClass.
The best way is to define abstract method in Animal and override it in child classes. That's how the polymorphism works.
No need of overloadings.
public abstract class Animal {
public abstract void say();
}
public class Dog extends Animal {
#Override
public void say() {
System.out.println("Bark");
}
}
public class Cat extends Animal {
#Override
public void say() {
System.out.println("Meow");
}
}
Usage:
public class Main() {
public static void main(String[] args) {
List<Animals> aList = new ArrayList<>();
a.add(new Dog());
a.add(new Cat());
for (Animals a : aList)
a.say();
}
}
Output:
Bark
Meow
____UPDATE_1
I would like to add some comments why the overloading these methods is not a good idea.
If you will add the following to your code - it will compile:
public methodOverloaded(Animal a) {
a.say();
}
But it will not work as you're expecting. It will call public methodOverloaded(Animal a) for all the elements of List.
Why does this happen?
For all iterations of the loop, the compile-time type of the parameter is Animal. The runtime type is different in each iteration, but this does not affect the choice of overloading. Because the compile-time type of the parameter is Animal, the only applicable overloading is the third one.
The behavior of this program is counterintuitive because selection among overloaded methods is static, while selection among overridden methods is dynamic.
The correct version of an overridden method is chosen at runtime, based on the runtime type of the object on which the method is invoked.
This can be fixed with:
public methodOverloaded(Animal a) {
if (a instanceof Cat) ? "Meow" :
(a instanceof Dog) ? "Bark" : "Unknown Animal"
}
Of course suggested option with overriding methods demonstrates better approach and more clean code.
Also, a safe, conservative policy is never to export two overloadings with
the same number of parameters, because it can confuse the client of the API. You can always give methods different names instead of overloading them.
But there is the case when at least one corresponding formal parameter in each pair of overloadings has a “radically different” (when it's clearly impossible to cast an instance of either type to the other) type in the two overloadings.
For example, ArrayList has one constructor that takes an int and a second constructor that takes a Collection. It is hard to imagine any confusion over which of these two constructors will be invoked under any circumstances.
You need to define the method in Animal and make it abstract
abstract class Animal {
public abstract void say();
}
this way, you can override this method in each child of Animal, and all you got to do is a.say()
each object will call their respective method.
You can do it like this:
for(Animals a:aList){
if(a instanceof Dog){
methodOverloaded((Dog) a);
}else if(a instanceof Cat){
methodOverloaded((Cat) a);
}
}
But according to the scenario you have described in the question, #J-Alex answer is a good way to go.
I can show you how "Factory Design pattern" is the suitable way here.
Define you main class like:
public abstract class Animal {
public abstract void say();
}
public class Dog extends Animal {
#Override
public void say() {
System.out.println("Bark");
}
}
public class Cat extends Animal {
#Override
public void say() {
System.out.println("Meow");
}
}
public class FactoryClass{
public static Animal getCorrectAnimal(String type){
if("Cat".equalsIgnoreCase(type)) return new Cat();
else if ("Dog".equalsIgnoreCase(type)) return new Dog();
return null;
}
}
public class TestFactoryClass {
public static void main(String[] args) {
Animal an = ComputerFactory.getCorrectAnimal("Cat");
List<Animals> aList = new ArrayList<>();
a.add(FactoryClass.getCorrectAnimal("Dog"));
a.add(FactoryClass.getCorrectAnimal("Cat"));
for (Animals a : aList)
a.say();
}
}
}
Trust me, if you will analyse the level of Abstraction here, it is awesome. The client/consumer never has to know the Dog or Cat class, he/she just has to know the type and a general abstract class Animal. You can even get rid of type here if you use one higher level of abstraction; you can read "Abstract Factory Design" for that. In this way, you expose the least of your class features (like here you exposed Dog and Cat class by using them directly with new in main class). Please upvote if you are satisfied.
why do I have to write like this
animal a = new cat();
cat b = (cat)a;
b.makesound();
a.makesound();
but not like this
animal a = new cat();
animal b = new cat();
a.makesound();
b.makesound();
they give the same outputs
This is the entire code.
public class DownCasting
{
public static void main(String args[])
{
animal a = new cat();
cat b = (cat)a;
b.makesound();
a.makesound();
}
}
class animal
{
public void makesound()
{
System.out.println('w');
}
}
class cat extends animal
{
public void makesound()
{
System.out.println("meow");
}
}
so downcasting just give an object second name? or it has other uses?
In the second variant, you create two cats.
In the first, you assign the additional name b to the already existing animal a.
so downcasting just give an object second name? or it has other uses?
You might want to have a list of animals, f.ex. a dog:
class dog extends animal
{
public void makesound()
{
System.out.println("woof");
}
}
could be combined in the same list with cats.
Casting is the process of forcefully making a variable behave as a variable of another type. If a class shares an IS-A or inheritance relationship with another class or interface, their variables can be cast to each other’s type.
public class DownCasting
{
public static void main(String args[])
{
animal a = new cat();
cat b = (cat)a;
b.makesound();
a.makesound();
}
}
class animal
{
public void makesound()
{
System.out.println('w');
}
}
class cat extends animal
{
public void makesound()
{
System.out.println("meow");
}
}
In the line animal a = new cat(); you are using a variable of type Animal to refer an object of type Cat, and a.makesound(); will print "meow" because with inheritance, the instance methods bind at runtime.
However, if you try to do cat b = a; (without casting) the Java Compiler will try to use a variable of type Cat to reference an object of type Animal, and that is not possible (you cannot use a variable of a sub-class to reference (execute) methods from a super-class), so it is necessary cast the variable to indicate to the java compiler that it can be sure that despite a is a variable of type Animal, is actually a Cat.
Let me give you an example to make this more clear:
I have your two classes with some modifications:
class animal
{
public void makesound()
{
System.out.println('w');
}
void sleep(){
System.out.println("ZZZ");
}
}
class cat extends animal
{
public void makesound()
{
System.out.println("meow");
}
void play(){
System.out.println("I´m playing");
}
}
both classes now have a method that the other class does not have.
Now let's use it:
public class DownCasting
{
public static void main(String args[])
{
animal a = new cat();
}
}
If I do a.play(); it will give me a compilation error because Java searchs for the method play() inside the Animal Class and cannot find it... Why java does that? as I already said: "With inheritance, the instance methods bind at runtime", so if I want to call that method I have to cast the a variable... ((Cat)a).play();
But what happen if you try to do it the other way around?
Cat c = new Animal(); //This line will never compile...
So, I can cast it like this in order to make it compile:
Cat c = (Cat)new Animal();
c.play();
BUT, in runtime it will throw a java.lang.ClassCastException why?, because you cannot use a variable of a sub-class to reference (execute) methods from a super-class.
To sum up, remember that the type of the object reference variable and the type of the object being referred to may be different.
But there are rules on how different these can be.
To this topic I will recommend you OCA Java SE 7 Programmer I Certification Guide: Prepare for the 1ZO-803 exam specifically the chapter 6.
why do I have to write like this
to answer this question you need to know first what can make a sound?
the cat or the animal?
you do this :
animal a = new cat();
a.makesound();
when the method makesound is declared in animal
if not then you need to cast
This question already has answers here:
Why bark method can not be called
(5 answers)
Closed 6 years ago.
The Superclass reference variable can hold the subclass object, but using that variable you can access only the members of the superclass, so to access the members of both classes it is recommended to always create reference variable to the subclass.
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
public void bark() {
System.out.println("Dogs can bark");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move(); // runs the method in Animal class
b.move(); // runs the method in Dog class
b.bark();
}
}
output:
TestDog.java:26: error: cannot find symbol
b.bark();
^
symbol: method bark()
location: variable b of type Animal
1 error
What I do not understand here is why is the object 'b' able to access the Dog.move() and not Dog.bark() because the statement mentioned above says it can access only the members of the superclass and not the subclass.Following this logic the output of b.move() should be "Animals can move" and not "Dogs can walk and run".But that is not case.Can anyone help me with this?Thanks in advance!
Congratulations - you just discovered polymorphism.
In Java the classes are bound dynamically. That is if you are invoking a method the implementation of the object is invoked (in your case the Dog) and not the method of the reference type (in your case the Animal).
This allows overwriting methods and replace or fulfill their implementation.
On the other hand, you can only access methods that are available in the type you are referencing, not the implementing type (in your case the Animal). To invoke the methods of the instance, you would have to use it as the reference type (in your case the Dog).
In your question Animal is a parent class which doesn't have bark() method so that method isn't overridden. If you were able to access bark() from parent class without declaring either abstract method or defining it, then that would be violation of the Polymorphism principle.
If you really want to access it that way, then you can either define a abstract public void bark(); in your parent or access that method by typecasting like this
((Dog) b).bark();
This will not compile since Animal does not have a method called bark.
Think of it this way, all dogs are animals, but not all animals are dogs. All dogs bark, but not all animals bark.
This code is wrong, as the line b.bark(); will give you a compiler error, because b is only defined as an Animal, which cannot bark().
If you change Animal b = new Dog(); to Dog d = new Dog(); it will work properly.
You've got inheritance mixed up. Dog can do what Animal can do, not vice versa.
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
#Override public void move() {
System.out.println("Dogs can walk and run");
}
public void bark() {
System.out.println("Dogs can bark");
}
public void moveSuper() {
super.move();
}
}
public class TestDog {
public static void main(final String args[]) {
final Animal a = new Animal(); // Animal reference and object
a.move(); // runs the method in Animal class
final Dog d = new Dog(); // Animal reference but Dog object
d.move(); // runs the method in Dog class
d.bark();
d.moveSuper();
}
}
I have this interface:
public interface Animal {
void Eat(String name);
}
And this code here implements the interface:
public class Dog implements Animal {
public void Eat(String food_name) {
System.out.printf(food_name);
}
public static void main(String args[]) {
Animal baby2 = new Dog(); // <- this line
baby2.Eat("Meat");
}
}
My question is, why does the code work? An interface cannot be instantiated. Yet in this case, interface was instantiated (marked with the comment).
What is happening here?
No it is not - you are instantiating a Dog, but since a Dog is an Animal, you can declare the variable to be an Animal. If you try to instantiate the interface Animal it would be:
Animal baby2 = new Animal();
Try that, and watch the compiler scream in horror :)
Dog is not an interface: Dog is a class that implements the Animal interface.
There's nothing untoward going on here.
Note that you can instantiate an anonymous implementation of an interface, like so:
Animal animal = new Animal() {
public void Eat(String food_name) {
System.out.printf("Someone ate " + food_name);
}
};
Let's consider below code:
interface Cookable {
public void cook();
}
class Food {
Cookable c = new Cookable() {
public void cook() {
System.out.println("anonymous cookable implementer");
}
};
}
The preceding code creates an instance of an anonymous inner class, but here, the new just-in-time class is an implementer of the Cookable interface. And note that this is the only time you will ever see the syntax:
new Cookable()
where Cookable is an interface rather than a nonabstract class type. Think about it:
You can't instantiate an interface, yet that's what the code looks like it's doing. But, of course, it's not instantiating a Cookable object-- it's creating an instance of a new anonymous implementer of Cookable.
You can read this line:
Cookable c = new Cookable(){}
as "Declare a reference variable of type Cookable that, obviously, will refer to an object from a class
that implements the Cookable interface. But, oh yes, we don't yet have
a class that implements Cookable, so we're going to make one right
here, right now. We don't need a name for the class, but it will be a
class that implements Cookable, and this curly brace starts the
definition of the new implementing class."
Important to remember for anonymous interface implementers-- they can implement only one interface. There simply isn't any mechanism to say that your anonymous inner class is going to implement multiple interfaces. In fact, an anonymous inner class can't even extend a class and implement an interface at the same time. The innve class has to choose either to be a subclass of a named class and not directly implement any interface at all or to implement a single interface.
So don't be fooled by any attempts to instantiate an interface except in the case of an anonymous inner class. The following is not legal:
Runnable r = new Runnable(); // can't instantiate interface
whereas the following is legal, because it's instantiating an implementer of the Runnable interface(an anonymous implementation class):
Runnable r = new Runnable() {
public void run(){ }
};
You can read my article here.
What you're observing here is the Dependency inversion aspect of SOLID.
Your code is depending on the abstraction of the Animal contract by instantiating a concrete implementation of it. You're merely stating, "I'm instantating some object, but regardless of what that object actually is, it will be bound to the contract of the Animal interface."
Take, for instance, these sorts of declarations:
List<String> wordList = new LinkedList<>();
Map<Integer, String> mapping = new HashMap<>();
In both of those cases, the primary aspect of the list and map is that they follow the generic contract for a List and Map.
Animal baby2 = new Dog(); //HERE!!!!!!!!!!!!!!!!!!!!!!
Surely you are not instantiating the Animal. You are only referring the Dog instance to it.
In java we can take the super class reference.
This is a case of polymorphism, It looks like you are creating 'Animal' object but it is not. You are creating 'Dog' object which is calculated on run time.'Animal' acts as contract. Interface can not be instantiated directly but can be used as type by upcasting its subclass. You can also use anonymous class to instantiate an object as 'Animal' type.
Animal baby2 = new Dog(); //upcasting polymorphically
Animal baby3=new Animal(){
public void Eat(String food){System.out.println("fdkfdfk"); }
}
//You can instantiate directly as anonymous class by implementing all the method of interface
The interface Animal is not be intantiated but be implemented by Dog.And a Dog is intantiated
When you say:
Animal baby2 = new Dog();
the reference type is Animal(the interface) which points to a concrete implementations (Dog). The object type Dog is concrete and can be instantiated. In this case, as long as Dog hasanimal point to Dog. a concrete implementation of all the methods in the interface, you can make a reference type of
If you did something like,
Animal baby2 = new Animal(); // here you are actually instantiating
this would be invalid because now you are trying to create a concrete object from an abstract implementation.
The Interface Animal acts as the data type to the class Dog. You're actually instantiating the Dog class not the interface or it's data type.
To have a wider picture :
Animal [] Zoo = new Animal[10] ; // is also correct
but why ?
The whole idea is that in the table above you can put 10 animals of different types. The only conditions for this is that all the animals entering the Zoo must implement the interface Animal .
public interface Animal {
void Eat();
}
class Wolf implements Animal { void Eat (){
System.out.println("Wolf eats meat ") ;}}
Class Zebra implements Animal{ void Eat (){
System.out.println("Zebra eats the grass ") ;}}
class test {
public static void main (String args []) {
Animal [] Zoo = new Animal[2] ;
Zoo[0] = new Wolf() ;
Zoo[1] = new Zebra() ;
//so you can feed your animals in Zoo like this
for (int i=0 ; i<Zoo.lenght;i++) {Zoo[i].Eat();}
}
}
You can't instantiate an interface. The functionality can be considered similar to that of an abstract class. You can have a reference to the interface but you don't create an object of interface. If you do something like this....
Animal a = new Animal();
The compiler will show an error- "Cannnot instantiate the type Animal".
Actually you can instantiate the interface. Here is the code you can try
public static void main(String args[]) {
System.out.println(new Animal() {
public String toString() {
return "test";
}
});
}
This program runs successfully and prints test
Try it.
Here it is just referencing to the interface but instantiation is done by the class only.
for e.g
Animanl a = new Dog
Animal a - variable is referenced
new Dog - now Memory is allocated
Java 8 let you use, the functional interface,
#FunctionalInterface // this is not mandatory
interface A{
void m1(); // only one abstract method allowed for functional interface
}
class Main{
public static void main(String a[]){
// old usage
A a1 = new A(){
#Override
public void m1(){
System.out.println("Call Me normally");
}
};
a1.m1();
// new in java 8, functional interface
A a2 = ()-> System.out.println("Call Me as functional interface");
a2.m1();
}
}
What have you done is type casting. You have created an instance of class dog and has type caste it to interface animal.It is an example of runtime polymorphosim. But yes an interface can be implemented and I have reached here while searching for this.
i.e.
public class demo16{
interface cardio{
void run();
}
static void foo(){
cardio c = new cardio(){ //HENCE instance of "interface cardio" is being created inside a method foo
public void run(){
System.out.println("How you doing ! ");
}; //HENCE observe the ";" beside }
}; //HENCE observe the ";" beside }
c.run();
}
public static void main(String [] args){
foo();
}
}
While coding, I got an interesting doubt about polymorphism and I couldn't understand a solution for this.
public class Animal {
public void getLegs() {
SOP("4 legs");
}
}
public class Kangaroo extends Animal {
public void getLegs() {
SOP("2 legs");
}
public static void main(String[] args) {
Animal a = new Kangaroo(); // without changing this how can I get Animal getLegs
SOP(a.getLegs()); // Important Line
}
}
Now If I want to call the getLegs method of Animal, how do I? Is it possible? Is it still polymorphism?
Yes, it is the most basic form of demonstrating polymorphisim.
Basically you are dealing with an Animal named a. When you call a.getLegs() your code doesn't bind to the implementation of getLegs() in Animal, rather it binds to the lowest sub-class implementation, getLegs() in Kangraoo().
If the Animal has an implementation, it is said to be hidden by the subclass implementation. If Animal has no implementation, then it is not possible to construct stand-alone classes of Animal as they lack implementations for all of the required methods, and under such a circumstance, Animal is said to be an abstract class (one that cannot be constructed directly, but only can be constructed by it's sub classes).
If you really want to call your method for Animal, and you can employ a static method, you can use hiding instead of overriding.
It works as follows: for static methods only, the called method is the one related to the declared type, not the object instance. In other words, it follows the class because the method is a class method, not an instance method.
An example, adapted from this page:
public class Animal {
public static void testClassMethod() {
System.out.println("The class" + " method in Animal.");
}
public void testInstanceMethod() {
System.out.println("The instance " + " method in Animal.");
}
}
public class Kangaroo extends Animal {
public static void testClassMethod() {
System.out.println("The class method" + " in Kangaroo.");
}
public void testInstanceMethod() {
System.out.println("The instance method" + " in Kangaroo.");
}
public static void main(String[] args) {
Kangaroo myRoo = new Kangaroo();
Animal myAnimal = myRoo;
myRoo.testInstanceMethod();
myAnimal.testInstanceMethod();
Kangaroo.testClassMethod();
Animal.testClassMethod();
}
}
The result will be (pay attention to the 3rd and 4th lines, as opposed to the 1st and 2nd):
The instance method in Kangaroo.
The instance method in Kangaroo.
The class method in Kangaroo.
The class method in Animal.
In Java it's not possible to access Animal's implementation. It will always return Kangaroo's version.
(Note in C# it is possible by tagging the overriding method with "new", but it's a fairly specialised use case).
Accessing what appears to be an Animal but getting the behaviour specified by Kangaroo is exactly what polymorphism is - the ability for a child object to be substituted wherever its parent is expected.
In general you wouldn't want to have the calling code know about the inheritance hierarchy because this would tightly couple your code together. If you genuinely need to access Animal's implementation of this method it suggests your design is probably wrong.
The spirit of Polymorphism is to execute different code decided at runtime. To make it more clear, I'll modify your code a bit.
public class Animal {
public void getLegs(){
SOP('4 legs');
}
}
public class Kangaroo extends Animal{
public void getLegs(){
SOP('2 legs');
}
public static void main(String[] args){
Animal a = new Kangaroo(); //without changing this how can I get Animal getLegs
Kangaroo kng= new Kangaroo ();
Animal an = new Animal();
SOP(a.getLegs()); // Kangaroo's version is called
SOP(kng.getLegs()); //Again, Kangaroo's version is called
SOP(an.getLegs()); //Animal version is called
}
}
and Yes, as all say you can't call Animal from your line Animal a = new Kangaroo();..as none will want to do it. Rather he will directly write. Animal a = new Animal();..
So finally it is the object not referance which decides which method will be called
Now If I want to call the getLegs method of Animal, how do I? Is it possible?
If you want to access the overridden method - which contradicts polymorphism - you can use reflection. Get the getLegs method from Animal's class, and then invoke it on your Kangaroo object. However, this is a hack, and not something you'd do in a regular program.
SOP( Animal.class.getMethod("getLegs").invoke(a) );