Lesson Weekend

Now that we know how to create both classes, and custom methods within those classes, let's explore a special type of method called a constructor that will make the process of instantiating new objects much, much easier.

Currently, the App.java file of our car dealership program looks like this:

App.java
import models.Vehicle;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class App {
   public static void main(String[] args) {

       BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
       System.out.println("What is your maximum budget for a vehicle?");

       try {
           String stringUserMaxBudget = bufferedReader.readLine();

           Vehicle hatchback = new Vehicle();
           hatchback.year = 1994;
           hatchback.brand = "Subaru";
           hatchback.model = "Legacy";
           hatchback.miles = 170000;
           hatchback.price = 4000;

           Vehicle suv = new Vehicle();
           suv.year = 2002;
           suv.brand = "Ford";
           suv.model = "Explorer";
           suv.miles = 100000;
           suv.price = 7000;

           Vehicle sedan = new Vehicle();
           sedan.year = 2015;
           sedan.brand = "Toyota";
           sedan.model = "Camry";
           sedan.miles = 50000;
           sedan.price = 30000;

           Vehicle truck = new Vehicle();
           truck.year = 1999;
           truck.brand = "Ford";
           truck.model = "Ranger";
           truck.miles = 100000;
           truck.price = 4000;

           Vehicle crossover = new Vehicle();
           crossover.year = 1998;
           crossover.brand = "Toyota";
           crossover.model = "Rav-4";
           crossover.miles = 200000;
           crossover.price = 3500;

           Vehicle[] allVehicles = {hatchback, suv, sedan, truck, crossover};

           int userMaxBudget = Integer.parseInt(stringUserMaxBudget);

           System.out.println("Alright, here's what we have in your price range:");

           for (Vehicle individualVehicle : allVehicles) {
               if (worthBuying(individualVehicle.price, userMaxBudget)) {
                   System.out.println("----------------------");
                   System.out.println(individualVehicle.year);
                   System.out.println(individualVehicle.brand);
                   System.out.println(individualVehicle.model);
                   System.out.println(individualVehicle.miles);
                   System.out.println(individualVehicle.price);
               }
           }
       }
       catch(IOException e)
       {
           e.printStackTrace();
       }
   }
}

Our dealership only has 5 cars right now, but don't you think that's a lot of code we had to include just to create our 5 Vehicle objects? It's 30 whole lines!

In previous lessons we walked through how to DRY up our code using custom methods we defined for our applications. Thankfully, there's a special type of method we can create to make the process of instantiating new objects much, much quicker.

Constructors

A constructor is a method that creates a new instance of a class. It constructs a new object, if you will. Any information regarding the initial setup of a new object can be included in a constructor.

Writing Constructor Methods

Next, let's walk through adding a constructor to our Vehicle class together:

Vehicle.java
public class Vehicle {

  public int year;
  public String brand;
  public String model;
  public int miles;
  public int price;

  public Vehicle(int year, String brand, String model, int miles, int price) {
    this.year = year;
    this.brand = brand;
    this.model = model;
    this.miles = miles;
    this.price = price;
  }

  public boolean worthBuying(int maxPrice){
    return (this.price < maxPrice);
  }

}

As you can see, constructors look a lot like 'normal' methods. But what makes them special is that their return type is the type of the class they belong to. In this case, Vehicle. Additionally, you can see it has an access modifier, which we have set to public. And it takes multiple parameters. Each of these parameters correspond to the properties a Vehicle object should have, including an int value to represent its year, a String containing the name of the vehicle's brand, etc.

Within the method, we simply take each of the parameters we've passed in, and used them to define the object's various properties. The first parameter, an int named year will be the new object's year property. The second, a String called brand will represent the new object's brand property. So on, and so forth.

Calling Constructor Methods

Constructors create new instances of a class when the new keyword is used. new denotes that we're creating a new instance of this class:

 Vehicle firstCar =  new Vehicle(1990, "Chrysler", "Lebaron", 200000, 4000);
  • Just like every other variable, it needs a type declaration. That's why the name of our custom class is the first element in this line of code.
  • It also has a name like any other variable. We're calling ours firstCar.
  • The word Vehicle is included again after the new keyword because this is also the name of our constructor (it's best practice to name your constructor after your class).
  • Finally, we include the five arguments required by our constructor. They denote the year, brand, model, miles, and price that belong to this specific car at our dealership.

When our car dealership attains another Vehicle to sell, we can create another instance of this class, but with different details:

Vehicle secondCar =  new Vehicle(1998, "Toyota", "Rav-4", 150000, 7000);

Using Constructors in Java Applications

Now, let's use our new constructor in the command line interface of our car dealership application.

We can refactor this:

App.java
import models.Vehicle;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class App {
   public static void main(String[] args) {

       BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
       System.out.println("What is your maximum budget for a vehicle?");

       try {
           String stringUserMaxBudget = bufferedReader.readLine();

           Vehicle hatchback = new Vehicle();
           hatchback.year = 1994;
           hatchback.brand = "Subaru";
           hatchback.model = "Legacy";
           hatchback.miles = 170000;
           hatchback.price = 4000;

           Vehicle suv = new Vehicle();
           suv.year = 2002;
           suv.brand = "Ford";
           suv.model = "Explorer";
           suv.miles = 100000;
           suv.price = 7000;

           Vehicle sedan = new Vehicle();
           sedan.year = 2015;
           sedan.brand = "Toyota";
           sedan.model = "Camry";
           sedan.miles = 50000;
           sedan.price = 30000;

           Vehicle truck = new Vehicle();
           truck.year = 1999;
           truck.brand = "Ford";
           truck.model = "Ranger";
           truck.miles = 100000;
           truck.price = 4000;

           Vehicle crossover = new Vehicle();
           crossover.year = 1998;
           crossover.brand = "Toyota";
           crossover.model = "Rav-4";
           crossover.miles = 200000;
           crossover.price = 3500;

           Vehicle[] allVehicles = {hatchback, suv, sedan, truck, crossover};

           int userMaxBudget = Integer.parseInt(stringUserMaxBudget);

           System.out.println("Alright, here's what we have in your price range:");

           for (Vehicle individualVehicle : allVehicles) {
               if (individualVehicle.worthBuying(userMaxBudget)) {
                   System.out.println("----------------------");
                   System.out.println(individualVehicle.year);
                   System.out.println(individualVehicle.brand);
                   System.out.println(individualVehicle.model);
                   System.out.println(individualVehicle.miles);
                   System.out.println(individualVehicle.price);
               }
           }
       }
       catch(IOException e)
       {
           e.printStackTrace();
       }
   }

}

Into this:

App.java
import models.Vehicle;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class App {
   public static void main(String[] args) {

       BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
       System.out.println("What is your maximum budget for a vehicle?");

       try {
           String stringUserMaxBudget = bufferedReader.readLine();

           Vehicle hatchback = new Vehicle(1994, "Subaru", "Legacy", 170000, 4000);
           Vehicle suv = new Vehicle(2002, "Ford", "Explorer", 100000, 7000);
           Vehicle sedan = new Vehicle(2015, "Toyota", "Camry", 50000, 30000);
           Vehicle truck = new Vehicle(1999, "Ford", "Ranger", 100000, 4000);
           Vehicle crossover = new Vehicle(1998, "Toyota", "Rav-4", 200000, 3500);

           Vehicle[] allVehicles = {hatchback, suv, sedan, truck, crossover};

           int userMaxBudget = Integer.parseInt(stringUserMaxBudget);

           System.out.println("Alright, here's what we have in your price range:");

           for (Vehicle individualVehicle : allVehicles) {
               if (individualVehicle.worthBuying(userMaxBudget)) {
                   System.out.println("----------------------");
                   System.out.println(individualVehicle.year);
                   System.out.println(individualVehicle.brand);
                   System.out.println(individualVehicle.model);
                   System.out.println(individualVehicle.miles);
                   System.out.println(individualVehicle.price);
               }
           }
       }
       catch(IOException e)
       {
           e.printStackTrace();
       }
   }

}

Isn't this so much cleaner?! And if we save, compile, and run the application one more time, each of our Vehicle objects are still present!

> What is your maximum budget for a vehicle?
50000

> Alright, here's what we have in your price range:
----------------------
1994
Subaru
Legacy
170000
4000
----------------------
2002
Ford
Explorer
100000
7000
----------------------
2015
Toyota
Camry
50000
30000
----------------------
1999
Ford
Ranger
100000
4000
----------------------
1998
Toyota
Rav-4
200000
3500

Moving forward, use constructor methods to create instances of custom classes in all your applications.


Example GitHub Repo for Car Dealership

Terminology


  • Constructors: method that runs to create a new instance of a class. It constructs a new object, if you will. Any information regarding the initial setup of a new object can be included in a constructor.

Overview


  • Constructor methods have a return type that matches the object they're constructing. For instance, a Vehicle constructor method will return a Vehicle type object.

  • Constructor methods take multiple arguments. They use the information provided in arguments to define the attributes of the new object they're creating:

  public Vehicle(int year, String brand, String model, int miles, int price) {
    this.year = year;
    this.brand = brand;
    this.model = model;
    this.miles = miles;
    this.price = price;
  }
  • Constructors create new instances of a class when the new keyword is used. new denotes that we're creating a new instance of this class:
 Vehicle firstCar =  new Vehicle(1990, "Chrysler", "Lebaron", 200000, 4000);

Examples


Example GitHub Repo for Car Dealership