一、反射是什么?
反射是动态语言的关键,反射机制运行java在执行期间,借助Reflection提供的API取得任何类的内部信息,
并能直接操作任意对象的内部属性与方法。
二、反射机制:动态代理的关键
1.主要API:
- java.lang.Class:代表一个类:用来描述类的类,个人视其为反射的源头,因为涉及反射都要先使用Class
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类的成员变量
- java.lang.reflect.Constructor;代表类的构造器*
号外:几个不熟悉的单词:
Declare:声明,属性 - invoke:调用
2.疑问
反射机制与面向对象中的封装性是否矛盾?
答:不矛盾,二者各有各自的使用环境
两者的使用时机:
-
1.一般情况下建议使用直接new的方式
-
2.使用反射方式的时机:
-
1> 编译时无法确定到底要造哪个类的对象,可以使用反射的方式
-
2> 根据实际情况动态的使用
二、反射的简易实例和基础方法:
@Test
public void Test2() throws Exception {
//反射的操作
//通过反射造类的对象
Class clazz =Person.class;
//通过反射获取构造器
Constructor cons = clazz.getConstructor(String.class, int.class);//获取构造器
Object tom = cons.newInstance(“Tom”, 12);//造Person类的对象
Person p = (Person) tom;
System.out.println(p.toString());
//通过反射获取对象的属性方法Field age = clazz.getDeclaredField("age");//创造属性的对象age.set(p,10);System.out.println(p.toString());//获取类中的方法Method show = clazz.getDeclaredMethod("show");show.invoke(p);//调用对象p的show方法System.out.println("************************");//通过反射,可以调用Person类的私有结构,比如私有的构造器,私有的方法Constructor con1 = clazz.getDeclaredConstructor(String.class);con1.setAccessible(true);//构建p1的对象Person p1 =(Person) con1.newInstance("Jerry");//私有属性age = 0System.out.println(p1);//调用私有方法Field name = clazz.getDeclaredField("name");name.setAccessible(true);//修改p1对象的属性name.set(p1,"HanMeiMei");System.out.println(p1);//调用私有的方法Method showNation = clazz.getDeclaredMethod("showNation", String.class);showNation.setAccessible(true);//调用p1的私有方法,填入参数String nation = (String) showNation.invoke(p1, "中国");//私有方法的返回值类型就是该方法的类型System.out.println(nation);
}
三、Class类实例创建方式:
//Class的实例的获取
@Test
public void Test1() throws ClassNotFoundException {
//获取Class实例的方式:四种
//方式一:调用运行时类的属性
Class clazz1 = Person.class;
System.out.println(clazz1);
//方式二:通过运行时类的对象:调用getclass方法
Person person1 = new Person();
Class<? extends Person> clazz2 = person1.getClass();
System.out.println(clazz2);
//方式三:调用Class的静态方法,需要输入包在内的类的全类名
//此方法可以更好的展现java反射API的动态性
Class<?> Clazz3 = Class.forName(“ReflectionTest.Person”);
Class<?> Clazz4 = Class.forName(“java.lang.String”);
System.out.println(Clazz3);
System.out.println(Clazz4);
//判断地址值是否指向同一对象:true
//表明几种方式只是不同的获取方式,并非不同的创建方式
//只要数组的元素类型和维度一样,就是同一个class
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz1 == Clazz3);//true
//方式四:使用类的加载器;ClassLoader
//通过当前测试类.class获取ClassLoader
ClassLoader classLoader = Reflections.class.getClassLoader();
//使用classloader的loadclass方法,输入全类名来获取Class类的实例
Class<?> clazz5 = classLoader.loadClass(“ReflectionTest.Person”);
System.out.println(clazz5);
}
哪些类可以拥有Class类的实例对象?
1.class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
* 2.interface:接口
* 3.enum:枚举
* 4.[]数组
* 5.annotation:注解
* 6.primitive type:基本数据类型
* 7.void:void也可以视作一种void类
总结
反射是之后动态代理的关键,反射的引用让java有了一定的动态性。加载完类之后,在堆内的方法区中就产生了一个Class类型的对象,
这个对象就包含了完整的类的结构信息,我们可以通过这个对象看到类的结构,这个对象就像一面镜子,透过这个镜子看到类的结构,所以
将其称之为反射