目录
一、获取一个类的Class
对象的几种方法
Class
对象是访问类元数据的入口,通过它可以获取类的名称、方法、字段、构造器、注解等信息,还可以创建类的实例、调用方法等。
在Java中,获取一个类的Class
对象主要有以下几种方式:
(1)使用.class
语法: 对于任何类型(包括基本类型)的变量,都可以使用.class
来获取其Class
对象。
(2)使用对象的getClass()
方法: 如果你有一个对象,你可以调用它的getClass()
方法来获取它的Class
对象。
(3)使用Class.forName()
方法: 如果你知道类的全名(包括包名),你可以使用Class.forName()
方法来获取其Class
对象。这种方式通常用于动态加载类。
(4)使用对象的getSuperclass()方法:一个已经存在的Class
对象,代表某个类的类型。调用getSuperclass()
方法会返回表示该类父类的Class
对象。如果该类没有显式地继承其他类,那么它隐式地继承自java.lang.Object
类,因此getSuperclass()
方法将返回Object
类的Class
对象。
(5)使用基本类型的包装类中的TYPE
字段: 对于基本类型,它们的包装类都有一个名为TYPE
的静态字段,该字段是该基本类型的Class
对象。
注意:
int.class
和Integer.class
是不同的,前者是基本类型的Class
对象,后者是包装类的Class
对象。
代码
在这个代码中,展示了获取一个类的Class
对象的几种方法,并调用了c4.hashCode()
方法,这会返回c4
对象(即表示父类的Class
对象)的哈希码。哈希码通常用于在哈希表等数据结构中快速定位对象。
每个对象的哈希码在对象的生命周期内应该保持一致,并且不同的对象根据
equals()
方法的比较结果,可能拥有相同的哈希码(这种情况称为哈希冲突)。
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println(person.name);
Class c1 = person.getClass();
System.out.println(c1.hashCode());
Class c2 = Student.class;
System.out.println(c2.hashCode());
Class c3 = Class.forName("com.itheima.sjms.Student");
System.out.println(c3.hashCode());
Class c4 = c1.getSuperclass();
System.out.println(c4.hashCode());
Class c5 = Person.class;
System.out.println(c5.hashCode());
Class c6 = Integer.TYPE;
System.out.println(c6.hashCode());
}
}
class Person{
String name;
public Person(String name){
this.name = name;
}
public Person() {
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student() {
this.name = "学生";
}
}
class Teacher extends Person{
public Teacher() {
this.name = "老师";
}
}
总结:在Java中,获取Class
对象的方式主要有.class
语法、对象的getClass()
方法、Class.forName()
方法以及基本类型的包装类中的TYPE
字段(但通常我们使用.class
语法来获取基本类型的Class
对象)。
- 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
- 已知某个类的实例,调用该实例的getClass()方法获取Class对象
- 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
- 内置基本数据类型可以直接用类名.Type
- 还可以利用ClassLoader
二、哪些类型可以有Class对象?
Class
对象是访问类元数据的入口,通过它可以获取类的名称、方法、字段、构造器、注解等信息,还可以创建类的实例、调用方法等。
在Java中,几乎所有类型都可以有对应的Class
对象。这些类型包括:
代码
在这个代码中,展示了可以有Class对象的一些类型,
-
普通类(包括内部类和匿名类): 每个加载到JVM中的普通类都会有一个对应的
Class
对象。这包括顶层类、嵌套类(静态内部类)和非静态内部类。 -
接口: 接口也有对应的
Class
对象。虽然接口不能实例化,但它们的Class
对象描述了接口的结构,包括方法签名等。 -
数组: 数组在Java中是对象,并且每种数组类型都有其对应的
Class
对象。例如,int[].class
和String[].class
分别表示整型数组和字符串数组的Class
对象。 -
基本类型: 虽然基本类型(如
int
、char
、boolean
等)不是对象,但Java为每种基本类型提供了包装类(如Integer
、Character
、Boolean
等),并且每种基本类型都有其对应的Class
对象,如int.class
。不过要注意,这里的int.class
实际上是一个特殊语法,因为基本类型本身不是类。这种语法是为了在反射时能够方便地获取基本类型的Class
对象。 -
枚举: 枚举类型在Java中是特殊的类,每个枚举类型都有一个
Class
对象。 -
注解类型: 注解也是一种特殊的接口,它们也有自己的
Class
对象。 -
oid类型:
void
类型也有对应的Class
对象,即void.class
。虽然void
类型表示无返回值,但在反射中有时需要表示方法的返回类型为void
。 -
泛型类型: 泛型类型本身在运行时由于类型擦除不会有特定的
Class
对象。但是,你可以获取表示泛型边界或泛型超类的Class
对象。例如,List<String>.class
这样的表达式是不合法的,但你可以获取List.class
并通过反射来检查其泛型信息(尽管这些信息在运行时是受限的)。
import scala.Int;
import java.lang.annotation.ElementType;
public class Test {
public static void main(String[] args){
test2();
}
public static void test2(){
Class c1 = Object.class; // 类
Class c2 = int[].class; // 一维数组
Class c3 = String[][].class; // 二维数组
Class c4 = void.class; // void
Class c5 = Override.class; // 注解
Class c6 = Integer.class; // 基本数据类型
Class c7 = Class.class; // Class
Class c8 = ElementType.class; // 枚举
Class c9 = Comparable.class; // 接口
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9);
}
public static void test1() throws ClassNotFoundException {
Person person = new Student();
System.out.println(person.name);
Class c1 = person.getClass();
System.out.println(c1.hashCode());
Class c2 = Student.class;
System.out.println(c2.hashCode());
Class c3 = Class.forName("com.itheima.sjms.Student");
System.out.println(c3.hashCode());
Class c4 = c1.getSuperclass();
System.out.println(c4.hashCode());
Class c5 = Person.class;
System.out.println(c5.hashCode());
Class c6 = Integer.TYPE;
System.out.println(c6.hashCode());
}
}
class Person{
String name;
public Person(String name){
this.name = name;
}
public Person() {
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student() {
this.name = "学生";
}
}
class Teacher extends Person{
public Teacher() {
this.name = "老师";
}
}
同时,我们也可以看到,两个长度不一样的数组,只要它们类型一(,此处都是int类型),那么它们的哈希code,也就是它们底层的Class类依旧是一样的,和数组的长度无关。
int[] arr1 = new int[10];
int[] arr2 = new int[100];
System.out.println(arr1.getClass().hashCode());
System.out.println(arr2.getClass().hashCode());