反射
reflection:java动态特性之一
动态语言
程序运行时,可以改变程序结构或者变量类型。
例如:Python、javascript语言,如下
function test{var s="var a=3;var b=5;alert(a+b)";eval(s);//eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。}
JAVA不是动态语言,但具有一定的动态性,可以利用反射机制、字节码操作获得类似动态语言的特性
反射机制:reflection
1、指的是在程序运行期间,可以加载一些任何你知道相关名称的类,可以让程序变得更加灵活。
2、程序在运行状态中,可以动态加载一个只有名称的类,对于任何一个已加载的类,都能够知道这个类的所有属性和方法,对于任何一个对象都能够调用它的任何方法和属性。
3、Class c=Class.forName(“包名.类名”);
Class对象
1、Class类:表示正在运行的java应用程序中的类和接口。和其他普通的类一样也具有实例化对象
2、Class对象:表示的是一些数据的封装,一个类被加载到JVM之后JVM会在堆内存中自动创建一个对应类的Class对象,类的整个结构信息会被放到对应的Class对象当中去。
3、Class对象就像是一面镜子,通过这面镜子可以看到对应类的全部信息,所以称为反射。
4、一个类只有一个Class对象:类只会被加载一次,加载一次后产生一个Class对象。
获取Class对象的方法
①、类.class
//获取String类的对象Class clazz=String.class;
②、Class clazz=Class.forName(“包名.类名”);
③、其他类的对象.getClass()
//通过String类的对象path获取String path=“扒鸡”;Class claz=path.getclass();
常见作用
一、动态加载类、动态获取类的信息(属性、方法、构造器)
①、动态加载类
String path="study.Student";Class claz=Class.forName(path);
②、获取类名
claz.getSimpleName();
③、public属性
claz.getFields();
④、所有属性
claz.getDeclaredFields();
⑤、指定名称的属性
claz.getDeclaredField("name");
⑥、类的所有方法
claz.getDeclaredMethods();
⑦、方法名和参数类的某个方法
Method med=claz.getDeclaredMethod("getName",null);
⑧、获取构造方法信息
Constructor[] constructors= claz.getConstructors(); //获得所有构造器for (Constructor temp:constructors) {System.out.println("构造方法:"+temp);}
⑨、获取指定参数的构造器
Constructor constructor=claz.getDeclaredConstructor(int.class,String.class,int.class);System.out.println(constructor);
Demo代码
/*** @auther TongFangPing* @date 2019/10/15 15:26.* 通过反射获取类的结构信息*/public class ReflectionDemo01 {public static void main(String[] args) {String path="study.Student";try {Class claz=Class.forName(path);System.out.println(claz.getSimpleName());//获得类名:Student//获得属性信息Field[]fields=claz.getFields(); //只能获得public的属性System.out.println(fields.length);fields=claz.getDeclaredFields(); //获得所有的属性System.out.println(fields.length );Field fd=claz.getDeclaredField("name");//获得指定名字的属性System.out.println(fd.getName());for (Field temp:fields) {System.out.println("属性:"+temp);}//获取类的方法的信息Method[] method=claz.getDeclaredMethods(); //获得所有方法Method med=claz.getDeclaredMethod("getName",null);//通过方法名和参数获得类的某个方法,参数用于重载。System.out.println("getName方法:"+med);for (Method temp:method) {System.out.println("方法:"+temp);}//获取构造方法信息Constructor[] constructors= claz.getConstructors(); //获得所有构造器for (Constructor temp:constructors) {System.out.println("构造方法:"+temp);}//获取指定参数的构造器Constructor constructor=claz.getDeclaredConstructor(int.class,String.class,int.class);System.out.println(constructor);} catch (Exception e) {e.printStackTrace();}}}
动态构造对象
①、调用无参构造器,并且实例化对象
claz.getConstructor().newInstance();
②、有参构造器、实例化对象
Constructor<Student>c=claz.getDeclaredConstructor(int.class,String.class,int.class);Student s=c.newInstance(001,"扒鸡1号",32);
获取方法对象
claz.getDeclaredMethod+invoke(Object obj, Object... args)//通过反射API调用普通方法Student s2=(Student)claz.getConstructor().newInstance();//获得方法对象Method method=claz.getDeclaredMethod("setName", String.class);method.invoke(s2,"扒鸡2号"); //s2.setName("扒鸡2号");System.out.println(s2.getName());
动态调用和处理属性(私有)
1、获取Field对象:claz.getDeclaredField("name");2、禁用安全检查:.setAccessible(true);3、操作私有属性:.set(s3,"扒鸡3号");//通过反射API动态的操作属性(私有)Student s3=(Student) claz.getConstructor().newInstance();Field field=claz.getDeclaredField("name");field.setAccessible(true);//表示这个属性不用做安全检查,直接可以访问field.set(s3,"扒鸡3号"); //通过反射直接写属性System.out.println(field.get(s3)); //通过反射读属性
Demo代码
/*** @auther TongFangPing* @date 2019/10/15 17:47.* 通过反射API动态的操作:构造器、方法、属性* 动态调用和处理属性*/public class ReflectionDemo02 {public static void main(String[] args) {String path="study.Student";try {Class claz=Class.forName(path);Student student=(Student)claz.getConstructor().newInstance();//调用Student的无参构造器,并且实例化System.out.println(student);//调用有参构造器、实例化对象Constructor<Student>c=claz.getDeclaredConstructor(int.class,String.class,int.class);Student s=c.newInstance(001,"扒鸡1号",32);System.out.println(s.getName());//通过反射API调用普通方法Student s2=(Student)claz.getConstructor().newInstance();//获得方法对象Method method=claz.getDeclaredMethod("setName", String.class);method.invoke(s2,"扒鸡2号"); //s2.setName("扒鸡2号");System.out.println(s2.getName());//通过反射API动态的操作属性(私有)Student s3=(Student) claz.getConstructor().newInstance();Field field=claz.getDeclaredField("name");field.setAccessible(true);//表示这个属性不用做安全检查,直接可以访问field.set(s3,"扒鸡3号"); //通过反射直接写属性System.out.println(field.get(s3)); //通过反射读属性} catch (Exception e) {e.printStackTrace();}}}
java泛型机制
java采用泛型擦除机制来引入泛型。java中的泛型仅仅是给编译器使用的,确保数据的安全性和免去强制类型转换的麻烦。在编译之后程序会采取 去泛型化 的措施。也就是说,只在编译期间有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦除,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说:泛型信息不回进入运行阶段,也就是说:泛型类型在逻辑上看成是多个不同的类型,实际上都是相同的基本类型。
反射操作泛型
为了迎合开发的需要。java新增了几种类型来保存泛型的信息
反射操作泛型
1、ParameterizedType:表示一种参数化的类型,比如Collection
2、GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
3、TypeVariable:表示各种类型变量的的公共父接口
4、WildcardType:代表通配符类型表达式
反射操作注解
步骤:
①、获取对应类或者类的方法或者类的属性的Class对象
②、通过Class对象.getAnnotation(”注解名”)方法获取注解
Demo代码
/*** @auther TongFangPing* @date 2019/10/14 22:53.* 使用反射读取注解的信息* 通过反射获取类、类的属性、累的方法中的注解,可以用来拼接成SQL语句。*/public class Demo {public static void main(String[] args) {try {//反射获取Class对象Class claz=Class.forName("com.annotate.study.Student");//获取Student类的所有注解Annotation[] annotations=claz.getAnnotations();for (Annotation aos:annotations) {System.out.println(aos);}//获取类的指定注解TableAnnotation tban= (TableAnnotation)claz.getAnnotation(TableAnnotation.class);System.out.println(tban.value());//获得类的属性的注解Field field =claz.getDeclaredField("name");FileldAnnotation fdAn=field.getAnnotation(FileldAnnotation.class);System.out.println(fdAn.columnName()+"--"+fdAn.type()+"--"+fdAn.length());//根据获得的表名、字段的信息、拼出SQL语句,使用JDBC执行,生成数据表} catch (Exception e) {e.printStackTrace();}}}
