Most efficient way of using toString() JAVA - java

I have 2 classes of shapes one is rectangle and the second is circle, both extend "shape" class.
I should print the relevant info from each class for example x, y represent a point which is relevant to all of the shapes and the color as well.
rectangle class has its width and height and circle has a radius.
I'm trying to use toString method in each class by overriding, using super and adding more info but one thing looks strange. should I create a new string builder object for each method? looks quite not right even though it works. Tried looking it up online but so far its either this or using a bunch of string. Am I missing something?
here is what I did in shape class:
public String toString() {
StringBuilder shapeBuilder = new StringBuilder();
System.out.println(shapeBuilder.append("The x axis is: ").append(x).append(" and the y axis is: ").append(y).append(" The color of ")
.append(this.getClass().getSimpleName()).append(" is ").append(color));
return shapeBuilder.toString();
}
rectangle class:
public String toString() {
super.toString();
StringBuilder rectangleBuilder = new StringBuilder();
System.out.println(rectangleBuilder.append("The height of the rectangle is: ").append(height)
.append(" And the width is: ").append(width));
return rectangleBuilder.toString();
}
circle class:
public String toString() {
super.toString();
StringBuilder circleBuilder = new StringBuilder();
System.out.println(circleBuilder.append("the radius of the circle is: ").append(getRadius()));
return circleBuilder.toString();
}
I'm calling them from main using object name.toString();

The obvious problems are
In your Rectangle and Circle class, you called super.toString() and do nothing with the result. There is no reason calling it. Or, I guess what you are trying to do is something like : (e.g. Rectangle )
public String toString() {
return super.toString()
+ " height " + this.height
+ " width " + this.width;
}
In your case, you do not need to explicitly use StringBuilder. Simply
e.g. Shape class
public String toString() {
return "The x axis is: " + x
+ " and the y axis is:" + y
+ " The color of " + this.getClass().getSimpleName()
+ " is " + color;
}
is good enough. Always-use-StringBuilder is not necessary better.

Use System.out.println(super.toString() to print/use super class toString().
Code Below:
public class Shape {
int x;
int y;
#Override
public String toString() {
return "Shape [x=" + x + ", y=" + y + "]";
}
}
public class Rectangle extends Shape{
double width,height;
#Override
public String toString() {
System.out.println(super.toString());
return "Rectangle [width=" + width + ", height=" + height + "]";
}
public static void main(String[] args) {
Rectangle rectangle=new Rectangle();
rectangle.x=10;
rectangle.y=30;
rectangle.width=20;
rectangle.height=100;
System.out.println(rectangle);
}
}

Related

Issues with writing a subclass of the Rectangle class in Java

I'm a student working on a project in Java where I need to practice using inheritance by extending the default Rectangle class; the child class MyRectangle needs to have constructors that accept parameters that describe the rectangle's border and fill colors as well as its dimensions. I also need to include getter/setter methods for the border/color attributes, a method that will rotate a rectangle by 180 degrees, and methods to calculate and return the area and perimeter of a rectangle. All of the required methods/fields are described in greater detail in the documentation file:///C:/Users/sweis/Downloads/MyRectangle.html
here, and the output should end up looking like this: https://i.stack.imgur.com/KP7LB.png
I've written some code, but I've gotten a lot of error messages referencing the portion of the program where I actually define the MyRectangle class and set up constructors, including "Non-static variable cannot be referenced from a static context" and "error: cannot find symbol". I'm pretty new at Java so I'm really not sure, but I'm afraid I'm fundamentally misunderstanding something about inheritance, and I'm struggling to resolve these errors on my own. I would really appreciate it if someone could look at what I've written so far and help me understand what I'm doing wrong so I can better understand this concept. Here are the portions that are causing problems:
import java.awt.Rectangle;
class Main {
public static void main(String[] args) {
MyRectangle mr1 = new MyRectangle(0, 0, 4, 2, "blue", "red", true);
MyRectangle mr2 = new MyRectangle(5, 5, 10, 3, "green");
MyRectangle mr3 = new MyRectangle();
System.out.println(mr1 + " " + "area = " + mr1.area() + " perimeter = " + mr1.perimeter());
System.out.println(mr2 + " " + "area = " + mr2.area() + " perimeter = " + mr2.perimeter());
System.out.println(mr3 + " " + "area = " + mr3.area() + " perimeter = " + mr3.perimeter());
System.out.println(mr4 + " " + "area = " + mr4.area() + " perimeter = " + mr4.perimeter());
}
public static class MyRectangle extends Rectangle {
public static int width, height;
public String color, borderColor;
public boolean border;
public MyRectangle() {
super();
}
public MyRectangle(int x, int y, int w, int h, String c) {
width = w;
height = h;
color = c;
}
public MyRectangle(int x, int y, int w, int h, String c, String bc, boolean b) {
borderColor = bc;
border = b;
}
public int area() {
return (width * height);
}
public int perimeter() {
return ((width * 2) + (height * 2));
}
public void setBorder(boolean newBorder) {
border = newBorder;
}
}
}
}
If you have any questions or need me to clarify anything I'll definitely do so. Thank you!
The issue not really with the inheritance here.
Non-static variable cannot be referenced from a static context
As main method is static, it can't access inner non-static class MyRectangle inside it. You have already added static keyword to your MyRectangle class definition so this should fix this issue. You call also move MyRectangle class outside your main class. This would automatically make it static as all "Top level classes are static by default".
There is another issue here, the variables width, height from MyRectangle class are defined as static. This would result in these variables shared across all the different MyRectangle objects that you have created and override each others values. So remove the static keyword from there as they need to be different for each instance.
error: cannot find symbol
Object mr4 is not created but used in the print statements, this would be resulting in cannot find symbol. So just creating this object should fix your issue.
After these fixes your code should look something like:
class Main {
public static void main(String[] args) {
MyRectangle mr1 = new MyRectangle(0, 0, 4, 2, "blue", "red", true);
MyRectangle mr2 = new MyRectangle(5, 5, 10, 3, "green");
MyRectangle mr3 = new MyRectangle();
MyRectangle mr4 = new MyRectangle(); // now mr4 is created
System.out.println(mr1 + " " + "area = " + mr1.area() + " perimeter = " + mr1.perimeter());
System.out.println(mr2 + " " + "area = " + mr2.area() + " perimeter = " + mr2.perimeter());
System.out.println(mr3 + " " + "area = " + mr3.area() + " perimeter = " + mr3.perimeter());
System.out.println(mr4 + " " + "area = " + mr4.area() + " perimeter = " + mr4.perimeter());
}
static class MyRectangle extends Rectangle {
public int width, height; // this should be non static
public String color, borderColor;
public boolean border;
public MyRectangle() {
super();
}
public MyRectangle(int x, int y, int w, int h, String c) {
width = w;
height = h;
color = c;
}
public MyRectangle(int x, int y, int w, int h, String c, String bc, boolean b) {
this(x, y, w, h, c); // this should initialise other args by calling different constructor
borderColor = bc;
border = b;
}
public int area() {
return (width * height);
}
public int perimeter() {
return ((width * 2) + (height * 2));
}
public void setBorder(boolean newBorder) {
border = newBorder;
}
}
}

How to fix "Cannot invoke "java.awt.Point.getX()" because "this.p" is null"

For an inheritance practice assignment, I have a class Square which extends rectangle, and here are the relevant methods:
public class Square extends Rectangle {
private Point p;
private int sideLength;
public Square(Point p, int sideLength){
super(p);
this.sideLength = sideLength;
}
public String toString(){
return getClass().getName() + "\nCenter point: (" + p.getX() + ',' + p.getY() + ") \nSide Length: " + sideLength + " \nArea: " + this.getArea() + " \nPerimeter: " + this.getPerimeter();
}
}
there's also a getArea() and getPerimeter() method but neither of those are causing this issue.
I have a separate class to test this one:
public class SquareTest {
public static void main(String[] args){
ArrayList<Square> squareList = new ArrayList<>();
Point p1 = new Point(1, 1);
Point p2 = new Point(1, 2);
Point p3 = new Point(4, 1);
Point p4 = new Point(2, 3);
Point p5 = new Point(5, 4);
Square one = new Square(p1, 1);
Square two = new Square(p2, 2);
Square three = new Square(p3, 4);
Square four = new Square(p4, 4);
Square five = new Square(p5,5);
squareList.add(one);
squareList.add(two);
squareList.add(three);
squareList.add(four);
squareList.add(five);
for (Square each : squareList){
System.out.println(each.toString());
System.out.println();
}
}
}
What it's supposed to do is print out the toString() result for each of the five square objects, where one square looks like this:
Square
Center point: (1,1)
Side Length: 1
Area: 1
Perimeter: 1
but instead i get the following runtime error:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.awt.Point.getX()" because "this.p" is null
at Square.toString(Square.java:21)
at SquareTest.main(SquareTest.java:23)
I'm confused as to why it thinks this.p is null when I've clearly instantiated five Point objects. Any ideas?
NullPointerException was caused because you haven't initialized the p in Square class. Yu have just passed it to the Rectangle constructor so it is the p in Rectangle class which is getting initialized.
Since you are not using the point object in your Square rather than just passing it to the super class, there is no need to declare a Point object in the Square class. If your Rectangle class has a getter method for Point p then, you could use that in the Square class.
Assuming that Rectangle class has a getter method for p, You could refactor your Square class to :
public class Square extends Rectangle {
private int sideLength;
public Square(Point p, int sideLength){
super(p);
this.sideLength = sideLength;
}
public String toString(){
return getClass().getName()
+ "\nCenter point: (" + getP().getX() + ',' + getP().getY()
+ ") \nSide Length: " + sideLength
+ " \nArea: " + this.getArea()
+ " \nPerimeter: " + this.getPerimeter();
}
}

Problems with toString() and Overriding Methods

I am having a problem with this code. It is not calculating area correctly. I need it to calculate the cross-sectional area of a Cylinder/Piston and the surface area of the cylinder. If you notice the output it seems that both values are the same values for when I use the getArea() method. Java is getter confused as to what getArea() to use? strong text I am trying to over-ride the getArea() [Surface Area] with getArea() [cross -sectional area] but it is not working?
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println(
"\n\nInput the radius, then the height, then if the cylinder is filled (input 1 if it is filled and input 0 if not, and then enter the color");
double radius = scan.nextDouble();
double height = scan.nextDouble();
int filled = scan.nextInt();
boolean isFilled;
if (filled == 1) {
isFilled = true;
} else {
isFilled = false;
}
String c = scan.nextLine();
String x = scan.nextLine();
Cylinder cyl = new Cylinder(radius, height, isFilled, x);
System.out.println("\n\n This is a Cylinder and its properties");
System.out.println(cyl);
Piston small= new Piston();
System.out.println ("\n\n This is small Piston");
System.out.println(small);
Piston big = new Piston(55.6, 1234.4, true, "red", 1200, 12.3);
System.out.println ("\n\n This is big Piston");
System.out.println(big);
}
}
class Shape {
private String color = "yellow";
private boolean filled;
public Shape() {
}
public Shape(String color, boolean filled) {
this.color = color;
this.filled = filled;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public boolean isFilled() {
return filled;
}
public void setFilled(boolean filled) {
this.filled = filled;
}
public String toString() {
return "\nThe color is : " + color + " and shape fill is : " + filled;
}
}
class Cylinder extends Shape {
private double cylinderRadius;
private double cylinderHieght;
public Cylinder() {
cylinderHieght = 10;
cylinderRadius = 2.5;
}
public Cylinder(double height, double radius) {
cylinderRadius = radius;
cylinderHieght = height;
}
public Cylinder(double height, double radius, boolean filled, String color) {
super(color, filled);
cylinderRadius = radius;
cylinderHieght = height;
}
public double getRadius() {
return cylinderRadius;
}
public double getHieght() {
return cylinderHieght;
}
public double getArea() {
double p = 3.14;
return 2 * p * cylinderRadius * cylinderRadius + 2 * p * cylinderRadius * cylinderHieght;
}
public double getVolume() {
double p = 3.14;
return p * cylinderRadius * cylinderRadius * cylinderHieght;
}
#Override
public String toString() {
return super.toString() + " \nRadius= " + cylinderRadius + " Height= " + cylinderHieght
+ " Cylinder total surface Area= " + getArea() + " volume= " + this.getVolume() + ".";
}
}
class Piston extends Cylinder{
private double shaftLength;
private double myPressure;
public Piston(){
shaftLength=1;
myPressure=1;
}
public Piston(double height, double radius, boolean filled, String color, double length, double pressure){
super(height, radius, filled, color);
shaftLength=length;
myPressure=pressure;
}
public double getShaftLength(){
return shaftLength;
}
public double getPressure(){
return myPressure;
}
#Override
public double getArea(){
return getRadius()*getRadius()*3.14;
}
public double getVolume(){
return super.getVolume();
}
#Override
public String toString(){
return super.toString()+"\n the cross sectional area of Piston = "+this.getArea()+" shaftlength="+shaftLength+" pressure="+myPressure+" .";
}
}
Here is the output if I put in a radius of 5 and a height of 10.
Input the radius, then the height, then if the cylinder is filled
(input 1 if it is filled and input 0 if not, and then enter the color
5 10 1 Blue
This is a Cylinder and its properties
The color is : Blue and shape fill is : true Radius= 10.0 Height= 5.0
Cylinder total surface Area= 942.0 volume= 1570.0.
This is small Piston
The color is : yellow and shape fill is : false Radius= 2.5 Height=
10.0 Cylinder total surface Area= 19.625 volume= 196.25. the cross sectional area of Piston = 19.625 shaftlength=1.0 pressure=1.0 .
This is big Piston
The color is : red and shape fill is : true Radius= 1234.4 Height=
55.6 Cylinder total surface Area= 4784554.150400002 volume= 2.6602121076224005E8. the cross sectional area of Piston = 4784554.150400002 shaftlength=1200.0 pressure=12.3 .
To clarify -- it seems like this is the situation:
You have one class (Cylider) that defines a method (getArea()) to do one thing. Another method on Cylider (toString()) calls that getArea() method.
Then, you sub-classed Chylidar with a child type (Piston) and overrode the getArea() function to do a different thing.
Now, when you're code in the Cylider class clls the getArea() method, you expected it to use the Cylider version of getArea() because the code was written in the same class, but in reality it used the overriden Piston version of getArea() because the object you were calling it on actually was a Piston.
This isn't really a bug or even a problem to solve -- it's just a function of how Java resolves method calls. It will pick the one that is most specific given the actual type of the object you are working with (even if it's not obvious at compile time what that type would be) not the one that is written closest to the sight of the caller.
There isn't really a way to get around this. I would take this as a sign that your design is bad -- or at least not idiomatic. Overriding functions is intended for you to give a different, more correct way to calculate the same idea for a different type, not just as a way to re-use function names.
The easiest change would probably be to just make a new method on Cylinder called getCylinderArea(). Cylider.getArea() could call this function by default, but you could call it explicity in Cylider.toString() if you wanted that function to only ever use the plain Cylinder method of calculating area.
Alternatively, Maybe Piston shouldn't actually be a subtype of Cylinder because, even though they share some characteristics, a Piston isn't substitute-able for a generic cylinder anywhere you would use a cylinder -- for example, when calculating the area. Look up the Substitution Principle for more.
Personally, though, I tend to stay away from inheritance altogether for this exact kind of reason. I would actually recommend just using interfaces and a flat hierarchy in this case instead.
This StackOverflow thread might be interesting if you want more detail on calling super methods.

Null-Pointer Exception Error at toString

The null-pointer exception error occurs in my toString method. I'm at a loss as to why. The error can occur through multiple ways. Most commonly, an object's reference is declared but the object itself remains uncreated. I've declared and created (is initialized the right word?) Mycircle circle1 = new Mycircle (); and Mypoint center = new Mypoint ();
I suspected that I hadn't initialized any of my fields when I invoked my getter methods, but that's not true. The setter methods work cleanly -- I've been successful in inputting values. Doesn't that imply that my getter methods can access some non-null value.
import java.util.Scanner;
public class MyCircle {
private Mypoint center;
private double radius;
Scanner input = new Scanner (System.in);
public MyCircle() {
radius = 0.0;
Mypoint center = new Mypoint ();
System.out.println("Enter coordinates here");
center.setCoordinateX(input.nextDouble());
center.setCoordinateY(input.nextDouble());
}
public String toString(MyCircle object) {
return "Circle # " + "(" + object.center.getCoordinateX() + "," +
object.center.getCoordinateY() + ")" + ". Its radius is " +
object.radius;
}
public double calcArea(MyCircle object) {
double area = Math.pow(object.radius, 2) * Math.PI;
return area;
}
public static void main (String[]args) {
MyCircle circle1 = new MyCircle ();
circle1.radius = 3.0;
System.out.println(circle1.calcArea(circle1));
System.out.println(circle1.toString(circle1));
}
}
class Mypoint {
private double posX;
private double posY;
public void setCoordinateX(double x) {
posX = x;
}
public void setCoordinateY(double y) {
posY = y;
}
public double getCoordinateX() {
return posX;
}
public double getCoordinateY() {
return posY;
}
}
In your MyCircle constructor, you're creating a local variable called center here:
Mypoint center = new Mypoint ();
What you probably want is to initialize the instance member:
center = new Mypoint ();
Your code doesn't make much sense, presumably this
public String toString(MyCircle object)
{
return "Circle # " + "(" + object.center.getCoordinateX() + ","
+ object.center.getCoordinateY() + ")"
+ ". Its radius is " + object.radius;
}
Should be
#Override
public String toString() {
return "Circle # (" + center.getCoordinateX() + ","
+ center.getCoordinateY()
+ "). Its radius is " + radius;
}
Then let's fix your constructor, use this so you know you're updating the instance field (instead of shadowing it) -
public MyCircle() {
this.radius = 0.0;
this.center = new Mypoint(); // <-- this.center
System.out.println("Enter coordinates here");
this.center.setCoordinateX(input.nextDouble());
this.center.setCoordinateY(input.nextDouble());
}
First of all, your toString() method is untypical. You want a Circle#toString() with no argument and produce a print representaton of yourself (i.e. this instead of object=).
Your toString method can fail if:
object is null
object.center is null
object.center.getCoordinateX() or getCoordinateY() itself throws exception.
The later case would be visible in the stacktrace, the other two cases all show the same line number as the cause.
It looks like the second case is your problem (as you fill a local variable and not the field of MyCircle).
BTW: using a input scanner in a constructor is a horrible layering violation. You should seperate input/output/user interaction logic from the geometric (circly, point) classes.
There are many things wrong in your code beside what #Mike pointed out.
Getting input from the user within the constructor is bad. You should get the input in the main method, and pass it to the constructor. In addition, you don't initialize the radius. It remains 0.0.
The constructor call should look like this (the MyPoint object passed to the constructor should be initialized prior to calling the constructor) :
MyCircle circle1 = new MyCircle (center, radius);
The constructor should look like this :
public MyCircle(MyPoint center, double radius)
{
this.radius = 0.0;
this.center = center;
}
The toString and calcArea methods don't need a parameter. They should operate on the current object (this) :
public String toString()
{
return "Circle # " + "(" + this.center.getCoordinateX() + "," + this.center.getCoordinateY() + ")" + ". Its radius is " + this.radius;
}

toString() and accessors

public class Fan {
public static void main(String[] args){
Fan fan1 = new Fan();
fan1.setSpeed(FAST);
fan1.setRadius(10);
fan1.setColor("yellow");
fan1.setOn(true);
System.out.println(fan1.toString());
}
// fan speed variables
final static int SLOW = 1;
final static int MEDIUM = 2;
final static int FAST = 3;
// Other fan variables
private int speed;
private boolean on; // true means on
private double radius; // radius of fan
String color;
// No-arg constructor
public void Fan(){
speed = SLOW;
on = false;
radius = 5;
color = "blue";
}
// Mutator methods
public void setSpeed(int newSpeed){
if(newSpeed < 0)
System.out.println("Illegal speed!");
else
speed = newSpeed;
}
public void setOn(boolean newOn){
on = newOn;
}
public void setRadius(int newRadius){
if(newRadius < 0)
System.out.println("Illegal radius!");
else
radius = newRadius;
}
public void setColor(String newColor){
color = newColor;
}
// Accessor methods
public int getSpeed(){
return speed;
}
public boolean getOn(){
return on;
}
public double getRadius(){
return radius;
}
public String getColor(){
return color;
}
// toString method to output Fan data
public String toString(){
if(on = false)
return "Fan is off.";
else
return "Fan Properties:\n" + "Fan speed: " + speed + "\n"
+ "Color: " + color + "\n"
+ "Radius: " + radius + "\n";
}
}
The above piece of code is simple but I was wondering how the toString method uses the on variable even though I didn't supply parameters for that method. Also, why do we not need to invoke get methods in the main class and only need to invoke the set methods? (please explain how each method invokes one another until the final output)
Thanks a lot!
As far as you are in this class body you can access everything (except for static can not access non-static). That means that you can easily set and get variables like that:
var = <value>;
System.out.println(var);
However nobody stops you from using the accessor methods - getter and setters. It is just not required.
One final note:
if(on = false)
This will always fail - it does assignment to false and then checks the newly assigned value (which is false). You need to check for equality here. Like that:
if(on == false)
Or even better:
if(!on)
I just copied-pasted your code into a new file and compiled it. It compiled and ran. The output was
$ java Fan
Fan Properties:
Fan speed: 3
Color: yellow
Radius: 10.0
This is because the comparison in your toString method is wrong. It should be as following:
public String toString(){
if(on)
return "Fan Properties:\n" + "Fan speed: " + speed + "\n"
+ "Color: " + color + "\n"
+ "Radius: " + radius + "\n";
else
return "Fan is off.";
}

Categories