【知了堂学习笔记】JAVA反射及注解--轻松学会反射
java的反射
反射是java的重要机制,java语言的动态性与它有着莫大的关系。
通过反射可以获得获得类、属性、构造方法、方法、注解的信息
也可以利用反射机制动态操作这些内容,可以调用构造函数、操作属性、调用方法
用反射操作类中内容的步骤:
1.获取Class对象
2.得到对应实例
3.操作实例
注:Class:该对象并不是class,它是一个类的原模板,储存了类的所有信息,一维数组和二维数组不是同一个类,对象创建自动加载Class类。
同一类对象创建的模板是一致的,都是它所属类的模板。
获取Class的方法有(返回对象是Class):
1.类名.class
2.对象名.getclass()
3.Class.forName(path) --> path是java类所属路径
举个例子:
/** * 演示说明Class * @author Administrator * */ public class Test { public static void main(String[] args) throws ClassNotFoundException { Class cls=Class.forName("com.zlt.test1.Test");//用Class.forName获取Class System.out.println("打印Class的名字: "+cls.getSimpleName()); String a = "aaa"; String b = "bbb"; System.out.println("同一类创建对象的Class: " + a.getClass()+" "+b.getClass()); String aa[]= {}; String bb[][]= {}; System.out.println("一维数组和二维的Class: "+ aa.getClass() +" "+ bb.getClass()); System.out.println("String的Class"+String.class); } }
运行结果:
用反射对class的操作:
1.获得类的相关信息
注:操作类的信息室,用带有Declared的方法能访问私有属性,方法,否则不能访问私有方法
类返回Class
属性返回Field
方法返回Method
构造函数返回Constructor
注解返回Annotation
操作方法基本一致:
package com.zlt.test1; import java.lang.reflect.*; /** * 用反射操作类 * @author Administrator * */ public class OpterClass { public static void main(String[] args) throws Exception { Class cls=Class.forName("com.zlt.test1.AAA"); //1.得到类 //获得类信息 String name=cls.getName();//获取包名+类名 String fullName=cls.getSimpleName();//获取类名 //获得属性,返回Field类型 Field f=cls.getDeclaredField("str1");//获取指定属性,能访问私有的 System.out.println(f.getName()); Field fid[]=cls.getFields();//获取属性,私有的访问不到 for(Field ff:fid) { System.out.println(ff.getName()); } //获取方法 Method method=cls.getDeclaredMethod("Print", String.class);// 方法名,参数类型列表 --> 没有参数就无须添加 Method []methods=cls.getDeclaredMethods();//获取全部方法,任何访问级别 System.out.println(method.getName()); //获取构造函数 Constructor cons=cls.getConstructor(); //不需要跟方法名,直接给参数即可,也是参数的模板Class类 System.out.println(cons.getName()); } } class AAA{ public String str1="aaa"; private String str2="bbb"; public AAA() { System.out.println("无参构造"); } public AAA(String aaa) { this.str1=aaa; } public void Print(String a) { System.out.println("print"); } }
注:(1)在获取属性,方法,构造函数时,如果要访问私有的,需使用带Declared的get方法
(2)在获取指定方法时,要传参,分别是方法名和参数的模板类(类名.calss),如果没有参数则只需要方法名
(3)获取构造方法时,直接以模板类(类名.calss)作为参数即可
(4)如果直接获取所有属性、方法、构造函数,则返回对应类型的数组
2.操作属性,方法,构造函数
package com.zlt.test1; import java.lang.reflect.*; public class OpterClass2 { public static void main(String[] args) throws Exception { Class cls=BBB.class;//获取Class对象 Constructor<BBB> cons1=cls.getConstructor();//获取无参构造 Constructor<BBB> cons2=cls.getConstructor(String.class);//获取有参构造 //调用构造函数 BBB b1=cons1.newInstance(); BBB b2=cons2.newInstance("新新参数"); //获取方法 Method m1=cls.getDeclaredMethod("Print");//无参方法 Method m2=cls.getDeclaredMethod("Print",String.class);//有参方法 //使用方法 m1.invoke(b1);//执行b1对象的无参方法 m2.invoke(b1,"aaa");//执行b1对象的有参方法 m1.invoke(b2);//执行b2对象的无参方法 m2.invoke(b2,"aaa");//执行b2对象的有参方法 //获取属性 Field f=cls.getDeclaredField("name"); //操作属性 f.setAccessible(true);//操作私有属性要关闭安全检查 f.set(b1, "new b1");//设置b1的name属性 f.set(b2, "new b2");//设置b2的name属性 m1.invoke(b1); m1.invoke(b2); } } class BBB{ private String name="aaa"; public BBB() { System.out.println("无参构造"); } public BBB(String name) { this.name=name; System.out.println("有参构造"); } public void Print() { System.out.println(this.name); System.out.println("调用无参方法"); } public void Print(String a) { System.out.println("调用有参构造方法"); } }
结果如下:
注:(1)操作属性时,如果要访问私有属性,要关闭安全检查 -------- setAccessible(true)
(2)使用类的方法一般用构造函数newInstances创建对象操作,成员方法的使用都与对象离不开关系
(3)注意获得方法和使用方法传递的参数的区别
3.操作注解
步骤:
(1)先获得Class对象
(2)获得对应类、属性、方法…的注解,返回对应注解的类型
(3)获取注解的值
案例:把类映射成sql语句
先定义两个注解
package com.zlt.fluance; /** * 表名信息 */ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Table { String data();//属于哪个数据库 String name();//表名 }
package com.zlt.fluance; /** * 表的每一列 */ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column { String name();//列名 String type();//数据类型 int length() default 1;//长度 String[] key() default "";//约束 }
用反射操作注解
package com.zlt.fluance; import java.lang.annotation.Annotation; import java.lang.reflect.Field; public class CreateTable { public String Create(Class cls) { String sql="";//sql语句 Table table=(Table)cls.getAnnotation(Table.class);//获得类的注解 String tableOfData=table.data();//表所在的数据库 String tableName=table.name();//表名 if(tableOfData!=null) sql+="use "+tableOfData+"\r"; sql+="create table "+tableName +" (\n\t"; Field[] f=cls.getDeclaredFields(); for(int i=0;i<f.length;i++) {//遍历属性 Field field=f[i]; Column cloumn=field.getAnnotation(Column.class);//获得属性的注解 String keys=""; for(int k=0;k<cloumn.key().length;k++) {//添加约束 keys+=" "+cloumn.key()[k]; } String row="";//属性 if(i==(f.length-1)) row=cloumn.name()+" "+cloumn.type()+"("+cloumn.length()+")"+keys+"\r"; else row=cloumn.name()+" "+cloumn.type()+"("+cloumn.length()+")"+keys+",\r\t"; sql+=row; } sql+=");"; return sql; } }
函数调用
package com.zlt.fluance; /** * 调用封装的函数 * 把类映射出对应的sql语句 * @author Administrator * */ public class Test { public static void main(String[] args) { CreateTable ct=new CreateTable(); String sql=ct.Create(Student.class); System.out.println(sql); } }
结果:
注:注解的使用遵循开头的三步走战略
总结:(1)反射操作的核心是Class对象,反射就是不断操作这个对象,再通过它的API来操作信息。
(2)反射会降低程序运行效率
(3)反射能大大提高程序开发效率,在企业常被使用,希望大家能掌握。
- 【知了堂学习笔记】JAVA用反射写一个Servlet简易框架
- [知了堂学习笔记]_浅谈Java反射
- Java Reflection(反射) 入门学习笔记 之三 (Array)
- 黑马程序员学习笔记之八(Java 反射机制)
- 黑马程序员 java学习笔记 Day10:反射
- Java 注解学习笔记
- 黑马程序员--Java基础加强学习笔记之Class类、反射(Reflect)
- Java 注解(Annoation)学习笔记
- Java 反射学习笔记
- JAVA学习笔记-反射
- Java 注解学习笔记
- JavaSE基础学习笔记-提高篇-Java反射概要
- Java 反射学习笔记(一)
- Cedar老师的java中的反射学习笔记(二)--动态加载
- 我的java学习笔记(14)关于反射(part 3)
- JAVA学习笔记(六十一)- 反射Reflection
- 黑马程序员——JAVA学习笔记——反射机制(下)
- Java 反射机制-学习笔记
- java基础学习笔记(六) java反射
- java学习笔记09--反射机制