Java 反射机制详解(一)
主要介绍以下几方面内容
- 理解 Class 类
- 理解 Java 的类加载机制
- 学会使用 ClassLoader 进行类加载
- 理解反射的机制
- 掌握 Constructor、Method、Field 类的用法
- 理解并掌握动态代理
1.Class类
通过Class类可以得到的信息某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口等,对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象,一个 Class 对象包含了特定某个类的有关信息,Class 对象只能由系统建立对象 ,一个类在 JVM 中只会有一个Class实例,每个类的实例都会记得自己是由哪个 Class 实例所生成。
1.1 Class是什么?
答: Class是一个类
1.2 Class类封装了什么信息?
答:封装了当前对象所对应的类的信息,包含类中的属性,方法,构造器等
例如: 有一个Person类,一个Order类,一个Book类,这些都是不同的类,现在需要一个类,用来描述这些类,这就是Class类,它应该有类名,属性,方法,构造器等。Class是用来描述类的类 Class类是一个对象照镜子的结果,对象可以看到自己有哪些属性,方法,构造器,实现了哪些接口等等
定义Person类:
public class Person {
String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// 带参的构造器
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
// 不带参的构造器
public Person() {
super();
}
通过Class类获取类对象:
public class ReflectionTest {
@Test
public void testClass() {
Class clazz = null;
//1.得到Class对象
clazz = Person.class;
System.out.println(); //插入断点
}
}
在断点处就可以看到Class对像包含的信息:
同样,这些属性值是可以获取的:
public class ReflectionTest {
@Test
public void testClass() {
Class clazz = null;
//1.得到Class对象
clazz = Person.class;
//2.返回字段的数组
Field[] fields = clazz.getDeclaredFields();
System.out.println(); //插入断点
}
}
fields的内容如下:
1.3 为什么需要Class类对象?
a.有可能这个对象是别人传过来的
b.有可能没有对象,只有一个全类名
通过反射,可以得到这个类里面的信息
1.4 如何获取Class对象?
a.通过类名获取 类名.class
b.通过对象获取 对象名.getClass()
c.通过全类名获取 Class.forName(全类名)
public class ReflectionTest {
@Test
public void testClass() throws ClassNotFoundException {
Class clazz = null;
//1.通过类名
clazz = Person.class;
//2.通过对象名
//这种方式是用在传进来一个对象,却不知道对象类型的时候使用
Person person = new Person();
clazz = person.getClass();
//上面这个例子的意义不大,因为已经知道person类型是Person类,再这样写就没有必要了
//如果传进来是一个Object类,这种做法就是应该的
Object obj = new Person();
clazz = obj.getClass();
//3.通过全类名(会抛出异常)
//一般框架开发中这种用的比较多,因为配置文件中一般配的都是全类名,通过这种方式可以得到Class实例
String className=" com.atguigu.java.fanshe.Person";
clazz = Class.forName(className);
//字符串的例子
clazz = String.class;
clazz = "javaTest".getClass();
clazz = Class.forName("java.lang.String");
System.out.println();
}
}
1.5 Class类有哪些方法?
- static Class forName(String name) 返回指定类名 name 的 Class 对象
- Object newInstance() 调用缺省构造函数,返回该Class对象的一个实例
- Object newInstance(Object []args) 调用当前格式构造函数,返回该Class对象的一个实例
- getName() 返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称
- Class getSuperClass() 返回当前Class对象的父类的Class对象
- Class [] getInterfaces() 获取当前Class对象的接口
- ClassLoader getClassLoader() 返回该类的类加载器
- Class getSuperclass() 返回表示此Class所表示的实体的超类的Class
Class类的newInstance()方法 :
public void testNewInstance() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
//1.获取Class对象
String className="com.atguigu.java.fanshe.Person";
Class clazz = Class.forName(className);
//利用Class对象的newInstance方法创建一个类的实例
Object obj = clazz.newInstance();
System.out.println(obj);
}
//结果是:com.atguigu.java.fanshe.Person@2866bb78
可以看出确实是创建了一个Person实例,但是Person类有两个构造方法,到底是调用的哪一个构造方法呢
实际调用的是类的无参数的构造器。所以在我们在定义一个类的时候,定义一个有参数的构造器,作用是对属性进行初始化,还要写一个无参数的构造器,作用就是反射时候用
一般地、一个类若声明一个带参的构造器,同时要声明一个无参数的构造器