Progress7 of 14 topics

50% complete

Classes and Objects in Java

Classes and objects are the fundamental building blocks of object-oriented programming in Java. This tutorial covers how to create and use classes, instantiate objects, work with constructors, and implement the principles of object-oriented design.

What Are Classes and Objects?

Java is an object-oriented programming language where everything revolves around classes and objects. But what exactly are they?

Class

A class is a blueprint or template that defines the attributes (variables) and behaviors (methods) common to all objects of a certain kind. It's like an architectural plan for a house.

Object

An object is an instance of a class. It's a concrete entity created according to the blueprint defined by the class. Going back to our analogy, an object is like an actual house built from the architectural plan.

Class vs Object

Class (Blueprint)
  • Defines properties (fields)
  • Defines behaviors (methods)
  • Template for creating objects
  • Defined once
  • No memory allocated when created
Objects (Instances)
  • Has actual property values
  • Can perform behaviors
  • Created from class template
  • Multiple can exist
  • Memory allocated when instantiated

Defining a Class in Java

Let's start by creating a simple class in Java:

java
1// Basic class definition
2public class Car {
3 // Instance variables (attributes/properties)
4 String make;
5 String model;
6 int year;
7 double price;
8
9 // Method to display car information
10 void displayInfo() {
11 System.out.println("Car: " + make + " " + model + " (" + year + ")");
12 System.out.println("Price: $" + price);
13 }
14}

Let's break down the components of a class:

  • Class Declaration: Starts with the keyword class followed by the class name.
  • Access Modifier: public means the class is accessible from any other class.
  • Instance Variables: Variables declared inside a class but outside any method represent the attributes of the class.
  • Methods: Functions defined inside a class that represent behaviors of the class.

Creating Objects

Once you have defined a class, you can create objects (instances) of that class:

java
1public class CarExample {
2 public static void main(String[] args) {
3 // Creating objects of the Car class
4 Car myCar = new Car();
5 Car friendsCar = new Car();
6
7 // Setting values for myCar
8 myCar.make = "Toyota";
9 myCar.model = "Camry";
10 myCar.year = 2022;
11 myCar.price = 25000.00;
12
13 // Setting values for friendsCar
14 friendsCar.make = "Honda";
15 friendsCar.model = "Accord";
16 friendsCar.year = 2021;
17 friendsCar.price = 24000.00;
18
19 // Displaying information
20 System.out.println("My car details:");
21 myCar.displayInfo();
22
23 System.out.println("
24My friend's car details:");
25 friendsCar.displayInfo();
26 }
27}
28
29// Output:
30// My car details:
31// Car: Toyota Camry (2022)
32// Price: $25000.0
33//
34// My friend's car details:
35// Car: Honda Accord (2021)
36// Price: $24000.0

The new keyword is used to create a new instance of a class. This allocates memory for the object and returns a reference to it. Each object has its own copy of the instance variables.

Constructors

A constructor is a special method used to initialize objects. It is called when an object is created with the new keyword. If you don't define any constructor, Java provides a default no-argument constructor.

java
1public class Student {
2 // Instance variables
3 String name;
4 int age;
5 String course;
6
7 // Default constructor
8 public Student() {
9 name = "Unknown";
10 age = 0;
11 course = "Not enrolled";
12 }
13
14 // Parameterized constructor
15 public Student(String studentName, int studentAge, String studentCourse) {
16 name = studentName;
17 age = studentAge;
18 course = studentCourse;
19 }
20
21 // Method to display student information
22 public void displayInfo() {
23 System.out.println("Student Name: " + name);
24 System.out.println("Student Age: " + age);
25 System.out.println("Enrolled Course: " + course);
26 }
27
28 public static void main(String[] args) {
29 // Creating objects using different constructors
30 Student student1 = new Student();
31 Student student2 = new Student("John Doe", 20, "Computer Science");
32
33 System.out.println("Student 1 Details:");
34 student1.displayInfo();
35
36 System.out.println("
37Student 2 Details:");
38 student2.displayInfo();
39 }
40}
41
42// Output:
43// Student 1 Details:
44// Student Name: Unknown
45// Student Age: 0
46// Enrolled Course: Not enrolled
47//
48// Student 2 Details:
49// Student Name: John Doe
50// Student Age: 20
51// Enrolled Course: Computer Science

Constructor Rules

  • Constructor name must be the same as the class name
  • Constructors don't have return types (not even void)
  • Constructors can be overloaded (multiple constructors with different parameters)
  • If you don't provide any constructor, Java provides a default no-argument constructor
  • If you provide any constructor, Java doesn't provide the default constructor

The 'this' Keyword

The this keyword refers to the current object instance. It's often used to distinguish between instance variables and parameters with the same name, or to call one constructor from another.

java
1public class Rectangle {
2 // Instance variables
3 private int length;
4 private int width;
5
6 // Constructor with same-named parameters
7 public Rectangle(int length, int width) {
8 // Using 'this' to refer to instance variables
9 this.length = length;
10 this.width = width;
11 }
12
13 // Overloaded constructor for a square
14 public Rectangle(int side) {
15 // Using 'this' to call another constructor
16 this(side, side); // Calls Rectangle(int length, int width)
17 }
18
19 // Method to calculate area
20 public int area() {
21 return length * width;
22 }
23
24 // Method to display information
25 public void display() {
26 System.out.println("Length: " + this.length);
27 System.out.println("Width: " + this.width);
28 System.out.println("Area: " + this.area());
29 }
30
31 public static void main(String[] args) {
32 Rectangle rectangle = new Rectangle(5, 3);
33 Rectangle square = new Rectangle(4);
34
35 System.out.println("Rectangle:");
36 rectangle.display();
37
38 System.out.println("
39Square:");
40 square.display();
41 }
42}
43
44// Output:
45// Rectangle:
46// Length: 5
47// Width: 3
48// Area: 15
49//
50// Square:
51// Length: 4
52// Width: 4
53// Area: 16

Access Modifiers

Access modifiers control the visibility and accessibility of classes, methods, and variables. Java provides four types of access modifiers:

Access ModifierClassPackageSubclassWorld
public
protected
default (no modifier)
private
java
1public class AccessModifierExample {
2 // Public: accessible from anywhere
3 public String publicVar = "I am public";
4
5 // Protected: accessible within same package and subclasses
6 protected String protectedVar = "I am protected";
7
8 // Default (no modifier): accessible only within same package
9 String defaultVar = "I am default";
10
11 // Private: accessible only within the same class
12 private String privateVar = "I am private";
13
14 public void displayVars() {
15 // Can access all variables here because we're inside the class
16 System.out.println(publicVar);
17 System.out.println(protectedVar);
18 System.out.println(defaultVar);
19 System.out.println(privateVar);
20 }
21}

Encapsulation and Getter/Setter Methods

Encapsulation is one of the four fundamental principles of object-oriented programming. It refers to the bundling of data (variables) and methods that operate on the data into a single unit (class), and restricting direct access to some of the object's components.

This is typically achieved by making variables private and providing public getter and setter methods:

java
1public class Person {
2 // Private variables for encapsulation
3 private String name;
4 private int age;
5 private double salary;
6
7 // Constructor
8 public Person(String name, int age, double salary) {
9 this.name = name;
10 this.setAge(age); // Using setter for validation
11 this.setSalary(salary);
12 }
13
14 // Getter for name
15 public String getName() {
16 return name;
17 }
18
19 // Setter for name
20 public void setName(String name) {
21 this.name = name;
22 }
23
24 // Getter for age
25 public int getAge() {
26 return age;
27 }
28
29 // Setter for age with validation
30 public void setAge(int age) {
31 if (age > 0 && age < 120) {
32 this.age = age;
33 } else {
34 System.out.println("Invalid age. Age must be between 1 and 120.");
35 this.age = 0; // Default value
36 }
37 }
38
39 // Getter for salary
40 public double getSalary() {
41 return salary;
42 }
43
44 // Setter for salary with validation
45 public void setSalary(double salary) {
46 if (salary >= 0) {
47 this.salary = salary;
48 } else {
49 System.out.println("Invalid salary. Salary cannot be negative.");
50 this.salary = 0; // Default value
51 }
52 }
53
54 public void displayInfo() {
55 System.out.println("Name: " + name);
56 System.out.println("Age: " + age);
57 System.out.println("Salary: $" + salary);
58 }
59
60 public static void main(String[] args) {
61 Person person = new Person("Alice Smith", 30, 75000);
62 person.displayInfo();
63
64 // Using getters
65 System.out.println("
66Using getters:");
67 System.out.println("Name: " + person.getName());
68 System.out.println("Age: " + person.getAge());
69 System.out.println("Salary: $" + person.getSalary());
70
71 // Using setters
72 System.out.println("
73After using setters:");
74 person.setName("Alice Johnson");
75 person.setAge(31);
76 person.setSalary(80000);
77 person.displayInfo();
78
79 // Testing validation
80 System.out.println("
81Testing validation:");
82 person.setAge(-5); // Invalid age
83 person.setSalary(-1000); // Invalid salary
84 person.displayInfo();
85 }
86}
87
88// Output:
89// Name: Alice Smith
90// Age: 30
91// Salary: $75000.0
92//
93// Using getters:
94// Name: Alice Smith
95// Age: 30
96// Salary: $75000.0
97//
98// After using setters:
99// Name: Alice Johnson
100// Age: 31
101// Salary: $80000.0
102//
103// Testing validation:
104// Invalid age. Age must be between 1 and 120.
105// Invalid salary. Salary cannot be negative.
106// Name: Alice Johnson
107// Age: 0
108// Salary: $0.0

Static Members

Static members (variables and methods) belong to the class rather than instances of the class. They are shared among all instances of the class.

java
1public class BankAccount {
2 // Instance variables
3 private String accountHolder;
4 private double balance;
5
6 // Static variable shared across all instances
7 private static double interestRate = 0.05; // 5%
8 private static int totalAccounts = 0;
9
10 // Constructor
11 public BankAccount(String accountHolder, double initialDeposit) {
12 this.accountHolder = accountHolder;
13 this.balance = initialDeposit;
14 totalAccounts++; // Increment the total count when a new account is created
15 }
16
17 // Instance method
18 public void deposit(double amount) {
19 if (amount > 0) {
20 balance += amount;
21 System.out.println("$" + amount + " deposited. New balance: $" + balance);
22 } else {
23 System.out.println("Invalid deposit amount.");
24 }
25 }
26
27 // Instance method
28 public void withdraw(double amount) {
29 if (amount > 0 && amount <= balance) {
30 balance -= amount;
31 System.out.println("$" + amount + " withdrawn. New balance: $" + balance);
32 } else {
33 System.out.println("Invalid withdrawal amount or insufficient funds.");
34 }
35 }
36
37 // Method that uses the static interest rate
38 public void addYearlyInterest() {
39 double interest = balance * interestRate;
40 balance += interest;
41 System.out.println("Annual interest added. New balance: $" + balance);
42 }
43
44 // Static method to change interest rate
45 public static void setInterestRate(double newRate) {
46 if (newRate >= 0 && newRate <= 0.1) { // Limit between 0% and 10%
47 interestRate = newRate;
48 System.out.println("Interest rate changed to " + (interestRate * 100) + "%");
49 } else {
50 System.out.println("Invalid interest rate. Must be between 0% and 10%.");
51 }
52 }
53
54 // Static method to get total accounts
55 public static int getTotalAccounts() {
56 return totalAccounts;
57 }
58
59 // Display account info
60 public void displayInfo() {
61 System.out.println("Account Holder: " + accountHolder);
62 System.out.println("Current Balance: $" + balance);
63 System.out.println("Current Interest Rate: " + (interestRate * 100) + "%");
64 }
65
66 public static void main(String[] args) {
67 System.out.println("Total accounts before: " + BankAccount.getTotalAccounts());
68
69 BankAccount account1 = new BankAccount("John Smith", 1000);
70 BankAccount account2 = new BankAccount("Sarah Johnson", 2500);
71
72 System.out.println("Total accounts after: " + BankAccount.getTotalAccounts());
73
74 System.out.println("
75Account 1:");
76 account1.displayInfo();
77
78 System.out.println("
79Account 2:");
80 account2.displayInfo();
81
82 // Change interest rate using static method
83 System.out.println("
84Changing interest rate:");
85 BankAccount.setInterestRate(0.06); // Change to 6%
86
87 // Both accounts now have the new interest rate
88 System.out.println("
89Account 1 after interest rate change:");
90 account1.displayInfo();
91
92 System.out.println("
93Account 2 after interest rate change:");
94 account2.displayInfo();
95
96 // Add yearly interest to account1
97 System.out.println("
98Adding yearly interest to account 1:");
99 account1.addYearlyInterest();
100 account1.displayInfo();
101 }
102}
103
104// Output:
105// Total accounts before: 0
106// Total accounts after: 2
107//
108// Account 1:
109// Account Holder: John Smith
110// Current Balance: $1000.0
111// Current Interest Rate: 5.0%
112//
113// Account 2:
114// Account Holder: Sarah Johnson
115// Current Balance: $2500.0
116// Current Interest Rate: 5.0%
117//
118// Changing interest rate:
119// Interest rate changed to 6.0%
120//
121// Account 1 after interest rate change:
122// Account Holder: John Smith
123// Current Balance: $1000.0
124// Current Interest Rate: 6.0%
125//
126// Account 2 after interest rate change:
127// Account Holder: Sarah Johnson
128// Current Balance: $2500.0
129// Current Interest Rate: 6.0%
130//
131// Adding yearly interest to account 1:
132// Annual interest added. New balance: $1060.0
133// Account Holder: John Smith
134// Current Balance: $1060.0
135// Current Interest Rate: 6.0%

Key Points About Static Members

  • Static variables are shared among all instances of a class
  • Static methods can be called without creating an instance of the class
  • Static methods cannot access instance variables or instance methods directly
  • Static methods cannot use the this keyword
  • Non-static methods can access both static and instance members

Practical Application: A Complete Class Example

Let's put everything together with a comprehensive example of a Product class for an e-commerce system:

java
1public class Product {
2 // Instance variables with private access (encapsulation)
3 private String name;
4 private String description;
5 private double price;
6 private int stockQuantity;
7 private String category;
8
9 // Static variables
10 private static int totalProducts = 0;
11 private static double taxRate = 0.08; // 8% tax
12
13 // Default constructor
14 public Product() {
15 this.name = "Unnamed Product";
16 this.description = "No description available";
17 this.price = 0.0;
18 this.stockQuantity = 0;
19 this.category = "Uncategorized";
20 totalProducts++;
21 }
22
23 // Parameterized constructor
24 public Product(String name, String description, double price, int stockQuantity, String category) {
25 this.name = name;
26 this.description = description;
27 setPrice(price); // Using setter for validation
28 setStockQuantity(stockQuantity); // Using setter for validation
29 this.category = category;
30 totalProducts++;
31 }
32
33 // Getters and setters
34 public String getName() {
35 return name;
36 }
37
38 public void setName(String name) {
39 this.name = name;
40 }
41
42 public String getDescription() {
43 return description;
44 }
45
46 public void setDescription(String description) {
47 this.description = description;
48 }
49
50 public double getPrice() {
51 return price;
52 }
53
54 public void setPrice(double price) {
55 if (price >= 0) {
56 this.price = price;
57 } else {
58 System.out.println("Error: Price cannot be negative.");
59 this.price = 0.0;
60 }
61 }
62
63 public int getStockQuantity() {
64 return stockQuantity;
65 }
66
67 public void setStockQuantity(int stockQuantity) {
68 if (stockQuantity >= 0) {
69 this.stockQuantity = stockQuantity;
70 } else {
71 System.out.println("Error: Stock quantity cannot be negative.");
72 this.stockQuantity = 0;
73 }
74 }
75
76 public String getCategory() {
77 return category;
78 }
79
80 public void setCategory(String category) {
81 this.category = category;
82 }
83
84 // Instance methods
85 public double getPriceWithTax() {
86 return price * (1 + taxRate);
87 }
88
89 public boolean isInStock() {
90 return stockQuantity > 0;
91 }
92
93 public void addStock(int quantity) {
94 if (quantity > 0) {
95 this.stockQuantity += quantity;
96 System.out.println(quantity + " units added to stock. New quantity: " + this.stockQuantity);
97 } else {
98 System.out.println("Error: Quantity to add must be positive.");
99 }
100 }
101
102 public boolean sellProduct(int quantity) {
103 if (quantity <= 0) {
104 System.out.println("Error: Quantity to sell must be positive.");
105 return false;
106 }
107
108 if (quantity > stockQuantity) {
109 System.out.println("Error: Not enough stock available.");
110 return false;
111 }
112
113 stockQuantity -= quantity;
114 System.out.println(quantity + " units sold. Remaining stock: " + stockQuantity);
115 return true;
116 }
117
118 // Display method
119 public void displayInfo() {
120 System.out.println("Product: " + name);
121 System.out.println("Description: " + description);
122 System.out.println("Category: " + category);
123 System.out.println("Price: $" + price);
124 System.out.println("Price with tax: $" + getPriceWithTax());
125 System.out.println("Stock Quantity: " + stockQuantity);
126 System.out.println("In Stock: " + (isInStock() ? "Yes" : "No"));
127 }
128
129 // Static methods
130 public static int getTotalProducts() {
131 return totalProducts;
132 }
133
134 public static double getTaxRate() {
135 return taxRate;
136 }
137
138 public static void setTaxRate(double newRate) {
139 if (newRate >= 0 && newRate <= 0.3) { // Limit between 0% and 30%
140 taxRate = newRate;
141 System.out.println("Tax rate updated to " + (taxRate * 100) + "%");
142 } else {
143 System.out.println("Error: Tax rate must be between 0% and 30%.");
144 }
145 }
146
147 // Main method for testing
148 public static void main(String[] args) {
149 // Creating products
150 Product laptop = new Product("Laptop Pro", "High-performance laptop for professionals", 1299.99, 10, "Electronics");
151 Product phone = new Product("SmartPhone X", "Latest smartphone with advanced features", 799.99, 15, "Electronics");
152 Product desk = new Product("Office Desk", "Sturdy wooden desk for home office", 249.99, 5, "Furniture");
153
154 // Displaying total products
155 System.out.println("Total products in inventory: " + Product.getTotalProducts());
156 System.out.println("Current tax rate: " + (Product.getTaxRate() * 100) + "%");
157
158 // Displaying product information
159 System.out.println("
160=== Product 1 ===");
161 laptop.displayInfo();
162
163 System.out.println("
164=== Product 2 ===");
165 phone.displayInfo();
166
167 System.out.println("
168=== Product 3 ===");
169 desk.displayInfo();
170
171 // Testing methods
172 System.out.println("
173=== Testing Product Operations ===");
174 laptop.sellProduct(2);
175 phone.addStock(5);
176 desk.sellProduct(6); // Should fail, only 5 in stock
177
178 // Changing tax rate
179 System.out.println("
180=== Changing Tax Rate ===");
181 Product.setTaxRate(0.095); // 9.5%
182
183 // Display updated information
184 System.out.println("
185=== Updated Product Information ===");
186 laptop.displayInfo();
187 }
188}

Best Practices for Class and Object Design

Encapsulation

Make instance variables private and provide public getter and setter methods to control access and validation.

Single Responsibility

A class should have only one reason to change, meaning it should have only one responsibility or job.

Meaningful Names

Choose clear, descriptive names for classes, variables, and methods that indicate their purpose or behavior.

Immutability When Possible

Consider making classes immutable (variables can't change after initialization) when appropriate to prevent unexpected side effects.

Practice Exercises

  1. Create a Book class with appropriate attributes and methods for a library system.
  2. Implement a BankAccount class with methods for deposit, withdrawal, and interest calculation.
  3. Design a Student class with arrays to track courses and grades.
  4. Create a Circle class with methods to calculate area and circumference.
  5. Implement a Date class with validation and methods to compare dates.

Summary

In this tutorial, you've learned:

  • The concepts of classes and objects in Java
  • How to define classes and create objects
  • How to use constructors to initialize objects
  • The purpose and usage of the this keyword
  • Access modifiers and their role in encapsulation
  • How to implement encapsulation with getters and setters
  • The difference between static and instance members
  • Best practices for designing classes and objects

Classes and objects form the foundation of object-oriented programming in Java. Understanding these concepts is essential for building robust and maintainable Java applications. In the next tutorials, you'll learn about inheritance, interfaces, and other advanced OOP concepts that build upon these fundamentals.

Related Tutorials

Learn how to create and use methods in Java.

Learn more

Understand the core concepts of OOP in Java.

Learn more

Learn about class inheritance and method overriding.

Learn more