- 一、反射,被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能操作任意对象内部属性及方法。
- 正常方式:引入需要的“包类”名称–>通过new实例化–>取得实例化对象
- 反射方式:实例化对象–>getClass()方法–>得到完整的“包类”名称
- 二、功能:
- 1.在运行时判断任意一个对象所属的类
- 2.在运行时构造任意一个类的对象
- 3.在运行时判断一个类所具有的成员变量和方法
- 4.在运行时调用任意一个对象的成员变量和成员方法
- 5.生成动态代理
- 三、Class类:对照镜子可以得到的信息,包括某个类的方法、属性、构造器、实现的那些接口,对于每个类而言JRE为每个类都保存了一个不变的Class类对象,一个Class对象包含了特定某个类的有关信息
- 1.Class本身也是一个类
- 2.Class对象是能由系统建立对象
- 3.一个类在JVM中只有一个Class实例
- 4.一个Class对象对应的是一个加载到JVM中的一个.class文件
- 5.每个类的实例都会记得自己是由哪个Class实例所生成的
- 6.通过Class可以得到完整的一个类的完整结构
四、步骤:
- 1.创建Class对象 Calss cla = Person.class,编辑时只是编辑成.class文件,运行时才会加载到内存
- 2.使用newInstance()创建运行时对象,比如:Person p = cla.newInstance();
- 3.获取运行时类的属性,比如name属性,Field f1 = cla.getField(“name”)
- 4.并设置属性,比如name,f1.set(p, “李斯”);
五、代码:
public class TestReflection {
//若不使用反射,如何创建一个对象,并调用其中的方法、属性
/*@Test
public void test1(){
Person p = new Person();
p.setAge(22);
p.setName("张三");
System.out.println(p.toString());
p.display("HK");
}*/
//使用反射创建对象
@Test
public void test2() throws Exception{
Class<Person> cla = Person.class;
//1.首先创建cla对应的运行时类Person类的对象
Person p = cla.newInstance();
System.out.println("反射机制创建对象:"+p);
//2.通过反射调用并设置运行时类指定的属性
//设置属性有两种方法,
//其一这个属性的权限修饰符为public,使用getField()
Field f1 = cla.getField("name");//首先获取一个属性,属性的名字叫name,赋给Field类型的变量f1
f1.set(p, "李斯"); //其次为这个属性赋值,对象為Person,属性名为name,f1调用set方法为属性赋值
System.out.println("为对象的一个属性name赋值:"+p);//输出这个对象
//其二.这个属性的权限修饰符为private,使用getDeclareField()
Field f2 = cla.getDeclaredField("age");
//设置私有的变量允许访问。
f2.setAccessible(true);
f2.set(p, 22);
System.out.println("为对象的第二个属性age赋值:"+p);
//3.通过反射调用运行时方法,有二种其一方法有参数,方法无参数
Method m1 = cla.getMethod("display",String.class);
m1.invoke(p,"中国");//invoke(对象,方法形参)
}
/**
* java.long.Class类是反射的源头,getClass()返回值类型是Class类型。
*创建一个类,通过编译(javac.exe)生成相应的.class文件,
*之后使用java.exe加载(JVM类加载器完成).class文件,此.class文件加载到内存之后就是一个运行时类,存到缓冲区。
*那么这个运行时类本身就是一个Class的实例。
*1.每个运行时类只加载一次
*2.有了Class类的实例之,才可以进行如下操作:
* ①创建对应的运行时类对象
* ②获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在包、异常、注解...)
* ③调用运行时类的指定结构(属性、方法、构造器)
* ④反射的应用:动态代理
*/
@Test
public void test3() throws Exception{
Person p = new Person();
Class clas= p.getClass();//获取该对象的类名,由哪个类创建的,以及包名路径
System.out.println(clas == Person.class);
System.out.println(clas);//clas = Person
Class ca = Class.forName("反射机制.Person");
System.out.println(ca);//ca = Person
}
/**
* 如何获取Class的实例,方法有四种
*其一:调用类本身的.class属性
*其二:通过运行时类的对象获取,使用getClass()
*其三:通过Class的静态方法获取
*其四:(了解)通过类的加载器
* @throws ClassNotFoundException
*/
@Test
public void test4() throws ClassNotFoundException{
//方法一
Class clas1 = Person.class;
System.out.println("方法一:"+clas1.getName());
Class clas2 = String.class;
System.out.println("方法一:"+clas2.getName());
//方法二
Person p = new Person();
Class clas3 = p.getClass();
System.out.println("方法二:"+clas3.getName());
//方法三
Class clas4 = Class.forName("反射机制.Person");
System.out.println("方法三:"+clas4.getName());
//方法四
ClassLoader cl = this.getClass().getClassLoader();
Class clas5 = cl.loadClass("反射机制.Person");
System.out.println("方法四:"+clas5.getName());
}
/**
* 类加载器:是用来将类加载进内存的,JVM规范定义了两种类加载器:启动加载器和用户自定义加载器。JVM在运行时会产生
*三个类加载器组成初始化类加载器层次结构:依次为
*1.引导类加载器:用C++编写是JVM自带的类加载器,负责java平台的核心库,用来加载核心类库,给加载器无法直接获取
*2.扩展类加载器:负责jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包装入工作库
*3.系统类加载器:负责java-classpath或-D java.class.path所指的目录下的类与jar包装入工作,是最常用的加载器
*
*Bootstrap ClassLoader——>Extension ClassLoader——>System ClassLoader
*/
@Test
public void test5(){
ClassLoader cl1 = ClassLoader.getSystemClassLoader();
System.out.println(cl1); //系统加载器
ClassLoader cl2 = cl1.getParent();
System.out.println(cl2); //扩展加载器
ClassLoader cl3 = cl2.getParent();
System.out.println(cl3); //引导加载器
Class clas6 = Person.class;
ClassLoader cl4 = clas6.getClassLoader();
System.out.println(cl4);
}
}