I'm currently in a Java-based university class and for coding samples the professor is using protected fields for the subclasses to access.
I asked if this was bad practice and was told it is normal. Is this true, why not use setters and getters for abstract methods? I thought it was always best practice to restrict as much information as possible unless required otherwise.
I tested out using setters and getters with abstract parent and it works fine for abstract parent classes that are subclassed. Although abstract classes cannot be instantiated, they can still be used to create objects when a subclass is instantiated as far as I understand.
Here is a short example:
public abstract class Animal {
protected int height;
}
public class Dog extends Animal {
public Dog() {
height = 6;
}
}
public class Cat extends Animal {
public Cat() {
height = 2;
}
}
As opposed to using:
public abstract class Animal {
private int height;
public getHeight() {
return height;
}
public setHeight(int height) {
this.height = height;
}
}
public class Dog extends Animal {
public Dog() {
setHeight(6);
}
}
public class Cat extends Animal {
public Cat() {
setHeight(2);
}
}
While you can certainly do both ways the protected field way is less desirable and I would argue less idiomatic particularly if this is library code that you plan to share.
You can see this in the Java Collections API as well as Guava. You will be hard pressed to find Abstract classes that have protected fields (let alone any fields).
That being said there are always exceptions and you are not always writing library code (ie public api).
Here is my opinion on protected and/or private fields and abstract classes. If you are going to do it than make a constructor that takes the initial values:
public abstract class Animal {
private int height;
public Animal(int height) { this.height = height; }
public int getHeight() { return this.height }
}
public class Cat extends Animal {
public Cat() {
super(2);
}
}
Now your subclasses are required to set height to something as they have to call the constructor that takes height.
In your first example, only subclasses of Animal can access the protected field height.
In you second example, any class whatsoever can manipulate the field height indirectly via the public setter method.
See the difference?
Related
I've been trying my best with some basic code, and I am completely stuck...
I have an abstract class "Piece":
public abstract class Piece {
private static int type;
public int getType() {
return type;
}
}
The "Pawn" is the Child:
public class Pawn extends Piece {
private static final int type = 1;
}
And now for the problem: When creating the Pawn with Pawn p = new Pawn();, p.getType() returns 0, not 1...
How can I fix this?
The problem is that you already have a variable declared in your abstract class. You shouldn't redeclare it in your subclass. Instead, set the abstract class's variable like this:
public class Pawn extends Piece {
public Pawn() {
type = 1;
}
}
You should also declare the variable as protected so that subclasses can access it and refrain from making it static, since that will allow only one value for all subclasses:
public abstract class Piece {
protected int type;
public int getType() {
return type;
}
}
This code you write relies on an instance and not on a static context:
Pawn p = new Pawn();
p.getType();
A static final field is not designed to be inherited by child classes.
And creating a static final field in the child class with the same name as in the parent class doesn't allow to override it either.
1) So you should use an instance field and not a static field for the type field.
2) If you want to override the behavior of getType() in the child class, in fact you don't even need to use a field. Using a method should be enough.
In the base class :
public abstract class Piece {
public int getType() {
return 0;
}
}
In the child class :
public class Pawn extends Piece {
#Override
public int getType() {
return 1;
}
}
Here is one way. But you really need to read up on classes and abstract classes.
public abstract class Piece {
public int getType() {
return 0;
}
}
public class Pawn extends Piece {
public int getType() {
return 1;
}
}
Having a static variable in a class means that all instances of that class share the same value. I don't think that's what you intended.
Also, you can use the hierarchy of inheritance to your advantage by not redefining the getType() method.
Here is one of many ways to solve it:
public abstract class Piece {
protected int type;
public int getType() {
return type;
}
}
public class Pawn extends Piece {
public Pawn() {
type = 1;
}
}
There are two problems with your approach.
The first is that Java does not support inheritance of static methods. Not that it couldn't have supported this - it's just a design choice. What this means is that any method of class Piece, which calls getType() - calls the Piece class' implementation of getType(), not a polymorphic call to getType() of whatever the actual subclass is.
The second problem is that you're sort of reinventing the wheel. Java has rich reflection facilities: You can use getClass() and instanceof for your check:
if(myObject instanceof Piece && myObject.getClass() != Piece.class) {
// do stuff
}
and of course you can make this a method of the piece class (no need to override it).
I'm making a game with different types of building. I'm making an interface for each type. Some buildings have more than 1 type.
I have this code:
public interface DefenseBuilding {
int range;
int damage;
public void shoot ();
}
It gives me an error on the 2 variable declarations (range & damage). The error being something along the lines of "Final variable may not be initialised"
It works if I assign the variable in the interface, but I don't want to do that.
I can't just extend a class, because - as said earlier - some buildings need more than 1 type. Classes can only extend 1 other class so I need to use interfaces.
What I'm asking is, is there a way to have variables in an interface without having to initialise the variable inside the interface?
The whole point of interfaces is to specify as interface - i.e. how will your classes interface with client classes. Instance variables are clearly not part of any interface at all.
Instead, try this:
public interface DefenseBuilding {
public void shoot ();
}
and this:
public abstract class AbstractDefenseBuilding implements DefenceBuilding {
protected int range;
protected int damage;
}
edit:
Your classes should now extend AbstractDefenseBuilding, so they will inherit the variables. They also indirectly implement DefenceBuilding so they'll still be forced to implement the shoot() method (unless they are also abstract)
You can use a property method aproach.
public interface DefenseBuilding {
public void setRange(int range);
public int getRange();
public void setDamage(int damage);
public int getDamage();
public void shoot ();
}
Then in your class
public MyClass implements DefenseBuilding{
int range;
int damage;
public int getRange() {
return range;
}
public void setRange(int range) {
this.range = range;
}
public int getDamage() {
return damage;
}
public void setDamage(int damage) {
this.damage = damage;
}
public void shoot (){...}
}
All variables in Interface are static and final. Hence, unless initialized, compiler will keep giving an error that it is not initialized. This is enforced because interface cannot be instantiated and therefore any variable should be of static in nature and cannot be changed.
If your intention is to define class variables, do as NickJ suggested.
Interfaces define behavior but not state (other than constants). Protected variables are a potential danger to proper encapsulation of data (an object should hide its data and provide access through methods unless there is a very compelling reason not to). An alternative would be the following:
public interface DefenseBuilding {
public void shoot();
public int getRange();
public int getDamage();
}
It's also VERY common to provide an abstract class that partially implements the interface:
public abstract class AbstractDefenseBuilding implements DefensBuilding {
private int range;
private int damage;
public AbstractDefenseBuilding(int range, int damage) {
this.range = range;
this.damage = damage;
}
public int getRange() {
return range;
}
public int getDamage() {
return damage;
}
}
What I'm trying to do is create a class (Square) that uses a Builder pattern, and then extend this class as an inner class (MyCube) inside the Object where it's needed (DrawMyCube).
For reasons that are a bit to complex to get into it's preferred to extend these as inner classes (references to local variables).
I've tried to make the example as simple as possible because the real use case is too complex to use on here:
public abstract class Square {
protected Integer length;
protected Integer width;
public abstract static class Builder {
protected Integer length;
protected Integer width;
public abstract Builder length(Integer length);
public abstract Builder width(Integer width);
}
protected Square(Builder builder) {
this.length = builder.length;
this.width = builder.width;
}
}
Now I need to extend and use this in here:
public class DrawMyCube {
private String myText;
private Integer height;
private String canvas;
private MyCube myCube;
public DrawMyCube(String canvas) {
this.canvas = canvas;
myCube = new MyCube.Builder().length(10).width(10).text("HolaWorld").build();
}
public void drawRoutine() {
myCube.drawMe(canvas);
}
protected class MyCube extends Square {
protected String text;
public static class Builder extends Square.Builder{
protected String text;
public Square.Builder length(Integer length) {this.length = length; return this;}
public Square.Builder width(Integer width) {this.width = width; return this;}
public Square.Builder text(String text) {this.text = text; return this;}
}
protected MyCube(Builder builder) {
super(builder);
this.text = text;
}
protected void drawMe(String canvas) {
canvas.equals(this);
}
}
}
However the problem is the static Builder in the inner class:
The member type Builder cannot be declared static; static types can
only be declared in static or top level types.
Alternatively, I can create the inner class MyCube as a regular class, but then the problem becomes that I can not refer back to anything inside the DrawMyCube class (and in the real use case there are many references to various of these).
Static nested classes can only be declared in a static context, which is why you're seeing that compiler error. Just declare your Builder class adjacent to MyCube (or anywhere else in static context, it doesn't matter). For example:
public class DrawMyCube {
protected class MyCube extends Square { }
public static class MyCubeBuilder extends Square.Builder { }
}
Note that the builder will need a reference to the outer DrawMyCube instance in order to instantiate a new MyCube. For this reason you might just make it an inner (non-static) class of MyCube:
public class DrawMyCube {
protected class MyCube extends Square { }
public class MyCubeBuilder extends Square.Builder { }
}
As you can see I still declared it adjacent to MyCube because having a builder as an inner class to what it builds just doesn't make sense.
Edit: As you mentioned, a simple alternative would be to make MyCube static:
public class DrawMyCube {
protected static class MyCube extends Square {
public static class Builder extends Square.Builder { }
}
}
Because honestly there isn't a huge benefit to using inner classes - just the implicit outer instance reference - and this would let you keep your existing hierarchy and naming conventions. You can easily implement the reference to the outer DrawMyCube yourself - it just takes a little more code.
As a side note you're probably going to want to use generics to implement your builder pattern, for example an abstract Builder<T> where an implementation builds an instance of T. As it is, there won't be a way to narrow down what your deriving builder classes produce. Here's a sketch of what I'm hinting at:
abstract class Square { }
abstract class SquareBuilder<T extends Square> { }
class MyCube extends Square { }
class MyCubeBuilder extends SquareBuilder<MyCube> { }
I wish to know is there any way in which I can make it compulsory for the implementer class to declare the objects handles/primitives as they do with methods.
for e.g.:
public interface Rectangle {
int height = 0;
int width = 0;
public int getHeight();
public int getWidth();
public void setHeight(int height);
public void setWidth(int width);
}
public class Tile implements Rectangle{
#Override
public int getHeight() {
return 0;
}
#Override
public int getWidth() {
return 0;
}
#Override
public void setHeight(int height) {
}
#Override
public void setWidth(int width) {
}
}
In the above method how can we compel Tile class to declare height and width attributes using the interface? For some reason I wish to do it with interface only!
I initially thought of using it with inheritance.
But thing is I have to deal with 3 classes.!
Rectangle
Tile
JLabel.!
class Tile extends JLabel implements Rectangle {}
would work.!
but
class Tile extends JLabel extends Rectangle {}
woud not.!
The point of an interface is to specify the public API. An interface has no state. Any variables that you create are really constants (so be careful about making mutable objects in interfaces).
Basically an interface says here are all of the methods that a class that implements it must support. It probably would have been better if the creators of Java had not allowed constants in interfaces, but too late to get rid of that now (and there are some cases where constants are sensible in interfaces).
Because you are just specifying what methods have to be implemented there is no idea of state (no instance variables). If you want to require that every class has a certain variable you need to use an abstract class.
Finally, you should, generally speaking, not use public variables, so the idea of putting variables into an interface is a bad idea to begin with.
Short answer - you can't do what you want because it is "wrong" in Java.
Edit:
class Tile
implements Rectangle
{
private int height;
private int width;
#Override
public int getHeight() {
return height;
}
#Override
public int getWidth() {
return width;
}
#Override
public void setHeight(int h) {
height = h;
}
#Override
public void setWidth(int w) {
width = w;
}
}
an alternative version would be:
abstract class AbstractRectangle
implements Rectangle
{
private int height;
private int width;
#Override
public int getHeight() {
return height;
}
#Override
public int getWidth() {
return width;
}
#Override
public void setHeight(int h) {
height = h;
}
#Override
public void setWidth(int w) {
width = w;
}
}
class Tile
extends AbstractRectangle
{
}
Interfaces cannot require instance variables to be defined -- only methods.
(Variables can be defined in interfaces, but they do not behave as might be expected: they are treated as final static.)
Happy coding.
Java 8 introduced default methods for interfaces using which you can body to the methods. According to OOPs interfaces should act as contract between two systems/parties.
But still i found a way to achieve storing properties in the interface. I admit it is kinda ugly implementation.
import java.util.Map;
import java.util.WeakHashMap;
interface Rectangle
{
class Storage
{
private static final Map<Rectangle, Integer> heightMap = new WeakHashMap<>();
private static final Map<Rectangle, Integer> widthMap = new WeakHashMap<>();
}
default public int getHeight()
{
return Storage.heightMap.get(this);
}
default public int getWidth()
{
return Storage.widthMap.get(this);
}
default public void setHeight(int height)
{
Storage.heightMap.put(this, height);
}
default public void setWidth(int width)
{
Storage.widthMap.put(this, width);
}
}
This interface is ugly. For storing simple property it needed two hashmaps and each hashmap by default creates 16 entries by default. Additionally when real object is dereferenced JVM additionally need to remove this weak reference.
You can only do this with an abstract class, not with an interface.
Declare Rectangle as an abstract class instead of an interface and declare the methods that must be implemented by the sub-class as public abstract. Then class Tile extends class Rectangle and must implement the abstract methods from Rectangle.
In Java you can't. Interface has to do with methods and signature, it does not have to do with the internal state of an object -- that is an implementation question. And this makes sense too -- I mean, simply because certain attributes exist, it does not mean that they have to be used by the implementing class. getHeight could actually point to the width variable (assuming that the implementer is a sadist).
(As a note -- this is not true of all languages, ActionScript allows for declaration of pseudo attributes, and I believe C# does too)
Fields in interfaces are implicitly public static final. (Also methods are implicitly public, so you can drop the public keyword.) Even if you use an abstract class instead of an interface, I strongly suggest making all non-constant (public static final of a primitive or immutable object reference) private. More generally "prefer composition to inheritance" - a Tile is-not-a Rectangle (of course, you can play word games with "is-a" and "has-a").
Like everyone says, you cannot add attributes to an interface.
But, I follows this answer: https://stackoverflow.com/a/25907755/12955288
You can use an service with a WeakHashMap to store attributes.
To reduce maps, use a Map of keys like this:
In java 11:
public interface Rectangle {
class Storage {
private static final Map<Rectangle, Map<String, Object>> attributes = new WeakHashMap<>();
}
private Map<String, Object> getAttributes(){
return Storage.attributes.computeIfAbsent(this, k -> new HashMap<>());
}
default public int getHeight() {
return (int) getAttributes().getOrDefault("height", 0);
}
default public int getWidth() {
return (int) getAttributes().getOrDefault("width", 0);
}
default public void setHeight(int height) {
getAttributes().put("height", height);
}
default public void setWidth(int width) {
getAttributes().put("width", width);
}
}
Something important has been said by Tom:
if you use the has-a concept, you avoid the issue.
Indeed, if instead of using extends and implements you define two attributes, one of type rectangle, one of type JLabel in your Tile class, then you can define a Rectangle to be either an interface or a class.
Furthermore, I would normally encourage the use of interfaces in connection with has-a, but I guess it would be an overkill in your situation. However, you are the only one that can decide on this point (tradeoff flexibility/over-engineering).
For interfaces with member variables, use an abstract class:
public abstract class Rectangle {
int height = 0;
int width = 0;
public abstract int getHeight();
public abstract int getWidth();
public abstract void setHeight(int height);
public abstract void setWidth(int width);
}
An ancillary point:
I always thought declaring attributes in an interface is sort of an anti-pattern as interfaces are stateless. And I haven't had a practical use case for it until I required dependency injection on all the concrete classes implementing the interface. While I could manually inject the dependencies on each class, it would be easier to inherit them from a parent class.
So, as many people have already mentioned, using an Abstract class is the way to go where the dependency can be injected (#Inject), and all the child classes could extend this and override (#Override) the methods while using the attributes of the parent class.
This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
Why do abstract classes in Java have constructors?
abstract class constructors?
We know abstract class can't be instantiated but on the other hand it can have constructor. Please explain why abstract class can have a constructor ? How compiler handles this situation?
The constructor of an abstract class is used for initializing the abstract class' data members. It is never invoked directly, and the compiler won't allow it. It is always invoked as a part of an instantiation of a concrete subclass.
For example, consider an Animal abstract class:
class Animal {
private int lifeExpectency;
private String name;
private boolean domestic;
public Animal(String name, int lifeExpectancy, boolean domestic) {
this.lifeExpectency = lifeExpectancy;
this.name = name;
this.domestic = domestic;
}
public int getLifeExpectency() {
return lifeExpectency;
}
public String getName() {
return name;
}
public boolean isDomestic() {
return domestic;
}
}
This class takes care of handling all basic animal properties.
It's constructor will be used by subclasses, e.g. :
class Cat extends Animal {
public Cat(String name) {
super(name, 13, true);
}
public void groom() {
}
}
This is probably not the best explanation but here it goes. Abstract classes enforce a contract much like an interface but can also provide implementation. Classes that inherit from the abstract class also inherit the implemented functions and depending on the language you can override the default implementation as needed.
Say you have abstract class A:
abstract class A {
private int x;
public A(int x) {
this.x = x;
}
public int getX() {
return x;
}
}
Notice, that the only way to set x is through the constructor, and then it becomes immutable
Now I have class B that extends A:
class B extends A {
private int y;
public B(int x, int y) {
super(x);
this.y = y;
}
public int getY() {
return y;
}
}
Now B can also set x by using super(x) but it has on top of that an immutable property y.
But you can't call new A(5) since the class is abstract you need to use B or any other child class.
Abstract class can have constructor that can be called in derived classes. So usually constructor is marked as protected in abstract class.