Post

09. Java Classes & Objects

🚀 Dive into the world of Java classes! Master everything from basic classes and objects to interfaces, singletons, inner classes, and beyond, unlocking the core building blocks for robust Java applications. 🎓

09. Java Classes & Objects

What we will learn in this post?

  • 👉 Understanding Classes and Objects in Java
  • 👉 Class vs Interface
  • 👉 Singleton Class in Java
  • 👉 Object Class in Java
  • 👉 Inner Class in Java
  • 👉 Abstract Classes in Java
  • 👉 Throwable Class in Java
  • 👉 Conclusion!

Classes and Objects in Java: A Friendly Guide 🚀

Let’s explore the core concepts of object-oriented programming in Java: classes and objects. Think of a class as a blueprint, like an architect’s plan for a house. It defines the structure and behavior of something but isn’t the actual thing. An object, on the other hand, is the actual house built using that blueprint. It’s a real instance, with its own unique data. Understanding this Java class-object relationship is fundamental to writing good Java code.

Classes: The Blueprint 📐

  • Classes are templates that define the characteristics (data or attributes) and actions (methods or behaviors) of objects.
  • They don’t exist physically; they’re abstract descriptions of things.
  • For example, a Dog class could have attributes like breed, name, and age, and methods like bark(), eat(), and sleep().
  • Here is a simple class code:
1
2
3
4
5
6
7
8
9
class Dog {
  String breed;
  String name;
  int age;

  void bark() {
    System.out.println("Woof!");
  }
}

Objects: The Real Deal 🐕

  • Objects are instances of a class; they are the real things created from a blueprint.
  • Each object has its own set of values for the attributes defined in its class.
  • For example, you can have several Dog objects, each with its own breed, name, and age.
  • This is how we create an object of the Dog class:

    1
    2
    3
    4
    5
    
    Dog myDog = new Dog(); //Instantiation
    myDog.breed = "Golden Retriever";
    myDog.name = "Buddy";
    myDog.age = 3;
    myDog.bark(); // Output: Woof!
    
  • Another Dog object:

    1
    2
    3
    4
    5
    
    Dog anotherDog = new Dog();
    anotherDog.breed = "Pug";
    anotherDog.name = "Max";
    anotherDog.age = 5;
    anotherDog.bark(); // Output: Woof!
    

The Java Class-Object Relationship 🔗

The core of the Java class-object relationship lies in the fact that:

  • A class is a type or category, while an object is a specific thing belonging to that type.
  • You can create multiple objects from the same class, each with its own unique state.
  • Think of a cookie cutter (class) and the cookies made (objects). The shape is the same but each cookie can have its own sprinkles, frostings etc.
flowchart TD
    %% Node Styles
    classDef classNode fill:#4CAF50,stroke:#2E7D32,color:#FFFFFF,font-size:16px,stroke-width:2,rounded
    classDef objectNode fill:#2196F3,stroke:#1976D2,color:#FFFFFF,font-size:14px,stroke-width:2,rounded
    classDef attributeNode fill:#FF9800,stroke:#F57C00,color:#000000,font-size:16px,stroke-dasharray:5 5,rounded

    %% Nodes
    A[Class: Dog 🐾]:::classNode
    B[Object: myDog 🐶]:::objectNode
    C[Object: anotherDog 🐕]:::objectNode
    D{breed: Golden Retriever<br>name: Buddy<br>age: 3}:::attributeNode
    E{breed: Pug<br>name: Max<br>age: 5}:::attributeNode

    %% Connections
    A --> B
    A --> C
    B --> D
    C --> E

Key Takeaways

  • The class defines the blueprint, object represents the actual instance.
  • Classes serve as a template for creating multiple objects.
  • Each object can have its own set of values for the attributes/properties.
  • It’s the most important concept of object-oriented programming in Java.

By understanding this relationship, you’ll be well on your way to mastering Java and writing structured and maintainable code.

For more information, check out these resources:

Class vs Interface in Java: Understanding the Difference 🧐

Understanding the differences between classes and interfaces is crucial for solid Java OOP design. Let’s break it down in simple terms.

What’s the Deal? 🤷‍♀️

  • Classes: Think of a class as a blueprint for creating objects. It’s a complete package that defines the state (data/variables) and behavior (methods) an object will have.

    • Implementation: Classes provide actual implementation of methods. For example, a Dog class could have a bark() method with concrete code.
    • Use Cases: Use classes when you need to create concrete objects with specific states and actions.
    • Example:

      1
      2
      3
      4
      5
      6
      
        class Dog {
         String breed;
         public void bark() {
           System.out.println("Woof!");
        }
       }
      
  • Interfaces: An interface is more like a contract. It defines what methods an implementing class must have, but it doesn’t provide how those methods should work.

    • Implementation: Interfaces only declare methods without implementation. Classes that use an interface must provide the actual code for those methods. This is ‘Java class interface differences’.
    • Use Cases: Use interfaces to enforce certain behaviors across different classes or to achieve polymorphism (treating objects of different classes as objects of a common type).

      • Example:

        1
        2
        3
        
        interface Animal {
            void makeSound();
         }
        

Key Differences - Class vs Interface in Java 🤔

  • Implementation:
    • Classes can contain both abstract and implemented methods.
    • Interfaces can only have abstract methods or default and static implemented methods.
  • Instantiation:
    • You can create objects (instances) of a class.
    • You cannot directly create objects of an interface.
  • Inheritance:
    • A class can only inherit from one other class (single inheritance).
    • A class can implement multiple interfaces.
    • An interface can extend multiple interfaces.
  • Purpose:
    • Classes are for creating specific object types with defined data and actions.
    • Interfaces are for defining contracts and ensuring that classes adhere to specific behaviours (‘Java OOP interfaces’).

When to Use What? 🤔

  • Use a Class when:
    • You have a concrete concept that needs to have a specific state and behaviour (like a Car, Book, or User).
  • Use an Interface when:
    • You want to establish a set of methods that various unrelated classes should implement.
    • You want to achieve decoupling and flexibility in your code.
    • You want to support polymorphism.

For instance, a Car class could implement an Engine interface which might have a start() and stop() method. Different car models (SportsCar, Truck) could implement the same interface but use their own custom way for starting the engine.

graph LR
    %% Node Styles
    classDef classNode fill:#4CAF50,stroke:#2E7D32,color:#FFFFFF,font-size:16px,stroke-width:2,rounded
    classDef interfaceNode fill:#FF9800,stroke:#F57C00,color:#000000,font-size:16px,stroke-dasharray:5 5,rounded
    classDef methodNode fill:#2196F3,stroke:#1976D2,color:#FFFFFF,font-size:14px,stroke-width:2,rounded

    %% Nodes
    A[Car 🚗]:::classNode
    C[SportsCar 🏎️]:::classNode
    D[Truck 🚚]:::classNode
    B[implements<br>Engine 🛠️]:::interfaceNode
    E[start]:::methodNode
    F[stop]:::methodNode

    %% Connections
    A --> B
    C --> B
    D --> B
    B --> E
    B --> F

Resources:

Hopefully, this breakdown makes the distinction between classes and interfaces clearer! 😊

The Singleton Design Pattern in Java 🧐

Let’s explore the singleton design pattern in Java, a clever technique that ensures a class has only one instance throughout your application. Think of it like having a single commander-in-chief – you wouldn’t want multiple leaders giving conflicting orders, right? This pattern restricts the creation of multiple objects, making it a single instance class in Java.

Why Use a Singleton? 🤔

  • Resource Management: Ideal for managing resources like database connections or thread pools, preventing multiple instances from competing.
  • Global Access Point: Provides a single, easily accessible point for accessing data or functionalities.
  • Configuration Settings: Perfect for centralizing application settings, ensuring all parts of the code use the same settings.

Implementing a Java Singleton Example 🛠️

Here’s a straightforward example of how to create a Singleton class in Java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Singleton {

    private static Singleton instance; // Static instance

    private Singleton() { // Private constructor to prevent instantiation
        // Initialization logic (if any)
    }

    public static Singleton getInstance() { // Static method to get the instance
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

    public void showMessage() {
        System.out.println("Hello from Singleton!");
    }
}

Explanation:

  • Private Constructor: The private Singleton() constructor prevents other classes from creating Singleton objects directly.
  • Static Instance Variable: The private static Singleton instance; variable holds the single instance of the class.
  • Static getInstance() Method: The public static Singleton getInstance() method is the access point for obtaining the single instance. It checks if an instance exists and creates it only if needed (lazy initialization).

How to Use the Singleton

1
2
3
4
5
6
7
8
9
10
11
12
public class Main {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();

        // Both variables will point to the same instance
        System.out.println(singleton1 == singleton2); // Output: true

        singleton1.showMessage(); // Output: Hello from Singleton!
        singleton2.showMessage(); // Output: Hello from Singleton!
    }
}

This shows that both singleton1 and singleton2 reference the same Singleton instance.


Diagram of Singleton:

classDiagram
    %% Classes
    class Singleton {
        - static instance: Singleton
        - Singleton()
        + static getInstance(): Singleton
        + showMessage(): void
    }
    class Client {
        + main(): void
    }

    %% Relationships
    Client --> Singleton: Uses getInstance()

    %% Style Definitions
    classDef classNode fill:#4CAF50,stroke:#2E7D32,color:#FFFFFF,font-size:16px,stroke-width:2,rounded
    classDef relationshipArrow stroke:#1976D2,stroke-width:2


Key Takeaways 🎯

  • Uniqueness: Ensures that only one instance of a class exists.
  • Global Access: Provides a single access point.
  • Controlled Instantiation: The constructor is private and prevents direct creation.
  • Lazy Loading: Instance created only when needed via getInstance().

Resources:

By using the singleton design pattern in Java, you can manage your resources efficiently and ensure a well-structured application. This makes it an important tool for any Java developer looking to create robust and maintainable code. Remember the Java singleton example provided when building your own systems.

The Mighty Java Object Class 👑

Let’s dive into the heart of Java – the Object class! It’s the ultimate ancestor, sitting at the very top of the Java class hierarchy. Every single class you create, either directly or indirectly, inherits from this Object class. This means that all Java objects have access to the methods defined within the Object class. Think of it as the foundational DNA for all Java creations. These methods, though basic, provide essential functionalities for every object.

Significance of the Object Class

  • It ensures consistency among all objects in the Java world.
  • It provides fundamental behaviors common to all objects, such as comparison, string representation and more.
  • Being the root, any class can be treated as an Object, enabling polymorphism.


Key Object Class Methods

Here are some key Object class methods and how you might see them in action:

  • public boolean equals(Object obj): Compares if two objects are equal. By default, it checks for reference equality (are they the same object?). You often override it to check for logical equality (do they represent the same value?).

    1
    2
    3
    
    String str1 = new String("hello");
    String str2 = new String("hello");
    System.out.println(str1.equals(str2)); // true (String overrides equals)
    
  • public int hashCode(): Generates a hash code, an integer representing the object. It’s critical for hash-based collections like HashMap.

    1
    2
    
     String str = "example";
     System.out.println(str.hashCode()); // Output: A hash code value (not fixed).
    
  • public String toString(): Returns a string representation of the object. Often used for debugging.

    1
    2
    
    Object obj = new Object();
    System.out.println(obj.toString()); // Output: something like "java.lang.Object@7344699f"
    
  • protected void finalize() throws Throwable: Called by the garbage collector before an object is reclaimed. Be careful with finalize(), as its timing is unpredictable. (Rarely used directly)
  • public final Class<?> getClass(): Returns the runtime class of the object.

    1
    2
    
      String text = "Hello";
      System.out.println(text.getClass()); // Output: class java.lang.String
    
  • protected Object clone() throws CloneNotSupportedException - Creates and returns a copy of the object. You have to implement the Cloneable interface for your classes to use this.

Java Object Class Hierarchy Diagram

graph LR
    A[Object 🟢]:::startNode --> B[Class 1 🔧]:::processNode
    A --> C[Class 2 🔧]:::processNode
    B --> D[SubClass 1 of Class 1 🔄]:::processNode
    C --> E[SubClass 1 of Class 2 🔄]:::processNode

    classDef startNode fill:#4CAF50,stroke:#2E7D32,color:#FFFFFF,fontsize:16px,rx:10,ry:10
    classDef processNode fill:#2196F3,stroke:#1976D2,color:#FFFFFF,fontsize:14px,rx:10,ry:10
    classDef decisionNode fill:#FF9800,stroke:#F57C00,color:#000000,fontsize:16px,border-style:dashed
    linkStyle default stroke-width:2px,fill:none


    style A fill:#f9f,stroke:#333,stroke-width:2px

The above diagram shows that Object is the root of every java class


Further Exploration 🧐

To learn more, check out these resources:

Understanding the Object class is key to mastering Java. It’s the silent foundation that empowers all our objects with shared basic abilities!

Inner Classes in Java: A Nested World 🏠

Inner classes, also called Java nested classes, are classes defined inside another class. They’re like a secret club within a building! This concept helps organize code and enhance encapsulation. Let’s explore their types and why they’re useful.

Types of Inner Classes 🤔

There are four main types of inner classes in Java:

  • Member Inner Class:

    • Declared inside a class (but not within a method).
    • Has access to all members (including private ones) of the outer class.
    1
    2
    3
    4
    5
    6
    7
    8
    
    class Outer {
        private int outerVar = 10;
        class MemberInner {
            void display() {
                System.out.println("Outer variable: " + outerVar);
            }
         }
    }
    
  • Static Nested Class:

    • Declared with the static keyword inside a class.
    • Doesn’t require an instance of the outer class to be created.
    • Only has access to static members of the outer class.
    1
    2
    3
    4
    5
    6
    7
    8
    
    class Outer {
      static int outerVar = 10;
      static class StaticInner {
         void display() {
             System.out.println("Outer static variable: " + outerVar);
         }
      }
    }
    
  • Local Inner Class:

    • Declared within a method.
    • Visible only within that method.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    class Outer {
      void method() {
          class LocalInner {
              void display() {
                  System.out.println("Local Inner class");
              }
          }
          LocalInner inner = new LocalInner();
          inner.display();
      }
    }
    
  • Anonymous Inner Class:

    • An inner class without a name.
    • Often used for implementing interfaces or extending classes.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
     interface MyInterface {
      void display();
     }
     class Outer {
       void method(){
        MyInterface anonymousInner = new MyInterface() {
          @Override
          public void display() {
            System.out.println("Anonymous Inner class");
           }
         };
          anonymousInner.display();
       }
     }
    

Benefits of Inner Classes ✨

  • Encapsulation: Hides implementation details, keeping code clean and organized.
  • Code Readability: Groups related classes together.
  • Access to Private Members: Member inner classes can access private members of the outer class.
  • Specific Functionality: Useful for callbacks and event handling, as seen with anonymous inner classes.
graph LR
    A[🏁 Outer Class] -->|Solid| B(⚙️ Member_Inner_Class)
    A -->|Solid| C(⚙️ Static_Nested_Class)
    A -->|Solid| D{❓ Method}
    D -->|Dotted| E(🔒 Local_Inner_Class)
    A -->|Dotted| F(💬 Anonymous_Inner_Class)

    class A start_end;
    class B,C process;
    class D decision;
    class E,F return_end;

    classDef start_end fill:#4CAF50,stroke:#2E7D32,color:#FFFFFF,font-size:16px,rx:15px;
    classDef process fill:#2196F3,stroke:#1976D2,color:#FFFFFF,font-size:14px,rx:15px;
    classDef decision fill:#FF9800,stroke:#F57C00,color:#000000,font-size:16px,stroke-dasharray:5 5;
    classDef return_end fill:#4CAF50,stroke:#2E7D32,color:#FFFFFF,font-size:16px,rx:15px;

For more information:

Understanding Abstract Classes in Java 🎭

Abstract classes in Java are like blueprints that cannot be used to create objects directly. Think of them as incomplete templates that provide a common structure and shared functionality for their subclasses.

Abstract Class vs Interface 🤔

A key point when discussing abstract classes in Java is how they compare to interfaces. Both define a contract, but they differ. An interface can only declare methods (all abstract) while an abstract class can contain both abstract and concrete (implemented) methods, as well as fields. Unlike interfaces, classes can only inherit from one abstract class (single inheritance). This means you should use an abstract class vs interface when you have common implementation logic shared across several classes.

Java Abstract Class Usage 🧭

So, when should you consider using an abstract class? When you want to:

  • Provide a basic structure for a family of classes.
  • Share common methods implementation but also have some abstract methods that subclasses must implement.
  • Avoid redundant code in multiple subclasses that should behave similarly

In summary, you’d use abstract classes when you have common implementations while needing some specific details to be filled in by the inheriting classes.

Let’s see how to implement one!

graph TD
    A[🏁 Abstract Class] -->|Solid| B(⚙️ Subclass_1)
    A -->|Solid| C(⚙️ Subclass_2)

    %% Use an interface node to demonstrate the difference
    D[❓ Interface] -->|Dotted| E(⚙️ Implementer_1)
    D -->|Dotted| F(⚙️ Implementer_2)

    class A start_end;
    class B,C process;
    class D decision;
    class E,F process;

    classDef start_end fill:#4CAF50,stroke:#2E7D32,color:#FFFFFF,font-size:16px,rx:15px;
    classDef process fill:#2196F3,stroke:#1976D2,color:#FFFFFF,font-size:14px,rx:15px;
    classDef decision fill:#FF9800,stroke:#F57C00,color:#000000,font-size:16px,stroke-dasharray:5 5;

    %% Abstract Class (with additional details)
    class A fill:#66BB6A,stroke:#388E3C,color:#FFFFFF,font-size:16px,rx:15px;
    %% Interface node style (with different color)
    class D fill:#FFEB3B,stroke:#FBC02D,color:#000000,font-size:16px,rx:15px;

    %% Add arrow and descriptive labels to illustrate differences
    A -->|Defines both abstract and concrete methods| D
    D -->|Can only declare abstract methods| A
    A -->|Single Inheritance| B
    D -->|Multiple Implementations *can be implemented by multiple classes*| E
    B -->|Can inherit concrete methods| C

Example Implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Abstract class example
abstract class Shape {
    // Abstract method (must be implemented by subclasses)
    abstract double calculateArea();

    // Concrete method (shared by subclasses)
    public void displayDetails() {
        System.out.println("This is a shape.");
    }
}

// Subclass extending the abstract class
class Circle extends Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    double calculateArea() {
        return Math.PI * radius * radius;
    }
}

class Rectangle extends Shape{
    private double width;
    private double height;
    public Rectangle(double width, double height) {
        this.width=width;
        this.height= height;

    }
    @Override
    double calculateArea() {
        return width * height;
    }
}

public class Main {
    public static void main(String[] args) {
        Circle circle = new Circle(5);
        circle.displayDetails(); // Calling the shared method
        System.out.println("Area of the circle: " + circle.calculateArea()); // Calling the implemented abstract method
        Rectangle rectangle = new Rectangle(4,6);
        rectangle.displayDetails();
        System.out.println("Area of the rectangle : " + rectangle.calculateArea());
    }
}
  • Shape is an abstract class. It defines a method calculateArea that has to be implemented by concrete subclasses. displayDetails is a concrete method, shared by subclasses.
  • Circle and Rectangle are concrete classes that extend Shape, they must define an implementation for the abstract method calculateArea().

Abstract classes give structure with flexibility, providing the common base while allowing for specialization. Knowing how to use an abstract class in Java can significantly improve your design and avoid redundancy. You can learn more here: Oracle’s Java Documentation and GeeksforGeeks Abstract Class

Error: Invalid response structure for ‘Throwable Class in Java’.

Conclusion

And that’s a wrap! 🎉 We hope you enjoyed diving into this topic with us. Your thoughts are super important, so don’t be shy! What did you think? Any questions or ideas popping up? 🤔 We’d absolutely love to hear them all! Please drop your comments, feedback, or suggestions in the section below. Let’s chat and keep the conversation going! 💬😊

This post is licensed under CC BY 4.0 by the author.