Let's assume I have the following classes:
public class Cat {
private final String noise = "meow";
pulic static void makeNoise(){
System.out.println(noise);
}
}
public class Dog {
private final String noise = "woof";
pulic static void makeNoise(){
System.out.println(noise);
}
}
As you can see, these two classes share pretty much the same code. To remove redundant code, I'd create a parent class like this:
public abstract class Animal {
protected final String noise;
public Animal(String noise) {
this.noise = noise;
}
public void makeNoise() {
System.out.println(noise);
}
}
public class Dog extends Animal{
public Dog(){
super("woof");
}
}
Now unfortunately I'm running into a two problems:
Since make noise of animal can't be static anymore, as the constants
will have to be assigned through the constructor of animal, you will
need to create a cat or dog to get the noise of that animal. Even
though it is a constant.
The method makeNoise() need's to work in the class Animal - which
doens't have a noise per default.
A possible solution would be something along the line like this:
public abstract void makeNoise();
which is neither allowed, nor would it erase the need to copy the code into each and everyone of the children of Animal.
How would you erase the need to have redundant code in the children of animal while keeping the method makeNoise static?
Static methods in Java can't be overridden in subclasses.
If you define a static method in a subclass with the same signature as the static method in the parent class, the method is not overriding the parent method is hiding it. The methods in the parent and the child class has no relation to each other.
In your example, if method static void makeNoise() exists in Animal and any subclass define the method as well, the subclass is just hiding the makeNoise method in Animal.
In your example, the best you can do with static methods is:
public static void makeNoise(String noise) {
System.out.println(noise);
}
And invoke the method this way:
Animal.makeNoise(Cat.NOISE); // A constant NOISE is defined in each subclass
If the method makeNoise is non-static, inheritance could be used to use a different noise in each subclass:
public abstract class Animal {
protected String noise;
protected Animal(String noise) {
this.noise = noise;
}
public void makeNoise() {
System.out.println(noise);
}
}
public class Cat extends Animal{
public static final String NOISE = "meow";
public Cat() {
super(NOISE);
}
}
Why would you represent a real world object behavior with a static method? Each animal has it's own behavior so you want to differentiate between them.
enum AnimalBehavior {
MEOW, WOOF, ROAR
}
You could use an enum which contains every animal behavior.
Also consider the following situation: A wolf keeps howling during a full moon night. He keeps doing it until he gets exhausted. You want to track a bar which indicates the level of energy your wolf has.
private int energy = 100;
public static void wolfHowl() {
System.out.println(AnimalBehavior.ROAR);
energy = energy - 10;
}
This won't work technically because you're using static methods.. so keep in mind how you design your stuff since that wolf could actually howl without getting tired until someone gets really pissed off.
Related
So say, for the purposes of illustration that I have an abstract class Animal, and every Animal has a numberOfLegs.
Dog extends Animal and all dogs have a numberOfLegs of 4.
Is it possible to make numberOfLegs...
Static
Required (everything that extends Animal has to define numberOfLegs, or there is some default value)
Accessible from Animal (this one I'm not as concerned about, but if say the method walk() was called from Dog, could Animal view the number of legs without having to pass an extra value?)
Sorry if this is a strange question, and yes, I understand that I could do this easily in other ways, such as making it an instance variable instead of static, but I'm just kind of curious if there's a better way.
Neither static variables or instance variables participate in polymorphism. Just declare an abstract method, e.g. int getNumberOfLegs(), in the abstract class. Your Dog class could be:
class Dog extends Animal {
private static final int NUMBER_OF_LEGS = 4;
public int getNumberOfLegs () {
return NUMBER_OF_LEGS;
}
}
Is it possible to make numberOfLegs: Static
This would make every instance of a class that extends Animal have the same numberOfLegs. See: here for an explanation.
public abstract class Animal
{
private static int NUMBER_OF_LEGS = 4;
}
Is it possible to make numberOfLegs: Required
Yes, you just have to make a property in the abstract class and initialise it in the constructor.
public abstract class Animal
{
private int numberOfLegs;
public int getNumberOfLegs()
{
return this.numberOfLegs;
}
public Animal(int numberOfLegs)
{
this.numberOfLegs = numberOfLegs;
}
}
public class Zebra extends Animal
{
public Animal(int numberOfLegs)
{
super(numberOfLegs);
}
}
everything that extends Animal has to define numberOfLegs, or there is some default value
Furthermore, if you wanted a default value for number of legs, you could inlcude a constructor for Animal without a numberOfLegs parameter and set it to a value, say 4.
public abstract class Animal
{
private int numberOfLegs;
public Animal()
{
this.numberOfLegs = 4;
}
}
Is it possible to make numberOfLegs: Accessible from Animal
Yes, you can call the method (if it's abstract in the Animal class) from any object that extends Animal
Zebra z = new Zebra(4);
System.out.println(z.getNumberOfLegs());
Kind of a noob question, this, but I cannot figure it out.
This is animal.java. I want it to be a superclass for all animal subclasses. It's in the same package as all the subclasses.
public class Animal {
protected static String call = "Animals make noises, but do not have a default noise, so we're just printing this instead.";
public static void sound()
{
System.out.println(call);
}
}
This is cow.java
class Cow extends Animal {
call = "moo";
}
Evidently, this does not run. But I want to be able to run Cow.sound() and have the output read "moo". I also want to be able to create more classes that override the 'call' with their own string. What should I be doing instead?
You can't override instance variables. You can only override methods. You can override the sound method (once you change it to an instance method, since static methods can't be overridden), or you can override a method that sound will call (for example getSound()). Then each animal can returns its own sound :
public class Animal {
static String call = "Animals make noises, but do not have a default noise, so we're just printing this instead.";
public void sound()
{
System.out.println(getSound ());
}
public String getSound ()
{
return call;
}
}
class Cow extends Animal {
#Override
public String getSound ()
{
return "moo";
}
}
Variables are never overriden, so sub class variable replacing supercall variable will not be possible.
Another option was to override the method but then its static, static also cannot be overridden.
So with current setup its not possible unless you look to override non static methods.
I have this abstract base class and each of it's childs should have a specific mandatory function but slightly different. Is this possible using the abstract class or should I be using an interface for this?
I will be using the structure like this
public abstract class Animal
{
//Mandatory method
Public void sound()
{
}
}
public class Cat extends Animal
{
public void sound()
{
System.out.println("Miauw");
}
}
public class Dog extends Animal
{
public void sound()
{
System.out.println("Woof");
}
}
//I will put all these child objects in a List<Animal> and need to call these methods.
for (Animal a : animalList)
{
a.sound();
}
How would one go about this structure? I have to add that I am using an abstract class because there are plenty of identical methods that need to be shared among the child classes. Just some of the methods need to be different from each other but mandatory and accessible from the base class.
You are looking for:
public abstract class Animal
{
//Mandatory method
abstract public void sound();
}
But also look at other users advices:
use lowercase for method names
the keyword publicalways goes in lowercase
use interfaces if your Animal class hasn't common code for all children classes
Both an abstract class and an interface would work in this case. The times when you'd want to use an abstract class is when there are common methods and data that you want shared among all subclasses. Such as, if Animal had a weight variable, and each subclass sets that variable.
NOTE: In an abstract class, any methods that you don't want to implement, you must declare as abstract. See how I modified Sound() below. Also, a bonus tip is that the standards say that method names should start with a lowercase letter, so I changed Sound to sound.
public abstract class Animal
{
private int weight;
public void setWeight(int weight) {
this.weight = weight;
}
public int getWeight() {
return weight;
}
//Mandatory method
abstract public void sound();
}
public class Cat extends Animal
{
public Cat(int weight) {
this.setWeight(weight);
}
public void sound()
{
System.out.println("Miauw");
}
}
public class Dog extends Animal
{
public Dog(int weight) {
this.setWeight(weight);
}
public void sound()
{
System.out.println("Woof");
}
}
You are looking for Java's abstract modifier. The official Java Documentation contains more specific information about abstract and final here.
public abstract class Animal
{
// Mandatory method with no "default" implementation.
public abstract void Sound();
// Optional method with a default implementation.
public void Move() {
// some actions here
}
// Optional method with a fixed implementation (it can't be changed in a child class).
public final void Eat(Food food) {
// some actions here
}
}
you should use interface in this case because you are not defining any method, if you only want to provide declaration interface is ok for that
if you use abstract class you overhead by overriding the method and define it again
Animal Base Class
public class Animal
{
protected String pig;
protected String dog;
protected String cat;
public void setPig(String pig_)
{
pig=pig_;
}
public void setCat(String cat_)
{
cat=cat_;
}
public void setDog(String dog_)
{
dog=dog_;
}
}
AnimalAction Class
public class AnimalAction extends Animal
{
public AnimalAction(String pig, String cat, String dog)
{
super.pig = pig;
super.cat = cat;
super.dog = dog;
}
}
Would this be the correct way to set protected variables? Is using protected variables the correct way to do this? Is there a more professional OO way to do?
You can use private variables instead of protected. This will be more apt.
You can use the constructor to set the value of the super class.
Edited:
public class Animal{
private String pig;
private String dog;
private String cat;
public Animal(String pig,String dog,String cat){
this.pig=pig;
this.dog=dog;
this.cat=cat;
}
}
public class AnimalAction extends Animal
{
public AnimalAction(String pig, String cat, String dog)
{
super(pig,dog,cat);
}
}
You should be able to use this.pig etc, since you inherited the protected members. You could also actually call the public setPig(...) methods.
There is nothing wrong in using protected member variable and then inherit them in subclass .
But If a developer comes along and subclasses your class they may mess it up because they don't understand it fully. With private members, other than the public interface, they can't see the implementation specific details of how things are being done which gives you the flexibility of changing it later.
By providing protected member variables you are just coupling tight between you subclass and superclass.
The less your member variables can be seen outside the class, the better. I would make the class variables private and make the getters public (or as required) & the setters protected.
There's no need to use the super prefix, or any other prefix, to access protected variables.
BTW - I disagree with Thomas on one point - do not call the setter methods of the superclass in your constructor. Using non-final setters in a constructor may have ugly effects if a subclass overrides them. Then they could be called on an incompletely constructed object. But you should consider making your setters final if you don't mean them to be overridden.
The principle of "design for inheritance or forbid it" is explained in the Effective Java book by Joshua Bloch.
Your example is quite confusing, but it would work. I'll give another example:
// use capitals for classes/interfaces/enums, lower case for methods/fields.
public class Animal
{
protected String name;
protected int numberOfFeet;
public Animal(String name)
{
this.name = name;
}
public void setNumberOfFeet(int numberOfFeet)
{
this.numberOfFeet = numberOfFeet;
}
}
public class Dog extends Animal
{
public Dog()
{
super("dog"); // call the constructor of the super class.
// because Dog extends Animal and numberOfFeet is protected, numberOfFeet becomes part of "this" class.
this.numberOfFeet = 4;
}
}
//Now you can create instances of Animal like:
Animal bird = new Animal("bird");
bird.setNumberOfFeet(2);
//Or use Dog to create an animal "dog" with 4 feet.
Animal dog = new Dog();
//after an accident
dog.setNumberOfFeet(3);
The only examples of polymorphic method overriding I ever see involve methods that take no parameters, or at least have identical parameter lists. Consider the common Animal/Dog/Cat example:
public abstract class Animal
{
public abstract void makeSound();
}
public class Dog extends Animal
{
public void makeSound()
{
System.out.println("woof");
}
}
public class Cat extends Animal
{
public void makeSound()
{
System.out.println("meow");
}
}
public class ListenToAnimals
{
public static void main(String[] args)
{
AnimalFactory factory = new AnimalFactory();
Animal a = factory.getRandomAnimal(); // generate a dog or cat at random
a.makeSound();
}
}
In this case, everything works out just fine. Now let's add another method that gets partially implemented in the abstract class while getting the more specific behavior in the subclasses:
public abstract class Animal
{
public abstract void makeSound();
public void speak(String name)
{
System.out.println("My name is " + name);
}
}
public class Dog extends Animal
{
public void makeSound()
{
System.out.println("woof");
}
public void speak(String name)
{
super.speak(name);
System.out.println("I'm a dog");
}
}
public class Cat extends Animal
{
public void makeSound()
{
System.out.println("meow");
}
public void speak(String name, int lives)
{
super.speak(name);
System.out.println("I'm a cat and I have " + lives + " lives");
}
}
public class ListenToAnimals
{
public static void main(String[] args)
{
AnimalFactory factory = new AnimalFactory();
Animal a = factory.getRandomAnimal(); // generate a dog or cat at random
a.makeSound();
// a.speak(NOW WHAT?
}
}
In that last (commented) line of the main method, I don't know what to put there because I don't know what type of Animal I have. I didn't have to worry about this before because makeSound() didn't take any arguments. But speak() does, and the arguments depend on the type of Animal.
I've read that some languages, such as Objective-C, allow for variable argument lists, so an issue like this should never arise. Is anyone aware of a good way to implement this kind of thing in Java?
You are confusing method overriding and method overloading. In your example the Cat class has two methods:
public void speak(String name) // It gets this from its super class
public void speak(String name, int lives)
Overloading is a way to define methods with similar functions but different parameters. There would be no difference if you had named the method thusly:
public void speakWithLives(String name, int lives)
To avoid confusion the recommendation in java is to use the #Override annotation when you are attempting to override a method. Therefore:
// Compiles
#Override
public void speak(String name)
// Doesn't compile - no overriding occurs!
#Override
public void speak(String name, int lives)
EDIT: Other answers mention this but I am repeating it for emphasis. Adding the new method made the Cat class no longer able to be represented as an Animal in all cases, thus removing the advantage of polymorphism. To make use of the new method you would need to downcast it to the Cat type:
Animal mightBeACat = ...
if(mightBeACat instanceof Cat) {
Cat definitelyACat = (Cat) mightBeACat;
definitelyACat.speak("Whiskers", 9);
} else {
// Definitely not a cat!
mightBeACat.speak("Fred");
}
The code inspection tool in my IDE puts a warning on the instanceof as the keyword indicates possible polymorphic abstraction failure.
Your example Cat isn't polymorphic anymore, since you have to know it's a Cat to pass that parameter. Even if Java allowed it, how would you use it?
As far as I know java doesn't allow you to do that. speak(name, lives) is now just the Cat's function. Some languages do allow this type of flexibility. To force java to allow this, you can make the paramater an array of objects or some other collection.
However, consider that when you call speak, you now must know which parameters to pass in regardless, so the point is somewhat moot.
When you call a polymorphic method as:
a.speak("Gerorge");
You don't need to know what type of Animal has instantiated because this is the objective of polymorphism. Also since you have user the sentence:
super.speak(name);
Both Cat an Dog will have the behavior of Animal plus the own behavior.
You can do
public void speak(Map ... mappedData)
{
System.out.println("My name is " + mappedData.get("name")+ " and I have "+mappedData.get("lives");
}
However, I would advise making lives an instance variable of Cat and have your factory pass a default value (or have the constructor have a default parameter for it).
In this case best way is to use a DTO,
public class SpeakDTO
{
//use getters and setters when you actually implement this
String name;
int lives;
}
public class Dog extends Animal
{
public void speak(SpeakDTO dto)
{
super.speak(dto.name);
System.out.println("I'm a dog");
}
}
public class Cat extends Animal
{
public void speak(SpeakDTO dto)
{
super.speak(dto.name);
System.out.println("I'm a cat and I have " + dto.lives + " lives");
}
}
public class ListenToAnimals
{
public static void main(String[] args)
{
AnimalFactory factory = new AnimalFactory();
Animal a = factory.getRandomAnimal(); // generate a dog or cat at random
a.makeSound();
SpeakDTO dto = new SpeakDTO();
dto.name = "big cat";
dto.lives = 7;
a.speak(dto);
}
}
If you want to make a call like that, you could use reflection to get the class:
if (a.getclass() == Cat.class) {
// speak like a cat
} else if (a.getclass() == Dog.class) {
.
.
.
Of course this might not be the best design, and reflection should be used with care.
Java also has variable argument lists, but I'd argue that's not the "best" way to do it, at least not in all circumstances.
When subclasses have behavior that isn't defined by the interface, you don't have many options in Java that aren't verbose or a bit wonky.
You could have a speak () that takes a marker interface and delegate arg construction to a factory. You could pass a parameter map. You could use varargs.
Ultimately, you need to know what to pass to the method, no matter what language.
I agree with the comments about how you've really broken polymorphism if you must know the type of object before you can call the speak method. If you absolutely MUST have access to both speak methods, here is one way you could implement it.
public class Animal {
public void speak(String name) {
throw new UnsupportedOperationException("Speak without lives not implemented");
}
public void speak(String name, int lives) {
throw new UnsupportedOperationException("Speak with lives not implemented");
}
}
public class Dog extends Animal {
public void speak(String name) {
System.out.println("My name is " + name);
System.out.println("I'm a dog");
}
}
public class Cat extends Animal {
public void speak(String name, int lives) {
System.out.println("My name is " + name);
System.out.println("I'm a cat and I have " + lives + " lives");
}
}
Alternately you can put the UnsupportedOperationExceptions into the child classes (or you might want to used a checked exception). I'm not actually advocating either of these, but I think this is the closest way to implement what you requested, and I have actually seen systems that used something like this.