Bootstrap

【Java八股文之基础篇(五)】Java里Object类的getClass方法返回类型的详解

问题

最进在看反射的八股文,对getClass的返回类型很迷惑,看了很多博客,也不理解。然后自己写了一个例子帮助理解一下。

getClass方法的介绍


    /**
     * Returns the runtime class of this {@code Object}. The returned
     * {@code Class} object is the object that is locked by {@code
     * static synchronized} methods of the represented class.
     *
     * <p><b>The actual result type is {@code Class<? extends |X|>}
     * where {@code |X|} is the erasure of the static type of the
     * expression on which {@code getClass} is called.</b> For
     * example, no cast is required in this code fragment:</p>
     *
     * <p>
     * {@code Number n = 0;                             }<br>
     * {@code Class<? extends Number> c = n.getClass(); }
     * </p>
     *
     * @return The {@code Class} object that represents the runtime
     *         class of this object.
     * @jls 15.8.2 Class Literals
     */
    public final native Class<?> getClass();

这是JDK8里关于getClass的介绍,觉得奇怪的地方是方法的返回类型写的是Class<?>,但是注释里又说The actual result type is {@code Class<? extends |X|>}。有博客说是【开洞】处理。我不理解,也没有找到解释,有懂得小伙伴可以在评论区说一说。

既然没有找到关于这个方法的解释,我就写了一个案例运行一下,代码如下:

父类

package javase.day12;

import java.lang.reflect.Type;

public class Father {
    private int age;

    public Father() {
        System.out.println("--------Father的无参构造执行了-----------");
        Class<? extends Father> faClass = getClass();
        System.out.println("faClass.getTypeName() = " + faClass.getTypeName());
        Class<?> fsuperclass = faClass.getSuperclass();
        System.out.println("fsuperclass.getTypeName() = " + fsuperclass.getTypeName());
        Type fgenericSuperclass = faClass.getGenericSuperclass();
        System.out.println("fgenericSuperclass.getTypeName() = " + fgenericSuperclass.getTypeName());
    }

    public Father(int age) {
        this.age = age;
    }



    public void eat(){
        System.out.println("eat");
    }
}

子类

package javase.day12;

import java.lang.reflect.Type;

public class GetClassTest extends Father {
    public static void main(String[] args) {
        GetClassTest g = new GetClassTest();
        g.test();
    }
    public GetClassTest(){
        System.out.println("-------GetClassTest的无参构造执行了-----------。");
        Class<? extends GetClassTest> aClass = getClass();
        System.out.println("aClass.getTypeName() = " + aClass.getTypeName());
    }
    public void test(){
        Class<? extends GetClassTest> aClass = getClass();
        Class<?> superclass = aClass.getSuperclass();
        Type genericSuperclass = aClass.getGenericSuperclass();
        try {
            GetClassTest getClassTest = aClass.newInstance();
            getClassTest.play();
            System.out.println("aClass.getTypeName() = " + aClass.getTypeName());
            Father o = (Father)superclass.newInstance();
            o.eat();
            System.out.println("superclass.getTypeName() = " + superclass.getTypeName());
            //genericSuperclass没有创建对象的方法
            System.out.println("genericSuperclass.getTypeName() = " + genericSuperclass.getTypeName());
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
    public void play(){
        System.out.println("play");
    }
}

运行结果是

--------Father的无参构造执行了-----------
faClass.getTypeName() = javase.day12.GetClassTest
fsuperclass.getTypeName() = javase.day12.Father
fgenericSuperclass.getTypeName() = javase.day12.Father
-------GetClassTest的无参构造执行了-----------。
aClass.getTypeName() = javase.day12.GetClassTest
--------Father的无参构造执行了-----------
faClass.getTypeName() = javase.day12.GetClassTest
fsuperclass.getTypeName() = javase.day12.Father
fgenericSuperclass.getTypeName() = javase.day12.Father
-------GetClassTest的无参构造执行了-----------。
aClass.getTypeName() = javase.day12.GetClassTest
play
aClass.getTypeName() = javase.day12.GetClassTest
--------Father的无参构造执行了-----------
faClass.getTypeName() = javase.day12.Father
fsuperclass.getTypeName() = java.lang.Object
fgenericSuperclass.getTypeName() = java.lang.Object
eat
superclass.getTypeName() = javase.day12.Father
genericSuperclass.getTypeName() = javase.day12.Father

所以我只能根据运行结果解释这个返回值到底是什么了。

解释

  • 首先,main方法的第一行是创建子类对象,所以会先调用父类的构造方法,这时调用getClass返回的是子类GetClassTest的Class对象。通过getSuperclass()可以拿到父类Father的Class对象。然后执行子类GetClassTest的构造方法,此时执行getClass返回就是GetClassTest的Class对象。
  • 当执行到Father o = (Father)superclass.newInstance()时,Father的无参构造再次被执行,但是此时getClass返回的就是Father的Class对象,通过getSuperclass()可以拿到父类Object的Class对象。
  • 所以,只存在一种情况会返回子类的Class对象,那就是:那就是创建子类对象时,调用了父类的构造方法,在父类构造方法里使用了getClass方法,这时返回的是子类Class对象。其他时候返回的都是调用者的Class对象。虽然在写代码时自动补充类型会补充为Class<? extends X>,但是返回的还是X的Class对象,我也不明白为什么JDK这么设计。

结语

有时候很多不理解的知识点完全可以换一个角度解决,就是不要死磕知识点的细节(会碰到很多晦涩难懂的术语,掉入细节的泥潭,对初学者不友好),好的方法就是写demo去看结果。

;