Variables 2a (using classes and objects)

Level 1 - Basics

Objects are special places in memory that can hold a set of values that belong together. An example of this is the Point in Java. An object of the class Point has two int values: the x and y value of the point. They always belong together. Classes and objects are the way Java implements this mechanism.

Copy this fragment to the run() method of an exercise in IntelliJ. Run the program to check if it works. Is the output what you expect?

// add this to the imports, otherwise Java won't recognize the Point (and other) types.
// import java.awt.*;

// "new Point" creates a new object of type Point
// it is assigned to the variable "p1" after it has been created.
Point p1 = new Point(); 
p1.x = 10;
p1.y = 20;

Point p2 = new Point();
p2.x = 100;
p2.y = 120;

SaxionApp.printLine("x of the first point is: " + p1.x);
SaxionApp.printLine("x of the second point: " + p2.x);

This program creates two point variables with the name p1 and p2. Both contain different x and y coordinates.

Change the program to also show the y-coordinates.

// add this to the imports, otherwise Java won't recognize the Point (and other) types. // import java.awt.*; Point p1 = new Point(); p1.x = 10; p1.y = 20; Point p2 = new Point(); p2.x = 100; p2.y = 120; SaxionApp.printLine("x of the first point is: " + p1.x); SaxionApp.printLine("y of the first point is: " + p1.y); // add this SaxionApp.printLine("x of the second point: " + p2.x); SaxionApp.printLine("y of the second point: " + p2.y); // and this

Change the program so that the coordinates are not printed, but let it draw two circles on screen, at the coordinates of p1 and p2, with a diameter of 20. Use the x and y variables of the Point objects for this.

Point p1 = new Point(); p1.x = 10; p1.y = 20; Point p2 = new Point(); p2.x = 100; p2.y = 120; SaxionApp.drawCircle(p1.x, p1.y, 20); SaxionApp.drawCircle(p2.x, p2.y, 20);

Change the program, so that a line is also drawn from the first point to the second point.

Point p1 = new Point(); p1.x = 10; p1.y = 20; Point p2 = new Point(); p2.x = 100; p2.y = 120; // it's nicer when the circles are drawn // on top of the line, so draw the line first. SaxionApp.drawLine(p1.x, p1.y, p2.x, p2.y); SaxionApp.drawCircle(p1.x, p1.y, 20); SaxionApp.drawCircle(p2.x, p2.y, 20);

Level 2 - creating new objects

Now create a new program. In this program, you are going to use the Rectangle class. This is an existing class in the Java library which has x and y variables, just like the Point class, but also has a width and height.

Create a new variable of type Rectangle, and assign a new Rectangle to it. Set the x, y, width and height properties of the object to some values (10, 20, 200, 150 or whatever).

Rectangle r = new Rectangle(); r.x = 10; r.y = 20; r.width = 200; r.height = 150;

Extend the program so it will draw the rectangle on screen.

Rectangle r = new Rectangle(); r.x = 10; r.y = 20; r.width = 200; r.height = 150; SaxionApp.drawRectangle(r.x, r.y, r.width, r.height);

Create a new program. Ask the user for an x and also ask for a y coordinate. Store the result in a new Point object. Do this two times, so you end up with two Point objects. Afterwards, draw a line from the first point to the second and/or draw circles at the location of the points.

Point firstPoint = new Point(); Point secondPoint = new Point(); SaxionApp.print("Please enter x1: "); firstPoint.x = SaxionApp.readInt(); SaxionApp.print("Please enter y1: "); firstPoint.y = SaxionApp.readInt(); SaxionApp.print("Please enter x2: "); secondPoint.x = SaxionApp.readInt(); SaxionApp.print("Please enter y2: "); secondPoint.y = SaxionApp.readInt(); // draw stuff SaxionApp.drawLine(firstPoint.x, firstPoint.y, secondPoint.x, secondPoint.y); SaxionApp.drawCircle(firstPoint.x, firstPoint.y, 20); SaxionApp.drawCircle(secondPoint.x, secondPoint.y, 20);

Level 3 - Using objects as parameters in methods

It is possible to use objects as arguments for methods. Copy this fragment to IntelliJ, but remove the existing run() method first.

public void run() {

    Point p1 = new Point();
    p1.x = 150;
    p1.y = 100;

    drawCircle(p1, 50);
}

public void drawCircle(Point p, int r) {
    // does nothing yet...
}

The method drawCircle doesn't do anything. Edit the code so it will draw the circle on screen in the drawCircle method.

public void run() { Point p1 = new Point(); p1.x = 150; p1.y = 100; drawCircle(p1, 50); } public void drawCircle(Point p, int r) { // use the x and y of p to draw the circle: SaxionApp.drawCircle(p.x, p.y, r); }

Add another point object with different values, and draw a circle there as well, by again calling our drawCircle method.

Point p1 = new Point(); p1.x = 150; p1.y = 100; drawCircle(p1, 50); // same code but different variable name (and different x and y values) Point p2 = new Point(); p2.x = 250; p2.y = 100; drawCircle(p2, 100);

Create a new program. Ask the user for an x, y, width and height. Store the values in a Rectangle object. Create a method that takes a Rectangle as argument and draws the rectangle on screen.

public void run() { Rectangle r1 = new Rectangle(); r1.x = SaxionApp.readInt(); r1.y = SaxionApp.readInt(); r1.width = SaxionApp.readInt(); r1.height = SaxionApp.readInt(); drawRect(r1); } public void drawRect(Rectangle r) { SaxionApp.drawRectangle(r.x, r.y, r.width, r.height); }

Level 4 - using objects as returnvalue from methods

Copy this method into your program:

public Rectangle createRectangle(Point topLeft, Point bottomRight) {
    Rectangle r = new Rectangle();
    r.x = topLeft.x;
    r.y = topLeft.y;
    r.width = bottomRight.x - topLeft.x;
    r.height = bottomRight.y - topLeft.y;
    return r;
}

Extend your program: create two points or ask the user for two points. Use these points and the method createRectangle to convert the points into a rectangle. Draw the rectangle on screen (using the method you created earlier).

SaxionApp.printLine("Enter topleft x and y:"); Point p1 = new Point(); p1.x = SaxionApp.readInt(); p1.y = SaxionApp.readInt(); SaxionApp.printLine("Enter bottomright x and y:"); Point p2 = new Point(); p2.x = SaxionApp.readInt(); p2.y = SaxionApp.readInt(); Rectangle r = createRectangle(p1, p2); drawRect(r); // you can combine these last two lines if you want: // drawRect(createRectange(p1, p2));

Create a new program. Create a new method getRandomPoint that returns a Point with a random x and y (within the boundaries of your canvas). Call this method in a loop and draw a circle at the returned point each time. Run the loop 50 times.

public void run() { int i = 0; while (i < 50) { Point p = getRandomPoint(); SaxionApp.drawCircle(p.x, p.y, 20); i++; } } public Point getRandomPoint() { Point p = new Point(); // use SaxionApp.getWidth and Height for the canvas size // (or just enter the values as numbers) p.x = SaxionApp.getRandomValueBetween(0, SaxionApp.getWidth()); p.y = SaxionApp.getRandomValueBetween(0, SaxionApp.getHeight()); return p; }

Level 5 - using objects in an ArrayList

It is possible to use ArrayLists to store objects. Copy the following code to the run method:

// add this to the imports, otherwise Java won't recognize the ArrayList type.
// import java.util.ArrayList;

// create a new, empty list and store it in listOfPoints
ArrayList<Point> listOfPoints = new ArrayList<>();

// create a new point
Point p1 = new Point();
p1.x = 10;
p1.y = 20;

// add it to the list
listOfPoints.add(p1);

Extend the code and add a second point to the list. To create the point, use the getRandomPoint() method you created earlier.

// add this to the imports, otherwise Java won't recognize the ArrayList type. // import java.util.ArrayList; ArrayList<Point> listOfPoints = new ArrayList<>(); Point p1 = new Point(); p1.x = 10; p1.y = 20; listOfPoints.add(p1); Point p2 = getRandomPoint(); listOfPoints.add(p2); // or do it in one line: // listOfPoints.add(getRandomPoint());

This program doesn't do anything yet, it would be nice to draw all points on the screen now. To do this, add an enhanced for-loop that loops over all values of listOfPoints using a variable Point p. Draw each point on screen by calling the drawCircle method you created earlier (or copy it from a solution above).

ArrayList<Point> listOfPoints = new ArrayList<>(); Point p1 = new Point(); p1.x = 10; p1.y = 20; listOfPoints.add(p1); Point p2 = getRandomPoint(); listOfPoints.add(p2); for (Point p : listOfPoints) { drawCircle(p, 20); }

Change the program so it adds 150 random points to the list (hint: use a loop) and let it draw all the points afterwards.

ArrayList<Point> listOfPoints = new ArrayList<>(); int i = 0; while (i < 150) { listOfPoints.add(getRandomPoint()); i++; } for (Point p : listOfPoints) { drawCircle(p, 20); }

Level 5 - Pitfalls

Understanding how variables can hold objects and how using the new keyword creates new objects is essential when working with classes and objects.

Consider the following example:

Point p = new Point();
p.x = 10;
p.y = 20;

// same variable is used
p = new Point();
p.x = 30;
p.y = 40;

SaxionApp.print(p.x); 

What happens to the first Point object? What will be printed? Try it out.

Point p = new Point(); p.x = 10; p.y = 20; // the first object is lost forever, because here a new Point object // is created and assigned to the p variable. // Because there is no way to access the first Point object any longer, it is destroyed by Java p = new Point(); p.x = 30; p.y = 40; SaxionApp.print(p.x); // "30" is printed.

Consider this example:

ArrayList<Point> points = new ArrayList<>();

Point p = new Point();
p.x = 10;
p.y = 20;
points.add(p);

// same variable is used
p = new Point();
p.x = 30;
p.y = 40;
points.add(p);

SaxionApp.print(p.get(0).x);

What happens to the first Point object now? What is printed? Try it out.

ArrayList<Point> points = new ArrayList<>(); Point p = new Point(); p.x = 10; p.y = 20; // The first Point object is added to the arraylist here. points.add(p); // So even while the p variable is reused for the second Point here, // the first point is still accessible via the arraylist: points.get(0) // So both points stay. p = new Point(); p.x = 30; p.y = 40; points.add(p); // "10" is printed. SaxionApp.print(p.get(0).x);

Consider this example:

ArrayList points = new ArrayList<>();

Point p = new Point();
p.x = 10;
p.y = 20;
points.add(p);

// reuse same variable
p.x = 30;
p.y = 40;
points.add(p);

SaxionApp.print(p.get(0).x);

What is the difference with the previous example? What happens now? What is printed? Try it out!

ArrayList<Point> points = new ArrayList<>(); // This is a program with an error: it only creates one Point object. Point p = new Point(); p.x = 10; p.y = 20; // It adds the object to the arraylist here points.add(p); // But then it just overwrites the existing values of x and y // of the first point with other values, without creating a new Point p.x = 30; p.y = 40; // It now *again* adds the same object to the list. // That is allowed, but now the list contains 2 references to the same object! points.add(p); // Because there is only one object, it doesn't matter if you // print p.get(0).x or p.get(1).x. Both print "30". SaxionApp.print(p.get(0).x);

Level 6 - Do it yourself

Create a new program. Add a method askRectangle that ask the user for x, y, width and height and returns a Rectangle. Call this method 3 times and add all rectangles to a list of rectangles. Afterwards, add up the areas of all the rectangles and return the total (area is width x height).

public void run() { ArrayList<Rectangle> rectangles = new ArrayList<>(); // instead of using an index variable (i), we can just // check the size of the arraylist in the while condition. // (But using i < 3 is also okay). while (rectangles.size() < 3) { Rectangle r = askRectangle(); rectangles.add(r); } int areaSum = 0; for (Rectangle r : rectangles) { int area = r.width * r.height; areaSum = areaSum + area; } SaxionApp.printLine("The total area is: " + areaSum); } private Rectangle askRectangle() { SaxionApp.printLine("Give x, y, width and height (on separate lines):"); Rectangle result = new Rectangle(); result.x = SaxionApp.readInt(); result.y = SaxionApp.readInt(); result.width = SaxionApp.readInt(); result.height = SaxionApp.readInt(); return result; }