Keywords - this, static, final#
Lecture 13#
Java Programming (4343203)
Diploma in ICT - Semester IV
Gujarat Technological University
Press Space for next page
layout: default#
Learning Objectives#
By the end of this lecture, you will be able to:
- ๐ฏ Master the ’this’ keyword for object self-reference
- ๐๏ธ Understand static members and class-level programming
- ๐ Apply the ‘final’ keyword for immutability and constants
- ๐ก Differentiate between instance and static contexts
- ๐ ๏ธ Implement utility classes and singleton patterns
- ๐ Practice with real-world examples and best practices
Let's master Java's powerful keywords! ๐ฏ๐
layout: center#
Java Keywords Overview#
graph TD
A[Java Keywords] --> B[this Keyword]
A --> C[static Keyword]
A --> D[final Keyword]
B --> E[Object Reference]
B --> F[Constructor Chaining]
B --> G[Method Parameters]
C --> H[Class Variables]
C --> I[Class Methods]
C --> J[Static Blocks]
D --> K[Final Variables]
D --> L[Final Methods]
D --> M[Final Classes]
style B fill:#e3f2fd
style C fill:#e8f5e8
style D fill:#fff3e0
style E fill:#f3e5f5
style F fill:#f3e5f5
style G fill:#f3e5f5
Today's Focus: Understanding object identity, class-level programming, and immutability
layout: default#
The ’this’ Keyword#
๐ฏ What is ’this’?#
- Reference to the current object
- Distinguishes instance variables from parameters
- Enables method chaining
- Used in constructor chaining
- Clarifies code intent
๐ Basic ’this’ Usage#
public class Student {
private String name;
private int age;
// Constructor with parameters having same names
public Student(String name, int age) {
this.name = name; // this.name refers to instance variable
this.age = age; // age without this refers to parameter
}
// Setter methods using this
public void setName(String name) {
this.name = name; // Avoiding ambiguity
}
public void setAge(int age) {
this.age = age;
}
}
๐ Without ’this’ - Ambiguity Problem#
public class BadExample {
private String name;
private int age;
public BadExample(String name, int age) {
name = name; // โ Parameter assigns to itself!
age = age; // โ Instance variable remains unchanged!
}
public void setName(String name) {
name = name; // โ No effect on instance variable!
}
}
// Testing the problem
BadExample student = new BadExample("Alice", 20);
System.out.println(student.getName()); // null (not "Alice")
Problems without ’this’:
- Parameter shadows instance variable
- Instance variables remain uninitialized
- Assignments have no effect
- Debugging becomes difficult
โ ๏ธ Critical: Always use 'this' when parameter and instance variable names match!
layout: default#
Advanced ’this’ Usage#
๐ Method Chaining with ’this'#
public class FluentStudent {
private String name;
private int age;
private String course;
private double gpa;
// Method chaining pattern
public FluentStudent setName(String name) {
this.name = name;
return this; // Return current object
}
public FluentStudent setAge(int age) {
this.age = age;
return this;
}
public FluentStudent setCourse(String course) {
this.course = course;
return this;
}
public FluentStudent setGpa(double gpa) {
this.gpa = gpa;
return this;
}
public void displayInfo() {
System.out.println("Student: " + name + ", Age: " + age +
", Course: " + course + ", GPA: " + gpa);
}
}
๐ Fluent Interface Usage#
public class ChainDemo {
public static void main(String[] args) {
// Traditional way (verbose)
FluentStudent student1 = new FluentStudent();
student1.setName("Alice");
student1.setAge(20);
student1.setCourse("Computer Science");
student1.setGpa(3.8);
student1.displayInfo();
// Fluent interface (elegant)
FluentStudent student2 = new FluentStudent()
.setName("Bob")
.setAge(21)
.setCourse("Information Technology")
.setGpa(3.9);
student2.displayInfo();
// One-liner creation and setup
new FluentStudent()
.setName("Charlie")
.setAge(19)
.setCourse("Software Engineering")
.setGpa(3.7)
.displayInfo();
}
}
๐ Benefits:
- โข More readable and concise code
- โข Popular in modern libraries (Builder pattern)
- โข Enables fluent APIs
layout: default#
Constructor Chaining with ’this'#
๐๏ธ Constructor Overloading and Chaining#
public class Employee {
private String name;
private int employeeId;
private String department;
private double salary;
private String email;
// Primary constructor with all parameters
public Employee(String name, int employeeId, String department,
double salary, String email) {
this.name = name;
this.employeeId = employeeId;
this.department = department;
this.salary = salary;
this.email = email;
}
// Constructor with default department
public Employee(String name, int employeeId, double salary, String email) {
this(name, employeeId, "General", salary, email); // Call primary constructor
}
// Constructor with default department and email
public Employee(String name, int employeeId, double salary) {
this(name, employeeId, salary, name.toLowerCase().replace(" ", ".") + "@company.com");
}
// Constructor with minimal parameters
public Employee(String name, int employeeId) {
this(name, employeeId, 30000.0); // Default salary
}
}
๐ฏ Constructor Chaining Benefits#
public class EmployeeDemo {
public static void main(String[] args) {
// Different ways to create Employee objects
// Full specification
Employee emp1 = new Employee("Alice Johnson", 101, "IT", 75000, "alice.johnson@company.com");
// Default department
Employee emp2 = new Employee("Bob Smith", 102, 68000, "bob.smith@company.com");
// Default department and auto-generated email
Employee emp3 = new Employee("Charlie Brown", 103, 72000);
// Minimal information with defaults
Employee emp4 = new Employee("Diana Prince", 104);
// Display all employees
emp1.displayInfo();
emp2.displayInfo();
emp3.displayInfo();
emp4.displayInfo();
}
}
Constructor Chaining Rules:
this()call must be the first statement in constructor- Cannot call
this()andsuper()in same constructor - Prevents code duplication
- Ensures consistent initialization
๐ก Best Practice: Use constructor chaining to avoid code duplication and ensure consistent object initialization!
layout: default#
The ‘static’ Keyword#
๐๏ธ Class-Level Programming#
- Belongs to the class, not instances
- Shared among all objects
- Can be accessed without creating objects
- Memory efficient for common data
- Used for utility methods and constants
๐ Instance vs Static Memory#
graph TD
A[Memory Layout] --> B[Heap Memory]
A --> C[Method Area]
B --> D[Object 1<br/>Instance Variables]
B --> E[Object 2<br/>Instance Variables]
B --> F[Object 3<br/>Instance Variables]
C --> G[Class Definition]
C --> H[Static Variables<br/>Shared by all objects]
C --> I[Static Methods]
style B fill:#e3f2fd
style C fill:#e8f5e8
๐ Static Variables Example#
public class Student {
// Static variable - shared by all students
private static int totalStudents = 0;
private static String schoolName = "GTU Engineering College";
// Instance variables - unique per student
private String name;
private int rollNumber;
public Student(String name, int rollNumber) {
this.name = name;
this.rollNumber = rollNumber;
totalStudents++; // Increment for each new student
}
// Static method - accessible without object
public static int getTotalStudents() {
return totalStudents;
}
public static String getSchoolName() {
return schoolName;
}
// Instance method
public void displayInfo() {
System.out.println("Name: " + name);
System.out.println("Roll: " + rollNumber);
System.out.println("School: " + schoolName); // Can access static
System.out.println("Total Students: " + totalStudents);
}
}
layout: default#
Static Methods and Utility Classes#
๐ ๏ธ Utility Class Design#
public class MathUtils {
// Static constants
public static final double PI = 3.14159265359;
public static final double E = 2.71828182846;
// Private constructor to prevent instantiation
private MathUtils() {
throw new AssertionError("Utility class cannot be instantiated");
}
// Static utility methods
public static double calculateCircleArea(double radius) {
return PI * radius * radius;
}
public static double calculateCirclePerimeter(double radius) {
return 2 * PI * radius;
}
public static boolean isPrime(int number) {
if (number <= 1) return false;
if (number <= 3) return true;
if (number % 2 == 0 || number % 3 == 0) return false;
for (int i = 5; i * i <= number; i += 6) {
if (number % i == 0 || number % (i + 2) == 0) {
return false;
}
}
return true;
}
public static int factorial(int n) {
if (n < 0) throw new IllegalArgumentException("Negative numbers not allowed");
if (n <= 1) return 1;
int result = 1;
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
}
๐ฏ Using Static Utilities#
public class MathUtilsDemo {
public static void main(String[] args) {
// No object creation needed - call directly on class
// Circle calculations
double radius = 5.0;
double area = MathUtils.calculateCircleArea(radius);
double perimeter = MathUtils.calculateCirclePerimeter(radius);
System.out.println("Circle with radius " + radius + ":");
System.out.println("Area: " + area);
System.out.println("Perimeter: " + perimeter);
// Prime number checking
int[] numbers = {17, 25, 29, 33, 37};
System.out.println("\nPrime number check:");
for (int num : numbers) {
System.out.println(num + " is prime: " + MathUtils.isPrime(num));
}
// Factorial calculations
System.out.println("\nFactorial calculations:");
for (int i = 0; i <= 10; i++) {
System.out.println(i + "! = " + MathUtils.factorial(i));
}
// Using constants
System.out.println("\nMath constants:");
System.out.println("PI = " + MathUtils.PI);
System.out.println("E = " + MathUtils.E);
}
}
๐ฏ Benefits of Static Utilities:
- โข No object creation overhead
- โข Globally accessible functionality
- โข Memory efficient
- โข Clear intent (stateless operations)
layout: default#
Static Blocks and Initialization#
โก Static Block Execution#
public class DatabaseConfig {
// Static variables
private static String databaseUrl;
private static String username;
private static boolean isConnected;
// Static block - executed when class is first loaded
static {
System.out.println("Loading database configuration...");
// Complex initialization logic
databaseUrl = loadConfigProperty("db.url", "localhost:5432");
username = loadConfigProperty("db.username", "admin");
// Attempt connection
try {
establishConnection();
isConnected = true;
System.out.println("Database connection established successfully!");
} catch (Exception e) {
isConnected = false;
System.out.println("Failed to connect to database: " + e.getMessage());
}
}
// Helper methods for static block
private static String loadConfigProperty(String key, String defaultValue) {
// Simulate loading from configuration file
System.out.println("Loading property: " + key);
return defaultValue; // In real app, would read from file/environment
}
private static void establishConnection() throws Exception {
// Simulate database connection
System.out.println("Connecting to database at: " + databaseUrl);
Thread.sleep(100); // Simulate connection delay
}
// Static methods to access configuration
public static String getDatabaseUrl() {
return databaseUrl;
}
public static boolean isConnected() {
return isConnected;
}
}
๐ Static Block Execution Order#
public class InitializationDemo {
// Static variable with direct initialization
private static String message1 = initMessage1();
// Static block 1
static {
System.out.println("Static block 1 executed");
message2 = "Initialized in static block 1";
}
// Another static variable
private static String message2;
// Static block 2
static {
System.out.println("Static block 2 executed");
message3 = "Initialized in static block 2";
}
private static String message3;
// Static method for initialization
private static String initMessage1() {
System.out.println("Static method initMessage1() called");
return "Initialized by static method";
}
public static void displayMessages() {
System.out.println("Message 1: " + message1);
System.out.println("Message 2: " + message2);
System.out.println("Message 3: " + message3);
}
public static void main(String[] args) {
System.out.println("Main method started");
// First access to class triggers static initialization
InitializationDemo.displayMessages();
// Check database configuration
System.out.println("\nDatabase Status:");
System.out.println("URL: " + DatabaseConfig.getDatabaseUrl());
System.out.println("Connected: " + DatabaseConfig.isConnected());
}
}
Execution Order:
- Static variables in declaration order
- Static blocks in declaration order
- Class is ready for use
layout: default#
Static Context Restrictions#
โ ๏ธ Static Method Limitations#
public class StaticRestrictions {
private String instanceVariable = "Instance";
private static String staticVariable = "Static";
// Instance method - can access everything
public void instanceMethod() {
System.out.println(instanceVariable); // โ
OK
System.out.println(staticVariable); // โ
OK
this.anotherInstanceMethod(); // โ
OK
StaticRestrictions.staticMethod(); // โ
OK
}
// Static method - restricted access
public static void staticMethod() {
// System.out.println(instanceVariable); // โ Cannot access
System.out.println(staticVariable); // โ
OK
// this.anotherInstanceMethod(); // โ Cannot use 'this'
// anotherInstanceMethod(); // โ Cannot call instance method
StaticRestrictions.anotherStaticMethod(); // โ
OK
anotherStaticMethod(); // โ
OK (same class)
// To access instance members, need object reference
StaticRestrictions obj = new StaticRestrictions();
System.out.println(obj.instanceVariable); // โ
OK with object
obj.anotherInstanceMethod(); // โ
OK with object
}
public void anotherInstanceMethod() {
System.out.println("Another instance method");
}
public static void anotherStaticMethod() {
System.out.println("Another static method");
}
}
๐ฏ Common Static Mistakes#
public class CommonMistakes {
private int count = 0;
private static int totalCount = 0;
// โ WRONG: Trying to initialize static with instance data
// private static int wrongInit = count; // Compilation error!
// โ
CORRECT: Static initialized with static or constants
private static int correctInit = 100;
public void instanceMethod() {
count++; // โ
Instance method can modify instance variable
totalCount++; // โ
Instance method can modify static variable
}
public static void staticMethod() {
// count++; // โ Static method cannot access instance variable
totalCount++; // โ
Static method can modify static variable
// Creating object to access instance members
CommonMistakes obj = new CommonMistakes();
obj.count++; // โ
OK with object reference
}
// โ WRONG: Instance variable dependent on static
private String message = "Total: " + totalCount; // Problematic!
// โ
CORRECT: Calculate in method when needed
public String getMessage() {
return "Total: " + totalCount;
}
}
โ ๏ธ Remember: Static context cannot access instance members directly - they belong to objects, not the class!
layout: default#
The ‘final’ Keyword#
๐ Immutability and Constants#
- final variables - cannot be reassigned
- final methods - cannot be overridden
- final classes - cannot be extended
- Ensures immutability and design integrity
- Improves performance through optimization
๐ Final Variables#
public class FinalVariables {
// Final instance variable - must be initialized
private final String id;
private final long creationTime;
// Final static variable - class constant
public static final String APPLICATION_NAME = "Student Management System";
public static final double VERSION = 1.0;
public static final int MAX_STUDENTS = 1000;
// Final local variables in constructor
public FinalVariables(String id) {
this.id = id; // โ
Can initialize once
this.creationTime = System.currentTimeMillis();
final int tempValue = 42; // Final local variable
System.out.println("Temp value: " + tempValue);
// tempValue = 50; // โ Cannot reassign
}
public void someMethod() {
// this.id = "new_id"; // โ Cannot change final field
System.out.println("ID: " + id); // โ
Can read final field
}
}
๐ฏ Final Methods and Classes#
// Final class - cannot be extended
public final class ImmutablePerson {
private final String name;
private final int age;
private final String email;
public ImmutablePerson(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
// Getters only - no setters for immutability
public String getName() { return name; }
public int getAge() { return age; }
public String getEmail() { return email; }
// Final method - cannot be overridden
public final String getFormattedInfo() {
return String.format("Person[name=%s, age=%d, email=%s]",
name, age, email);
}
}
// This would cause compilation error:
// class ExtendedPerson extends ImmutablePerson { } // โ Cannot extend final class
public class RegularClass {
// Final method in non-final class
public final void criticalOperation() {
System.out.println("This method cannot be overridden");
}
public void normalMethod() {
System.out.println("This method can be overridden");
}
}
class SubClass extends RegularClass {
// @Override
// public void criticalOperation() { } // โ Cannot override final method
@Override
public void normalMethod() { // โ
Can override normal method
System.out.println("Overridden implementation");
}
}
layout: default#
Final Collections and Complex Objects#
๐ฆ Final Reference vs Final Object#
import java.util.*;
public class FinalCollections {
// Final reference to ArrayList
private final List<String> names = new ArrayList<>();
// Final reference to array
private final int[] numbers = {1, 2, 3, 4, 5};
public void demonstrateFinalCollections() {
// โ
Can modify contents of final collection
names.add("Alice");
names.add("Bob");
names.remove(0);
names.clear();
// โ
Can modify elements of final array
numbers[0] = 100;
numbers[1] = 200;
// โ Cannot reassign final references
// names = new ArrayList<>(); // Compilation error!
// numbers = new int[10]; // Compilation error!
System.out.println("Names: " + names);
System.out.println("Numbers: " + Arrays.toString(numbers));
}
// Method with final parameter
public void processData(final List<String> data) {
data.add("processed"); // โ
Can modify contents
data.clear(); // โ
Can modify contents
// data = new ArrayList<>(); // โ Cannot reassign parameter
}
}
๐ Creating Truly Immutable Classes#
import java.util.*;
public final class ImmutableStudent {
private final String name;
private final int rollNumber;
private final List<String> courses;
private final Map<String, Integer> grades;
public ImmutableStudent(String name, int rollNumber,
List<String> courses, Map<String, Integer> grades) {
this.name = name;
this.rollNumber = rollNumber;
// Defensive copying for mutable objects
this.courses = Collections.unmodifiableList(new ArrayList<>(courses));
this.grades = Collections.unmodifiableMap(new HashMap<>(grades));
}
// Only getters, no setters
public String getName() { return name; }
public int getRollNumber() { return rollNumber; }
// Return defensive copies or unmodifiable views
public List<String> getCourses() {
return courses; // Already unmodifiable
}
public Map<String, Integer> getGrades() {
return grades; // Already unmodifiable
}
// Factory method for creation
public static ImmutableStudent createStudent(String name, int rollNumber) {
return new ImmutableStudent(name, rollNumber,
new ArrayList<>(), new HashMap<>());
}
// Method to create modified copy (immutable pattern)
public ImmutableStudent withName(String newName) {
return new ImmutableStudent(newName, this.rollNumber,
new ArrayList<>(this.courses),
new HashMap<>(this.grades));
}
}
layout: default#
Real-World Example: Configuration System#
โ๏ธ Application Configuration#
public final class AppConfig {
// Final static constants
public static final String APP_NAME = "Student Management System";
public static final String VERSION = "2.1.0";
public static final int MAX_LOGIN_ATTEMPTS = 3;
public static final long SESSION_TIMEOUT = 1800000; // 30 minutes
// Final instance configuration
private final String databaseUrl;
private final String databaseUser;
private final boolean debugMode;
private final List<String> allowedFeatures;
// Static instance for singleton pattern
private static AppConfig instance;
// Private constructor
private AppConfig() {
this.databaseUrl = loadProperty("db.url", "localhost:5432");
this.databaseUser = loadProperty("db.user", "admin");
this.debugMode = Boolean.parseBoolean(loadProperty("debug.mode", "false"));
// Initialize allowed features
List<String> features = new ArrayList<>();
features.add("user_management");
features.add("grade_tracking");
features.add("attendance_monitoring");
this.allowedFeatures = Collections.unmodifiableList(features);
}
// Static method to get singleton instance
public static synchronized AppConfig getInstance() {
if (instance == null) {
instance = new AppConfig();
}
return instance;
}
// Helper method for loading properties
private static String loadProperty(String key, String defaultValue) {
// In real application, would read from properties file
return System.getProperty(key, defaultValue);
}
}
๐ฏ Using the Configuration System#
public class ConfigDemo {
public static void main(String[] args) {
// Access static constants
System.out.println("Application: " + AppConfig.APP_NAME);
System.out.println("Version: " + AppConfig.VERSION);
System.out.println("Max Login Attempts: " + AppConfig.MAX_LOGIN_ATTEMPTS);
// Get configuration instance
AppConfig config = AppConfig.getInstance();
// Another reference to same instance
AppConfig config2 = AppConfig.getInstance();
// Verify singleton behavior
System.out.println("Same instance: " + (config == config2));
// Access configuration values
System.out.println("Database URL: " + config.getDatabaseUrl());
System.out.println("Debug Mode: " + config.isDebugMode());
// Access allowed features
List<String> features = config.getAllowedFeatures();
System.out.println("Allowed Features: " + features);
// Try to modify features (will fail)
try {
features.add("unauthorized_feature"); // UnsupportedOperationException
} catch (UnsupportedOperationException e) {
System.out.println("Cannot modify configuration - it's immutable!");
}
}
}
// Utility class with static methods
public final class ValidationUtils {
// Private constructor prevents instantiation
private ValidationUtils() {
throw new AssertionError("Utility class cannot be instantiated");
}
public static final int MIN_PASSWORD_LENGTH = 8;
public static final String EMAIL_REGEX = "^[A-Za-z0-9+_.-]+@(.+)$";
public static boolean isValidEmail(final String email) {
return email != null && email.matches(EMAIL_REGEX);
}
public static boolean isValidPassword(final String password) {
return password != null && password.length() >= MIN_PASSWORD_LENGTH;
}
}
layout: default#
Practical Exercise: Student Management System#
๐ ๏ธ Design Challenge#
Requirements:
- Create a Student class using all three keywords
- Implement proper encapsulation with ’this’
- Add static counters and utility methods
- Use final for constants and immutable data
- Demonstrate method chaining
- Create a utility class for validation
public class Student {
// TODO: Add static counter for total students
// TODO: Add static final constants
// TODO: Add final instance variables
// TODO: Add regular instance variables
// TODO: Constructor using 'this' keyword
// TODO: Multiple constructors with chaining
// TODO: Setter methods with 'this' and return 'this'
// TODO: Static utility methods
// TODO: Instance methods accessing static members
// TODO: Final method that cannot be overridden
}
๐ฏ Expected Implementation Features#
// Usage example:
public class StudentSystemDemo {
public static void main(String[] args) {
// TODO: Demonstrate static access
System.out.println("Total students: " + Student.getTotalStudents());
// TODO: Demonstrate method chaining
Student student = new Student("Alice", 101)
.setDepartment("Computer Science")
.setGPA(3.8)
.setEmail("alice@university.edu");
// TODO: Demonstrate final constants
System.out.println("Max GPA: " + Student.MAX_GPA);
// TODO: Demonstrate static utility methods
boolean valid = Student.validateStudentId(101);
// TODO: Show immutable properties
// student.setStudentId(999); // Should not be possible
}
}
Success Criteria:
- Proper use of ’this’ throughout
- Static members correctly implemented
- Final variables appropriately used
- Method chaining working
- Utility methods accessible statically
- Immutable data protected
layout: default#
Best Practices and Common Pitfalls#
โ Best Practices
'this' keyword:
- โข Use when parameters shadow instance variables
- โข Enable method chaining for fluent APIs
- โข Use in constructor chaining
'static' keyword:
- โข Use for utility methods
- โข Constants as static final
- โข Shared counters and caches
'final' keyword:
- โข Constants and configuration
- โข Immutable object design
- โข Prevent inheritance/override
โ Common Mistakes
```java
// Wrong: Static method accessing instance variables
public static void badMethod() {
System.out.println(this.name); // โ Error!
}
// Wrong: Not using ’this’ when needed public void setName(String name) { name = name; // โ No effect! }
</div>
<div>
```java
// Wrong: Final collection modification confusion
private final List<String> items = new ArrayList<>();
public void modify() {
items = new ArrayList<>(); // โ Cannot reassign
items.add("item"); // โ
Can modify contents
}
โ ๏ธ Memory Considerations
- โข Static variables exist for entire application lifetime
- โข Static blocks execute only once during class loading
- โข Final objects may be optimized by JVM
- โข Use static sparingly to avoid memory leaks
layout: center class: text-center#
Summary#
๐ What We Learned
- โข 'this' keyword for object self-reference
- โข Method chaining and constructor chaining
- โข 'static' for class-level programming
- โข Static methods, variables, and blocks
- โข 'final' for immutability and constants
- โข Best practices and common pitfalls
๐ฏ Next Steps
- โข Constructor implementation and overloading
- โข Advanced object initialization techniques
- โข Method overloading concepts
- โข Object-oriented design patterns
- โข Memory management and optimization
Java keywords mastered! Ready for advanced OOP! ๐ฏ๐
layout: center class: text-center#
Questions & Discussion#
โ
Any questions about 'this', 'static', 'final' keywords, or their practical applications?
Next lecture: **Constructors**
Ready to build objects with constructors! ๐

