Java Class

A class in java is a representation of an object. It is a blueprint. It describes the attributes and behavior of an object.

Every class will have the basic structure shown below.

public class Name{  //defines the new class/data type

}

All classes are capitalized and the files associated with them will also be named after the class by convention.

Class Header and Attributes

The very first line of a class is the class header. It describes the name of the class. The attributes come after the class. The keyword private, typically used on attributes, keeps information visible only to the segments of code inside the class such as the constructor and methods. The constructors typically follow after the attributes then the methods.

public class Ball{
//attributes
private int width;
private Color color;

//constructors not shown
//other methods not shown
}

Constructors

As mentioned in previous sections, the constructor helps set up an object being created from the class (the template). At the very least, a constructor setups the attributes of the object by initializing them with a given value. If you do not provide a constructor for a class, Java will automatically give you a no-parameter constructor. If that happens, all of the attributes are assigned initial values by default. Numerical types are set to zero, booleans are set to false, and any object type is set to null. The header for a constructor is as follows. Note that you will work with public constructors in this class.

public class ClassName{
public ClassName(){
//default constructor - provided by java if no constructors are added
}
public ClassName(pType1 pName1, pType2 pName2, ... , pTypeN pNameN){} //a non-default constructor - notice the parameters
}

The Job of the constructor is to set up the instance variables:

For beginner programmers, you cannot go wrong with memorizing that the job of the constructor is to set up the instance variables. For example, the constructor may initialize the starting values of an object's instance variables! It's especially obvious when dealing with non-default constructors where the values for the instance variables are passed in as arguments to the constructor.

You saw this in Unit 2! Let's remind you what that looked like from Unit 2.

Rectangle r = new Rectangle(30, 50, 100, 200); //rectangle with top-left corner at 30, 50 with a width of 100 and height of 200.


In the example above, the right side of the assignment statement is the call to the constructor. Notice the literal values being passed into the constructor, the values 30, 50, 100, and 200 represent the x, y, width, and height of the rectangle where x, y is the top-left corner.

What would the constructor and class look like for this?

Example Non-Default Constructor

public class Rectangle{
private int x, y;
private int width, height;

public Rectangle(int paramX, int paramY, int paramWidth, int paramHeight){ //<--- params in constructor
x = paramX;
y = paramY;
width = paramWidth;
height = paramHeight;
}
}

As you can see above, the constructor is assigning the instance variables to the parameter values. It's safe to just remember that the main job of a constructor is to set up the instance variables. When you learn data structures later, sometimes this means creating 1D, 2D or ArrayLists!

Overloading Constructors

Recall that method overloading is when you have multiple methods of the same name. The difference in the signature of the method is defined by the uniqueness of the parameter list. The same applies to constructor overloading. You can have multiple constructors as long as the parameter list is unique.

The default constructor is the constructor without any parameters. What is the point of having multiple constructors? It allows you to create objects where you can pass in information for the object that is to be constructed. For example, what if you wanted to create an object and give it a name? Imagine also that only at certain times do you want to create objects with an initial name and age. Having different constructors that take in different data (parameters) allows you to have this type of flexibility.

public class Ball{
private int width;
private Color c;

//a default constructor - notice the lack of parameters
public Ball(){
//the main job of the constructor is to assign values to the instance variables
// which means a bunch of assignment statements for most classes!
width = 50;
c = Color.black;
}

//a non-default constructor that allows specifying the width and color
public Ball(int paramWidth, Color paramColor){
//the main job of the constructor is to assign values to the instance variables
        //in a non-default constructor, the values are coming from parameters
width = paramWidth;
color = paramColor;
}

//you can overload constructors similar to how you can overload methods in java
//As long as the list of parameters is unique then it should work!
public Ball(Color c){
this(); //calls default constructor
 
//when the name of the attribute is the same as the name of a parameter
//you must specify when you are working with the attribute with the this keyword
this.c = c;
}
}

public class Pomekon{
private int hp;
private String type;

public Pomekon(){        //constructor 1 - no parameters - default constructor
hp = 100;
}

public Pomekon(int newHP){ //constructor 2 - a constructor that allows settings hp intance var
hp = newHP;
}

public Pomekon(String newType){ //constructor 3 - a constructor that allows settings the type instance var
type = newType;
}
}
Pomekon p1 = new Pomekon();       //will call default constructor (constructor 1)
Pomekon p2 = new Pomekon(200);    //will call constructor 2
Pomekon p3 = new Pomekon("Fire"); //will call constructor 3!

The two lines of code above calls upon the Pomekon constructors. The right side of the assignment is the call to the constructor. Java will match the call to the constructor based on the given data inside the parentheses. The first call to the constructor will run the code for the constructor without parameters. The second call, taking in a String literal, will invoke the third constructor.

Constructor Header

public ClassName( /*parameter list */) //header for class constructor

public returnType methodName( /* parameter list */) //header for a method

It will be difficult to write the constructors for classes if you do not fully understand the need for headers (constructors or methods). Headers fully describe a block of code. If you look inside a constructor or a method, you will see that there is nothing special or new that happens in the methods. That is because they are just a block of code that has been sectioned off as a constructor or method. This allows you to easily call upon that block of code anytime you want.

Name and Return Type

Anytime you want to call upon the constructor, you need to know the name. This is the same with methods! You can't invoke a method without having any idea of its name. For constructors, the name must match the class in which it exists.

For example, if you are writing a constructor that is going inside a class name Book then the constructor will be named Book. Unlike methods that are either void or non-void, constructors DO NOT have anything in front of the name describing any sort of return. The public modifier will appear by convention. This keyword allows access to the constructor. We will go into this in detail later.

public class Book{ //this defines the name of the class as Book
private int numPages;
private double price;
private String author;

public Book(){} //notice how the constructor is named after the class name! Very important!

public Book(double paramPrice){} //all constructors will be named after the class

//constructors do not have a "return type"

}

Parameters

A class is made up of attributes or instance variables. Sometimes when you are creating objects you want to specify a value for one or more of these attributes. That is where you need a constructor with parameters.
public class Book{ //this defines the name of the class as Book
private int numPages;
private double price;
private String author;
//notice how the constructor is named after the class name! Very important!
public Book(){/* implementation not shown */ }

public Book(double paramPrice){/* implementation not shown */} //all constructors will be named after the class

//constructors do not have a "return type"

}

Since the class above has multiple constructors, you can create Book objects depending on what you want to specify during the creation of the objects.
Book b = new Book(); //if you do not want to set any values during the call to the constructor
Book b = new Book(14.99); //using the other constructor if you want to set the price

Comments and Conditions

You can make your code more readable by adding comments. In a working environment, it is very common for many programmers to use your code and help you maintain it. This is where it is especially useful to comment and now is a good time to develop the habit. Comments will help you recall what you were doing when you look back at your code at a later time. It's possible you have already been commenting throughout units 1-4! The 3 types of comments in Java programming are:
1. // Single line comment
2. /* Multiline comment */
3. /** Documentation comment */
As you may have already seen in practice, // are used to mark the rest of the line as a comment. This is true not just in Java but in many programming languages. Sometimes if your comment spans multiple lines, it is a good idea to use the multi-line comment which begins with /* and ends with */. You add /* at the beginning of your comments and add */ at the end. Finally, the last type of comment in Java is for documentation. Java has a built-in Javadoc tool that will read these comments and create web pages summarizing them. These are similar to the multiline comment but they have two asterisks to start them. 

/** */ These types of comments are used in all parts of your code from the start of a class, the beginning of methods, and with instance variables. For all of these three types of comments, the compiler will skip over them and they will not affect how your program runs! In fact, you likely commented out code that didn't run in order to try to debug your programs. Below are examples of the uses of comments in a Java program.
/**
* Dog.java
* @author Jak
* @since 5-4-2050
* This class keeps track of the max score.
*/
public class ScoreKeeper{
    private int max = 10; // this keeps track of the max score
    /* The print() method prints out the max */
    public print() {
        System.out.println(max);
    }
}
Here are some common tags for Javadoc documentation: @author Author of the program @since Date released @version Version of the program @param Parameter of a method @return Return value for a method

Preconditions and Postconditions

You can add preconditions and postconditions to the beginning of methods inside comments. Preconditions are things that should be true for your method to work such as assuming the parameters passed in are not null or negative. The preconditions can act like requirements for someone to call your methods. The programmer can still check these preconditions before running the rest of the method, but it is not necessary. The postcondition comment is what is true after running the method. It is what the method claims to do. These comments describe the outcome of the method such as returning instance variables or looking for the index of the biggest number in an array. Postconditions and Preconditions are most useful when other programmers try to use methods programmed by others. They provide a very quick summary of how to get correct results from a method. Below is an example of preconditions, postconditions, and @param.
/**
* Constructor that takes the x and y position for the ball
* Preconditions: parameters x and y are coordinates from 0 to
* the width and height of the world.
* Postconditions: the ball is placed in (x,y) coordinates
* @param x the x position to place the ball
* @param y the y position to place the ball
*/
public Ball(int x, int y){
    xPos = x;
    yPos = y;
} 

AP Test

The AP Exam does make use of a lot of comments, preconditions, and postconditions. It is a good idea to familiarize yourself with reading these types of comments when looking through sets of code that someone else provided! This will be the case with the AP Exam as you will read a lot of provided code and your ability to scan the comments quickly can help you manage your time. Don't worry though. You will have plenty of experience reading code with these types of comments and writing them throughout the rest of the units.

Getters

Instance variables of classes are typically marked as private to the class so the programmer must provide public methods that allow safe access to these instance variables. Accessor methods, often called getters or get methods, give this functionality. These methods allow other blocks of code to access the instance variables outside of the class. You can write getters for each instance variable provided you want read-access to it. A getter looks like the following:
public class Ball{
    //instance variable for the ball for location
    private int x;
    private int y;
    
    //getter (accessor method) for the instance variable x     public int getX(){         return x;     } }
You can then use this outside of the class such as in the main method of another class as seen below.
public class Driver{
    public static void main(String[] arg){
        Ball b = new Ball(); // create a Ball object
        //use the getter and print out the x-location of the object b
        System.out.println("Ball is located at x: " + b.getX());
    }
} 

toString() Method

Often times you will write a special type of getter method for a class called the toString method. This method is intended to return a description of the instance variables of an object as a String. This method is automatically called whenever you pass objects to the print or println methods! It happens anytime there is a need to convert the object to a String. The code below is how the toString method is invoked.
public class Ball{
    //instance variable for the ball for location
    private int x;
    private int y;
    public Ball(){         x = 30;         y = 40;     }     public String to String(){         return "Ball is located at x:"+x+" y:"+y;     }     /* some other getters */ } public class Driver{     public static void main(String[] arg){         Ball b = new Ball(); // create a Ball object         //use the getter and print out the x-location of the object b         System.out.println(b);     } }
The Driver class will print "The ball is located at x:30 y:40". Notice that you do not have to explicitly call the method for the object! It is automatically invoked.

Accessor Method Headers

By convention the general template of an accessor method is as shown:
public InstanceVarType getInstanceVarName(){
    return instanceVarName;
}
Reminders: Do not forget the return type and make sure it matches the type of the instance variable. When you add a return type other than a void to a method, you are promising that the method returns data therefore be sure to return a value at the end of the method. If you are using an object's getter, what are you doing with the data? Be sure to save it to a variable or use it right away such as in a print statement.

Setters

Accesors (Setters / Mutators)

As discussed previously, programmers must provide methods to allow access to private instance variables. While getters allow someone to read the value of an instance variable, setters (accessors) allow the changing of the value of an instance variable. These methods have a parameter, the desired value for the instance variable, but they do not return a value and so are void methods. Here are some examples:
public class Temple {
    //Instance variable declaration
    private varType varName;
    // Mutator (setter) method template
    public void setVarName(varType newValue){
        varName = newValue;
    }
}
public class Ball{     //instance variable for x location     private int x;     //setter for x     public void setX(int newX){         x = newX;     } }
In some other blocks of code such as the main method, you can then invoke the setter.
public static void main(String[] args){
    // To call a set method, use objectName.setVar(newValue)
    Ball b= new Ball();
    b.setX(400);
}

When you have a block of code that you can potentially re-use or want to use without caring too much about the details of how it works, you can wrap it in a method. This is known as procedural abstraction since you are abstracting away the details. Any programmer can then just read the precondition and postcondition of the method when they want to use it without knowing how the logic is implemented. Writing methods can allow for greater organization of someone's code. You can prevent copy-pasting code in multiple sections of your project and can just call the method.

Organizing big blocks of code into methods can also make it easier to maintain and debug your program as you can often isolate the problems into individual methods. It can be great practice to test methods separately and incrementally. By this time, you will have likely seen a lot of methods and used them! This familiarity will help you write them. Here's an example block of code of someone wanting to calculate the area of 3 rectangles with random widths and height.

public static void main(String[] arg){
    int w1 = (int)(Math.random()*100)+50;
    int h1 = (int)(Math.random()*100)+50;
    System.out.println( "Area is "+(w1*h1));
    int w2 = (int)(Math.random()*100)+50;     int h2 = (int)(Math.random()*100)+50;     System.out.println( "Area is "+(w2*h2));
    int w3 = (int)(Math.random()*100)+50;     int h3 = (int)(Math.random()*100)+50;     System.out.println( "Area is "+(w3*h3)); }
As you can see above, if you continued trying to generate more random squares you will have a lot of copy-pasting. Of course, you can also write a loop to do it for you but let's see how we can use methods and classes.
public class Rectangle{
    private int width, height;
    public Rectangle(){         width = (int)(Math.random()*100)+50;         height = (int)(Math.random()*100)+50;     }
    public int calculateArea(){         return width * height;     } }
In the example above, the method calculateArea is added to return the product of the instance variables since they represent the width and height of a Rectangle object. You can then have the following block of code running elsewhere.

public class Runner{
    public static void main(String[] arg){
    //create 3 rectangles, the constructor will generate random width/height values for them.
    Rectangle a = new Rectangle();     Rectangle a = new Rectangle();     Rectangle a = new Rectangle();
    //you can then use the method to get their area     System.out.println("Area is "+a.calculateArea());     System.out.println("Area is "+a.calculateArea());     System.out.println("Area is "+a.calculateArea());
    /* using a loop to create 5 random Rectangles are printing their area! */     for(int i = 0 ; i < 5; i++){         Rectangle a = new Rectangle();         System.out.println("Area is "+a.calculateArea());     }
}

Parameters

You have seen parameters before when calling methods from the earlier units. Recently, you used a parameter for setters! The list of variables that go inside the parenthesis of methods is the parameters. You can think of it as defining what type of data the method needs in order to do its work. In order to use the method, you will then need to give or pass actual parameters such as literal values or stored in local variables.

Recall the general form of a method in java:
public returnType methodName(paramType1 paramName1, paramType2 paramName2, ..., paramTypeN paramNameN){

}

Example:
public double power(double base, double exponent){
/* logic */
}

Method Overloading

You can actually the same method names in a given class such as the one shown below. You can have methods of the same name as long as the number and/or type of parameters are different.
public class Example{
    public void mystery(int a){ System.out.println("first"); }
    public void mystery(int a, int b){ System.out.println("second");}
    public void mystery(double a){ System.out.println("third");}
}
As you can see above, the class has three methods and all are named mystery. What is different is the number and type of parameters for each method.
public class Runner{
    public static void main(String[] arg){
        Example a = new Example();
        a.mystery(1);
        a.mystery(1, 2);
        a.mystery(3.14);
    }
}
The method above will output the following to the console: first second third Java will know which one to call based on the number of parameters, order of parameters and/or type!

Static Variables and Methods

Recall when you use the methods from the Math class such as Math.random() and Math.pow(). These are actually static methods. Static methods and classes below to a class rather than objects. In this use, you are learning to create classes for which to create objects. It is these objects that hold the instance variables and instance methods. When it comes to static methods and variables, you do not need an instance of the class! You simply call the name of the class followed by the instance method or variable as you did with the Math class static methods.

Writing Static Methods

public class Ball{
//You write static methods by adding the keyword static in front of the return type of a method!
    public static double getArea(double radius){ /* some logic */ }
}
As shown above, all you have to do to write static methods is to include the static keyword in front of the method's return type. By doing this, you can now invoke that method with or without the presence of an object as shown below.
public class Driver{
    public static void main(String[] arg){
        //call the getArea static method directly with the Class name hence w/o an object
        System.out.println(Ball.getArea(3.5));
       
         //Calling it through an object is actually also valid!         Ball myBall = new Ball();         System.out.println(myBall.getArea(3.5)); //the method is invoke through the object!     } }
You should be aware by now that methods can call other methods!

However, static methods can only call other static variables or static methods.
Static methods CANNOT access or change the values of instance variables. Why is this? Recall that static methods do not need to be called upon through the existence of an object! Because of this, when a static method is called, it cannot assume that there was an object that encapsulates the instance methods and instance variables. The other way around, however, is completely valid! Instance methods can always invoke other instance methods and instance variables.

Static Variables

When you have static variables and methods, only one copy of them exists for the class. For example, take the Person class below, since the population variable is static, only one copy of it exists. This means that if all objects updated the variable once, then you can keep a track of the total population of people (number of Person objects that were created).
public class Person{
    public static int population = 0;
    
    public Person(){         population++;     }
    public static void main(String[] arg){         Person a = new Person();         Person b = new Person();         System.out.println(Person.population); //will print 2 to console     } }