Superclass/Subclass methods [duplicate] - java

This question already has answers here:
why java polymorphism not work in my example
(3 answers)
Closed 6 years ago.
I have a situation
public class Animal
{
String noise;
public String makeNoise()
{
return noise;
}
}
Then there will be a subclass with the concrete definition of the noise.
public class Dog extends Animal{
String noise = "woof";
}
also
public class Cat extends Animal{
String noise = "meow";
}
What I want to do is
Animal cat = new Cat();
cat.makeNoise(); // This will be 'meow'
and
Animal dog = new Dog();
dog.makeNoise(); // This will be 'woof'
Basically, I don't want to repeat the makeNoise() method when I create an animal. However, this will not work. (Noise is an empty string)
I could use a static object like
static String NoiseDog = "woof"
static String NoiseCat = "meow"
but then again I have to write the makeNoise() method for each animal. Is there a better way to architect this?

If you want to force all sub-classes of Animal to have a noise defined, you can enforce that in the constructor:
public abstract class Animal {
private final String noise;
public Animal(final String noise) {
this.noise = noise;
}
public String makeNoise() {
return noise;
}
}
Then Dog:
public class Dog extends Animal {
public Dog() {
super("woof");
}
}
And Cat:
public class Cat extends Animal {
public Cat() {
super("meow");
}
}
And to test it out:
public class Test {
public static void main(String[] args) {
final Animal dog = new Dog();
System.out.println(dog.makeNoise());
final Animal cat = new Cat();
System.out.println(cat.makeNoise());
}
}
Output:
woof
meow

public class Cat extends Animal{
String noise = "meow";
}
This creates an instance variable named "noise" that hides the superclass variable.
Instead, you need this to set the superclass value:
public class Cat extends Animal{
public Cat() {
noise = "meow";
}
}

Make the Animal class abstract. This way, there can be no such thing as an Animal object which calls makeNoise.
Then, set the noise String to a value within the constructor of each subclass as appropriate to that animal's sound.

Alternatively, you could implement an interface like so:
Animal:
public interface Animal {
public String makeNoise();
}
Dog:
public class Dog implements Animal {
public String makeNoise() {
return "woof";
}
}
Cat:
public class Cat implements Animal {
public String makeNoise() {
return "meow";
}
}
Test:
public class Test {
public static void main(String[] args) {
Animal dog = new Dog();
System.out.println(dog.makeNoise());
Animal cat = new Cat();
System.out.println(cat.makeNoise());
}
}
Output:
woof
meow

Related

do i have to use instanof in this problem? or how should i code instead?

i wrote an example code for my question. i want to use polimorfism and i try to change a variable by the type of object. This code is working but is it the best way of that? Should i use a common method in both classes to return the variable? Thanks
package example;
import java.util.Scanner;
class Animal{}
class Dog extends Animal{}
class Bird extends Animal{}
public class Example {
public static void main(String[] args) {
Animal a;
int leg=0;
Scanner k=new Scanner(System.in);
String s=k.next();
if(s.equals("dog")) a=new Dog();
else a=new Bird();
if(a instanceof Dog) leg+=4;
else if(a instanceof Bird) leg+=2;
System.out.println(leg);
}
}
You should place common functionality into the parent class Animal and implement specific functionality into child classes Bird and Dog.
abstract class Animal {
abstract int legs();
}
class Bird extends Animal {
#Override
int legs() {
return 2;
}
}
class Dog extends Animal {
#Override
int legs() {
return 4;
}
}
There's no need for instanceof, just call the legs method of Animal and the implementing class will output the correct value.
public class Example {
public static void main(String[] args) {
Animal animal;
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
if(s.equals("dog")) {
animal = new Dog();
} else {
animal = new Bird();
}
System.out.println(animal.legs());
}
}
Put the common attributes and behaviors to the parent
abstract class Animal {
public abstract int getLegs();
}
class Bird extends Animal {
#Override
public int getLegs() {
return 2;
}
}
class Dog extends Animal {
#Override
public int getLegs() {
return 4;
}
}
, Add a method that creates an object based on parameter this is Factory Design pattern factory_pattern.htm
public static void main(String[] args) {
Animal animal;
Scanner scanner = new Scanner(System.in);
String animalType = scanner.next();
animal = getAnimal(animalType);
if (animal != null)
System.out.println(animal.getLegs());
scanner.close();
}
static Animal getAnimal(String type) {
if(type==null || "".equals(type)) return null;
Animal animal;
if ("dog".equalsIgnoreCase(type)) {
animal = new Dog();
} else if("bird".equalsIgnoreCase(type){
animal = new Bird();
}
return animal;
}
The number of legs the animal has should be contained within the subclass of Animal rather than set from the outside as you've currently got. Something like:
public abstract class Animal {
protected int numLegs;
public int getNumLegs() {
return numLegs;
}
}
public class Dog extends Animal {
public Dog() {
numLegs = 4;
}
}
Good luck!

Java. Get specific type using generics in enum

Here is some enum with get() method.
public class ZooTest {
public enum Animals {
CHLOE("cat"),
MOLLY("dog"),
LUNA("cat"),
TOBY("dog"),
ZOE("parrot"),
SNICKERS("cat");
private final String type;
Animals(String type) {
this.type = type;
}
public class Animal {
}
public class Cat extends Animal {
}
public class Dog extends Animal {
}
public class Parrot extends Animal {
}
public Animal get() {
return "cat".equals(type)
? new Cat()
: "dog".equals(type)
? new Dog()
: new Parrot();
}
}
#Test
public void shouldReturnSpecificClass() {
assertTrue(Animals.CHLOE.get() instanceof Cat);
}
#Test(expectedExceptions = {ClassCastException.class})
public void shouldReturnSpecificClass2() {
Dog dog = (Dog) Animals.CHLOE.get();
}
}
The question is how can it be improved to return specific type of animal without using type casting outside enum. Of course I can use methods like
public <T extends Animal> T get(Class<T> clazz) { return (T) get(); }
but maybe there is less clumsy way.
This answer is based on assumption that you don't actually need separate instances of Cat for CHLOE, LUNA, or SNICKERS. Also since your Animals didn't have any methods or state it doesn't look like you really need them as separate classes. So maybe something like this will be easier:
public enum AnimalType {
Cat, Dog, Parrot;
}
public enum Animals {
CHLOE(AnimalType.Cat),
MOLLY(AnimalType.Dog),
LUNA(AnimalType.Cat),
TOBY(AnimalType.Dog),
ZOE(AnimalType.Parrot),
SNICKERS(AnimalType.Cat);
private final AnimalType type;
Animals(AnimalType type) {
this.type = type;
}
public AnimalType get() {
return type;
}
}
You can create an abstract method get that and each instance of Animals has to implement:
public enum Animals {
CHLOE("cat") {
#Override
public Animal get() { return new Cat(); }
},
MOLLY("dog") {
#Override
public Animal get() { return new Dog(); }
}
//... and so on
public abstract Animal get();
}
You have two mistakes of enum using. The first enum entities must provided something like type not instance (how it pointed Quirliom), and then your Animal enum must contains members cat, dog etc. The second unfortunately you can not extend any class from enum.

In an ArrayList of Object, how can I convert Object into one of 3 instance of classes contained in an ArrayList?

I'm doing a simple Zoo application to understand oriented object concepts in Java.
My model is as follow:
1) A Zoo has a number of Cages
2) A Cage has a a mixture of Feline, Primate or Bird
3) An Animal can eat, sleep or drink
4) Feline extends Animal (Do extra Feline stuff)
5) Primate extends Animal (Do extra Primate stuff)
6) Bird extends Animal (Do extra Bird stuff)
The problem:
While it's pretty easy to handle x number of cages in a zoo (ArrayList of Cage), I'm struggling with the Animals in Cage.
I found out that I need to have an ArrayList of Object.
So far so good, but when I try to obtain my animal back and have him scratch a post, it's not a Feline anymore, it's an Object.
public class Cage{
private String name;
private ArrayList<Object> animals = new ArrayList<Object>();
public Cage(String name){
this.name = name;
}
public void addFeline(String name){
Feline newFeline= new Feline(name);
this.animals.add(newFeline);
}
public void addPrimate(String name){
Primate newPrimate= new Primate(name);
this.animals.add(newPrimate);
}
public void addBird(String name){
Bird newBird= new Bird(name);
this.animals.add(newBird);
}
public void removeAnimal(int index){
this.animals.remove(index);
}
public Object getAnimal(int index){
Object myAnimal = this.animals.get(index);
return myAnimal;
}
}
And the way I call it:
Zoo myZoo = new Zoo("My Zoo");
myZoo.addCage("Monkey Exhibit");
Cage myCage = myZoo.getCage(0);
myCage.addFeline("Leo");
Object MyAnimal = myCage.getAnimal(0);
The Question: How can I turn Object back into instance of class Feline so it can Scratch a Post?
I think the best way to approach this problem would be using the Strategy design pattern.
Feline, Primate and Bird should implement an interface Animal. The Cage would then have a method public void addAnimal(Animal animal);
The object creation for Feline, Primate and Bird should be outside of Cage.
I have put together some code if this can help. I would design the application similar to something below.
Behaviours should be encapsulated using interfaces. e.g. EatingBehaviour
public interface Animal {
public String getName();
}
public interface EatingBehaviour {
public void howManyTimes();
}
public class RealLionEatingBehaviour implements EatingBehaviour{
#Override
public void howManyTimes() {
System.out.println("I eat once a day");
}
}
public class ToyLionEatingBehaviour implements EatingBehaviour {
#Override
public void howManyTimes() {
System.out.println("I never eat! I am a toy lion.");
}
}
public abstract class Feline implements Animal{
public abstract void scratchPost();
private EatingBehaviour eatingBehaviour;
public EatingBehaviour getEatingBehaviour() {
return eatingBehaviour;
}
public void setEatingBehaviour(EatingBehaviour eatingBehaviour) {
this.eatingBehaviour = eatingBehaviour;
}
}
public class Lion extends Feline {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
Lion (String name) {
this.name=name;
}
public void scratchPost(){
System.out.println(getName() + " Lion Scratching Post!");
}
}
public class AnimalFactory {
public static Animal getAnimalInstance(String type, String name){
Animal animal=null;
if ("lion".equalsIgnoreCase(type)) {
animal = new Lion(name);
}
return animal;
}
}
import java.util.ArrayList;
import java.util.List;
public class Cage {
private List<Animal> animals = new ArrayList<Animal>();
public void addAnimal(Animal animal) {
animals.add(animal);
}
public void removeAnimal(int index){
this.animals.remove(index);
}
public Animal getAnimal(int index){
return this.animals.get(index);
}
}
public class Zoo {
public static void main(String args[]) {
Cage cage = new Cage();
Animal animal = null;
animal = AnimalFactory.getAnimalInstance("Lion", "Sweety");
cage.addAnimal(animal);
Animal animalFromCage = cage.getAnimal(0);
if (animalFromCage instanceof Feline) {
Feline feline = (Feline) animalFromCage;
feline.setEatingBehaviour(new RealLionEatingBehaviour());
feline.scratchPost();
feline.getEatingBehaviour().howManyTimes();
feline.setEatingBehaviour(new ToyLionEatingBehaviour());
feline.getEatingBehaviour().howManyTimes();
}
}
}
Use a cast:
Object myAnimal = myCage.getAnimal(0);
Feline f = (Feline) myAnimal;
private List<Animal> animals = new ArrayList<Animal>();
public void findAnimal(int index) {
Animal myAnimal = animals.get(index);
if (myAnimal instanceof Feline) {
Feline feline = (Feline) myAnimal;
//do the work with Feline
} else if (myAnimal instanceof Primate) {
//do the work with Primate
}
// continue with the other types.
}
this will avoid a unexpected classcast exception. Since you know the type use the super type (Animal) in the Arraylist instead fo Object. if it is Obejct you can add anything to the List.
You should use an ArrayList<? extends Animal> instead of ArrayList<Object>. You would then cast a return value to the appropriate subclass of Animal.

How to protect class to be instantiated directly

How can I change this implementation:
public interface Animal()
{
public void eat();
}
public class Dog implements Animal
{
public void eat()
{}
}
public void main()
{
// Animal can be instantiated like this:
Animal dog = new Dog();
// But I dont want the user to create an instance like this, how can I prevent this declaration?
Dog anotherDog = new Dog();
}
Create a factory method and protect the constructor:
public class Dog implements Animal {
protected Dog () {
}
public static Animal createAsAnimal () {
new Dog ();
}
}
You can do it as follows by creating a factory method :
public interface Animal {
public void eat();
public class Factory {
public static Animal getAnimal() {
return new Dog();
}
private static class Dog implements Animal {
public void eat() {
System.out.println("eats");
}
}
}
}
The Dog class is not visible to the user.
To run :
Animal dog= Animal.Factory.getAnimal();
dog.eat();//eats

Method chaining + inheritance don’t play well together?

This question has been asked in a C++ context but I'm curious about Java. The concerns about virtual methods don't apply (I think), but if you have this situation:
abstract class Pet
{
private String name;
public Pet setName(String name) { this.name = name; return this; }
}
class Cat extends Pet
{
public Cat catchMice() {
System.out.println("I caught a mouse!");
return this;
}
}
class Dog extends Pet
{
public Dog catchFrisbee() {
System.out.println("I caught a frisbee!");
return this;
}
}
class Bird extends Pet
{
public Bird layEgg() {
...
return this;
}
}
{
Cat c = new Cat();
c.setName("Morris").catchMice(); // error! setName returns Pet, not Cat
Dog d = new Dog();
d.setName("Snoopy").catchFrisbee(); // error! setName returns Pet, not Dog
Bird b = new Bird();
b.setName("Tweety").layEgg(); // error! setName returns Pet, not Bird
}
In this sort of class hierarchy, is there any way to return this in a way that doesn't (effectively) upcast the the object type?
If you want to avoid unchecked cast warnings from your compiler (and don't want to #SuppressWarnings("unchecked")), then you need to do a little more:
First of all, your definition of Pet must be self-referential, because Pet is always a generic type:
abstract class Pet <T extends Pet<T>>
Secondly, the (T) this cast in setName is also unchecked. To avoid this, use the "getThis" technique in the excellent Generics FAQ by Angelika Langer:
The "getThis" trick provides a way to
recover the exact type of the this
reference.
This results in the code below, which compiles and runs without warnings. If you want to extend your subclasses, then the technique still holds (though you'll probably need to genericise your intermediate classes).
The resulting code is:
public class TestClass {
static abstract class Pet <T extends Pet<T>> {
private String name;
protected abstract T getThis();
public T setName(String name) {
this.name = name;
return getThis(); }
}
static class Cat extends Pet<Cat> {
#Override protected Cat getThis() { return this; }
public Cat catchMice() {
System.out.println("I caught a mouse!");
return getThis();
}
}
static class Dog extends Pet<Dog> {
#Override protected Dog getThis() { return this; }
public Dog catchFrisbee() {
System.out.println("I caught a frisbee!");
return getThis();
}
}
public static void main(String[] args) {
Cat c = new Cat();
c.setName("Morris").catchMice();
Dog d = new Dog();
d.setName("Snoopy").catchFrisbee();
}
}
How about this old trick:
abstract class Pet<T extends Pet>
{
private String name;
public T setName(String name) { this.name = name; return (T) this; }
}
class Cat extends Pet<Cat>
{
/* ... */
}
class Dog extends Pet<Dog>
{
/* ... */
}
No, not really. You could work around it by using covariant return types (thanks to McDowell for the correct name):
#Override
public Cat setName(String name) {
super.setName(name);
return this;
}
(Covariant return types are only in Java 5 and above, if that's a concern for you.)
It's a bit convoluted, but you can do this with generics:
abstract class Pet< T extends Pet > {
private String name;
public T setName( String name ) {
this.name = name;
return (T)this;
}
public static class Cat extends Pet< Cat > {
public Cat catchMice() {
System.out.println( "I caught a mouse!" );
return this;
}
}
public static class Dog extends Pet< Dog > {
public Dog catchFrisbee() {
System.out.println( "I caught a frisbee!" );
return this;
}
}
public static void main (String[] args){
Cat c = new Cat();
c.setName( "Morris" ).catchMice(); // error! setName returns Pet, not Cat
Dog d = new Dog();
d.setName( "Snoopy" ).catchFrisbee(); // error! setName returns Pet, not Dog
}
}
public class Pet<AnimalType extends Pet> {
private String name;
public AnimalType setName(String name) {
this.name = name; return (AnimalType)this;
}
}
and
public class Cat extends Pet<Cat> {
public Cat catchMice() {return this;}
public static void main(String[] args) {
Cat c = new Cat().setName("bob").catchMice();
}
}

Categories

Resources