Interfaces and Abstract Classes

Interface

An interface is an abstraction of behavior.

  1. Abstract methods: Before Java 8, interfaces could only have abstract methods.
  2. Default methods: Provide method bodies, available since Java 8.
  3. Static methods: Provide method bodies, available since Java 8, can be called via Interface.method().
 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
public interface MyInterface {
    // Abstract method
    void abstractMethod();

    // Default method
    default void defaultMethod() {
        System.out.println("This is the default method of the interface");
        privateHelperMethod();  // Call private helper method (Note: private methods are a Java 9 feature, shown here for example only)
    }

    // Static method
    static void staticMethod() {
        System.out.println("This is the static method of the interface");
    }

    // Private helper method (Java 9 feature, but included for completeness)
    private void privateHelperMethod() {
        System.out.println("This is the private helper method of the interface");
    }
}

public class MyClass implements MyInterface {
    @Override
    public void abstractMethod() {
        System.out.println("Implementing the abstract method of the interface");
    }

    // Can choose to override the default method
    @Override
    public void defaultMethod() {
        System.out.println("Overriding the default method of the interface");
        MyInterface.super.defaultMethod();  // Call the default method of the interface
    }
}

public class Main {
    public static void main(String[] args) {
        MyClass myClass = new MyClass();

        // Call the implemented abstract method
        myClass.abstractMethod();

        // Call the default method
        myClass.defaultMethod();  // Note that the overridden version is called here

        // Call the static method of the interface
        MyInterface.staticMethod();
    }
}

Abstract Class

Abstract classes typically serve as base classes, such as Person, Animal. Because the body of certain methods may differ among various subclasses, these methods are placed as abstract methods in the abstract class.

An abstract class can inherit from another class and can implement multiple interfaces.

 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
public interface Sing {
    public void sing();
}
public interface Dance {
    public void dance();
}

public abstract class Animal implements Dance, Sing{
    @Override
    public void dance(){
        System.out.println("Animal dance");
    }
    @Override
    public void sing(){
        System.out.println("Animal sing");
    }
    abstract void eat();
}

public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("cat eat");
    }
}

public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("Dog eats");
    }
}
  1. Sing and Dance both represent capabilities, so they are interfaces implemented by the Animal abstract class.
  2. The Animal class provides the abstract method eat().
  3. The Cat and Dog classes then provide different method bodies for the eat() method.

Autoboxing & Unboxing

  1. Autoboxing: Automatically converts primitive types to their corresponding wrapper class objects, actually calling methods like Integer.valueOf(), Double.valueOf(), etc.
1
2
int num = 10;
Integer boxedNum = num;  // Autoboxing (int → Integer)
  1. Unboxing: Automatically converts wrapper class objects to primitive types. Actually calls methods like intValue(), doubleValue(), etc.

  2. Performance issues: Autoboxing/unboxing creates temporary objects, and frequent use in loops can lead to performance degradation.

  3. When comparing wrapper class objects, == compares memory addresses, not values!

1
2
3
4
5
6
7
Integer a = 127;
Integer b = 127;
System.out.println(a == b);  // true (JVM caches small integer objects)

Integer c = 128;
Integer d = 128;
System.out.println(c == d);  // false (outside cache range, new objects created)