In Java, encapsulation means keeping the internal details of a class hidden and exposing only what is necessary through well-defined interfaces. One common way to enforce encapsulation is by making fields (variables) private and providing public getter and setter methods to access and modify these fields. This approach ensures controlled access to the data and improves code maintainability.
Together, getters and setters provide controlled access to fields without exposing them directly.
Getters and setters follow a standard naming pattern:
For a field fieldName
:
getFieldName()
(returns the field’s value)setFieldName(type value)
(updates the field’s value)If the field is a boolean, the getter can also be named isFieldName()
.
Example:
private int age;
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
Here’s a simple class Person
with private fields and public getters and setters:
class Person {
private String name;
private int age;
// Getter for name
public String getName() {
return name;
}
// Setter for name
public void setName(String name) {
this.name = name;
}
// Getter for age
public int getAge() {
return age;
}
// Setter for age with validation
public void setAge(int age) {
if (age >= 0) {
this.age = age;
} else {
System.out.println("Age cannot be negative.");
}
}
}
// Using Getters and Setters in `main`
public class Main {
public static void main(String[] args) {
Person person = new Person();
// Set values using setters
person.setName("Alice");
person.setAge(30);
// Try setting an invalid age
person.setAge(-5); // Prints: Age cannot be negative.
// Get values using getters
System.out.println("Name: " + person.getName()); // Name: Alice
System.out.println("Age: " + person.getAge()); // Age: 30
}
}
Most modern IDEs like Eclipse, IntelliJ IDEA, and NetBeans can auto-generate getters and setters for you. This saves time and ensures consistent naming and formatting.
For example, in IntelliJ IDEA, you can:
getFieldName()
, setFieldName()
, or isFieldName()
for booleans.Try creating your own classes with private fields and use getters and setters to interact with them. This foundational skill will improve your ability to write clean, secure, and maintainable Java code.
Java uses access modifiers to control the visibility of classes, fields, methods, and constructors. These modifiers help you enforce encapsulation and protect data by restricting where different parts of your program can access certain members.
Java has four access levels:
Modifier | Visible in Same Class | Same Package | Subclass (any package) | Other Packages (non-subclass) |
---|---|---|---|---|
public |
Yes | Yes | Yes | Yes |
protected |
Yes | Yes | Yes | No |
default (no modifier) | Yes | Yes | No | No |
private |
Yes | No | No | No |
public
public
can be accessed from anywhere, both inside and outside the package.Example:
public class BankAccount {
public String accountNumber;
}
private
Example:
public class BankAccount {
private double balance;
}
protected
protected
for data or methods intended for subclasses but hidden from unrelated classes.Example:
protected double interestRate;
Example:
int transactionCount; // accessible only in the package
package banking;
public class BankAccount {
private String accountNumber; // Hidden from all except BankAccount
private double balance; // Private balance
protected double interestRate; // Visible to subclasses & same package
public BankAccount(String accountNumber, double initialBalance) {
this.accountNumber = accountNumber;
this.balance = initialBalance;
this.interestRate = 0.01; // 1% interest rate
}
// Public method to access balance
public double getBalance() {
return balance;
}
// Public method to deposit money
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
// Private method (used internally)
private void applyInterest() {
balance += balance * interestRate;
}
}
Assuming the above BankAccount
class is in package banking
:
Inside BankAccount
, all members (private
, protected
, public
) are accessible.
package banking;
public class BankManager {
public void checkAccount() {
BankAccount acc = new BankAccount("1234", 1000);
// acc.accountNumber -> Not accessible (private)
// acc.balance -> Not accessible (private)
System.out.println(acc.getBalance()); // Accessible (public)
System.out.println(acc.interestRate); // Accessible (protected + same package)
}
}
package vipbanking;
import banking.BankAccount;
public class VIPAccount extends BankAccount {
public VIPAccount(String accNum, double balance) {
super(accNum, balance);
System.out.println(interestRate); // Accessible (protected)
}
public void showAccountNumber() {
// System.out.println(accountNumber); // Error: private field not accessible
}
}
package publicapp;
import banking.BankAccount;
public class App {
public static void main(String[] args) {
BankAccount acc = new BankAccount("9999", 5000);
// acc.balance -> Not accessible (private)
// acc.interestRate -> Not accessible (protected + different package + not subclass)
System.out.println(acc.getBalance()); // Accessible (public)
}
}
Modifier | Use Case |
---|---|
private |
Protect sensitive data, internal logic |
default | Share among related classes in same package |
protected |
Allow subclass access, hide from unrelated |
public |
Expose API, methods intended for all clients |
Try modifying the BankAccount
class or create your own class using different access modifiers to observe their effects in various packages and subclasses!
In Java, as your projects grow, organizing your code becomes essential. Packages help you group related classes and interfaces together, making your code easier to manage, reuse, and avoid naming conflicts. This section explains how to create packages, use import
statements to access classes across packages, and explores special import forms.
A package is essentially a folder (namespace) that contains related Java classes and interfaces. It acts like a container to organize your code logically.
User
in different packages).To place a class inside a package, you declare the package at the very top of your .java
file.
package com.example.models;
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Here, Person.java
belongs to the package com.example.models
.
To use classes from another package, you need to import them. The import
statement tells Java where to find these classes.
package com.example.app;
import com.example.models.Person;
public class MainApp {
public static void main(String[] args) {
Person person = new Person("Alice");
System.out.println(person.getName());
}
}
Without the import
, you’d have to use the fully qualified name:
com.example.models.Person person = new com.example.models.Person("Alice");
File: Person.java
package com.example.models;
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
File: MainApp.java
package com.example.app;
import com.example.models.Person;
public class MainApp {
public static void main(String[] args) {
Person p = new Person("Bob");
System.out.println("Hello, " + p.getName());
}
}
Here, MainApp
in com.example.app
imports and uses Person
from com.example.models
.
Instead of importing each class individually, you can use a wildcard (*
) to import all classes in a package:
import com.example.models.*;
This imports all public classes inside com.example.models
.
Note: Wildcard imports do not import subpackages automatically. For example, com.example.models.*
won’t import com.example.models.subpackage
.
Java also allows static imports to directly use static members (methods or variables) without qualifying them by class name.
Example:
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
public class Circle {
public double getCircumference(double radius) {
return 2 * PI * radius; // No need to write Math.PI
}
public double getSquareRoot(double value) {
return sqrt(value); // No need to write Math.sqrt
}
}
.java
file using package your.package.name;
.import
statements to bring other packages’ classes into your code for easier referencing.*
) bring in all classes in a package, but avoid overusing them to keep clarity.By structuring your code into packages and understanding imports, you’ll create clear, modular, and maintainable Java applications.