Getters & Setters


#1

I don’t know if it is appropriate to ask a non-syntax question here. I didn’t see anything in the FAQ that precluded it, so here goes…

I don’t understand the concept of Getters & Setters. This chapter introduces them. I am up to chapter 8 and I am generating Getters and Setters, but I have no idea why. For instance, here is the code from chapter 8:

    Private Date mDate;               //No problems here.  Just creating a variable called mDate of type Date.

public Date getDate() {           //I have no idea why I need this.  When I want mDate filled with the date I just use [i]mDate = new Date();[/i]
	return mDate;
}

public void setDate(Date date) {       //What does this do?
	mDate = date;
}

public boolean isSolved() {         //What does this do?
	return mSolved;
}

public void setSolved(boolean solved) {   //What does this do?
	mSolved = solved;
}

Thanks in advance. I apologize if this question is remedial.

Joel Dubey


#2

Hey Joel, getters and setters (also called accessors and mutators respectively) have to do with a very important part of object oriented programming (OOP) called encapsulation. The main idea is that an object protects its instance variables by limiting who can access them directly. Since your question has to do with OOP and not Android directly, I will only use regular Java code for examples. Assuming you know Java syntax, let’s go through the process of making a class called Car from scratch to see how it will use the concept of encapsulation.

Before we start coding, think about what actions a car preforms and what characteristics, or attributes, it has.

Attributes:

  • mileage
  • color

Actions:

  • honk

Attributes will be our instance variables and actions will be our methods. Now we can start making a simple class:

/**
 * Car.java
 */

public class Car {
    int mMileage;
    String mColor;

    public void honk() {
        System.out.println("Honk!");
    }
}

As you can see we have 2 instance variables and one method. Notice how the word private doesn’t show up in front of the instance variables (for more about access modifiers check out this page http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html). More on that later. Now, every time we make a new car object based on this class it will get its own attributes and actions, just like in real life. Let’s create 2 test cars:

/**
 * CarTester.java
 */

public class CarTester {
    public static void main(String[] arguments) {

        Car myCar = new Car();
        Car yourCar = new Car();
    }
}

Note that these are two separate files that are in the default package. This isn’t the best practice, but for this simple example it will do. Since these are in the same package and we didn’t provide any access modifiers, we can directly access the instance variables of each car using the dot (.) notation from the CarTester class. Now, let’s set some values for the color of the cars like so:

/**
 * CarTester.java
 */

public class CarTester {
    public static void main(String[] arguments) {

        Car myCar = new Car();
        Car yourCar = new Car();
        
        myCar.color = "green";
        yourCar.color = "blue";
    }
}

So far so good right? Now let’s set the mileage for the cars:

/**
 * CarTester.java
 */

public class CarTester {
    public static void main(String[] arguments) {

        Car myCar = new Car();
        Car yourCar = new Car();

        myCar.color = "green";
        yourCar.color = "blue";
        
        myCar.mileage = 69000;
        yourCar.mileage = -1300;
    }
}

Here is where we start to see a problem. The code will compile and run, but it doesn’t make sense to have a negative number as mileage for a car, and as a result is a pretty major logical error. This can happen because the instance variables can be directly accessed by someone other than the Car class. This would be like cracking open the gauge in your car and making that negative. I know there are no negative numbers in the dial on your real car, but hopefully you understand what I am getting at :smiley: . As a result, it only makes sense to only allow the car to have access to its instance variables. We can achieve this by putting the access modifier private in front of each instance variable:

/**
 * Car.java
 */

public class Car {
    private int mMileage;
    private String mColor;

    public void honk() {
        System.out.println("Honk!");
    }
}

Basically the private keyword makes it so only methods within the same class can use the variables. Now we have another problem; we can’t use the dot notation anymore to directly set or use the variables. Let’s put together what we know really fast.

  1. It isn’t a good idea to let anyone have access to a class’s instance variables because errors could occur
  2. A class may not want to share a certain variable for one reason or another
  3. Private instance variables can only be accessed by methods within the same class they are in

Finally we can talk about the importance of getters and setters. These types of methods allow you access to a class’s private instance variables, but in a way that won’t make the class misbehave. Let’s add these to our car class:

/**
 * Car.java
 */

public class Car {
    private int mMileage;
    private String mColor;

    public void honk() {
        System.out.println("Honk!");
    }

    public int getMileage() {
        return mMileage;
    }

    public void setMileage(int mileage) {
        mMileage = mileage;
    }

    public String getColor() {
        return mColor;
    }

    public void setColor(String color) {
        mColor = color;
    }
}

Let’s go through one getter and one setter a line at a time to see exactly what it is doing.

Getter:

public int getMileage() {
        return mMileage;
    }

The first line tells us that the method is public and returns an int value. The name of this method, getMilage(), gives us a clue that the int returned will be the milage of the current car. This is an important naming convention that Java programmers use. Getters and setters should be either get/set followed by the variable that you are accessing/mutation. While you could name this method anything you want, if another programmer uses your class or looks at you code he or she will know what this method does just from the name. The body of this function is simple (as are many getter methods) because all it has to do is return the mMileage instance variable.

Setter:

public void setMileage(int mileage) {
        mMileage = mileage;
    }

Again this is public, has no return type, and takes one argument. Since this methods doesn’t return anything we expect it to perform some action. That action is taking the argument and assigning it to the instance variable mMilage. Let’s update out CarTester to use these new methods:

/**
 * CarTester.java
 */

public class CarTester {
    public static void main(String arguments) {

        Car myCar = new Car();
        Car yourCar = new Car();

        myCar.setColor("green");
        yourCar.setColor("blue");

        myCar.setMileage(69000);
        yourCar.setMileage(-1300);
    }
}

That is the basic use of setters and getters. Now I bet you are asking yourself "Why do I need to use these methods since it seems to only add and extra step in accessing an instance variable? After all you are still setting the milage of yourCar to -1300 but just using a method this time instead of the dot notation. :imp: " Well you are right. As the code is, there is still room for errors such as allowing negative mileage, but that is the beautiful thing about getters/setters: they allow you to control what values can be assigned to instance variables and let you decide what to do if there is a bad value trying to be assigned to it. For instance we know that we do not want to allow the mileage to be negative, so in our setter for mileage we could do something like this:

public void setMileage(int mileage) {
        if(mileage >= 0) {
            mMileage = mileage;
        }
    }

Now if a negative mileage is passed in to setMilage, it will be ignored and the value of the variable will not change. We have restricted the mileage to only positive numbers. In addition to this, we could do any number of things if the value isn’t valid:

public void setMileage(int mileage) {
        if(mileage >= 0) {
            mMileage = mileage;
        } else {
            // display message to user here
            // or throw exception
            // or set mileage to a default value
            // or just do nothing
        }
    }

Using a setter in this way encapsulates the data inside the car object and makes it so the car class behaves as you would expect it to. As the programmer, the choices are up to you. I’ll let you try and figure out what the setters and getters do in your original post now. :mrgreen:

Finally here is an example you can run for yourself to see how these all work.

/**
 * Car.java
 */

public class Car {
    private int mMileage;
    private String mColor;

    /**
     * Default constructor
     */
    public Car() {
        mMileage = 0;
        mColor = "white";
    }

    public void honk() {
        System.out.println("Honk!");
    }

    /**
     *
     * @return Current mileage of the car
     */
    public int getMileage() {
        return mMileage;
    }

    /**
     * Sets the mileage of the car. Value must be positive or the mileage will not be changed
     * @param mileage Value to be assigned as the new mileage
     */
    public void setMileage(int mileage) {
        if(mileage >= 0) {
            mMileage = mileage;
        }
    }

    /**
     *
     * @return Current color of the car
     */
    public String getColor() {
        return mColor;
    }

    /**
     *
     * @param color New color of the car
     */
    public void setColor(String color) {
        mColor = color;
    }
}

and

/**
 * CarTester.java
 */

public class CarTester {
    public static void main(String[] arguments) {

        // Creates 2 cars with mileage == 0 and color == white by default constructor
        Car myCar = new Car();
        Car yourCar = new Car();

        // Changes the color and mileage of myCar, then displays it
        myCar.setColor("green");
        myCar.setMileage(69000);
        System.out.println("My car has " + myCar.getMileage() + " miles and is " + myCar.getColor() + ".");

        // Changes color and tries to set negative mileage of yourCar, then displays it
        yourCar.setColor("blue");
        yourCar.setMileage(-1300);
        System.out.println("Your car has " + yourCar.getMileage() + " miles and is " + yourCar.getColor() + ".");
    }
}

I haven’t really been programming that long so please forgive any mistakes here! :blush: Hope this helps you out a little!

  • GentlemanRabbit

#3

Wow. First let me thank you for the time you put into this response. I’m sure it took you a long time to type this. Secondly let me just say that this was an amazing explanation. You step-by-step walk through was great. I can now say I understand Getters and Setters. My programming background comes from the 80’s so OOP is still a fuzzy concept to me. I think that this tutorial actually puts a lot of OOP into perspective. Thanks again for taking the time out to do all this work!!!