Java之注解与反射
Java之注解与反射
注解(Annotation)简介
注解(Annotation)是从JDK5.0引入的新技术
Annotation作用:注解(Annotation)可以被其他程序如编译器等读取
Annotation格式:@"注释名",当然可以添加一些参数值(形如:
@Retention(RetentionPolicy.RUNTIME))它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
Annotation注解可以通过反射去读取
注解的定义
内置注解
@Override定义在
java.lang.Override中,此注释只适用于修辞方法,表示声明一个方法打算重写超类中的另一个方法。
@Deprecated定义在
java.lang.Deprecated中,此注释只适用于修辞方法,属性,类,表示不支持使用这样的元素
@SupperWarnings定义在
java.lang.SupperWarnings中,用来抑制编译告警时的警告信息,需要添加一个参数才能正确使用
元注解
元注解的作用就是负责注解其他注解,java定义了4个标准的meta-annotation类型:@Target/@Retention/@Document/@Inherited
元注解中重点为
@Target和
@Retention
@Target:用于描述注解的作用范围(比如作用在某个类或某个方法)
@Retention:描述注解的生命周期,对于反射就是可以在什么时候获取该注解(SOURCE<CLASS<RUNTIME)
自定义注解
使用@interface可以自定义注解。
@interface 注解名{ //自定义的注解内容 //如果参数只有一个值,建议写value String value(); }
例子
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; public class TestAnnotationDemo3 { //测试自定义注解 @MyAnnotation2("qifei") @MyAnnotation(name = "wuhu", id = 10) public void test(){ System.out.println("test"); } } @Target(value = {ElementType.TYPE,ElementType.METHOD}) //作用于 方法和类 @Retention(RetentionPolicy.RUNTIME) //作用于 运行时 @interface MyAnnotation{ //定义参数 String[] name() default ""; //参数默认为空,参数名为name int id(); } @Target(value = {ElementType.TYPE,ElementType.METHOD}) //作用于 方法和类 @Retention(RetentionPolicy.RUNTIME) //作用于 运行时 @interface MyAnnotation2{ //如果参数只有一个值,建议写value String value(); }
反射(Reflection)机制
Java反射(Reflection)是Java非常重要的动态特性,通过使用反射我们不仅可以获取到任何类的成员方法、成员变量、构造方法等信息,还可以动态创建Java类实例、调用任意的类方法、修改任意的类成员变量值等。注解和反射是各种java web框架的底层实现机制与灵魂。
Class类
反射首先要用到的就是Class类,Class类是一个描述类的类,但是Class本身也是一个类,一个在内存中加载的类在JVM中只会有一个对应的Class的实例话对象,通过Class可以完整的得到一个类中所有被加载的结构。Class类就是反射的根源
获取Class类实例
1、已知具体的类,通过类的class属性获取
Class c = Object.class;
2、已知某个类的实例,通过调用getClass()方法获取class对象
Person person = new Person(); Class c = person.getClass();
3、已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取class对象
Class c = Class.forName("com.reflection.demmo");
4、基本内置类型的包装类的Type属性获取c 56c lass对象
Class c = Integer.TYPE;
例子:
//测试class类的创建方式 public class ReflactionDemo02 { public static void main(String[] args) throws ClassNotFoundException { Person student = new Student(); System.out.println("这个人是:" + student.name); //获取Student类的class实例对象 //1、通过getClass() 获得 Class c1 = student.getClass(); System.out.println(c1.hashCode()); //2、通过Class类的forName() 获得 Class c2 = Class.forName("com.reflaction.Student"); System.out.println(c2.hashCode()); //3、通过student类的class属性获得 Class c3 = Student.class; System.out.println(c3.hashCode()); //4、基本内置类型的包装类的Type属性 Class c4 = Integer.TYPE; System.out.println(c4.hashCode()); //获得父类类型 Class c5 = c1.getSuperclass(); System.out.println(c5); } } class Person{ String name; public Person() { } public Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } } class Student extends Person{ public Stu 3ff8 dent(){ this.name = "学生"; } } class Teacher extends Person{ public Teacher(){ this.name = "老师"; } } 这个人是:学生 1627674070 1627674070 1627674070 1360875712 class com.reflaction.Person
具有Class实例对象的数据类型
//所有类型的class对象 public class ReflactionDemo03 { public static void main(String[] args) { Class c1 = Object.class; //类 Class c2 = Runnable.class; //接口 Class c3 = String[].class; //一维数组 Class c4 = String[][].class; //二维数组 Class c5 = Override.class; //注解 Class c6 = ElementType.class; //枚举 Class c7 = Integer.class; //基本数据类型包装类 Class c8 = void.class; //void Class c9 = Class.class; //Class System.out.println(c1); System.out.println(c2); System.out.println(c3); System.out.println(c4); System.out.println(c5); System.out.println(c6); System.out.println(c7); System.out.println(c8); System.out.println(c9); } } class java.lang.Object interface java.lang.Runnable class [Ljava.lang.String; class [[Ljava.lang.String; interface java.lang.Override class java.lang.annotation.ElementType class java.lang.Integer void class java.lang.Class
反射获取类运行时的完整结构
Field()
Field[] fields = c1.getFields(); //getFields 只能找到pubilc属性 fields = c1.getDeclaredFields(); //getDeclaredFields 可以找到所有属性 for (Field field : fields) { System.out.println(field); }
Method()
getMethods()获得本类和继承类的所有public方法
getDeclaredMethods()获取本类的所有方法
getMethod("方法名", 参数类型.class)获得指定的方法
//获得本类和继承类的所有public方法 Method[] methods = c1.getMethods(); for (Method method : methods ) { System.out.println("getMethods(): " + method); } //获取本类的所有方法 methods = c1.getDeclaredMethods(); for (Method method : methods ) { System.out.println("getDeclaredMethods(): " + method); } //获得指定的方法 Method setName = c1.getMethod("setName", String.class); Method getName = c1.getMethod("getName"); System.out.println(setName); System.out.println(getName);
Constructor()
//获取所有的构造器 Constructor[] constructors = c1.getConstructors(); //获取本类和父类的所有构造方法 for (Constructor constructor : constructors ) { System.out.println(constructor); } System.out.println("====================================="); constructors = c1.getDeclaredConstructors(); //获取本类所有构造方法 for (Constructor constructor : constructors) { System.out.println(constructor); } System.out.println("====================================="); //获取指定的构造器 Constructor constructor = c1.getConstructor(String.class, int.class, int.class); System.out.println(constructor);
反射类构造器获得实例化对象
- 反射获得User类的class对象
Class.forName()
- 调用有参或无参构造方法实例化对象
class.newInstance()
public static void main(String[] args) throws Exception{ //反射获得User类的class对象 Class c1 = Class.forName("com.reflaction.User"); User user = (User) c1.newInstance(); //调用无参构造实例化对象 System.out.println(user); //获得有参构造方法 Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class); //通过构造器获得实例话对象 User ago = (User) constructor.newInstance("ago", 18, 1); //有参构造获得实例化对象 System.out.println(ago); } User{name='null', age=0, id=0} User{name='ago', age=18, id=1}
反射获取调用普通方法
方式1: 反射获取目标类的class对象(Class.forName()) ==> 获取有参构造器(class.getDeclaredConstructor()) ==> 获取目标类实例化对象(constructor1.newInstance(param1, param2, param3 ,...)) ==> 调用方法(实例化对象.Method())
Class c2 = Class.forName("com.reflaction.User"); Constructor constructor1 = c2.getDeclaredConstructor(String.class, int.class, int.class); User zh1z3ven = (User) constructor1.newInstance("zh1z3ven", 20, 2); System.out.println(zh1z3ven.getAge()); System.out.println(zh1z3ven.getName()); zh1z3ven.setId(20); System.out.println(zh1z3ven.getId());
方式2: 反射获取目标类class对象(Class.forName()) ==> 获取指定方法(class.getMethod("方法名", 参数)) ==> 激活执行方法(.invoke(目标对象, 参数))
Class c2 = Class.forName("com.reflaction.User"); User user2 = (User) c2.newInstance(); Method setName = c2.getMethod("setName", String.class); setName.invoke(user2, "kfei"); System.out.println(user2.getName());
反射操作属性
- 获取class对象
class.getDeclaredField("属性名")
获取属性.set()
方法设置属性- 若为private修饰,出现无权限操作异常,可用
.setAccessible(true)
关闭安全检测,获取操作权限
Class c3 = Class.forName("com.reflaction.User"); User user4 = (User) c3.newInstance(); Field name = c3.getDeclaredField("name"); name.setAccessible(true); name.set(user4 ,"zgo"); System.out.println(user4.getName());
Invoke(Object obj, Obj... args)
Object对应原方法返回值,若无返回值,返回null
若原方法为静态方法,形参Object obj可为null
若原方法形参列表为空,Obj... args可为null
若原方法声明为private,在调用invoke()前,显示调用方法对象的
.setAccessible(true)方法,关闭安全检测,获取访问权限
反射调用Runtime()
import org.apache.commons.io.IOUtils; import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class RuntimeExecDemo { public static void main(String[] args) throws Exception{ String command = "ifconfig"; Class c = Class.forName("java.lang.Runtime"); //获取Runtime类的class对象 Constructor constructor = c.getDeclaredConstructor(); //获取构造器 constructor.setAccessible(true); //关闭安全检测,暴力反射 Object runtime = constructor.newInstance(); //构造runtime对象 Method exec = c.getMethod("exec", String.class); //获取exec方法 Process process = (Process) exec.invoke(runtime, command); //激活执行exec //获取命令回显结果 InputStream inputStream = process.getInputStream(); //获取process输入流中输出的数据 String ifconfig = IOUtils.toString(inputStream, "GBK"); //字节流转字符流 System.out.println(ifconfig); //打印结果 } }
反射操作泛型
import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; public class TestFanXingDemo { public void test01(Map<String, User> map, List<User> list){ System.out.println("test01"); } public Map<String, User> test02(){ System.out.println("test02"); return null; } public static void main(String[] args) throws NoSuchMethodException { Method method = TestFanXingDemo.class.getMethod("test01", Map.class, List.class); method.setAccessible(true); //关闭安全检测,暴力反射 Type[] genericParameterTypes = method.getGenericParameterTypes(); //获得泛型的参数类型 for (Type genericParameterType : genericParameterTypes) { System.out.println("#genericParameterType: " + genericParameterType); //遍历泛型类型 if (genericParameterType instanceof ParameterizedType){ //判断泛型参数类型是否是参数化类型 Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments(); //获得真实参数信息 //循环遍历参数 for (Type actualTypeArgument : actualTypeArguments) { System.out.println(actualTypeArgument); } } } } }
反射操作注解
ORM = Object Relationship Mapping ==> 对象关系映射
类和表对应,类的属性和表的字段对应,对象和记录对应
利用注解和反射完成类和表的结构的映射关系
import java.lang.annotation.*; import java.lang.reflect.Field; public class TestDemo12 { //反射操作注解 public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c1 = Class.forName("com.reflaction.Student2"); //通过反射获得全部注解 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } //获得注解的value值 TableStudent tableStudent = (TableStudent) c1.getAnnotation(TableStudent.class); String value = tableStudent.value();//获取注解的value System.out.println(value); //获取指定类的注解value Field f = c1.getDeclaredField("name"); FieldStudent annotation = f.getAnnotation(FieldStudent.class); System.out.println(annotation.columnName()); System.out.println(annotation.type()); System.out.println(annotation.length()); } } @TableStudent("db_student") class Student2{ @FieldStudent(columnName = "db_id", type = "int", length = 10) private int id; @FieldStudent(columnName = "db_age", type = "int", length = 10) private int age; @FieldStudent(columnName = "db_name", type = "varchar", length = 3) private String name; public Student2() { } public Student2(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } public int getId() { return id; } public int getAge() { return age; } public String getName() { return name; } public void setId(int id) { this.id = id; } public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student2{" + "id=" + id + ", age=" + age + ", name='" + name + '\'' + '}'; } } //类名的注解 @Target(ElementType.TYPE) //作用范围为类 @Retention(RetentionPolicy.RUNTIME) //作用为运行时可获取 @interface TableStudent{ String value(); } //属性的注解 @Target(ElementType.FIELD) //作用范围为类 @Retention(RetentionPolicy.RUNTIME) //作用为运行时可获取 @interface FieldStudent{ String columnName(); String type(); int length(); }
结尾
参考文章:
https://www.cnblogs.com/nice0e3/p/13498308.html
https://www.cnblogs.com/nice0e3/p/13494147.html
关于Process类、反射操作泛型和注解因为暂时刚需不大且还没研究透,记录的较少,后面会另出文章记录一下。
到此JavaSE部分基本就学完了(除了GUI)后面要开JavaWeb和框架了,冲冲冲!
- java注解实例-反射生成sql
- Java注解和反射
- java反射和自定义注解的综合应用
- java通过反射获取类名、属性名称以及@Table注解上的表名称
- Java基础学习记录-注解&反射
- Java中的反射和注解
- java反射+注解实现Entity类与Dto类相互转换
- Java反射,注解,以及动态代理
- java 利用反射完成自定义注解
- Java自定义注解和运行时靠反射获取注解
- Java学习记录 Day23(注解、反射)
- java注解和反射制作dao基类的练习
- Java自定义注解和反射获取注解
- JAVA反射与注解实例
- Java反射学习总结终(使用反射和注解模拟JUnit单元测试框架)
- Java高级应用之反射实现获取,注解(自定义注解)及模拟实现eclipse中Junit插件
- Java使用反射处理注解
- java 注解annotation的使用,以及反射如何获取注解
- java核心类库—9.枚举、注解和反射
- Java 自定义注解及利用反射读取注解的实例