code like this
public class LambdaTest {
public static void main(String[] args) {
final Animal animal = Dog::new;
animal.eat();
}
}
#FunctionalInterface
interface Animal {
void eat();
}
class Dog implements Animal {
public Dog() {
System.out.println("dog init.");
}
#Override
public void eat() {
System.out.println("dog eat");
}
When I ran this code, "dog init." was printed to the console, but "dog eat" was not. Why is that? Can someone tell me the reason?
I expected "dog init" and "dog eat" to be printed, but only "dog init" was printed. Additionally, I'm puzzled as to why there was no error when Animal animal = Dog::new;.
Animal is a functional interface with a single method void eat() (void return, no parameters) – also known as SAM type (single abstract method).
It is structurally identical to the java.util.Runnable interface (interface Runnable { void run(); }). Your code could as well be written as:
final Runnable runnable = Dog::new;
runnable.run(); // calls the constructor
You can assign it any lambda or method reference with zero arguments and no return value, e.g. () -> {}.
Dog::new is a method reference and equivalent to the lambda () -> { new Dog(); }. If you look closely, you will notice that this lambda does not return anything. It constructs a new Dog instance and then forgets about it again.
Assigning a method reference or a lambda to a variable does not execute it (yet). You have to explicitly invoke the lambda by calling the named method from your interface.
Now, your animal is an instance of your Animal interface and got assigned a method reference which can then be invoked later. animal.eat() invokes the assigned method reference, calling the constructor.
If you want your variable animal to hold a Dog instance and then invoke the eat method on it, call the constructor directly: Animal animal = new Dog();
The "problem" is the signature of your eat method, because it is equivalent to Runnable#run and allows assigning any "empty" action.
Lambdas and method references were introduced with Java 8. In Java versions before, you had to create an anonymous class to achieve the same behavior:
final Animal animal = new Animal() {
#Override public void eat() {
new Dog();
}
};
animal.eat(); // calls "eat" of the anonymous instance, which in turn calls the constructor; does NOT call `Dog#eat`
Animal is an interface with a single abstract method, eat. This method does not take any parameters and does not return anything. Because of this, it can represent any function that takes no parameters. For example:
Animal foo = () -> System.out.println("foo");
Now if I call foo.eat(), it will run the code in the lambda, which prints "foo".
I can also use a method reference instead of a lambda:
Animal foo = SomeClass::someStaticMethod;
Now foo.eat() will run the parameterless method called someStaticMethod located in SomeClass.
Notice that this works in exactly the same way as using the built-in Runnable interface and called its run method. Yours is just called Animal and eat, rather than Runnable and run.
So by the same logic, using a constructor reference of Dog will invoke the constructor of Dog.
Animal foo = Dog::new;
Runnable bar = Dog::new;
// these two lines do the same thing:
foo.eat();
bar.run();
Would you still have the confusion if you have written the code with Runnable instead?
Note that the fact that Dog implements Animal does not matter here. Dog implements Animal just means that you can do:
Animal animal = new Dog();
which has a completely different meaning. If at this point I do animal.eat(), then it will output what you expect - "dog eat".
Alternatively, you could also make a method reference to a newly-created Dog's eat method for it to output "dog eat":
Animal animal = new Dog()::eat;
Related
This question already has an answer here:
Overloading method invoke issue
(1 answer)
Closed 1 year ago.
class Animal{
void eat(Animal animal){
System.out.println("animal eats animal");
}
}
public class Dog extends Animal{
void eat(Dog dog){
System.out.println("dog eats dog");
}
public static void main(String[] args) {
Animal a = new Dog();
Dog b = new Dog();
a.eat(b);
b.eat(b);
}
}
In the above code, the output will be
animal eats animal
dog eats dog
Why this happened?
Probably you expect to see twice "dog eats dog". This does not happen because the two methods have a different signature. Therefore, Dog#eat(Dog) does not override Animal#eat(Animal) but provides a more specific eat method instead.
If you add #Override to void eat(Dog dog) there will be an error. Using this annotation is good practice because it denotes that the annotated method should override a method declaration in a supertype. If the method does not do that (as in your example) you get the following error to make you aware if it:
Method does not override method from its superclass
If you want to override the eat method in Dog, you need to provide the same signature:
#Override
void eat(Animal animal) { // instead of eat(Dog dog)
System.out.println("dog eats dog");
}
It is simply because Java does not support contravariant parameters. On the other hand, it supports covariant return types.
Due to the support for covariant return types, a subclass override can have a more specific return type in the hierarchy while overriding the base class method, like the code below is valid:
class Animal {
protected Animal getAnimal() {
System.out.println("Animal");
return this;
}
}
class Dog extends Animal {
#Override
protected Dog getAnimal() {
System.out.println("Dog");
return this;
}
}
In the above example, you can observe that Dog.getAnimal() returns a more specific Dog instead of the base Animal but it is still considered an override because Java supports covariant return types.
On the other hand, if you do that with parameters:
class Animal {
protected void petAnimal(Animal animal) {
System.out.println("Petting Animal");
}
}
class Dog extends Animal {
#Override
protected void petAnimal(Dog dog) {
System.out.println("Petting Dog");
}
}
This is not an override but an overload.
Hence both the petAnimal() methods (one with Animal as parameter and another with Dog as parameter) are treated as two different methods. Remember, parameters are part of the method signature whereas return types are not.
The second example does not even work as the #Override annotation finds out that the method is not an override. Whenever you want to ensure that you override, use the #Override annotation, it will let you know if you are not overriding the method. #Override can also be used when implementing interfaces.
It's based on the concept of Inheritance and Polymorphism
Overriding happens when the sub-class has the same signature methods as that of the superclass. In your code, in the below subclass *method, the parameter being passed is a Dog type object and in the superclass i.e Animal, the parameter passed is an Animal type object.
void eat(Dog dog){
System.out.println("dog eats dog");
}
So you can change the above method as below to see the overriding effect: -
void eat(Animal dog){
System.out.println("dog eats dog");
}
As suggested by #Mat, it's best to use #Override annotation because it will help the java compiler to find the issue at the compile time itself.
Below I'm trying to explain the concept of how inheritance and polymorphism are working once you change the signature of the eat method in Dog class: -
Inheritance is a way to base one class on another class, like a template built from an existing template. You could create a class called 'Dog' that acts as a template for all Dog objects. We could then create another class called 'Animal' that is a parent class of our 'Dog' class. All Dogs are animals, but not all animals are dogs. Our Animal class could define functionality for all Animals and then the Dog class could take all this functionality, without re-writing it, by extending/inheriting from the Animal class. The Dog class could then add more functionality, more variables, and methods, that are specific only to Dog objects.
The Dog class extends the Animal class, this is inheritance. The Dog class is overwriting the Animal class eat method.
When we say Animal a = new Dog();, we declare a variable a that is declared as an Animal type, but it initialized as a Dog object. This is polymorphism. Because the Dog extends from the Animal class, we can treat it as an Animal, and declare it as an Animal variable type. We cannot do the reverse, because the Animal class does not extend from the Dog class (not all Animals are dogs)
This is because the a variable is being treated as an Animal data type. This is why you will be able to access all the Animal class methods but the methods with the same signature as Dog will be overridden by the implementation from the Dog class. Remember, the left side of the equals '=' symbol is the declaration and the right side is the initialization.
Also, that's why when you declare Dog b = new Dog(); and call the eat() method it calls the implementation from the Class Dog and not Animal as it's explicitly mentioned as object type Dog
class Animal{
void eat(Animal animal){
System.out.println("animal eats animal");
}
}
public class Dog extends Animal{
void eat(Dog dog){
System.out.println("dog eats dog");
}
public static void main(String[] args) {
Animal a = new Dog(); //We use this when we don't know the exact runtime type of an object
//Parent can hold any child but only parent specific methods will be called.
Dog b = new Dog();
a.eat(b); //Parent method will be called i.e Animal.eat(...)
b.eat(b); //Dog Class method will be called i.e Dog.eat(...)
}
}
First of all, the eat() not being overridden in the child class Dog
Usually, method overloading doesn't necessarily need inheritance and can be achieved within the same class. However, in this code the eat() method is overloaded by child class Dog.
Overloaded methods are differentiated by the number and the type of the arguments passed into the method.
So, at compile time it always picks the most specific class implementation based on its type.
I am working with an API in my company where I would like to create a subclass for an existing object. Here are the caveats:
I cannot modify the superclass
I cannot modify how the superclass object is instantiated
The example I see most commonly is a Dog as a subclass of Animal, so I will use that. Let's say you have this class in the API:
//API class, which I cannot modify
public class Animal(){
public void eat(){
//All animals can do this
}
}
Now I would like to create a class like this, which adds a few methods to Animal.
//My subclass, which I can modify
public class Dog extends Animal(){
public void fetch(){
//Only dogs can do this
}
}
So now let's say I have an instance of Animal (one that is not a Dog). I essentially need to downcast it into a Dog. I get that downcasting is not directly supported in Java, but is there any workaround for this?
public class AnimalExample{
public static void main(String[] args){
Animal animal = MyApi.getAnAnimal();
//Dog dog = (Dog) animal; ---throws a runtime error
Dog dog = Dog.getDog(animal); //Maybe something like this?
//Then I should be able to call both eat() and fetch()
dog.eat();
dog.fetch();
}
}
Again, I understand that downcasting is not directly supported. But there has to be some workaround for this, and I can't figure it out. I know that I could use a wrapper class (eg DogWrapper), but that would be a little more difficult than I'd like because I still frequently call the dozens of superclass methods.
UPDATE: I understand that it's not yet a Dog, but I was wondering if there was a way to convert it into a Dog. It basically sounds like, from what people are saying, that I either have to convert it manually (copy each attribute/method over one-by-one) or just use a Wrapper class. A Wrapper class seems a lot less messy, so unfortunately I'll just have to go that route. So DogWrapper will have a fetch() method and a getAnimal() method. So if I want the Dog to eat, then I have to call dog.getAnimal().eat(). I was avoiding having to do that, but I guess there's no way around it. Does anyone see anything simpler than that?
You can have a constructor which takes Animal and instantiates the Dog part of the object with defaults or as required.
public Dog (Animal animal) {
super(); // any instantiation that has to be done for animal
// Dog instantiation
// Use animal properties as required
}
Dog dog = new Dog(animal);
Also having a static method as you mentioned Dog.getDog(animal) is an option, depends on your coding preference.
Let's suppose I create a method that requires a Dog, but is meant to extend the Animal API. Sure, I could just make the signature like so:
public void doFetch(Dog dog)
But as I said, I want to extend the Animal API. Now, if the given Animal is not a Dog, I can't fetch. With that in mind, I can do the following:
public void doFetch(Animal fetcher) {
if(fetcher instanceof Dog) {
Dog dog = (Dog) fetcher;
... //Do fetchy things
return;
}
//If we reach this point, then the animal is not a dog
throw new IllegalArgumentException("fetcher is not a Dog!");
}
Now let's suppose, as in your case, I have an Animal that is not a dog, but I want it to be a Dog for some reason. In this case, I could convert any Animal into a dog using some kind of translator. I prefer to define things like this as static methods in the Dog class itself:
//Breaks the laws of nature by making a Dog from any Animal.
public static Dog fromAnimal(Animal animal) {
Dog dog = new Dog();
//Here you would set all the properties of the animal, e.g.:
dog.setName(animal.getName());
...
return dog;
}
I have a Dog class described as:
class Dog {
//data members
void bark() {
//Bark Algorithm
}
}
Now in another class which has the main method and in the main method, if I do the following:
Object dog = new Dog();
dog.bark();
Shouldn't it work as the "dog" reference is holding a Dog instance? Why is this not valid?
The language used here is Java.
Thanks for the help in advance.
Java is very strongly typed. Java compiler performs a method check at compile time, not at runtime. dog is declared as Object, so compiler checks if Object class has a method named bark(). It doesn't, so it throws a compiler error. This is how Java is designed.
Note that this is not a limitation of polymorphism per se, but a limitation of the implementation of polymorphism in Java. This exact same code would perfectly compile (and work) in a more dynamically typed language like Groovy, which also runs on the JVM.
The class Object does not have a method called bark. Therefore, your code would not compile.
However, this does not mean that the compiler decides what method to call purely based on the reference type. Your reference type decides what methods you CAN call, while the instance type will decide what you method you WILL call. This is the essential mechanism for polymorphism.
For example,
class Animal
{
void makeSound()
{
//Generic animal sound algorithm
}
}
class Dog extends Animal{
void makeSound()
{
//Bark Algorithm
}
}
Then
Animal dog = new Dog();
Animal animal = new Animal();
dog.makeSound(); //calls bark
animal.makeSound(); //generic animal sound
I think I got the solution here. The compiler decides which function to call based on the reference type and not on the instance type that reference holds.
Like in this case, just like the Dog class, many other animals can also can be instantiated and Object references can be used to refer to their objects on the heap, but not all can bark(). Hence the compiler decides that the function call should be based on the reference type, rather than the instance type.
If you're sure about type of dog you can always do typecasting
Object dog = new Dog();
((Dog)dog).bark();
Safe version:
Object dog = new Dog();
if (dog instanceof Dog)
((Dog)dog).bark();
UPD
Polymorphism example:
interface Animal {
}
interface Barkable extends Animal {
void bark();
}
class Dog implements Barkable {
#Override
public void bark() {
System.out.println("woof-woof");
}
}
class Cat implements Barkable {
#Override
public void bark() {
System.out.println("meow");
}
}
class SilentCreature implements Animal {
}
....
Animal animal = new Dog();
animal.bark();
animal = new Cat();
animal.bark();
animal = new SilentCreature();
// new SilentCreature() returns new animal, but not Barkable
animal.bark(); // as Animal doesn't have method bark() this code won't compile
I have some question about upcast/downcast.
I created an abstract super class Animal, subclass Dog and subclass BigDog. and I also give abstract method in Animal, and override it in Dog and BigDog.
abstract public class Animal {
abstract public void greeting();
}
public class Dog extends Animal {
#Override
public void greeting() {
System.out.println("Woof!");
}
}
public class BigDog extends Dog {
#Override
public void greeting() {
System.out.println("Woow!");
}
}
now my test code:
public class TestAnimal {
public static void main(String[] args) {
Animal animal2 = new Dog();
Animal animal3 = new BigDog();
// Downcast
Dog dog2 = (Dog) animal2; //cast Animal class to Dog class, legit
BigDog bigDog2 = (BigDog) animal3; //cast Animal to BigDog, legit;
Dog dog3 = (Dog) animal3; //Animal Class contains BigDog cast into Dog?
dog2.greeting();
dog3.greeting(); //in which class the method is called?
}
}
I understand the relationship between superclass/subclass and how cast works. My question is, however, can you cast a superclass into a specific subclass, knowing there's a class in between? for example, if I have an Animal class object contains a BigDog object, can I cast the object to Dog? what if there are methods in BigDog that do not exist in Dog?
in short, you can certainly say a superclass object is a subclass object, but why can you invert?
On second thought,
I'm guessing this: I'm asking JVM cast an Animal class reference to Dog and link the new Dog reference to the BigDog object, rather than really casting the BigDog object.
So I can invoke all Dog and Animal methods on that Dog reference (to BigDog), but none of the BigDog methods, unless it was overridden in BigDog.
What Java checks when invoking a method is: if the reference (DOG) has the reference, and if the object(BigDog) has an override. if not, Dog method is called, otherwise, BigDog method is called.
Can anyone confirm my guess?
You can always cast to a specific subclass, unless the compiler is smart enough to know for certain that your cast is impossible.
The best way to cast to a subclass is to check if it can be done:
if ( doggy instanceof BigDog ) {
doSomethingWithBigdog( (BigDog) doggy );
} else if ( doggy instanceof SmallDog ) {
doSomethingWithSmalldog( (SmallDog) doggy );
} else {
// Neither a big dog nor a small dog
}
...
private void doSomethingWithBigdog( BigDog dog ) {
...
}
private void doSomethingWithSmalldog( SmallDog dog ) {
...
}
Keep in mind that casting is evil. Sometimes necessary, but often (not always) it can be designed away by implementing methods on the base class, or by not assigning a Dog to an Animal variable but to keep it a Dog.
If I have an Animal class object contains a BigDog object, can I cast the object to Dog? what if there are methods in BigDog that do not exist in Dog?.
Simply you will get compiler error.Since you can't call a method that is not declared in parent and declared in child class using parent reference
There is no method whose signature will match with these method calls :
dog2.greeting(dog3);
dog3.greeting(dog2);
so, Its pretty much a compilation failure.
You need to know about Dynamic Method Dispatch.
here are few links 1,2,3 go through them.
First correct the source code, so it will compile. The proper usage of the methods: dog2.greeting(); and dog3.greeting(); or add method public void greeting(Animal animal);.
dog3.greeting(); - invoking method greeting() for dog3. dog3 has the same reference as animal3. animal3 has reference of BigDog so method greeting() is invoked to the class BigDog and the output is Woow!
When you inherit Dog from class Animal, then class Dog have all methods from class Animal.
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();
}
}