MST

星途 面试题库

面试题:Java自定义泛型类在继承与多态场景下的应用

假设有一个自定义泛型类`GenericClass<T>`,现在创建两个类`SubClass1`和`SubClass2`继承自同一个父类`BaseClass`。请编写代码,展示如何创建一个以`SubClass1`和`SubClass2`为泛型参数的`GenericClass`实例,并在使用过程中体现多态性。说明在这种场景下,Java泛型类型擦除机制会带来哪些影响以及如何应对。
47.4万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

Java代码实现

class BaseClass {
    public void baseMethod() {
        System.out.println("This is a base method.");
    }
}

class SubClass1 extends BaseClass {
    @Override
    public void baseMethod() {
        System.out.println("This is SubClass1's implementation of base method.");
    }
}

class SubClass2 extends BaseClass {
    @Override
    public void baseMethod() {
        System.out.println("This is SubClass2's implementation of base method.");
    }
}

class GenericClass<T extends BaseClass> {
    private T instance;

    public GenericClass(T instance) {
        this.instance = instance;
    }

    public void callBaseMethod() {
        instance.baseMethod();
    }
}

public class Main {
    public static void main(String[] args) {
        GenericClass<SubClass1> subClass1GenericClass = new GenericClass<>(new SubClass1());
        GenericClass<SubClass2> subClass2GenericClass = new GenericClass<>(new SubClass2());

        subClass1GenericClass.callBaseMethod();
        subClass2GenericClass.callBaseMethod();
    }
}

多态性体现

在上述代码中,GenericClass接受一个继承自BaseClass的泛型参数T。通过创建GenericClass<SubClass1>GenericClass<SubClass2>的实例,并调用callBaseMethod方法,实际调用的是SubClass1SubClass2各自重写的baseMethod,这体现了多态性。

类型擦除影响及应对

  1. 影响:Java泛型在编译后会进行类型擦除,即泛型类型信息在运行时会丢失。例如,上述代码编译后,GenericClass中的T会被擦除为BaseClass。这可能导致在运行时无法获取准确的泛型类型信息,比如不能使用instanceof操作符来判断具体的泛型类型。
  2. 应对方式
    • 使用通配符:可以使用通配符?来在一定程度上处理类型擦除问题。例如,GenericClass<? extends BaseClass>可以接受任何继承自BaseClass的类型。
    • 传递Class对象:可以在构造函数中传递Class<T>对象,以便在运行时获取泛型类型信息。如下修改GenericClass
class GenericClass<T extends BaseClass> {
    private T instance;
    private Class<T> clazz;

    public GenericClass(Class<T> clazz) {
        this.clazz = clazz;
    }

    public void createInstance() throws IllegalAccessException, InstantiationException {
        this.instance = clazz.newInstance();
    }

    public void callBaseMethod() {
        if (instance != null) {
            instance.baseMethod();
        }
    }
}

然后在main方法中:

public class Main {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        GenericClass<SubClass1> subClass1GenericClass = new GenericClass<>(SubClass1.class);
        subClass1GenericClass.createInstance();
        subClass1GenericClass.callBaseMethod();

        GenericClass<SubClass2> subClass2GenericClass = new GenericClass<>(SubClass2.class);
        subClass2GenericClass.createInstance();
        subClass2GenericClass.callBaseMethod();
    }
}

通过传递Class对象,可以在运行时创建具体类型的实例,部分解决类型擦除带来的问题。