Creating Superclasses and Subclasses Java quesiton - java

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.

Related

What if my subclasses have different methods too?

I have a question about polymorphism in Java. I have a abstract base class Shape and two derived classes Rectangle and Circle. I know that I can call overridden methods in Circle and Rectangle class with a Shape class reference but what if I have a method that Shape class doesn't have but Circle class has. How can I use polymorphism in this situation?
You cannot use polymorphism in this situation. The very idea of polymorphism is that you can use an object in a specified way irrespective of its actual shape (specific object type). By requiring access to a method that is unique to (literally) a specific shape, you must forego polymorphism.
(The above argument would not apply if Circle actually had subclasses, in which case you could polymorphically call these methods, but this is just moving the argument somewhere else.)
This happens all the time. The answer is that you need to cast your Shape to a Circle to access the method
Shape s = ...;
if (s instanceof Circle) {
((Circle)s).foo(); //method only on Circle
}
If you store a Circle in a Shape instance, you can invoke Circle methods on s by casting s to Circle:
Shape s = new Circle();
...
if ( s.instanceof(Circle) ) {
((Circle)s).circleMethod();
}
Apart from the casting solution suggested by other answers, if you think all subclasses of Shape should provide that method but you can't/don't want to implement it on Shape, you can declare the method as abstract and implement the method in Circle and Rectangle.
public abstract class Shape {
public abstract void foo();
}
public class Circle extends Shape {
public void foo() {
// Implementation
}
}
then you can do:
Shape s = new Circle();
s.foo();

How can I add method to an existing object in Java?

I'm using a Processing library to build my project in Java. I use a function that returns me an object of type PShape (which I don't have access to source).
I need to make this object of type Shape (a class I designed that extends PShape).
How can I make that?
Basically I have:
PShape pShape = loadShape(filename);
Where loadShape is a function I don't have access to source code.
I want to somehow do:
class Shape extends PShape {...}
and then
Shape shape = (Shape) loadShape(filename);
But it won't work, once loadShape() will give me a PShape, not a Shape
How can I make loadShape returns a Shape?
Thank you
If loadShape() returns a PShape, then it returns a PShape. You can't make it return a subclass of PShape.
Easiest approach would be Shape either copies the PShape into a new instance:
e.g.
Shape myLoadShape(String filename)
{
return new Shape(loadShape(filename));
// Assumes you have a `Shape(PShape)` constructor.
}
or perhaps Shape isn't a subclass, but it contains a PShape data member.
class Shape
{
// No one picked up my C++ syntax goof ;-)
protected PShape pshape;
// Using a constructor is just one way to do it.
// A factory pattern may work or even just empty constructor and a
// load() method.
public Shape(String filename)
{
pshape = loadShape(filename);
// Add any Shape specific setup
}
}

Initialize superclass variables (needed in constructor) in a subclass

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 :-)

Can And Object Be Controlled By Multiple Classes? (and how to stop this happening)

I have a Point object that holds coordinates, I then use that Point in the creation of two other objects, a Triangle and a Circle, then inside circle object I translate that point. It also translates the point in the triangle class. Why is this? Have I just set up two variables to access the same object rather than have a 'copy' of that object in both shapes? How can I amend this?
I create the point in the main class then pass that point onto the constructors of both the Circle and Triangle classes which then assign it to a property of that class.
So it's like this:
//main class
Point p = new Point(50,50);
Circle c = new Circle(p);
Triangle t = new Triangle(p);
c.translate(20,30); //also translates the triangles point
//Circle class
public Circle(Point p) {
this.p = p;
}
//Triangle class
public Triangle(Point p) {
this.p = p;
}
Yes, you passed two references to the same Point object to Circle and Triangle.
To avoid this, there are basically two solutions:
create a copy of the Point object (either before passing it to Triangle and Circle, or in the constructor of those two classes, to make sure they use a different instances)
make the Point class immutable (all fields final, no setter), to make sure nobody can ever modify a Point. To translate a point, you would then be forced to create a new Point, with new coordinates. This is much safer, because you can't forget to make a copy. The immutability guarantees that the point can be shared between shapes without any way for them to modify each other by modifying their points.
The constructors for both your Circle and Triangle classes just assign the Point they are given to a data member. In this way, you're storing a reference to the same object, and every time it's manipulated, it will effect all references to it.
A safer way of handling such situations is, as you suggested, to copy the object passed to the constructor. E.g.:
//Circle class
public Circle(Point p) {
this.p = new Point(p.getX(), p.getY());
}
Alternatively, if you defined Point as clonable:
//Circle class
public Circle(Point p) {
this.p = p.clone();
}
Your making one instance of the Point object and making references to that one Point object in the Circle and Triangle object instances. The translate method modifies that Point object.

Setting an instance variable of a child class that extends an abstract class

I have a class called Shape that is abstract, and a class named Circle that extends Shape
Shape shapeCircle = new Circle();
I can set and get colors of shapeCircle fine because the color getters and setters are in Shape , but the dimensions of Circle is only for the Circle class (radius).
If Circle class has an instance variable private int radius and a method called getRadius(), how can I get/set the radius of shapeCircle? I tried shapeCircle.getRadius();, but no luck.
Only methods of Shape are accessible with object shapeCircle.
shapeCircle is type Shape, methods in Circle are not visible.
By using this,
Circle shapeCircle = new Circle();
you can call both method of Circle and Shape. The above case is take advantage of only Inheritance.
Edit
But if you add public abstract int getDimension(); in Shape class and Circle class implements getDimension() method
#Override
public int getDimension() {
return radius;
}
All classes that extends Shape needs to implements getDimension() method. But each subclass has its own dimension.
You can use
Shape shapeCircle = new Circle();
shapeCircle.getDimension();
This takes advantage of both polymorphism and abstract class.
Shape shapeCircle = new Circle();
Here the reference is of Shape and shape class doesn't defines radius variable.So you cannot use shapeCircle.getRadius();
To invoke get/set radious method type cast the shapecircle variable like this
Circle shapeCircle = (Circle)shapeCircle;
Now you can invoke the get/set radious methods. Please note that typecasting code should be in some different method to benefit using polymorphism.
EDIT:
You should design your abstract classes or interfaces to be having all important/common operations/methods which will help you in writing polymorphic code. For example: Radius field is specific to a Circle class.But consider you eventually want to calculate the area. So you should define CalculateArea() method in your abstract class and let every shape implement this method.This way, you achieve polymorphism.
Shape ShapeCicle = new Circle(Radius);
Float area = ShapeCircle.area();
Point is don't confine yourself with the radius example.Try to define classes in a way so that you can benefit from polymorphism.
You have to use instanceof keyword to check for the original type here . If the type is Circle, then you can type cast and call the getRadius method. Something like
if (shapeCircle instanceof Circle) {
Circle circle = (Circle)shapeCircle;
int radius = circle.getRadius();
}
That should do.
'Shape is not Circle' = Circle methods not available for Shape.

Categories

Resources