How can I have a generic abstract class, let's say Animal, and have it implement a constant (or a variable; it doesn't mind) which must be redefined by all subclasses?
Example:
abstract class Animal {
private static int venerableAge;
}
And force Dog to be defined something like
class Dog extends Animal {
private static int venerableAge = 10;
}
I don't want different subclasses to be able to read nor write each others' value. Just the one of themselves.
I.e., each class must have its own static "instance" of the variable. And no one will access the parent's.
Is that possible in Java?
The trick is to do this with getter methods rather than directly with fields:
abstract class Animal {
abstract int getVenerableAge();
}
class Dog extends Animal {
private static int venerableAge = 10;
public int getVenerableAge() {
return venerableAge;
}
}
EDIT:
How about letting the constructor do the contract binding:
abstract class Animal {
public Animal(int venerableAge){
//carry out sense checks here. i.e.:
if (venerableAge < 0) { /* doSomething */ }
}
}
class Dog extends Animal {
private static int venerableAge;
public Dog(int age) {
super(age)
venerableAge = age;
}
}
Now Dog and Cat are both forced to be created with venerable ages, but (as implemented above) can't see each others value.
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());
I have a super class named TestSuper
public class TestSuper {
int a = 0;
}
and I have 2 sub classes named TestSub and TestSub2 that extend TestSuper
public class TestSub extends TestSuper{
int a=1;
}
public class TestSub2 extends TestSuper{
int a=2;
}
in my main class i created a method that takes in a type TestSuper and returns the a value of it and in the main i display it on the console
public class Main {
public static void main(String[] args){
System.out.println(test(new TestSub())+" "+test(new TestSub2()));
}
public static int test(TestSuper b){
return b.a;
}
}
but the output is "0 0" instead of "1 2", what do I do?
You need to cast the reference so say which one you want.
public static int test(TestSuper b){
return b instanceof TestSub ? ((TestSub) b).a :
b instanceof TestSub2 ? ((TestSub2) b).a :
b.a;
}
If this seems needlessly complicated, it is. You should use polymorphism instead.
public class TestSuper {
int a = 0;
public int getA() { return a; }
}
public class TestSub extends TestSuper {
int a = 1;
public int getA() { return a; }
}
public class TestSub2 extends TestSuper {
int a = 2;
public int getA() { return a; }
}
public static int test(TestSuper b) {
return b.getA();
}
First understand the difference between hiding and overriding: https://docs.oracle.com/javase/tutorial/java/IandI/override.html
Then create a getter method in the base-class which you can override in the subclass.
You can look into the theory behind this, and then do the only reasonable thing -forget about writing such kind of code.
In good OOP you consider your fields to be part of your "secret" internal implementation. You don't use fields of sub classes in the super class context. Period.
You are even very conservative about making a field protected in the superclass and to use that in subclasses.
When you call test method like this:
test(new TestSub())+" "+test(new TestSub2())
You use upcasting. Upcasting seperates interface and implementation for an object. But for seperating interface and implementation and achieving true implementation in polymorphism, you must use polymorphic structures. The instance variables aren't polymorphic. Because of this, actually you call a variable which is in TestSuper class.
Only instance methods are polymorphic.
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.
I have classes like Dog.java,Cat.java,Bird.java,Fish.java,Not_Listed.java etc. I also have a ID.java which only keeps some final int mapping:
public class ID{
public static final int CAT = 1;
public static final int DOG = 3; // there maybe some integers skipped
public static final int FISH = 4; // but all integers are unique
public static final int BIRD = 6;
public static final int NOT_LISTED = -1;
}
All classes listed above extends Animal.java class.
What I need is given "6" I need to create a Bird object, given "1" I need to create Cat object. Given "2" or "5" I can return a Not_Listed object or simply throw an error(both works). I could simply do it with a switch case or HashMap but my list is somehow long and I dont want to update the code whenever my list grows. So I came up with reflection, but I have no idea how to do it?
Any other efficient solutions are also welcome. Sorry for being noob about reflection. Thanks in advance.
edit: IDs are must
You don't need reflection for this.
Create an enum instead of your id class and have a class reference inside the enum, i.e.:
enum Animal {
CAT(1, Cat.class),
DOG(2, Dog.class),
FISH(3, Fish.class);
private final Class clazz;
private final int id;
Animal(int id, Class clazz) {
this.id = id;
this.clazz = clazz;
}
public Object generateInstance() {
return clazz.generateInstance();
}
public class getGeneratedClass() {
return clazz;
}
public int getId() {
return id;
}
}
This makes use of the feature of Java that allows enums to be fully featured classes and it records the Class to use within each entry in the enum. You can then use that Class to generate new instances on demand so long as the class has a 0-argument constructor.
To use this just do:
Animal.DOG.generateInstance() // Returns a Dog object
Animal.CAT.generateInstance() // Returns a Cat object
If you wanted to be able to get a type from id you could either build a HashMap inside the enum to do the lookup or just loop over the enum.values() looking for a match.
A completely different approach so I'm doing it as a separate answer.
Just create a Map from id to class:
public static final int CAT = 1;
public static final int DOG = 3; // there maybe some integers skipped
public static final int FISH = 4; // but all integers are unique
public static final int BIRD = 6;
public static final int NOT_LISTED = -1;
Map<Integer, Class> classMap = new HashMap<>();
classMap.put(CAT, Cat.class);
classMap.put(DOG, Dog.class);
classMap.put(FISH, Fish.class);
public Object generateInstance(int id) {
// Will throw NullPointerException if id isnt in map, you might want to consider some checks
return classMap.get(id).generateInstance();
}
That will do what you want, you really should look at the enum design I posted in the other answer though - it will give much better results in the long term.
This has Factory design pattern written all over it. You can register each Animal class (e.g. Cat, Fish, Dog, Bird, etc.) in their respective classes.
See Class Registration - avoiding reflection on http://www.oodesign.com/factory-pattern.html
You can have an AnimalFactory that keeps a map of ID to class that implements Facotry Method. Then you would register it in each specific implementation of Animal. This way AnimalFactory wouldn't need to change, just each new Animal that is added would need to register the specific factory:
public class Dog extends Animal
{
...
static
{
AnimalFactory.instance().registerAnimal(ID.DOG, new DogCreator());
}
...
}
public class DogCreator extends AnimalFactory
{
//Abstract factory method in AnimalFactory that gets called to return the Animal
public Animal createAnimal
{
return new Dog();
}
}
Begin Edit
You can also have a generic Animal creator that uses reflection to make the new class (assuming each Animal has an empty constructor). This would still require you to register your specific id in each Animal implementation:
public class Dog extends Animal
{
...
static
{
AnimalFactory.instance().registerAnimal(ID.DOG, Dog.class);
}
...
}
Then AnimalFactory can use reflection to make the instance:
public Animal createAnimal(ID id)
{
return animalMap.get(id).newInstance();
}
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);