Hi chaps, I am looking for a not too difficult exercise which involves superclasses and subclasses (the java book I am reading doesn't really have any good one). So I was thinking about something like this:
Create a superclass 2DimensionalShapes and 2 subclasses Rectangles and Triangles. I will then need to calculate the area and perimeter of a Rectangles object and a Triangles object.
I am thinking to have the sides declared in the superclass and perhaps the methods in the subclasses, not sure what's best. Do you guys have any suggestion at all as to whether this could be a good exercise and the best way to implement it?
thanks

Recommended Answers

All 16 Replies

It's a reasonable one to start with - small and easy. Just get stuck in and try a few things and see what works best.
Implementation: simple guideline: put everything you can that is used in >1 subclass in the superclass, so you only have to do it once. This includes methods and variables. You may be able to think of some way to generalise what's in the subclasses to allow this.

thanks, I will build an application that does that then.

put everything you can that is used in >1 subclass in the superclass, so you only have to do it once

I was thinking about that too: I was thinking to have the methods int he superclass - calculate the area and perimeter of the 2 shapes - but the way they are calculated is different for each shape, so how do I account for that? Also the superclass will have only 2 variables representing the 2 sides of a shape, but the triangle needs 3, so should I declare a third side in the superclass or subclass?
thanks

Technically, both the triangle and the rectangle can be specified by a point and two vectors ;)

area and perimeter are ideal candidates for abstract methods in the (abstract) superclass with concrete implementations in each subclass - ie every Shape can calculate and return its area, but exactly how that happens is different in each subclass.
Sides are a bit more interesting... the two sides of a rectangle are not the same things as two sides of a triangle. Yes, they are all examples of a length, but they mean different things, and you can't use them in the same ways. Personally I would not try to share them, I'd have length and width in Rectangle vs side1,side2,side3 in Triangle

commented: Good choice for the exercise. +14

ah ok, so I should use abstract classes....ok I just read about them in my java book. Ok I will give it a go, not sure if I will implement it correctly. I will post the finished code later
thanks

Ok so essentially my TwoDimensionShape abstract class will look like this:

/*TwoDimensionShape.java, Superclass*/
public abstract class TwoDimensionShape{

    private double area;
    private double perimeter;
    //constructor uses the empty default one because there is nothing to set    
    //getters   
    public double getArea(){
        return area;
    }

    public double getPerimeter(){
        return perimeter;
    }

    //calculates area of shape
    public abstract double calculateArea();
    public abstract double calculatePerimeter();
}//end of class TwoDimensionShape

Problem there is that the "user" of this class has to know to call calculateArea before calling getArea, and do the same every time the dimensions of the Shape could change. It would be safer and easier to get rid of the area variable and the calculateArea method; just make getArea abstract and let the subclasses decide how to implement it. Unless you have some very extreme stuff going on it will be perfectly OK for the subclasses to calculate the area in their getArea() implementations, thus guaranteeing that it is always the current correct value. (Ditto for perimeter)

Oh I see tha will leave me with pretty much an empty superclass..

/*TwoDimensionShape.java, Superclass*/
public abstract class TwoDimensionShape{
    public abstract double  getArea();

    public abstract double  getPerimeter();
}//end of class TwoDimensionShape

Now, when you say that the subclasses will calculate the area and perimeter themselves in their own getArea()/getPerimeter() do I have to use the @override notation to achieve that correct?
One more thing, I take it is ok to declare all the variable in the subclasses as private?

Yes, so far it's pretty small - just an interface realy, but as you add stuff it will grow, eg if Shapes have a position (x,y coordinates) or a Color then all that can be handled in the superclass.
The @override annotation is always optional, but it's strongly recommended both for documentation, and because the compiler will then check that you are overriding correctly.
In general you should start by declaring all your variables as private, and only change that if you find a real need to - the one exception is when you declare variables in the superclass that you need to use in its subclasses. Oh, and the other exception is static final "variables" (a.k.a. constants).

Right, I have done the small application that calculates the area and perimeter of a triangle and a rectangle. The files with the code are attached.

Here's the output, which is what I have expected:

Rectangle information:

 Base of rectangle is : 10.000000
 Height of rectangle is : 5.000000
 The area is  50.000000
 The perimeter is : 30.000000

Triangle information:

 Base of triangle is : 10.000000
 Height of triangle is : 6.000000
 SideB of triangle is : 7.000000
 SideC of triangle is: 8.000000
 The area is : 30.000000
 The perimeter is : 25.000000
antobbo@antobbo-xps17-ubuntu:~/Documents/dell xps/My documents/java/tests/superAndSubClasses$ 

Needless to say I have a few questions:

1) the superclass, as said previously is pretty small:

/*TwoDimensionShape.java, Superclass*/
public abstract class TwoDimensionShape{

    public abstract void calculateArea();

    public abstract void calculatePerimeter();

}//end of class TwoDimensionShape

I wonder, what is the point of have those 2 methods in the TwoDimensionShape class? I appreciate that perhaps the choice of figures (rectangle and
triangle) wasn't the best ever because they don't have much in common so I suppose I could have done without the TwoDimensionShape class at all?

2)the infamous toString method. For the triangle (and the rectangle) I have used this:

@Override
    public String toString(){
        return String.format(
            "%s: %f\n %s: %f\n %s: %f\n %s: %f\n %s: %f\n %s: %f\n",
            "Base of triangle is ", getBase(),
            "Height of triangle is ", getHeight(),
            "SideB of triangle is ", getSideB(),
            "SideC of triangle is", getSideC(),
            "The area is ", getArea(),
            "The perimeter is ", getPerimeter() 
        );

Now, I used String.format() just because my book does it, and I wonder, could I have used a normal System.out.printf(...) inside the toString method instead of String.format? Is there any difference between the two?

If anybody fancies looking at the files, they are attached in a zip, I thought it would be a waste of space to have them all displayed in the thread.
thanks

toString: you have to return the String, not print it, so what you did is OK (maybe too much detail?)

The superclass isn't doing anything useful yet because you don't have a suitable test/demo case.
For example - suppose this is part of some kund of graphics app - so we'll add some stuff to the superclass like:

  int x, y; // position of shape
  void setPosition(int x, int y) ... etc
  Color color; // with accessors as usual
  abstract void draw(Graphics g); // draw the shape

and implement it in each subclass, eg

   (in Rectangle)...
   @override
   void draw(Graphics g) {
      g.setColor(color);
      g.fillRect(x, y, width, height);
      // uses color, x, y from superclass, width & height specific to this subclass
   }

then in some kind of window you could have something like

  ArrayList<Shape> shapes = new ArrayList<Shape>();
  shapes.add(new Rectangle...
  shapes.add(new Triangle...
  ...

  public void paintComponent(Graphics g) {
     for (Shape s : shapes) {
         s.draw(g);
     }
  }

thanks JamesCherril. I appreciate that my example isn't probably the best ever, but even in general terms, having a superclass that sets some values and some methods (I have read your example) seems in a way a waste because surely all the methods and variables declared in the superclass can easily be declared in the subclasses, more so if they are declared as abstract (now, bear in mind that I am really new to this concept of declaring an abstract class/method) because the abstract methods and classes practically don't seem to be that useful.

About the toString method I have just followed an example found on my book. You say I only need to return the string not to print it, so does it mean that I don't need to use a String.format() at all? If so how do I print the values, I mean where do I put all this code:

        "%s: %f\n %s: %f\n %s: %f\n %s: %f\n %s: %f\n %s: %f\n",
        "Base of triangle is ", getBase(),
        "Height of triangle is ", getHeight(),
        "SideB of triangle is ", getSideB(),
        "SideC of triangle is", getSideC(),
        "The area is ", getArea(),
        "The perimeter is ", getPerimeter() 

Sorry I don't find the the toString() overload method the friendliest one is causing

Declare them in the superclass - do it once - efficient
Declare them in each subclass - do it many times - inefficient and error-prone.

Your toString is OK. Don;t worry. It returns a nicely formatted String describing the object. It doesn't have to be so well formatted, or so detailed, but that's OK too.

Ok, I can obviously see that the idea is sound - and hey I didn't mean to criticise that, surely if everybody does that there is a good reason for it - it's just that being still at the beginning of my java trip I perhaps still don't appreciate the big picture : -)!
But that toString method, I really find it bemusing at times, it's like magic in a way!
Anyway, thanks for your help as usual much appreciated!

toString is really simple, no magic at all.
There are many times during development and debugging when you want to see the value of a variable. So you need a way to print/display any random Object. That's toString(). It's implemented on the Object class, so every possible object will have that method. So, for example, when you call
System.out.println(myObj);
the println method calls myObj.toString() and prints the resulting String.

Because it's intended for debugging not for final user interfaces, it usually returns a short, often technical, description, eg

class Rectangle {
   ...
   @override
   public void toString() {
      return "Rectangle " + width + "x" + height;
   }

You used String's format method to ctreate a beautiful String. That's OK, but not really necessary.

Simples!
J

eh eh, ok thanks for clearing that up, hopefully I will get that in my head then! I think it was also the fomat method that I haven't come across before to confuse things. Should be ok now, thanks : - )

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.