Polymorphic arguments work with superclass but not with subclass [duplicate] - java

This question already has answers here:
What does a "Cannot find symbol" or "Cannot resolve symbol" error mean?
(18 answers)
Closed 5 years ago.
I am only learning about polymorphism so be easy on me (literally copying from the book). I try to pass a class as an argument to a method. When I do that I can call the superclass methods, but not the actual subclass. Using the start() method, I try to make the wolf howl:
public class experiment {
public static void main(String[] args) {
PetOwner own = new PetOwner();
own.start();
}
}
//Trying polymorphic arguments
class Vet {
public void giveShot(Animal a) {
a.howl();
}
}
class PetOwner {
public void start() {
Vet v = new Vet();
Wolf w = new Wolf();
v.giveShot(w);
}
}
//Inheritance//
//Kingdom - Animal
class Animal {
public void move() {
System.out.println("*motions softly*");
}
}
//Family - canine
class Canine extends Animal {
public void bark() {
System.out.println("Woof!");
}
}
//Species - wolf
class Wolf extends Canine {
public void howl() {
System.out.println("Howl! Howl!");
}
}
If I pass the howl method to the superclass (Animal) it works fine. If I call it directly from the Wolf class - it works fine. The only instance where it doesn't work is if I try to pass the wolf class as an argument and call it from there.
Here is why I try it that way, quoted from Head First Java pg 187:
The Vet's giveShot() method can take any Animal you give it. As long
as the object you in as the argument is a subclass of Animal, it
will work
I am getting a "cannot find symbol symbol: method howl(), Location variable of type animal" error.

You're calling a.howl() while a is an instance of Animal class. Animal does not know how to howl. The only Wolf does.
You can defin a method say react() and then override it for any particular subclass of Animal;

You are calling the howl-Method inside the giveShot-Method. Animal doesn't have a howl method.
EDIT: If you cast animal to wolf inside the giveShot-Method it should work.

Yes, you could do something like:
class Vet {
public void giveShot(Animal a) {
a.makeNoise();
}
}
class Animal {
public void move() {
System.out.println("*motions softly*");
}
public void makeNoise() {
}
}
//Family - canine
class Canine extends Animal {
#Override
public void makeNoise() {
System.out.println("Woof!");
}
}
//Species - wolf
class Wolf extends Canine {
#Override
public void makeNoise() {
System.out.println("Howl! Howl!");
}
}

Related

Overriding an anonymous class's methods in Java

In below example (in the commented block) I'm trying to override jump() method of an anonymous class, however getting compilation error. Can someone help me understand what's wrong here?
class Animal {
public void bark() {
System.out.println("Inside bark");
}
public void jump() {
System.out.println("Inside jump");
}
}
public class AnonymousClassExample001 {
public static void main(String[] args) {
Animal animal = new Animal() {
public void bark() {
System.out.println("Subclass bark");
}
}; /* {
public void jump() {
System.out.println("Subclass jump");
}
};*/
/**
* Question is: Why can't we override by extending an anonymous class
* as attempted (and commented) above?
* */
animal.bark(); // Subclass bark
animal.jump(); // Trying to print "Subclass jump", by overriding (the subclass of Animal) above
}
}
Edit:
Here's the compilation error I'm getting in IDE - ';' expected.
And from the comments, it seems some folks are not getting my question. With the above example, I wanted to understand whether we can override an anonymous class's methods or not?.
Again, the main motive is to see (and understand) why Java compiler allowed to create an anonymous class by starting a {} block followed by new Animal(), and didn't allow the same behaviour further (chaining of {} blocks to allow creation of further subclasses)
Don't end and restart the block, override both methods in one block, same as you would in a regular subclass:
class AnonymousClassExample001 {
public static void main(String[] args) {
Animal animal = new Animal() {
#Override
public void bark() {
System.out.println("Subclass bark");
}
#Override
public void jump() {
System.out.println("Subclass jump");
}
};
animal.bark(); // Subclass bark
animal.jump(); // Subclass jump
}
}
UPDATE
Updates to the question says you're trying to subclass an anonymous class, e.g. you're trying to do this:
class AnonymousClassExample001 {
public static void main(String[] args) {
Animal barkingAnimal = new Animal() {
#Override
public void bark() {
System.out.println("Subclass bark");
}
};
Animal jumpingAnimal = <subclass barkingAnimal> { // Can't be done
#Override
public void jump() {
System.out.println("Subclass jump");
}
};
barkingAnimal.bark(); // Subclass bark
barkingAnimal.jump(); // Inside jump
jumpingAnimal.bark(); // Subclass bark
jumpingAnimal.jump(); // Subclass jump
}
}
You can't do that, because the unnamed anonymous class cannot be identified as the base class. You can however do it using local classes, which are like named anonymous classes, as contradictory as that sounds:
class AnonymousClassExample001 {
public static void main(String[] args) {
class BarkingAnimal extends Animal {
#Override
public void bark() {
System.out.println("Subclass bark");
}
};
class JumpingAnimal extends BarkingAnimal {
#Override
public void jump() {
System.out.println("Subclass jump");
}
};
Animal barkingAnimal = new BarkingAnimal();
Animal jumpingAnimal = new JumpingAnimal();
barkingAnimal.bark(); // Subclass bark
barkingAnimal.jump(); // Inside jump
jumpingAnimal.bark(); // Subclass bark
jumpingAnimal.jump(); // Subclass jump
}
}
Alternatively, jumpingAnimal could also be done using anonymous class syntax, instead of local class syntax.
I think it should be like this
public class AnonymousClassExample001 {
public static void main(String[] args) {
Animal animal = new Animal() {
public void bark() {
System.out.println("Subclass bark");
}
public void jump() {
System.out.println("Subclass jump");
}
};
/**
* Question is: Why can't we override by extending an anonymous class
* as attempted (and commented) above?
* */
animal.bark(); // Subclass bark
animal.jump(); // Trying to print "Subclass jump", by overriding (the subclass of Animal) above
}
}

Can private methods be hidden? [duplicate]

This question already has answers here:
Can a private method in super class be overridden in the sub-class?
(12 answers)
Closed 2 years ago.
I've read several conflicting sources online about whether or not private methods can be overridden.
What exactly is going on in this example then? Is method move being hidden?
class Animal {
private void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Dog b = new Dog(); // Dog reference and Dog object
b.move(); // runs the method in Dog class
}
}
https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html says that it's not technically overriding, so what is this called and will there be any unexpected behaviours?
You have to write your Test like this..
public class TestDog {
public static void main(String args[]) {
Animal b = new Dog(); // Animal reference but Dog object
b.move(); // runs the method in Dog class
}
}
Then, you get:
/TestDog.java:16: error: move() has private access in Animal
b.move(); // runs the method in Dog class
^
1 error
Your test case simply calls the move() in the Dog and it isn't overriden.
What you have done is not overriding. If you want to confirm this, just put #Override before public void move() in the class Dog and you will see compilation error.
Note: A private method is always hidden inside a class. There is no way to make it accessible outside the class.

Why do we use abstract classes or methods why not just override the super class method? [duplicate]

This question already has answers here:
Abstract class in Java
(15 answers)
Closed 6 years ago.
abstract class A
{
abstract void callme();
}
class B extends A
{
void callme()
{
System.out.println("this is callme.");
}
public static void main(String[] args)
{
B b=new B();
b.callme();
}
}
// if this can be done through overriding why use abstraction
class Animal
{
Animal myType()
{
return new Animal();
}
}
class Dog extends Animal
{
Dog myType() //Legal override after Java5 onward
{
return new Dog();
}
}
abstract class mainly used to bound the subclass to give the body of its abstract method.
where as in non abstract class you are not bounding the subclass to give the body of its methods.
in class B its mandatory to give the body of callme();
where as
in class Dog its not mandatory to give the body of myType();

Is it possible to extend Methods in Java?

I know it is possible to do this in Java:
public class animal {...}
And then
public class dog extends animal {...}
Then you can write whatever dog methods that can access animal method.
However, I am wondering is there a way to extend methods
for example
public void generateAnimal() {...}
and then
public void generateDog() extends generateAnimal() {...}
But this is not passing the compiler.
So my question is:
Is it possible to inherit methods in Java?
You cannot extend a method the way you are describing but you can inherit the method and then call the method from the superclass as follows:
#Override
public void inheritedMethod() {
super.inheritedMethod(); // This will call method from super class
// Do subclass specific work here
}
A method is not an object by itself. Methods are meant to be called.
Yes.
public class Animal {
public void someAction() {
System.out.println("from Animal class");
}
}
public class Dog extends Animal {
public void someAction() {
super.someAction();
System.out.println("from Dog class");
}
}
public class Main {
public static void main(String[] args){
Animal dog = new Dog();
dog.someAction();
}
}
Output:
from Dog class
from Animal class
So you extend functionality of method, but better to use composition instead of inheritance.
Yes.
It was done exactly as you showed there, without the extends generateAnimal() and by changing that method name to generateAnimal().
This is called Overriding. And allows you to utilize the annotation #Override.
public class A {
public void print(){
System.out.println("Hello from A!");
}
}
public class B extends A {
#Override // This method overrides A#print()
public void print(){
System.out.println("Hello from B!");
}
}
Then, calling some action like:
B b = new B();
b.print();
Will print out:
Hello from B!
This is more widely known as Inheritance
If they are in the same class, no. However, assuming you want to run all of generateAnimal() then add your generateDog() specific code you could do this:
public void generateDog(){
generateAnimal();
///do the rest of generateDog()
}
I hope that helps.

Regarding factory design pattern through reflection implemented in java [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Regarding factory design pattern through reflection
I was doing R&D on factory pattern I have developed the below code. Right now I know the subclasses are Dog and Cat, but please advise me. What to do if I want to achieve the same thing through reflection by passing the class name in main.java?
Animal
public abstract class Animal {
public abstract String makeSound();
}
Dog
public class Dog extends Animal {
#Override
public String makeSound() {
return "Woof";
}
}
Cat
public class Cat extends Animal {
#Override
public String makeSound() {
return "Meow";
}
}
AnimalFactory
public class AnimalFactory {
public Animal getAnimal(String type) {
if ("canine".equals(type)) {
return new Dog();
} else {
return new Cat();
}
}
}
Main
public class Main {
public static void main(String[] args) {
AnimalFactory animalFactory = new AnimalFactory();
Animal a1 = animalFactory.getAnimal("feline");
System.out.println("a1 sound: " + a1.makeSound());
Animal a2 = animalFactory.getAnimal("canine");
System.out.println("a2 sound: " + a2.makeSound());
}
}
Please advise it how I can add reflection functionality into it so that I don't need to even determine the type, just pass the class name in the main java and object of that subclass gets created.
If you pass the fullyqualified name of the class, you can instantiate them as following:
return (Animal) Class.forName(fullyQualifiedClassName).newInstance();
To avoid ClassCastException, you could test that the returned class of Class.forName() is indeed a subclass of Animal before invoking newInstance(). Use isAssignableFrom for that.
public Animal getAnimal(String clName) {
try {
return (Animal) Class.forName(clName).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

Categories

Resources