Anatomy of a Class
Why this matters
Imagine you're driving a car. You have access to the steering wheel, the gas and brake pedals, and the turn signal. These are the public controls, designed for you to use. You can interact with them safely to make the car go, stop, and turn.
Now, imagine if the hood were open and all the engine's complex wiring and moving parts were exposed right next to you. What if you accidentally bumped a critical wire while trying to change the radio station? The whole car could break down.
Car designers are smart. They hide the complex, delicate engine parts under the hood, a practice we call encapsulation. They give you a simple, safe interface to use the car. In programming, we do the exact same thing. This lesson is about how we build that "hood" for our code to make it safer, more reliable, and easier to use.
Concept overview
classDiagram
class Car {
-double currentSpeed
-boolean engineOn
+String model
+startEngine()
+stopEngine()
+accelerate(double amount)
+getSpeed() double
}
Core explanation
When we build classes, we're creating our own custom data types. Think of a Student, a BankAccount, or a GameCharacter. To make these classes robust and easy to work with, we need to be deliberate about their structure. This is where we get into the anatomy of a class, specifically using the keywords public and private.
Data Encapsulation: The "Black Box" Idea
Data encapsulation is a core principle of object-oriented programming. It means bundling the data (instance variables) and the methods that operate on that data together within a single class, and hiding the implementation details from the outside world.
Think of a microwave. You put your food in, press a few buttons (public methods like setTimer and start), and get hot food out. You don't know—and you don't need to know—exactly how the magnetron generates microwaves to heat your food. The complex details are encapsulated, or hidden. All you need is the simple, public interface.
In Java, we achieve encapsulation with access modifiers: public and private.
public: These members are accessible from anywhere. Any other class can see and use them. This is your public interface, like the buttons on the microwave.private: These members are only accessible from inside the class in which they are declared. No other class can see or touch them directly. This is the hidden wiring.
The Anatomy of a public Class
For the AP Computer Science A exam, the classes you write will always be public.
public class Student {
// ... class members go here
}
This public keyword on the class declaration means that code in other files can create Student objects. Now let's look inside.
Instance Variables: Keep Them private
Instance variables are the data that defines an object's state. For a Student class, this might be their name, ID number, and GPA. Each Student object you create gets its own copy of these variables. Liam's gpa is separate from Priya's gpa.
To properly encapsulate our data, we should almost always declare our instance variables as private.
public class Student {
private String name;
private int studentID;
private double gpa;
// ... constructors and methods follow
}
Why private? This is the most important takeaway. By making these variables private, we prevent other parts of our code from putting our object into an invalid state.
Imagine if gpa were public. Another piece of code could do this:
someStudent.gpa = 5.0; // A 5.0 GPA isn't possible!
anotherStudent.gpa = -100.0; // This is nonsense!
By making gpa private, we force other code to go through a method we provide, where we can add validation. This protects the integrity of our object's data.
Constructors: Make Them public
A constructor's job is to build a new object. To build a Student object from your main method (which is in another class), you need to be able to access the constructor. Therefore, in this course, constructors are always public.
public class Student {
private String name;
private int studentID;
private double gpa;
// The public constructor
public Student(String initialName, int id, double initialGpa) {
name = initialName;
studentID = id;
gpa = initialGpa;
}
// ... other methods
}
If the constructor were private, you couldn't create a Student from outside the Student class, which would make it pretty useless!
Methods: A Mix of public and private
Methods define an object's behaviors. These can be either public or private.
public Methods:
These methods form the object's interface—the services it offers to the outside world. These are things like "getters" that return the value of a private variable, "setters" that modify a private variable (with validation!), or other actions.
public class Student {
// ... instance variables and constructor
// A "getter" method
public double getGPA() {
return gpa;
}
// A "setter" method with validation
public void setGPA(double newGPA) {
if (newGPA >= 0.0 && newGPA <= 4.0) {
gpa = newGPA;
}
}
public void printIDCard() {
System.out.println("Name: " + name);
System.out.println("ID: " + studentID);
}
}
Anyone with a Student object can call getGPA() or printIDCard().
private Methods:
Sometimes, a public method is very complex. You can break that complexity down by writing private "helper" methods. These helper methods are not intended to be called by anyone outside the class; they are just an internal implementation detail.
Let's say we want a public method to determine if a student is on the honor roll, which has a complex calculation.
public class Student {
// ... instance variables, constructor, other methods
public boolean isOnHonorRoll() {
// A complex task is made simpler by calling a helper
boolean hasGoodGrades = checkGrades();
boolean hasGoodAttendance = checkAttendance();
return hasGoodGrades && hasGoodAttendance;
}
// A private helper method. No one outside this class
// needs to know how we check the grades.
private boolean checkGrades() {
// some complex logic to check grades...
return gpa > 3.5;
}
// Another private helper method
private boolean checkAttendance() {
// some complex logic to check attendance records...
return true; // simplified for example
}
}
The user of the Student class just calls isOnHonorRoll(). They don't need to see or use the checkGrades() or checkAttendance() methods. Using private helpers keeps our code organized and our public interface clean.
See it in action
Worked examples
Let's put these concepts into practice. Seeing how public and private work in a complete class is the best way to learn.
Example 1: Creating a Book Class
Problem: You're building a library app. Create a Book class that stores a title (String), author (String), and pageCount (int). The data must be encapsulated. The class needs a constructor to initialize a new book and a getSummary() method that returns a string like "To Kill a Mockingbird by Harper Lee".
Solution Walkthrough:
-
Define the class and instance variables. We'll start with a
publicclass. The core data—title,author,pageCount—should be hidden from the outside world to prevent invalid data. So, we make themprivate.public class Book { private String title; private String author; private int pageCount; -
Create the
publicconstructor. We need a way to createBookobjects. The constructor will take the initial values and assign them to ourprivateinstance variables.// Inside the Book class... public Book(String bookTitle, String bookAuthor, int pages) { title = bookTitle; author = bookAuthor; pageCount = pages; }Why is this
public? So that code in other files (like aLibraryclass) can create newBookobjects. -
Implement the
publicmethod. ThegetSummary()method is a behavior we want to offer to the public. It reads the internalprivatedata and formats it.// Inside the Book class... public String getSummary() { return title + " by " + author; }
Putting it all together:
public class Book {
private String title;
private String author;
private int pageCount;
public Book(String bookTitle, String bookAuthor, int pages) {
title = bookTitle;
author = bookAuthor;
pageCount = pages;
}
public String getSummary() {
return title + " by " + author;
}
}
Where students go wrong: A common mistake is making title or pageCount public. If pageCount were public, another programmer could write myBook.pageCount = -200;, which makes no sense. By making it private, we retain control.
Example 2: Using a private Helper Method
Problem: Let's expand our Book class. Add a public method getReadingTimeInMinutes() that estimates how long it will take to read the book. Assume a reading speed of 250 words per page and 1 minute per page. The calculation for words is just an estimate, so we'll hide it in a helper method.
Solution Walkthrough:
-
Define the
publicmethod. This is the method the outside world will call.// Inside the Book class... public int getReadingTimeInMinutes() { // For simplicity, let's say it's 1 minute per page. // A more complex calculation could go here. return pageCount; } -
Let's make it more complex to justify a helper. Let's say we want to add a 5-minute "settling in" period to any book over 100 pages. This logic clutters our public method. Let's move it to a helper.
-
Create a
privatehelper method. This method will contain the detailed calculation logic. It'sprivatebecause no one outside theBookclass needs to know how we calculate this bonus time.// Inside the Book class... private int calculateBonusTime() { if (pageCount > 100) { return 5; // Add 5 bonus minutes for long books } return 0; } -
Update the
publicmethod to use the helper.// Inside the Book class... public int getReadingTimeInMinutes() { int baseTime = pageCount; // 1 minute per page int bonusTime = calculateBonusTime(); // Call the private helper return baseTime + bonusTime; }Why do this? The public method
getReadingTimeInMinutes()is now clean and easy to read. The messy details are tucked away incalculateBonusTime(). If we later decide to change the bonus time calculation, we only have to change theprivatemethod. The public interface remains the same, and no other part of the program that uses theBookclass will break.
Try it yourself
Ready to build your own class blueprint? Give these a try.
-
Design a
Movieclass.- It should have
privateinstance variables fortitle(String),director(String), andrating(adoublefrom 1.0 to 10.0). - Write a
publicconstructor that initializes these three variables. - Hint: Remember the principle of encapsulation. Why is it important for
ratingto beprivate?
- It should have
-
Add a helper method to your
Movieclass.- First, add a
privateinstance variable forreleaseYear(anint). Don't forget to update your constructor! - Create a
publicmethod calledgetMovieDetails()that returns a String. - Inside
getMovieDetails(), call a newprivatehelper method namedisClassic(). This helper should returntrueif thereleaseYearis before 2000, andfalseotherwise. - If
isClassic()returnstrue, thegetMovieDetails()string should include the text "(Classic)". - Hint: Your public method's job is to assemble the string. Your private method's job is to make a single decision.
- First, add a
Practice — 8 questions
In simple terms, class anatomy is about using `public` and `private` labels to control which parts of your code can be seen and used by other parts of your program, just like a TV remote has public buttons but private internal wiring.
public class Student {
// ... class members go here
}
- 3.3.A: Develop code to designate access and visibility constraints to classes, data, constructors, and methods.
- 3.3.A.1
- Data encapsulation is a technique in which the implementation details of a class are kept hidden from external classes. The keywords public and private affect the access of classes, data, constructors, and methods. The keyword private restricts access to the declaring class, while the keyword public allows access from classes outside the declaring class.
- 3.3.A.2
- In this course, classes are always designated public and are declared with the keyword class.
- 3.3.A.3
- In this course, constructors are always designated public.
- 3.3.A.4
- Instance variables belong to the object, and each object has its own copy of the variable.
- 3.3.A.5
- Access to attributes should be kept internal to the class in order to accomplish encapsulation. Therefore, it is good programming practice to designate the instance variables for these attributes as private unless the class specification states otherwise.
- 3.3.A.6
- Access to behaviors can be internal or external to the class. Methods designated as public can be accessed internally or externally to a class, whereas methods designated as private can only be accessed internally to the class.
classDiagram
class Car {
-double currentSpeed
-boolean engineOn
+String model
+startEngine()
+stopEngine()
+accelerate(double amount)
+getSpeed() double
}
Read what Saavi narrates
Hi everyone, it's Saavi. Let's talk about building our own classes in Java.
Imagine you're driving a car. You use the steering wheel, the pedals, the turn signal... these are the public controls, designed for you. Now, imagine if all the engine's wiring was exposed right next to you. You could accidentally break something just by trying to change the radio station!
Car designers are smart. They hide the complex engine parts under the hood. They give you a simple, safe interface to use. In programming, we do the exact same thing. We decide what's `public`, like the steering wheel, and what's `private`, like the engine wiring. This is called encapsulation.
A class is just a blueprint for an object. The "anatomy" of that class is all about defining which parts are public and which are private.
Let's walk through an example. Say we're creating a `Book` class. A book has a title, an author, and a page count. This is its data. To protect this data, we declare these instance variables as `private`. This prevents some other part of the program from, say, setting the page count to a negative number.
To create a book, we need a `public` constructor. This is the factory that builds our `Book` object. And to get information, we create `public` methods. For example, a `public` method called `getSummary` could return a string like "To Kill a Mockingbird by Harper Lee". This method can access the `private` title and author because the method itself is inside the `Book` class.
Here's a really common mistake: making those instance variables public. It seems easier at first, but it breaks the whole "under the hood" safety principle. It allows anyone to mess with the object's data, which can lead to a lot of bugs. So remember the rule: instance variables are private. Methods and constructors that the outside world needs to use are public.
You're building blueprints for reliable, predictable, and safe objects. It's a powerful concept, and you are more than capable of mastering it. Keep practicing, and you'll get it.
This breaks encapsulation. It allows any other part of the code to directly change an object's data, potentially to an invalid value (e.g., a negative GPA or a bank balance of a trillion dollars).
Always declare instance variables as `private`. Provide `public` "getter" and "setter" methods if you need to allow controlled access.
The `private` keyword explicitly forbids this. The compiler will give you an error, like "The field `Book.title` is not visible".
Use the `public` methods the class provides. Instead of `myBook.title`, you should use a method like `myBook.getTitle()`.
This clutters your class's public interface with implementation details. It suggests to other programmers that they can or should use this method, when it's really just for internal use. If you change the helper method later, it could break their code.
If a method is only used by other methods *inside the same class*, make it `private`.
If the constructor is `private` (or has no access modifier in some contexts), you won't be able to create an object of that class from another class, which is usually the whole point.
In AP CSA, your constructors will always be `public`.
The `private` restriction is strict. Access is limited to the code *within the object itself*. Code in `book1`'s methods cannot directly access `book2.title`, even though they are both `Book` objects.
To have one object interact with another's data, you must use the second object's `public` methods. For example: `book1.isLongerThan(book2)` would be a public method where `book1` calls `book2.getPageCount()` to compare.