Java Class and Object Basics

In Java, an object is an instance of a class. A class is an abstract data type that defines a set of attributes and methods used to describe objects of a certain type. In Java, classes serve as templates for creating objects. When you define a class, you specify a generic data type along with the properties and methods associated with it. Subsequently, you can create any number of objects based on this class; each object possesses identical attributes and methods but may hold different attribute values.

For example, suppose you are writing a program to represent cars. You could define a class named "Car" that includes attributes such as "make", "model", "year", and "color". The class can also include methods like "start", "stop", "accelerate", and "brake". Then, based on this class, you can create multiple car objects; each object will have the same attributes and methods but with varying attribute values.

In Java, a class definition comprises the class name, properties (attributes), and methods.

Example

Below is an example of a simple Java class definition:

public class Car {
    private String make;
    private String model;
    private int year;
    private String color;
  
    public Car(String make, String model, int year, String color) {
        this.make = make;
        this.model = model;
        this.year = year;
        this.color = color;
    }
  
    public void start() {
        // code to start the car
    }
  
    public void stop() {
        // code to stop the car
    }
  
    public void accelerate() {
        // code to accelerate the car
    }
  
    public void brake() {
        // code to apply brakes to the car
    }
}

In the example above, the Car class contains four properties (make, model, year, and color) and four methods (start, stop, accelerate, and brake). The constructor public Car(String make, String model, int year, String color) is used to initialize property values when creating a Car object. These methods can be employed to manipulate the behavior of Car objects.

Inner Classes

Inner classes in Java are classes defined within another class. An inner class has access to all members of its enclosing (outer) class, including private members; conversely, an outer class cannot directly access the members of an inner class. Inner classes can be categorized into member inner classes, local inner classes, anonymous inner classes, and static inner classes.

  1. Member Inner Class:
    A member inner class is a class defined at the member level within an enclosing (outer) class. It has access to all members of the outer class, including private ones. Member inner classes can have access modifiers such as public, protected, default (package-private), or private. A member inner class can be referenced using the syntax: OuterClass.this.InnerClassName (though typically accessed via an instance variable holding a reference to the outer object).

  2. Local Inner Class:
    A local inner class is a class defined within a method or code block. It can only be used within that specific method or code block and cannot be instantiated directly by other classes outside its scope. While it has access to members of the enclosing class, it can only reference final (or effectively final) local variables from the outer class.

  3. Anonymous Inner Class:
    An anonymous inner class is an inner class without a name; it typically serves as a means to create an object that implements an interface or extends a specific class directly at instantiation time. It allows for method overriding of parent classes or interfaces during creation but cannot have access modifiers or the static keyword associated with its declaration.

  4. Static Inner Class:
    A static inner class is a non-instantiable class defined within an enclosing (outer) class. It can possess static members and methods, as well as access to static members of the outer class. Unlike instance-based inner classes, it does not have implicit references to its outer object's state unless explicitly passed or stored in fields. A static inner class is referenced using: OuterClass.InnerClassName.

The primary purpose of inner classes is to provide access to private members of an enclosing class and to organize logically related code together, thereby enhancing code readability and maintainability.

Abstract Classes

Introduction to Abstract Classes

In Java, an abstract class is a class that cannot be instantiated directly; it can only be extended (inherited). Its purpose is to serve as a base in the class hierarchy, providing common attributes and methods for subclasses. An abstract class may contain both abstract methods and non-abstract methods.

An abstract method is a method declaration without an implementation body; consequently, its subclass must provide a concrete implementation to override it. A non-abstract method contains actual code logic (an implementation). It is possible for an abstract class to include both abstract and non-abstract methods simultaneously.

To define an abstract class in Java, the abstract keyword must be used as a modifier on the class declaration. Below is an example of such a class:

public abstract class Shape {
    private String color;
  
    public Shape(String color) {
        this.color = color;
    }
  
    public String getColor() {
        return color;
    }
  
    // Abstract method declaration without body
    public abstract double getArea();
}

In the example above, Shape is an abstract class featuring a private property (color) and a constructor. It also includes an abstract method getArea() which lacks an implementation body. Because it declares an abstract method, this class must be declared as abstract itself.

Subclasses can inherit from an abstract class by providing concrete implementations to override the abstract methods defined therein.

Example of Abstract Class Usage

Below is an example demonstrating a subclass that extends the Shape abstract class:

public class Circle extends Shape {
    private double radius;
  
    public Circle(String color, double radius) {
        super(color); // Calls constructor in parent class (abstract classes cannot be instantiated directly here if not extended properly, but logic holds for inheritance chain)
        this.radius = radius;
    }
  
    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
}

In the example above, Circle extends the abstract class Shape and provides a concrete implementation to override the abstract method getArea(). Note that if a subclass fails to implement all declared abstract methods of its parent (and is not itself marked as abstract), it will result in a compilation error.