一、语言
动态语言:是一类在程序运行过程中可以接受改变的语言,如引进新的函数、对象、甚至是代码都可以改变。通俗来讲:程序运行时代码可以根据自身条件,改变自身结构。如:js语言。
静态语言:运行时结构无法发生改变的,比如:java,c,c++等。但java可以通过反射机制使其具有动态的特性,所以又被称为准动态语言。
二、什么是反射
1.反射机制
反射机制实在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用他的任意属性和方法;这种动态获取信息以及调用对象的方法的功能称为java语言的反射机制。但其的安全性有所降低。通过java中的Reflection API取得类的任何消息。
2.class类对象
理解类对象
什么是类对象? 什么是类的对象,比如Dog类 Dog dog = new Dog(); dog 就是Dog类的对象。万物皆为对象,Dog 类型是谁的对象呢? Dog 是 Class 的对象。Class 的实例就是类对象, 每个类加载就会在内存中创建出一个Class 的实例。
加载
Dog.java -> Dog.class ----------> Class obj1
Cat.java -> Cat.class -----------> Class obj2
Teacher.java0->Teacher.class-------> Class obj3
这个类对象存储和记录了 这个类型的全部信息( 类名 包名 实现接口 继承类 属性 方法 构造器 注解.... )。
3 获取类对象
- 对象.getClass()
- 类名.class
- Class.forName("包名.类名")
以上都返回的是一个Class类型的对象
public static void main(String[] args) throws ClassNotFoundException {
Foo obj = new Foo();
//1. getClass()
Class cls = obj.getClass();
System.out.println("对象.getClass():\t\t"+cls);
//2 . 类名.class获取类名
Class cls2 = Foo.class;
System.out.println("对象.class:\t\t\t"+cls2);
//3. Class.forName(“包.类”)获取类名
Class cls3 = Class.forName("classExample.reflect.Foo");
System.out.println("Class.forName(\"包.类名\"):"+cls3);
System.out.println(cls2==cls3);
}
三、反射的作用
1 提供的功能
在运行时是判断任意一个对象所属类在运行时可以构建任意一个类的对象
在运行时是判断任意一个对象所属类在运行时可以构建任意一个类的对象
在运行是判断任意一个类所具有的成员变量和方法在运行时获取泛型信息
在运行是判断任意一个类所具有的成员变量和方法在运行时获取泛型信息
在运行时调用任意的成员变量和方法在运行时处理注释 在运行时调用任意的成员变量和方法
在运行时处理注释生成动态代理 生成动态代理
2 获取类信息
Class类(描述类的类)
static ClassForName(String name) 返回指定类名的Class对象
getName() 返回此Class对象的实体类名称
Object newInstabce() 调用无参构造 返回Class对象实例与new的功能相似
Class getSuperClass() 获取当前Class对象的父类
Class[] getInterfaces() 返回当前Class对象的接口
Constructor getConstructors() 返回构造器对象参数
Method getMethod(String name,Class t)返回方法对象
Fiield[] getFields() 返回class对象所有的公共属性
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException {
//Class测试
//Foo obj = new Foo();
//1.获得Foo类对象
Class cls=Class.forName("classExample.reflect.Foo");
//2.获得Foo类对象的实体类名称
String FooName = cls.getName();
//String simpleFooName=cls.getSimpleName();//不包含包名的名字
System.out.println("---------------------cls.getName:获取类名称--------------------------\n"+FooName);
//3.使用其无参构造方法获取一个Foo的实例对象(同new的功能)
Foo o = (Foo)cls.newInstance();
System.out.println("-------------------cls.newInstance:实例化一个Foo类---------------------- \n"+o);
//4.获取cls的父类对象
Class superclass = cls.getSuperclass();
System.out.println("---------------------cls.getSupreclass()_父类的类名---------------------\n"+superclass.getName());
//5.返回cls实现的接口数组
Class[] interfaces = cls.getInterfaces();
System.out.println("------------------------class.getInterfaces()_获取cls实现的接口-------------------------");
for (Class c:interfaces) {
System.out.print(c.getName()+" ");
}
System.out.println();
//6.获取类属性
Field[] fields;
//fields=cls.getFields();//获取公开的属性public
fields = cls.getDeclaredFields();//获取全部属性
System.out.println("---------------------cls.getDeclaredFields()_获得类全部属性:----------------------");
for (Field field : fields) {
System.out.println(field+" ");
}
Field names = cls.getDeclaredField("name");
System.out.println("----------------------cls.getDeclaredField(\"name\")_获取指定属性name:----------------------"+names);
//7.获取方法
Method[] methods;
methods=cls.getMethods();//获取全部公开的方法(包括本类机器父类所有公共方法)
System.out.println("----------------------cls.getMethods()_获取全部公开方法(本包括从父类继承的)------------------- ");
for (Method method : methods) {
System.out.println(method+" ");
}
methods=cls.getDeclaredMethods();
System.out.println("----------------------cls.getDeclaredMethods()_获取全部方法(本类有的不包括父类)------------------- ");
for (Method method : methods) {
System.out.println(method+" ");
}
//8.获取构造器
System.out.println("----------------------cls.getConstructors()获取本类所有公共构造器------------------------");//本类所有构造器
Constructor[] Constructor=cls.getConstructors();
for (Constructor constructor : Constructor) {
System.out.println(constructor);
}
System.out.println("----------------------cls.getDeclaredConstructors()获取本类所有构造器------------------------");//本类所有构造器
Constructor = cls.getDeclaredConstructors();
for (Constructor constructor : Constructor) {
System.out.println(constructor);
}
System.out.println("----------------------cls.getDeclaredConstructors(String .....)获取指定构造器------------------------");//本类所有构造器
Constructor constructor = cls.getConstructor(String.class, int.class);
System.out.println(constructor);
}
3 创建类对象
用反射创建一个Foo类的实例,Foo类包括两个私有的属性,name,age.以及get和set方法和构造器.
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//反射创建对象
Class cla=forName("classExample.reflect.Foo");
//无参创建
System.out.println("-------------------五参构造创建对象");
Foo foo= (Foo)cla.newInstance();
System.out.println("无参构造:"+foo);
//有参构造
System.out.println("-------------------有参构造创建对象");
Constructor constructor=cla.getConstructor(String.class,int.class);
Foo foo1=(Foo)constructor.newInstance("张三",18);
System.out.println("有参构造:"+foo1);
System.out.println("--------------------调用方法修改姓名为李四");
//反射获取方法
Method setName=cla.getMethod("setName",String.class);//得到setName中参数为String的这个方法
setName.invoke(foo1,"李四");
System.out.println(foo1);
System.out.println("--------------------通过反射操作属性");
Field name = cla.getDeclaredField("name");
//关闭安全检查,这样通过反射才能对private属性赋值,否则会报错,抛出没有这个属性的异常
name.setAccessible(true);
name.set(foo1,"王五");
System.out.println(foo1);
}
总结(重点):
如何执行方法
通过cLass类getMethod完成,取得一个方法对象。并设置此方法需要的参数类型
之后使用object invoke( object, object[ ] obj)进行调用 *通过cLass类getMethod完成,取得一个方法对象。并设置此方法需要的参数类型*之后使用object invoke( object, object[ ] obj)进行调用
若原方法声明为private则需要在调用此方法invoke,显示调用方法对象的setAccessible(true)方法
setAccessible: 若原方法声明为private则需要在调用此方法invoke,显示调用方法对象的setAccessible(true)方法
setAccessible:
方法、属性、构造器对象都有此方法 *方法、属性、构造器对象都有此方法
setAccessiblef作用启动和禁用访问安全检查开关 *setAccessiblef作用启动和禁用访问安全检查开关
提高反射效率,如果代码中必须使用反射并且频繁调用则设为true 使原本无法访问成员自由访问
反射非常影响效率 *反射非常影响效率
4 反射时间测试
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
Class cla=forName("classExample.reflect.Foo");
Constructor constructor=cla.getConstructor(String.class,int.class);
Foo foo1=(Foo)constructor.newInstance("张三",18);
Field name = cla.getDeclaredField("name");
//关闭安全检查,这样通过反射才能对private属性赋值,否则会报错,抛出没有这个属性的异常
name.setAccessible(true);
Foo foo2=new Foo("测试1_普通",18);
long before=System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
foo2.setName("111");
}
long end=System.currentTimeMillis();
System.out.println("普通总计耗时:"+(end-before)+"ms");
before =System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
name.set(foo1,"测试2_反射");
}
end=System.currentTimeMillis();
System.out.println("反射总计耗时:"+(end-before)+"ms");
}