java.lang.Object-getClass()方法介绍

源码介绍

Returns the runtime class of this Object. The returned Class object is the object that is locked by static synchronized methods of the represented class.

译文

返回此对象的运行时类对象。

返回的类对象是由所表示类的静态同步方法锁定的对象。

解释一下

getClass()方法返回的是运行时的实际类对象。 即getClass()方法返回的对象只有在运行期才能确定,而不是编译期。

同步方法在执行之前获取监视器。 对于类(静态)方法,使用类的Class对象关联的监视器。 对于实例方法,使用与此关联的监视器(调用该方法的对象)。

稍微引申一点

同一个对象上的两个同步方法的调用不可能交错。即类方法不能交错,对象方法也不能交错,但是一个类方法和一个对象方法是可以交错执行。

Class类

用来表示运行时类型信息的对应类就是Class类。Class类也是一个实实在在的类,存在于JDK的java.lang包中。

Class对象是什么?

每个类的运行时的类型信息就是用Class对象表示的。

Java中每个类都有一个Class对象,每当我们编写并且编译一个新创建的类就会产生一个对应的Class对象并且这个Class对象会被保存在同名.class文件里(编译后的字节码文件保存的就是Class对象)。

基本类型有Class对象,数组也有Class对象。

那为什么需要这样一个Class对象呢?

当我们new一个新对象或者引用静态成员变量时,Java虚拟机(JVM)中的类加载器子系统会将对应Class对象加载到JVM中,然后JVM再根据这个类型信息相关的Class对象创建我们需要实例对象或者提供静态变量的引用值。注意,我们定义的一个类,无论创建多少个实例对象,在JVM中都只有一个Class对象与其对应,即:在内存中每个类有且只有一个相对应的Class对象

怎么获取Class对象?

获取Class对象引用的方式3种

通过继承Object类的getClass方法

Class类的静态方法forName

字面常量的方式.class

稍微引申一点

实例类的getClass方法和Class类的静态方法forName都将会触发类的初始化阶段,而字面常量获取Class对象的方式则不会触发初始化。

object.getClass()和object.class的区别

类名.class叫做“类字面量”,因class是关键字, 所以类名.class在编译时就能确定返回的类型对象。

而getclass()是某个具体的方法来调用,是运行时根据实际实例确定。

例如: 
String.class 是能对类名的引用取得在内存中该类型class对象的引用,而new String().getClass() 是通过实例对象取得在内存中该实际类型class对象的引用。

下面的例子可以形象的描述 

package object;

public class Dog extends Animal{
	
	public static void main(String[] args) {
        Animal animal = new Dog();
        System.out.println(animal.getClass().getName());
        //输出object.Dog
        System.out.println(Animal.class.getName());
        //输出object.Animal
    }
}

泛化的Class对象引用

Class引用添加泛型约束仅仅是为了提供编译期类型的检查从而避免将错误延续到运行时期

package object;

public class ClassTest {

	public static void main(String[] args) {
		//没有泛型
        Class intClass = int.class;
        //带泛型的Class对象
        Class<Integer> integerClass = int.class;
        integerClass = Integer.class;
        //没有泛型的约束,可以随意赋值
        intClass= double.class;
        //编译期错误,无法编译通过
        integerClass = double.class;
	}
}

从代码可以看出,声明普通的Class对象,在编译器并不会检查Class对象的确切类型是否符合要求,如果存在错误只有在运行时才得以暴露出来。

但是通过泛型声明指明类型的Class对象,编译器在编译期将对带泛型的类进行额外的类型检查,确保在编译期就能保证类型的正确性,实际上Integer.class就是一个Class<Integer>类的对象。

另一个问题

//编译无法通过
Class<Number> numberClass=Integer.class;

我们或许会想Integer不就是Number的子类吗?然而事实并非这般简单,毕竟Integer的Class对象并非Number的Class对象的子类。当然我们可以利用通配符“?”来解决。

Class<?> intClass = int.class;
intClass = double.class;

这样的语句并没有什么问题,毕竟通配符指明所有类型都适用,那么为什么不直接使用Class还要使用Class<?>呢?这样做的好处是告诉编译器,我们是确实是采用任意类型的泛型,而非忘记使用泛型约束,至少前者在编译器检查时不会产生警告信息。当然我们还可以使用extends关键字告诉编译器接收某个类型的子类,如解决前面Number与Integer的问题:

//编译通过!
Class<? extends Number> clazz = Integer.class;
//赋予其他类型
clazz = double.class;
clazz = Number.class;

参考

Java同步静态方法:锁定对象或类

深入理解Java类型信息(Class对象)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该错误信息是出现在Java代码中,表示尝试调用一个虚拟方法时出错。该方法Object类的getClass()方法,用于返回当前对象的运行时类型。当尝试调用一个对象的方法时,首先会去检查该对象是否为null,然后再执行对应的方法。然而在这个错误中,所调用的对象为null,导致无法执行getClass()方法。 出现这个错误的原因可能有多种,常见的有: 1. 对象为null:在调用一个对象的方法之前,应该先确保该对象不为null,否则会出现NullPointerException错误。 2. 方法名错误:检查调用方法的名称是否正确,确保没有拼写错误。 3. 对象类型错误:检查该对象是否确实拥有被调用方法。例如,如果定义一个父类对象,而尝试调用子类中新增的方法,就会出现该错误。 4. 引入错误的包:如果错误的导入了错误的包或类,也可能导致找不到相应的方法而出错。 为了解决这个错误,我们可以采取以下措施: 1. 检查对象是否为null,并确保对象的有效性。 2. 检查方法名是否正确,确保没有拼写错误。 3. 检查对象的类型,确保被调用的方法与对象的类型匹配。 4. 检查导入的包和类的正确性,确保没有导入错误的包或类。 总之,当出现"attempt to invoke virtual method 'java.lang.class java.lang.object.getclass()"错误时,需要仔细检查代码中调用方法的对象是否为null或者存在其他问题,以确保方法的正确调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值