Welcome to Lesson 7!
Learning Objectives for Today's Lesson
By the end of today's lesson, you should know...
- What is encapsulation?
- What is information hiding?
- What is the rationale for using encapsulation and information hiding and how do you implement them as part of your class?
- What are mutator methods (setters) and accessor methods (getters)?
- What is a toString() method and why is it useful?
1. Encapsulation and Information Hiding
Encapsulation and Information Hiding
The Prescription for Larger Programs
- To make larger programs more manageable, we use classes
- Two important features of classes are:
- Encapsulation
- Information hiding
- These two concepts are closely intertwined
- Sometimes you will see a reference to one term when the writer means both terms
Encapsulation
Encapsulation: inclusion of a number of items into a single unit
- We saw an example of encapsulation when we looked at our first phone class
- Encapsulation allowed us to group related variables in one container (capsule)
- If the variables in the grouping are logically related, we can more easily keep track of what is happening with the data
- For example, we can keep all the data about a product inside one container
- In addition to data, classes extend encapsulation to include member methods
- Member methods are methods that work with the member variables
- Thus, methods like
addYear() are grouped into the class that describes a Person
Information Hiding
Information hiding: hiding the parts of the design that are most likely to change (a.k.a. data hiding)
- As programs develop, developers change them frequently
- Even after a program is first completed and released, successful programs are updated with new features
- With large programs, making a change in one area can cause problems in other areas
- By hiding the parts of a program most likely to change, a programmer can make implementing changes much easier
- The ability to change parts of a program without affecting other parts becomes more important as programs grow larger
- Recall that the instance variables of our example classes
- In the first example we declared the variables with the modifier
public :
public String brand;
public double price;
- Yet good practice dictates that we would make these variables
private :
private String brand;
private double price;
- The modifier
public means there are no restrictions on accessing the variables. They can be accessed by any class.
- The modifier
private means the variable cannot be accessed outside of the class
- We could test this feature by writing a test like the following:
Phone iphone = new Phone();
iphone.brand = "iPhone";
iphone.price = 599.95;
- If we try to compile this code, then we get an error message
- However, if we remove the keyword
private , then the test code compiles without error
- So why bother with
private data?
- Good software engineering practice says you should almost always declare class variables
private
- One of the exceptions is that constants may be declared
public
- There are other rare cases, but you will not run across them in this course
- Thus, for this course, always declare non-constant instance variables
private
- The most important reason is to hide the internal implementation details of the class
- You want to prevent programmers from relying on those details so that you can safely modify your class implementation at any time without worrying that you will break code that uses the class
- Additionally, our methods define how we want users of our class to interact with the data. We
can control access and put checks in place in our methods to make sure
the data of our class is handled properly by other programmers.
Example Student Class (from Lesson 6 Practice Exam Questions)
public class Student {
public String name;
public double gpa;
public void printStudent() { System.out.println("Hi! My name is " + name + ".\n" + "And, my GPA is " + gpa + ".");
}
}
public class StudentTest { public static void main(String[] args) { Student Jackie = new Student(); Jackie.name = "Jackie Chan"; Jackie.gpa = 3.5; Jackie.printStudent();
}
}
- Note we are not free to make revisions to our class design without affecting the way in which a user will interact with it.
- For example, if we later revise our code to store first and last names of students as separate variables, the code in StudentTest (and all other classes relying on our code) will break.
public class Student {
public String firstName;
public String lastName;
public double gpa;
public void printStudent() { System.out.println("Hi! My name is " + name + ".\n" + "And, my GPA is " + gpa + ".");
}
}
public class StudentTest { public static void main(String[] args) { Student Jackie = new Student(); Jackie.name = "Jackie Chan"; //breaks!
Jackie.gpa = 3.5; Jackie.printStudent();
}
}
2. Accessor and Mutator Methods
- You should always make all instance variables of a class private
- However, you will still need to interact with the data of a class object.
- Applying the principle of information hiding, we can revise our Phone class from the prior lesson like so:
public class Phone {
private String brand; private String model; private double price;
public String getBrand() {
return brand;
}
public String getModel() {
return model;
} public double getPrice() {
return price;
} public void setBrand(String newBrand) {
brand = newBrand;
} public void setModel(String newModel) {
model = newModel;
}
public void setPrice(double newPrice) {
price = newPrice;
}
public void makeCall() {
System.out.println(brand + " is now making a call.");
}
public void makeCall(String name) {
System.out.println(brand + " is now making a call to " + name);
}
}
- Above, we make the member variables private, and define methods to allow users to interact with objects of the Phone class.
- We can then revise our PhoneTest class to call these methods:
public class PhoneTest {
public static void main(String[] args) {
Phone iphone = new Phone();
iphone.setBrand("iPhone");
iphone.setModel("7S"); iphone.setPrice(521.56);
Phone samsung = new Phone();
samsung.setBrand("Samsung");
samsung.setModel("Galaxy S8");
samsung.setPrice(499.99);
iphone.makeCall();
samsung.makeCall();
}
}
Mutator Methods
- Recall the
setbrand(), setModel() and setPrice() methods from the Phone class:
public class Phone {
private String brand; private String model; private double price;
public void setBrand(String newBrand) {
brand = newBrand;
}
public void setModel(String newModel) {
model = newModel;
} public void setPrice(double newPrice) {
price = newPrice;
}
}
- These methods are mutator methods - an operation that modifies the object
- Recall that the word mutate means to change
- After a mutator method executes, the state of the class changes
- In this case, the
setPrice(), setModel(), setBrand() methods change the values of the private member variables
- Typically, mutator methods have a void return type, but do take a parameter
Accessor Methods
- Recall the
getBrand(), getModel() and getPrice() methods from the Phone class:
public class Phone {
private String brand; private String model; private double price;
public String getBrand() {
return brand;
}
public String getModel() {
return model;
} public double getPrice() {
return price;
}
}
- The
getBrand(), getModel(), getPrice() methods are accessor methods
- An accessor method queries the object for some information without changing the state of the object
- These methods return information about a Phone without changing the state of the object.
- For example:
System.out.println("The price of this phone: " + iphone.getPrice());
- Therefore, these methods frequently have a non-void return type, but no parameters.
Get and Set Methods
- Changing and retrieving a single value is a common operation
- In these cases, the standard practice is to use the word get or set in front of the variable name
- Thus, the name for a mutator method to change the value of
price is setPrice() :
public void setPrice(double newPrice) {
price = newPrice;
}
- Colloquially, these mutator methods are known as "setters"
- The name for an accessor method to retrieve the value of
price is getPrice() :
public double getPrice() {
return price;
}
-
Colloquially, these accessor methods are called "getters"
Phone Class with Accessor and Mutator Methods
- At the end of last class, we altered our Phone class to employ "getters" and "setters" to allow users to access or modify the data stored in the member variables.
- Below is the Phone class that includes these getters and setters, as well as a new method called
toString() which now replaces the printPhone method.
Example Phone Class
/**
* Phone.java example
* @author parrishj
*
*/
public class Phone {
public String brand;
public String model;
public double price;
/**Accessors*/
/**
* Returns the brand of phone
* e.g. iPhone or Samsung
* @return the brand
*/
public String getBrand() {
return brand;
}
/**
* Returns the phone's model
* e.g. 7 or Galaxy S5
* @return the model
*/
public String getModel() {
return model;
}
/**
* Returns the phone's current
* market price
* @return the price
*/
public double getPrice() {
return price;
}
/**Mutators*/
/**
* Assigns a brand to the phone
* e.g. iPhone or Samsung
* @param newBrand the brand of phone
*/
public void setBrand(String newBrand) {
brand = newBrand;
}
/**
* Assigns a model to the phone
* e.g. 7 or Galaxy S5
* @param newModel the phone's model
*/
public void setModel(String newModel) {
model = newModel;
}
/**
* Assigns the phone the current
* market price for that brand
* and model
* @param newPrice the market price
*/
public void setPrice(double newPrice) {
price = newPrice;
}
/**Additional Methods*/
/**
* Displays a message alerting the user
* that the phone is now making a call
*/
public void makeCall() {
System.out.println(brand + " is now making a call.");
}
/**
* Displays a message alerting the user
* that the phone is now making a call
* to a specified person
* @param name the person who is being called
*/
public void makeCall(String name) {
System.out.println(brand + " is now calling " + name);
}
/**
* Returns a String of all the important
* information about the phone, including
* brand, model and price
* @return the important phone information
*/
@Override public String toString() {
return "Brand: " + brand
+ "\nModel: " + model
+ "\nPrice: " + price;
}
}
Local Variables, Parameters and Shadowing
- Shadowing is when a local variable or parameter has the same name as a member variable of a class
- Local variables and parameters with same name as a member variable hide the member variable
- Any use of the variable's name will refer to the local variable or parameter
- This is the source of many an elusive bug
- You should not use the same name for a local variable or parameter and a class member variable
- Remember that a parameter is like a local variable but initialized in a special way
- Thus you should use a different name for a parameter and a member variable
- Which lines contain local shadowing in the following program and how do you correct the problem.
Example of Shadowingpublic void setBrand(String brand) { brand = brand;
}
Activity 7.1: A Person Class with Accessors, Mutators, and Information Hiding (10 pts)- Open up Person.java class from the Lesson 6.
- Alter the member variables to make the access modifier private. For example:
private String name; //You alter the rest
- Next, write accessor and mutator methods to allow users to access and modify the data stored in the instance variables. For example:
public String getName() { return name;
}
public void setName(String theName) { name = theName;
}
- Note: As shown the mutator method definition above, please try to avoid "shadowing"
- Copy and paste the new test file below into PersonTest.java (you can erase the old contents of the file).
- Then add the method calls were indicated in below in bold.
/** * PersonTest.java, Activity 7.1 * @author * CIS 36B */
import java.util.Scanner;
public class PersonTest { public static void main(String[] args) { Scanner input = new Scanner(System.in); String name, gender; int age; Person person = new Person(); System.out.print("Welcome!\n\nEnter your name: "); name = input.nextLine();
//call setName here
System.out.println("You entered: " + //call getName here + "\n");
System.out.print("Enter your age: "); age = input.nextInt();
//call setAge here
System.out.println("You entered: " + //call getAge here + "\n");
System.out.print("Enter your gender: "); gender = input.next();
//call setGender here
System.out.println("You entered: " + //call getGender here + "\n");
System.out.println("Your Summary:\n" + person.printPerson); //fix mistake on this line } } - When you get the correct output (as shown below), upload Person.java and PersonTest.java to Canvas
Sample Output (Note that user input may vary):
Welcome!
Enter your name: Marta Gomez You entered: Marta Gomez
Enter your age: 25 You entered: 25
Enter your gender: Female You entered: Female
Your Summary: Name: Marta Gomez Age: 25 Gender: Female
3. Required Member Methods: toString()
Phone samsung = new Phone();
samsung.setBrand("Samsung");
samsung.setModel("Galaxy S8");
samsung.setPrice(499.99);
System.out.println(samsung); //invokes toString() automatically
//alternately
System.out.println(samsung.toString());
File file = new File("someFile.txt");
PrintWriter out = new PrintWriter(file);
out.println(samsung); //invokes toString() automatically
//alternately
out.println(samsung.toString());
out.close();
Activity 7.2: A Person Class with a toString Method (10 pts) - Open Person.java class from the previous activity.
- Remove the printPerson method from this class.
- Instead, write a toString() method that can be used to display the Student Object in the following manner:
Name: <The Name> Age: <The Age> Gender: <The Gender>
- Note the use of the <> above. Do not add these <> to your String. Instead, these <> are commonly used to mean a value will be filled in later.
- Don't forget the @Override tag in front of the toString() method
- Using the below starter code and the toString method, we will now display the Person object both to the console and to a File.
- Copy and paste the new test file below into PersonTest.java (you can erase the old contents of the file).
- Then, update the code to call the toString method to display the Person object both to the console and to a file.
- Notice the versatility of this method!
- Finally, refresh your project on Canvas (right-click on the project and select the refresh option). You should see the person.text file appear in the package exploreer. Open this file to verify that you get the correct output in person.txt.
/** * PersonTest.java, Activity 7.2 * @author * CIS 36B */
import java.util.Scanner; import java.io.*;
public class PersonTest { public static void main(String[] args) throws IOException{ Scanner input = new Scanner(System.in); File file = new File("person.txt");
PrintWriter out = new PrintWriter(file);
String name, gender; int age; Person person = new Person(); System.out.print("Welcome!\n\nEnter your name: "); name = input.nextLine(); person.setName(name); System.out.println("You entered: " + person.getName() + "\n");
System.out.print("Enter your age: "); age = input.nextInt(); person.setAge(age); System.out.println("You entered: " + person.getAge() + "\n");
System.out.print("Enter your gender: "); gender = input.next(); person.setGender(gender); System.out.println("You entered: " + person.getGender() + "\n");
System.out.println("Your Summary:\n" + //call toString here); out.println("Your Summary: "); //add one line of code to write person to the file - Hint: call toString! out.close();
} } - When you get the correct output (as shown below), upload Person.java and PersonTest.java to Canvas
Sample Output (Note that user input may vary):
Welcome!
Enter your name: Marta Gomez You entered: Marta Gomez
Enter your age: 25 You entered: 25
Enter your gender: Female You entered: Female
Your Summary: Name: Marta Gomez Age: 25 Gender: Female
Sample Output in person.txt: Your Summary: Name: Marta Gomez Age: 25 Gender: Female
Wrap Up
- Answer the Lesson 7 Practice Exam Questions on Canvas
Upcoming Assignments:- Lesson 7 Practice Exam Questions due Tuesday at 11:59pm
- Activities 7.1 and 7.2 due Tuesday at 11:59pm
- Quiz 4 due Friday at 11:59pm
- Peer Reviews of Lesson 7 Practice Exam Questions due Saturday at 11:59pm
- Lab 4 due next Monday at 11:59pm
~ Have a Great Day! ~ |