动态语言是值 程序在运行是能够改变程序结构和变量类型的语言
js 和python 就是动态语言
c和c++ 就不是
java的动态性为他提供了类似的特性,使得功能变得强大
动态性的实现有两个
1,反射
2,序列化和反序列化
***********************************
反射 reflection
反射是指 在程序运行是, 仍然可以加载一些你只知道名字的类;
Class clazz = Class.forName("annotation.Student");
加载完类以后,就会在堆内存里产生一个class 类型的对象,这个对象就包含了完整的类的结构信息,我们就可以通过这个对象看到类的结构, 这个对象就像一面镜子, 称之为反射。
所有的类被加载后都会生产一个Class 对象,变成一张图纸, 而这张图纸不会被重复生成
*********************
通过反射获取 类名 类的属性,方法 ,构造器
package annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Client {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException {
String path= "annotation.Student";
Class clazz = Class.forName(path);
// 获取类名
String str1= clazz.getName();
String str2= clazz.getSimpleName();
System.out.println(str1);
System.out.println(str2);
// 获取字段
// Field [] fields = clazz.getFields(); // 获取公开声明的字段
Field [] fields = clazz.getDeclaredFields(); // 获取公开声明的字段
Field field1 = clazz.getDeclaredField("name"); // 获取公开声明的字段
for (Field field : fields) {
System.out.println(field);
}
System.out.println(field1);
System.out.println("*********************methods");
// 获取方法
Method [] methods= clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("*********************method单个的,有参和无参的区别");
Method method1= clazz.getMethod("getName");
Method method2= clazz.getMethod("setName",String.class);
System.out.println(method1);
System.out.println(method2);
System.out.println("*********************构造器");
// 获取构造器
Constructor[] constructors= clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("*********************Constructor单个的,有参和无参的区别");
Constructor constructor1= clazz.getDeclaredConstructor(null);
Constructor constructor2= clazz.getDeclaredConstructor(String.class,int.class,int.class);
System.out.println(constructor1);
System.out.println(constructor2);
}
}
反射的三个应用
package annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Client1 {
public static void main(String[] args)throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// TODO Auto-generated method stub
String path= "annotation.Student";
Class clazz = Class.forName(path);
// 通过反射构造对象
Student xiaoming = (Student) clazz.newInstance(); // 其实是调用了无参数构造器
System.out.println(xiaoming);
// .......
Constructor constructor= clazz.getConstructor(String.class,int.class,int.class); // 使用反射来获取构造器;然后根据构造器
Student xiaogang = (Student) constructor.newInstance("xiaogang",20,1000);
System.out.println(xiaogang);
// 通过反射调用普通方法
Student xiaohong = (Student) clazz.newInstance(); // 其实是调用了无参数构造器
Method setName= clazz.getDeclaredMethod("setName", String.class); // 通过反射获取方法
setName.invoke(xiaohong,"小红"); // 通过反射调用, 这个后面会用在动态代理上面
System.out.println(xiaohong.getName());
System.out.println("(((((((((((((");
// 通过反射设置属性
Student xiaolv = (Student) clazz.newInstance(); // 其实是调用了无参数构造器
Field f= clazz.getDeclaredField("name"); // 通过反射获取字段
f.setAccessible(true); //停止安全检查
f.set(xiaolv, "小驴"); //通过 字段反射的方法 来设置名字
System.out.println(xiaolv.getName()); // 正常
System.out.println(f.get(xiaolv));//通过 字段反射的方法 来得到名字
}
}
********************
反射的三个话题
1,反射的性能问题
反射机制对我们性能有一定的影响, 反射带来方便,弊端就是性能消耗比较厉害
可以通过setAccessible 设置为true 禁止安全检查提高运行的概率;
普通方法的时间为1, 那么反射 执行的时间就是30倍,跳过安全检查就是14倍左右,
2,反射操作注解
注解的例子就是
3,反射操作泛型
编译器会使用泛型来完成编译,而一旦编译完成,那么将擦除泛型;
不常用就不 写代码了