Initialize superclass variables (needed in constructor) in a subclass - java

I'm writing a simple Asteroids-clone game, using Swing to display the graphics. I'm kind of following Derek Banas' tutorials, but decided to expand on my own.
The original idea is that every graphic element in the game (i.e. the Asteroids, the Spaceship and the Bullets) extends the Polygon class. Their constructor would look something like this:
public class SpaceShip extends Polygon {
//x and y coordinates
public static int[] polyXArray = {...};
public static int[] polyYArray = {...};
//other class variables
{...}
public SpaceShip() {
super(polyXArray, polyYArray, polyXArray.length);
}
}
And it will be similar for the other graphic elements.
EDIT: The key element here is that the two arrays don't store the actual coordinates of the objects, but their position relative to their centre, whose coordinates are double-type class-variable. Thus, the arrays describe just the shape of the object, while the subclass move() method will affect the centre's coordinates. The class responsible for the actual drawing will call the move() method and then apply an affine transform to move and rotate the shape (according to a properly defined angle parameter). I'm doing this to avoid precision problems related to dealing with double arithmetic.
Now, since the elements share a lot of "equal" variables (their centre coordinates, which I need in order to translate them with an affine transform, their speed components etc...) and methods (getters and setters, move() methods, etc...) I thought about making them be the extension of an abstract class - say, GameShape - which holds all these common methods and variables. GameShape would now be the one extending Polygon directly:
public abstract class GameShape extends Polygon {
//x and y coordinates, still unassigned
public static int[] polyXArray, polyYArray;
//other class variables
{...}
public GameShape() {
super(polyXArray, polyYArray, polyXArray.length);
}
}
Then, I'd want to assign the desired value to polyXArray and polyYArray when I define the different subclasses in order to draw the different shapes I need, but I haven't been able to find a way to do it.
I do want those variable to be static because they are specific properties of the single classes, and I wouldn't want to pass them as a parameter every time I instantiate a new object.
My situation is very similar to the one described in this question, but the proposed solution doesn't seem to work, since I need those very variables in the constructor. Is there a way to get over - or around - this problem? Regardless of the procedure, my main aim is to have a superclass common to all the graphic elements, in order to avoid tens of lines of copy-pasted code.

You have pairs of arrays that describe the shapes of specific kinds of game objects. If different game objects can have different shapes, then they cannot all share a single pair of arrays, as would be the case if they were static properties of a common superclass of all the game object classes. Different objects of the same kind can share the same pair of arrays (supposing that those don't need to be modified on a per-object basis), which could correspond to those arrays being static fields of the concrete game object classes. In that case, however, if you want a superclass of those classes to be able to access the correct shape data for a given game object, then it has to be told what those shape data are.
There are two main ways you could do that:
You could pass the appropriate shape arrays to the superclass's constructor. You say you don't want to do this, but I don't understand why.
You could define accessor methods on the superclass that the subclasses are supposed to override to provide the correct shape data (this is called the Template Method pattern).

The solution from this question will work if your classes will NOT extend shape, but provide shapes via accessor + private static field.
public abstract class GameObject {
...
public abstract Polygon getShape();
This also helps to escape shapes duplication.

If you really do want to initialize things in your constructor, just call the empty super(); and then loop against abstract getPolyXArray() and getPolyYArray() to feed addPoint.
public abstract class GameShape extends Polygon {
public GameShape() {
super();
final int length = getPolyXArray().length;
for (int i = 0; i < length; i++) {
addPoint(getPolyXArray()[i], getPolyYArray()[i]);
}
}
public abstract int[] getPolyXArray();
public abstract int[] getPolyYArray();
//common stuff...
}
public class Asteroids extends Polygon {
public int[] getPolyXArray() { return new int[]{1, 2, 3}; }
public int[] getPolyYArray() { return new int[]{1, 2, 3}; }
}

The array fields cannot be static because different shapes have different coordinates. Also you don't need these arrays in the specific subclasses because they are already in Polygon or GameShape.
Here is more-or-less how I would write GameShape (although I agree with #Michael that you don't need to pass both polyXArray and polyXArray.length to the constructor).
public abstract class GameShape extends Polygon {
// I got rid of the array fields as I think they are in Polygon anyway.
//other class variables
{...}
// I added arguments to your constructor.
public GameShape(int[] polyXArray, int[] polyYArray) {
super(polyXArray, polyYArray, polyXArray.length);
}
}
The trouble is that super must be the first line of a constructor, but you can do it using private methods to build the arrays:
public final class BoringRectangle extends GameShape {
public BoringRectangle(int left, int right, int top, int bottom) {
super(xArray(left, right), yArray(top, bottom));
}
private static int[] xArray(int left, int right) {
return new int[] {left, right, right, left};
}
private static int[] yArray(int top, int bottom) {
return new int[] {bottom, bottom, top, top};
}
}

I would think that polyXArray and polyYArray reside in the Polygon class; that's where they belong. Therefore it's not a good idea to have duplicate fields. Also, get rid of the ned to call the super constructor. I would design the class structure like this:
public class SquareShape extends Polygon {
private int size;
public SquareShape(int x, int y, int size) {
this.size = size;
int[] xpoints = new int[4]{
x - size / 2,
x - size / 2,
x + size / 2,
x + size / 2
};
int[] ypoints = new int[4]{
y - size / 2,
y + size / 2,
y + size / 2,
y - size / 2
};
setXArray(xpoints);
setYArray(ypoints);
}
}
This way, you can ensure that all SquareShape objects do indeed have a square shape, but you can customize things you should be able to customize. Like position and size, which should not be static shared fields. setXArray and setYArray should be protected methods residing in Polygon. You don't want the outside world messing with the individual points. You can add public getters, although.
NOTE
You may want to consider using a single array of a complex Point type, rather then two tightly coupled and dependent arrays. I feel like this will greatly simplify a lot of tasks in your project.

EDIT:
As VGR stated in the comments, this will not compile. So, we will have to change the implementation a little, namely, we will use the HAVE relationship instead of IS relationship :-)
First of all, do not make the poly array fields static. If you do, they will be the same for all of the subclasses as well, so what is the point?
Secondly, use a template method design pattern here. Your class will look something like this:
public abstract class GameShape {
//x and y coordinates, still unassigned
public int[] polyXArray, polyYArray;
private Polygon polygon;
//other class variables
{...}
public GameShape() {
instantiatePolyArrays();
this.polygon = new Polygon(polyXArray, polyYArray, polyXArray.length);
}
protected abstract void instantiatePolyArrays();
public final Polygon getPolygon(){
return this.polygon;
}
}
Every extending class will have to override this method and you can instantiate the arrays for each of the classes in each of the method overrides.
Also, a word about the IS-HAVE relationship problem - what you presented in your example is a IS relationship, in which the GameShape object IS a Polygon, hence the need to call the super constructor and the problem with that. In my solution this is replaces by a HAVE relationship, in which the GameShape object HAS a Polygon object inside, accessed with a getPolygon() method. This allows you to have lots of additional flexibility :-)

Related

Creating Superclasses and Subclasses Java quesiton

i started learning Java in university and we have an assignment that requires us to use a Superclass for Shape and Subclass that extend the shape.
This is the full questions:
Create a super class “Shape” from which you derive two subclasses “Square” and “Rectangle” with functions to calculate the square area and the rectangle area. In addition, to the function “toString” to display the square and rectangle info. Derive another sub class “Cube” from square with a function to calculate its area and a function “toString” to display the cube info."
What we need to do is calculate the shapes using the classes. Where should I start or move forward to solve the assignment?
This is where I think I should start, but need some guidance
public class Shapes {
class Shape {
}
class Rectangle extends Shape {
}
class Square extends Shape {
}
}
First, Shape class should be abstract, since you won't create any specific object of this class and you'll only use it as a "canvas".
This class has to have an abstract method, let's call it getArea(), that you'll have to override in your child classes to accomodate to the specified requirements for each kind of shape.
The toString() method belongs to Object class, since every class in Java extends from Object, you don't have to define anything, just override this method to return the desired String in every child class.
According to the definition you have post, the Cube class would be a composition of Square (a cube is composed by squares, but it's not a square), so I'd extend it from Shape and define it as a List or an array of 6 Square, so the getArea() of Cube would be the summatory of every Square area in it.
Putting aside the quality of the question:
You have a Shape class that will contain a method calculateSomething().
Shape does not define a specific shape so most likely you can return a -1 or 0?
Now, we can determine that the method of the Shape class does not provide us with any real value/info. Even if you create a Shape shape = new Shape() object and call its method, it does not help us at all.
Instead it provides us with a method that each subclass has to override in order to get the intended results.
What does that mean and how it works?
For you to not always have to do Rectangle rect = new Rectangle() for every single class and object, the Rectangle becomes a subclass of the Shape class.
This enables you to later do Shape rect = new Rectangle().
The big benefit of this is that you create an abstraction mechanism, meaning that you have a lot of shapes, either rectangles or triangles etc, but they all are Shape objects in the end.
So later you can just do:
Shape rect = new Rectangle();
Shape triangle = new Triangle();
rect.calculate();
triangle.calculate();
Instead of the more meticulous:
Rectangle rect = new Rectangle();
Triangle triangle = new Triangle();
rect.calculate();
triangle.calculate();
The former can further be utilised by:
// Putting all the objects in a list
List<Shape> shapes = new ArrayList<>();
// Create objects and add them
Shape rect = new Rectangle();
Shape triangle = new Triangle();
shapes.add(rect);
shapes.add(triangle);
As you can see for yourself, it is easier to handle and iterate over a list with all the elements being of type/class Shape.
// Basic example
for (Shape shape : shapes)
shape.calculateSomething();
Imagine if you had a hundred different shapes except Rectangle and Triangle. The latter method, without using inheritance, would quickly come to consume your project in an ever ending trial of maintenance and code changing.
By utilising inheritance otherwise, you can increase your Shape classes as much in quantity as you want and the same methods that used to work for a Shape, would still work for all the future new objects.
How does it work in practise? How do i create a subclass?
As you already know you can link your classes through the extend keyword.
But that is only the start.
To be able to utilize the inheritance, you will have to overwrite the method of your choosing, in the child class.
Take for instance the previous example:
Shape rect = new Rectangle();
rect.calculate();
But that raises the question, how can you get the correct value of calculate() method, when Shape class has a -1 or 0 returning from it and rect variable is now of type Shape?
Easily, you can override a method of the parent class through the #Override tag and by implementing the same method again on the child class but with different calculations. Example:
class Shape {
public void calculate() { return 0; }
}
class Rectangle extends Shape {
#Override
public void calculate() { return 2; }
}
Note that the name, variables etc of the method must be identical.
Now in the case of:
Shape rect = new Rectangle();
rect.calculate();
the calculate() method will return the number 2.
This happens because even though the rect object is of type Shape, it is also a Rectangle. Every Rectangle is a Shape. So when you try to call the desired method, the program knows to choose the overrided method of the Rectangle class, because in essence it is a Rectangle, covered by the abstraction Shape.
This works for any number of Shape subclasses, each with their own unique implementation of the method.
Also note that a Rectangle subclass can have its own private fields that are used in the other methods:
class Rectangle extends Shape {
private int height;
private int width;
// constructor
public Rectangle(int h, int w) {
this.height = h;
this.width = w;
}
#Override
public void calculate() {
return this.w * this.h;
}
}
So to answer your question, you just override the methods you want for each class as you desire. If a method is not overriden, then the original of the Shape parent class is run.
I hope this shined a little bit of light in your confusion towards abstraction and inheritance.
PS:
I know that you might be confused, but there are hundreds of answers and forums out there explaining this exact thing and that is how we all learned it. It needs time unfortunately but you will have a deeper understanding if you look at something yourself. I'm sure you have taken a taste of what is defined as 'wrong' or 'bad' to ask in here and that you will be more susceptible into studying it yourself in the future, considering there is material needed. I just tried to reach out to you because i have been in your place and believed i could make a difference with my approach.
If you have anything else to add or something to correct, it is always welcome in the comments section.
Edit:
As mentioned by the other guy that answered, the Shape class can and should be an abstract one. I just assumed you wanted it to be a normal one.

How to implement multiple subclasses with the same methods that use encapsulation?

I want to create a simple game in Java.
I'm struggling to understand how to use inheritance to accomplish how to implement subclasses that use encapsulation without needing to write out the same methods in the subclasses.
Ideally I'd like to make one base class "character" with a bunch of methods that use encapsulation, so that I can just declare different values for the private members of the subclasses. So something like,
public class Character {
private int hitPoints;
public int getHitPoints(){return hitPoints;}
}
And then just declare different values for the variables.
public class subCharacter extends Character {
private int hitPoints=100;
//getHitPoints() already inherited and should return 100
}
But to properly get the hit points of the subclass. I have to declare the same method in the subclass to actually get the method to work.
So isn't encapsulation incompatible with inheritance? Is there something basic here I'm misunderstanding or completely overlooking?
You should make the variable hitPoints protected in you Character class, and set it to 100 in the constructor of the subCharacter class. There is no need for the declaration of the getHitPoints method in the subclass. The code would look like this:
public class Character {
protected int hitPoints;
public int getHitPoints(){return hitPoints;}
}
public class subCharacter extends Character {
public subCharacter () {
hitPoints = 100;
}
}
Example of a subCharacter object:
subCharacter sub = new subCharacter();
System.out.println(sub.getHitPoints()); // prints 100
The reason this doesn't work like you think it should is because the subclass's hitpoints field is different from the superclass's hitpoints field. So while the superclass method is defined, it's trying to refer to a variable that you never actually initialized because it's not the same variable named hitpoints.
As others have already said, you should use the protected access modifier instead of the private access modifier on fields you want to have inherited to a subclass.
Then again, you probably don't actually need the SubCharacter class to begin with, if this is what you're actually writing for. You just need to have a constructor that takes a variable argument for hitpoints, or any other field in Character that needs to take different values.
//I'm not going to reproduce everything.
Character(int hp, String nm, boolean someBooleanThatIJustMadeUpToGetTheConceptAcross){
hitpoints = hp;
name = nm;
randomBoolean = someBooleanThatIJustMadeUpToGetTheConceptAcross;
}
This is not to say, however, that you don't need a superclass/subclass if, say, you're using this Character class for both enemies and player characters, for instance.
For an example of when you'd use inheritance...
public class Circle{
protected int radius;
Circle(){//It's always a good idea to have default constructors, by the way.
radius = 1;
}
Circle(int rad){
radius = rad;
}
}
public class Wheel extends Circle{
protected int numspokes;
Wheel(){
super(); //Calls the constructor for Circle, instead of reimplementing the wheel. badpuns++;.
numspokes = 0;
}
Wheel(int rad, int spokes){
super(rad); //This passes the radius up to the Circle this Wheel also is, so that any calls to this Wheel AS IF IT WAS a Circle, like an array or ArrayList of Circles, will function, which is the point of inheritance.
numspokes = spokes;
}
}

Subclass and Superclass methods

I'm creating a monopoly game with different types of squares.
Square is the Superclass and PropertySquare is the Subclass.
I've created a loop that rolls the dice and moves the players to a different square. The squares are in an array list and I am able to call the superclass methods on them. However, even if the squares are set to more specific types (subclass of square), I cannot call the subclass methods on them.
This is how I have initialised the squares in a board class.
private static final ArrayList<Square> squares = new ArrayList<Square>(40);
squares.add(1, new PropertySquare("Old Kent Road", 1, 60, "Brown"));
board.getSquare(pos).getName());
getName is a method in the superclass square. However, even if the square is a property type, I cannot call the methods in the PropertySquare class such as getPrice();
How would I change this or be able to call the subclass methods?
I assume board.getSquare() returns a Square, and Square doesn't have any getPrice() method, so you can't call getPrice() over an object declared as Square, even if the instance is actually a PropertySquare (a.k.a. polymorphism). To do so, you have to first cast to the specific subclass. For example:
final Square square = board.getSquare(pos);
if (square instanceof PropertySquare) {
((PropertySquare)square).getPrice();
}
You should use Generics with the ArrayList.
If your list only contains of type PropertySquare, do it like this:
private static final ArrayList<PropertySquare> squares = new ArrayList<>(40);
squares.add(1, new PropertySquare("Old Kent Road", 1, 60, "Brown"));
Then the list will returns objects of type PropertySquare.
If the list can contain any type of square, do it like this:
private static final ArrayList<Square> squares = new ArrayList<>(40);
squares.add(1, new PropertySquare("Old Kent Road", 1, 60, "Brown"));
Square sq = squares.get(0);
if(sq instanceof PropertySquare){
PropertySquare pSq = (PropertySquare) sq;
//now you can use any method of PropertySquare
}
The problem in your code is that your object is of type Square and does not know anything about the methods of any subclass. So you have to do a type cast.
you could handle the landing square in a group of ifs like:
if (square instanceof PropertySquare) {
((PropertySquare)square).getPrice();
}else if(square instanceof PrisonSquare) {
//do nothing
}//etc..
Your declared ArrayList is bound to Square meaning you will have a collection of Square objects and a Square reference when interacting with any items despite at run-time it being an instance of a subclass. This is known as polymorphism.
Due to the fact that the references are of type Square the only methods Java knows about are those declared in Square and any other inherited methods. For you to be able to call methods of a subclass you would need to check whether the reference is pointing to an instance of PropertySquare and then down-cast the reference to PropertySquare. You're then saying, it's okay I know its an instance of PropertySquare so I can safely call the getPrice() method declared in PropertySquare.
if (square instanceof PropertySquare) {
((PropertySquare)square).getPrice();
}
Alternatively you can look at the instances class name:
square.getClass().getSimpleName(); // Would just give you PropertySquare
square.getClass().getCanonicalName(); // Would give you the fully qualified name e.g. com.foo.bar.PropertySquare
For more info:
https://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html
NB: I'm going to answer this in the more generic sense, I realise that not all Monopoly Squares have a price... But the problem itself, in code, can be solved in two ways.
If all of your items have a price, you probably want to use an "Abstract" base class.
You then put in the methods in the superclass as
protected abstract int getPrice();
and implement it in your subclass.
So you could have subclasses such as undevelopedSquare, propertySquare, gardenSquare etc.
However, in the case of Monopoly, if only the propertySquare instances have getPrice, you should use
if (square instanceOf PropertySquare) {
price = ((PropertySquare)square).getPrice();
}
NB2: You also have "utilitySquare"s such as the Waterworks, which would have different properties alongside the price (you can't build a hotel on a utility even though you can buy it).
So in this case, maybe Interfaces would be more appropriate such as:
interface PlayableSquare -> Generic square things, you can land on one for instance
interface SaleableSquare -> has pricing etc
interface BuildableSquare -> can build hotels
And then have your generic as
private static final ArrayList<? extends Square> squares
The PropertySquare would then be:
public class PropertySquare extends AbstractSquare implements SaleableSquare, BuildableSquare
where the Abstract class implements "PlayableSquare". Although that may be a step too far as it would almost just be a marker interface.
you can use instanceOf to check for each interface implementation, i.e. if a Utility has a different method you wish to call.

Accessing methods via OBJECTS vs INHERITANCE

Consider this child class :
public class Circle extends BasicAreas{
public static void main(String args[])
{
BasicAreas ba = new BasicAreas();
Circle c = new Circle();
c.PrintCircleArea(ba);
}
void PrintCircleArea(BasicAreas ba)
{
System.out.println("Area of circle is : "+areaCircle(3.14));
}
}
and the parent class :
class BasicAreas{
double areaCircle(double radius)
{
return 3.14 * radius * radius;
}
int areaSquare(int side)
{
return side * side;
}
int areaRectangle(int len, int breadth)
{
return len * breadth;
}
}
Now, i am pretty well confused about this... :
System.out.println("Area of circle is : "+areaCircle(3.14));
When i extend a super-class...i can access the methods of that class without using an instantiated object like above....but
when i do not extend a class, i can access its method using an object like :
System.out.println("Area of circle is : "+ba.areaCircle(3.14)); /* "ba" being object */
So my question is that when should i prefer using objects and when to use extend to access other class methods...and whats the difference between them on basic level??
learning java...so please go easy...i know the question is pretty dumb, but there is no clear answer....i am also open to possibility that this question might be conceptually wrong too!!!
So my question is that when should i prefer using objects and when to use extend to access other class methods...and whats the difference between them on basic level??
the inheritance represents a is-a relationship. but the composition represents a has-a relationship. you can choose any of these two to solve your problem but to make a good design it is important to choose between the right one.
so inheritance should be used only when a subclass is-a superclass. for example in the above example circle is a basicArea. Otherwise use composition.
you can see this article or plenty of others avaiable on net to find the differences between these two with example.
When your class is not in the inheritance hierarchy, then you should use object method. When you extend a class, then the child gets the method by default as if it is its own method. THis is because child class is susbclass of superclass. i.e. In your case, Circle IS-A BasicAreas.
When you do not extend the class, then you do not have access to method as long as you instantiate the object.
In both cases, you are accessing the methods with objects.
When i extend a super-class...i can access the methods of that class
without using an instantiated object like above
This is wrong.
In the first case, you are accessing areaCircle() method on instance c.
When A class extends a class it can access the methods in super class i.e
double areaCircle(double radius)
in your case and when you are writing
System.out.println("Area of circle is : "+areaCircle(3.14));
this statement you are actually using object(this) for accessing this method the only point here is you are not creating this object.
this statement will be interpreted like this
System.out.println("Area of circle is : "+this.areaCircle(3.14));
so you always need object to access a method until it is not static. Because you can access static methods directly with class name.

Java: What's the reason to write Supertype a = new Subtyp()`?

Assume that class B extends from class A.
So what is the advantage of writing something like this:
A myClassA = new B();
What's the difference to:
B myClassA = new B();
This is the concept of programming to interfaces(or supertype)
we use supertype reference so that it can hold any sub type instance
eg: assume we have Class B & C extending A
& some method which accepts A as parameter
void print(A a) {System.out.println(a);}
this method canbe invoked by passing any instance of A or its subtype
Because then if C is a subtype of A, you can say
myClassA = new C();
and your code would (should) still work as intended.
That you may assign an instance of A to myClassA later.
The reason is that if B extends A but all exposed API is defined in A you can treat the object as A without knowing its real type. If future you will probably add yet another implementation C that extends A as well and will probably start using C and B together but you will not have to change the code that uses these objects because it treats them as A.
Program to interface, not an implemenation.
For example,
A myClassA = new B();
Here you can change the implementation, new C() without affecting the existing code since you just exposed the interface.
A myClassA = new C();
or
A myClassA = getClassATypeInstance();
A good example is always that of shapes. Let's say we have two shapes, a circle and a square. Both have different properties, but we can get the area of both.
public abstract class Shape {
public abstract float area();
}
public class Circle extends Shape {
private float radius;
public Circle(float radius) {
this.radius = radius;
}
#Override
public float area() {
return Math.PI * radius * radius;
}
}
public class Square extends Shape {
private float width;
private float height;
public Square (float width, float height) {
this.width = width;
this.height= height;
}
#Override
public float area() {
return width * height;
}
}
Now what this implementation allows, is to calculate the area of all shapes regardless of what types they are. You can for instance have an array of Shapes and iterate over them, calling the area function of each shape and summing the areas up.
One should always put the right information in the right class. Circles and squares both have areas, and so does other shapes to, so it is safe to assume that area is a property of a shape, i.e. circle's have an area because they are shapes.
Putting it lower in the class hierarchy gives your code a healthy level of abstraction. It becomes sort of a "need-to-know-basis"-principle, where you should never have access to more code that you need at the moment. Another rule of thumb is to code so that you always cast from subtype to base, and never the other way around (which is a lot harder than it sounds).
A good example is the Collections API.
Look at the static "min" method of java.util.Collections.
The Parameter type is "Collection" and a lot of classes implement this interface.
You may get the min from a ArrayList (implements List extends Collection) or the values of a HashMap (HashMap.values() returns a private implementation of the Collection interface).
If the java.util.Collections.min() has a ArrayList as parameter type you couldn't use the method to get the minimum value of a HashMap.
Declare your variables and parameters with the basetype if you don't need the additional methods you get through the Subtypes.

Categories

Resources