Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Advanced Object-Oriented Programming in Java: Static Members and Inheritance

Tech 2

Static Members

The static keyword in Java is used to modify member variables and methods, creating class-level members.

Static Member Variables

Member variables in Java are categorized into two types based on the presence of the static modifier: class variables and instance variables.

  • Class Variables: Belong to the class itself. Only one copy exists in memory, shared by all instances. Accessed via ClassName.variableName.
  • Instance Variables: Belong to individual objects. Each object has its own copy. Accessed via object.variableName.

Memory representation shows class variables stored in the method area, while instance variables reside within individual heap objects.

Summary:

  • Class variables: Single copy per class, accessed by class name.
  • Instance variibles: One copy per object, accessed by object reference.

Application of Static Member Variables

Static variables are ideal for data that should be singular and shared across all instances, such as counters or configuration settings.

Example: Tracking Object Creation

public class UserAccount {
    public static int totalAccounts;
    
    public UserAccount() {
        UserAccount.totalAccounts++;
    }
}

public class ApplicationTest {
    public static void main(String[] args) {
        new UserAccount();
        new UserAccount();
        new UserAccount();
        new UserAccount();
        
        System.out.println("Total UserAccount objects created: " + UserAccount.totalAccounts);
    }
}

Output: Total UserAccount objects created: 4

Static Member Methods

Methods are similarly divided:

  • Class Methods: Modified with static. Belong to the class, invoked via ClassName.methodName().
  • Instance Methods: No static modifier. Belong to objects, invoked via object.methodName().

Example:

public class StudentRecord {
    double examScore;
    
    // Class method
    public static void displayWelcome() {
        System.out.println("Welcome!");
        System.out.println("Welcome!");
    }
    
    // Instance method
    public void showResult() {
        System.out.println(examScore >= 60 ? "Pass" : "Fail");
    }
}

public class TestDemo {
    public static void main(String[] args) {
        // Invoke class method
        StudentRecord.displayWelcome();
        
        // Invoke instance method
        StudentRecord record = new StudentRecord();
        record.showResult();
        
        // Not recommended: calling class method via object
        record.displayWelcome();
    }
}

Memory Principle:

  • Class methods load with the class, enabling direct class invocation.
  • Instance methods may access instance variables, requiring object creation first.

Utility Classes

A utility class contains only static methods, providing convenient functionality accessible via the class name.

Example: Verification Code Generator

import java.util.Random;

public final class CodeGenerator {
    // Private constructor to prevent instantiation
    private CodeGenerator() {}
    
    public static String generateCode(int length) {
        StringBuilder codeBuilder = new StringBuilder();
        String characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        Random randomizer = new Random();
        
        for (int i = 0; i < length; i++) {
            int index = randomizer.nextInt(characters.length());
            codeBuilder.append(characters.charAt(index));
        }
        return codeBuilder.toString();
    }
}

// Usage in different contexts
public class LoginScreen {
    public static void main(String[] args) {
        System.out.println(CodeGenerator.generateCode(6));
    }
}

public class RegistrationForm {
    public static void main(String[] args) {
        System.out.println(CodeGenerator.generateCode(8));
    }
}

Static Usage Notes

public class Student {
    static String university; // Class variable
    double grade; // Instance variable
    
    // Class method: can access class members, not instance members
    public static void showMessage() {
        university = "Tech University"; // Valid
        displayStatic(); // Valid
        
        // System.out.println(grade); // Invalid
        // displayInstance(); // Invalid
        // System.out.println(this); // Invalid
    }
    
    public static void displayStatic() {}
    
    // Instance method: can access both class and instance members
    public void displayInstance() {
        university = "Tech University"; // Valid
        showMessage(); // Valid
        System.out.println(grade); // Valid
        displayPrivate(); // Valid
        System.out.println(this); // Valid
    }
    
    private void displayPrivate() {}
}

Static Code Blocks

Code blocks can be static or instance-based.

Static Code Block: Executes once when the class loads.

public class Course {
    static int maxStudents = 100;
    static String department;
    
    static {
        System.out.println("Static block executed.");
        department = "Computer Science";
    }
}

public class UniversityTest {
    public static void main(String[] args) {
        System.out.println(Course.maxStudents);
        System.out.println(Course.maxStudents);
        System.out.println(Course.department); // "Computer Science"
    }
}

Instance Code Block: Executes before each constructor call during object creation.

public class Employee {
    int yearsOfService;
    
    // Instance code block
    {
        System.out.println("Instance block executed.");
        yearsOfService = 1;
        System.out.println("Object created: " + this);
    }
    
    public Employee() {
        System.out.println("Default constructor executed.");
    }
    
    public Employee(String name) {
        System.out.println("Parameterized constructor executed.");
    }
}

public class CompanyTest {
    public static void main(String[] args) {
        Employee emp1 = new Employee();
        Employee emp2 = new Employee("Alice");
        System.out.println(emp1.yearsOfService); // 1
        System.out.println(emp2.yearsOfService); // 1
    }
}

Singleton Design Pattern

Design patterns represent optimal solutions to common programming problems. The Singleton pattern ensures a class has only one instance.

Inheritance

Inheritance is a fundamental OOP feature enabling code reuse and hierarchical class relationships.

Quick Start with Inheritance

public class BaseClass {
    public int publicField;
    public void publicMethod() {
        System.out.println("---publicMethod---");
    }
    
    private int privateField;
    private void privateMethod() {
        System.out.println("---privateMethod---");
    }
}

public class DerivedClass extends BaseClass {
    public void additionalMethod() {
        // Can access inherited public members
        System.out.println(publicField); // Valid
        publicMethod(); // Valid
        
        // Cannot access private members
        // System.out.println(privateField); // Invalid
        // privateMethod(); // Invalid
    }
}

public class InheritanceTest {
    public static void main(String[] args) {
        DerivedClass obj = new DerivedClass();
        System.out.println(obj.publicField); // Valid
        obj.publicMethod(); // Valid
        
        // System.out.println(obj.privateField); // Invalid
        // obj.privateMethod(); // Invalid
    }
}

A subclass object contains both its own members and inherited public members from the parent class.

Benefits of Inheritance

Primary benefit: Code reusability. Common attributes and behaviors can be defined in a parent class.

Example:

public class Person {
    private String fullName;
    
    public String getFullName() {
        return fullName;
    }
    
    public void setFullName(String fullName) {
        this.fullName = fullName;
    }
}

public class Instructor extends Person {
    private String expertise;
    
    public String getExpertise() {
        return expertise;
    }
    
    public void setExpertise(String expertise) {
        this.expertise = expertise;
    }
    
    public void displayInfo() {
        System.out.println(getFullName() + " specializes in: " + expertise);
    }
}

public class SchoolTest {
    public static void main(String[] args) {
        Instructor teacher = new Instructor();
        teacher.setFullName("Dr. Smith");
        teacher.setExpertise("Data Structures");
        System.out.println(teacher.getFullName());
        System.out.println(teacher.getExpertise());
        teacher.displayInfo();
    }
}

Access Modifiers

Access modifiers control member visibility:

  • private: Class only
  • Default (no modifier): Class and same package
  • protected: Class, same package, and subclasses
  • public: Anywhere
public class Parent {
    private void privateFunc() {
        System.out.println("private");
    }
    
    void defaultFunc() {
        System.out.println("default");
    }
    
    protected void protectedFunc() {
        System.out.println("protected");
    }
    
    public void publicFunc() {
        System.out.println("public");
    }
    
    public void testAccess() {
        privateFunc(); // Valid
        defaultFunc(); // Valid
        protectedFunc(); // Valid
        publicFunc(); // Valid
    }
}

// In same package
public class AccessDemo {
    public static void main(String[] args) {
        Parent p = new Parent();
        // p.privateFunc(); // Invalid
        p.defaultFunc(); // Valid
        p.protectedFunc(); // Valid
        p.publicFunc(); // Valid
    }
}

Single Inheritence and Object Class

Java supports single inheritance (one direct parent) but allows multi-level inheritance. All classes implicitly inherit from Object.

class LevelA {}
class LevelB extends LevelA {}
// class LevelC extends LevelB, LevelA {} // Invalid
class LevelD extends LevelB {}

public class InheritanceDemo {
    public static void main(String[] args) {
        LevelA a = new LevelA();
        LevelB b = new LevelB();
        
        java.util.ArrayList list = new java.util.ArrayList();
        list.add("Java");
        System.out.println(list.toString()); // Inherited from Object
    }
}

Method Overriding

Subclasses can override inherited methods to provide specialized implementations.

public class Shape {
    public void draw() {
        System.out.println("Drawing shape");
    }
    
    public void resize(int width, int height) {
        System.out.println("Resizing shape");
    }
}

public class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println("Drawing circle");
    }
    
    @Override
    public void resize(int width, int height) {
        System.out.println("Resizing circle");
    }
}

public class DrawingTest {
    public static void main(String[] args) {
        Circle circle = new Circle();
        circle.draw(); // "Drawing circle"
        circle.resize(10, 10); // "Resizing circle"
    }
}

Rules:

  • Use @Override annotation
  • Overriding method access must be equal or broader
  • Return type must match or be a subclass
  • Private and static methods cannot be overridden

Comon Application: Overriding Object.toString()

public class Product {
    private String itemName;
    private double price;
    
    public Product(String itemName, double price) {
        this.itemName = itemName;
        this.price = price;
    }
    
    @Override
    public String toString() {
        return "Product{name='" + itemName + "', price=" + price + "}";
    }
}

public class StoreTest {
    public static void main(String[] args) {
        Product p = new Product("Laptop", 999.99);
        System.out.println(p); // Calls overridden toString()
    }
}

Member Access Characteristics in Subclasses

Proximity Princpile: When accessing members, the closest declaration is used.

public class Vehicle {
    String type = "Vehicle";
    
    public void start() {
        System.out.println("Vehicle starting");
    }
}

public class Car extends Vehicle {
    String type = "Car";
    
    public void showType() {
        String type = "Local Car";
        System.out.println(type); // "Local Car"
        System.out.println(this.type); // "Car"
        System.out.println(super.type); // "Vehicle"
    }
    
    @Override
    public void start() {
        System.out.println("Car starting");
    }
    
    public void demonstrate() {
        start(); // "Car starting"
        super.start(); // "Vehicle starting"
    }
}

public class GarageTest {
    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.showType();
        myCar.demonstrate();
    }
}

Constructor Access in Subclasses

Rules:

  1. Subclass constructors implicitly call super() first
  2. Execution order: Parent constructor → Subclass constructor

Explicit Parent Constructor Call:

public class Animal {
    private String species;
    
    public Animal(String species) {
        this.species = species;
        System.out.println("Animal constructor: " + species);
    }
}

public class Mammal extends Animal {
    private boolean hasFur;
    
    public Mammal(String species, boolean hasFur) {
        super(species); // Must be first statement
        this.hasFur = hasFur;
        System.out.println("Mammal constructor: fur=" + hasFur);
    }
}

public class ZooTest {
    public static void main(String[] args) {
        Mammal dog = new Mammal("Canine", true);
    }
}

Calling Own Constructors:

public class Rectangle {
    private int width;
    private int height;
    
    public Rectangle() {
        this(1, 1); // Calls parameterized constructor
    }
    
    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }
}

Summary of this and super:

// Accessing own members
this.memberVariable
this.memberMethod()
this()           // Own no-arg constructor
this(parameters) // Own parameterized constructor

// Accessing parent members
super.memberVariable
super.memberMethod()
super()           // Parent no-arg constructor
super(parameters) // Parent parameterized constructor

// Note: Constructor calls must be the first statement in a constructor.
Tags: Java

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.