注解与反射
文章目录
一、内置注解
内置注解(了解即可):
- @ Override 用在方法上,表示这个方法重写了父类的方法,如toString()
- @Deprecated 表示这个方法已经过期,不建议开发者使用
- @SuppressWarnings 注解的用处是忽略警告信息 @SuppressWarnings (“all”)
- @FunctionalInterface 用于约定函数式接口
函数式接口概念: 如果接口中只有一个抽象方法(可以包含多个默认方法或多个static方法),该接口称为函数式接口。函数式接口其存在的意义,主要是配合Lambda 表达式 来使用。
二、元注解
元注解,定义注解的注解,使用元注解来定义注解
- @Target: 表示这个注解能放在什么位置上,是只能放在类上?还是即可以放在方法上,又可以放在属性上 (ElementType[]定义)
- ElementType.TYPE:能修饰类、接口或枚举类型
- ElementType.FIELD:能修饰成员变量
- ElementType.METHOD:能修饰方法
- ElementType.PARAMETER:能修饰参数
- ElementType.CONSTRUCTOR:能修饰构造器
- ElementType.LOCAL_VARIABLE:能修饰局部变量
- ElementType.ANNOTATION_TYPE:能修饰注解
- ElementType.PACKAGE:能修饰包
- @Retention : 表示生命周期,定义在编译或运行的时候是否可以使用 (RetentionPolicy定义,只能定义一个)
- RetentionPolicy.SOURCE: 注解只在源代码中存在,编译成class之后,就失效
- RetentionPolicy.CLASS:注解在java文件编程成.class文件后,依然存在,但是运行起来后失效
- RetentionPolicy.RUNTIME: 注解在运行起来之后依然存在,程序可以通过反射获取注解信息
- @Inherited : 表示该注解具有继承性,可以获取到父类DBUtil上的注解信息
- @Documented : 在用javadoc命令生成API文档后,DBUtil的文档里会出现该注解说明
- @Repeatable (java1.8 新增) : 当没有@Repeatable修饰的时候,注解在同一个位置,只能出现一次 , 使用@Repeatable之后,再配合一些其他动作,就可以在同一个地方使用多次了
三、自定义注解
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@SuppressWarnings("all")
@interface MyAnnotation{
String[] value();
int age() default -1 ;
int sex() default 0 ;
}
public class TestAnnotation{
//反射获取注解信息
@MyAnnotation("测试")
public static void textAnnotation() throws ClassNotFoundException, NoSuchMethodException {
Class clazz = Class.forName("com.json.annotation.TestAnnotation");
Method method = clazz.getMethod("textAnnotation");
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
if (annotation!=null) {
String[] value = annotation.value();
int age = annotation.age();
int sex = annotation.sex();
System.out.println(Arrays.toString(value));
System.out.println(age);
System.out.println(sex);
}
}
}
在工作中,大部分都是使用第三方注解, 当然第三方注解本身就是自定义注解。 理解这些第三方注解是如何工作的 。
四、Java反射机制
4.1静态语言与动态语言
- 动态语言:Object-C、C#、JavaScript、PHP、Python
- 静态语言:Java、C、C++
动态语言:是一类运行时可以改变其结构的语言,例如JavaScript中var可以代表任意变量
静态语言:与动态语言相对应,运行时结构不可变
Java不是动态语言,但Java可以称为“准动态语言”,即Java有一定的动态性,Java反射机制可以让Java有一定的动态性,让编程更加灵活,但会损失一些安全
4.2反射(Reflection)
Reflection(反射):反射机制允许程序在执行时取得任何类的内部信息,并能直接操作任意对象的内部属性及方法(private私有化一样能操作)
实例化对象:
4.3 反射机制的应用
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量与方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时获取注解信息
- 生成动态代理
- …
4.4 反射的优点与缺点
- 优点:可以实现动态创建对象和编译,体现出很大的灵活性
- 缺点:对性能有影响
4.5 反射相关的API
- java.lang.Class :代表类
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类的成员变量
- java.lang.reflect.Constructor:代表类的构造器
- ……
public class Test{
public static void main(String[] args){
Class clazz1 = Class.forName("org.com.junjie.reflect.Student");
System.out.println(clazz1.hashCode());
Student student = new Student();
Class clazz2 = student.getClass();
System.out.println(clazz2.hashCode());
Class clazz3 = Student.class;
System.out.println(clazz3.hashCode());
}
}
结果哈希值一样
五、Class类
JVM加载完类之后,在堆内存的方法区就产生一个Class类型的对象(一个普通类可以有多个对象,但只能有一个该类对象的Class对象),这个Class对象包括了完整的类的结构信息,可以通过操作该Class对象来操作类的一切
5.1概要
-
Class本身也是一个类
-
Class对象只能有系统建立对象(JVM)
-
一个类在内存中只有一个Class对象
-
一个Class对象对应的是一个加载到JVM中的一个.class文件(一个.class文件生成一个Class对象)
-
一个类被加载后,类的整个结构都会被封装在Class对象中
-
每个类的实例都会记得自己是由哪个Class实例所生成
-
Class对象时反射机制的唯一入口(想要用反射,必须获取Class对象)
5.2 获得Class对象的途径
- 实例对象.getClass();
- Class.forName(“全类名”);
- 类名.class;
public static void testClass(){
Class c1 = Object.class;//类
Class c2 = Serializable.class;//接口
Class c3 = String[].class;//数组
Class c4 = int[][].class;//二维数组
Class c5 = Target.class;//注解
Class c6 = Integer.class;//基本类型
Class c7 = void.class;//空
Class c8 = ElementType.class;//枚举
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);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YdxnzudO-1584323700570)(C:\Users\333\AppData\Roaming\Typora\typora-user-images\1584264009690.png)]
5.3 Class类的常用方法
操作类或接口:
- static Class forName(String name);返回指定类名的Class对象
- Class getSuperClass();返回该类Class对象的父类Class对象
- Class[] getInterfaces();获取当前Class对象的接口
操作方法:
- Method getMethod(String name, Class<?>… parameterTypes);返回该类或所有父类参数类型为parameterTypes名字为name的Method方法对象
- Method[] getMethods();返回该类或所有父类的所有Method方法对象数组
- Method getDeclaredMethod(String name, Class<?>… parameterTypes);返回**该类(不包括父类)**参数类型为parameterTypes名字为name的Method方法对象
- Method[] getDeclaredMethods();返回**该类(不包括父类)**的所有Method方法对象数组
操作成员变量:
- Field getField(String name);返回该类或所有父类的名字为name的Field成员变量对象
- Field[] getFields();返回该类或所有父类的所有Field成员变量对象数组
- Field getDeclaredField(String name);返回**该类(不包括父类)**的名字为name的Field成员变量对象
- Field[] getDeclaredFields();返回**该类(不包括父类)**的所有Field成员变量对象数组
操作构造器:
- Constructor< T > getConstructor(Class<?>… parameterTypes);返回**该类(不包括父类)**参数类型为parameterTypes的Constructor构造器对象
- Constructor<?>[] getConstructors();返回**该类(不包括父类)**的所有Constructor构造器对象数组
- Constructor< T > getDeclaredConstructor(Class<?>… parameterTypes);返回**该类(不包括父类)**参数类型为parameterTypes的Constructor构造器对象
- Constructor<?>[] getDeclaredConstructors();返回**该类(不包括父类)**的所有Constructor构造器对象数组
其他操作:
- String getName();获取此Class对象所表示的类的名称
- ClassLoader getClassLoader();返回该类的加载器
public class Test{
public static void main(String[] args){
//方式一
Class clazz1 = Class.forName("org.com.junjie.reflect.Student");
System.out.println(clazz1);
//方式二
Student student = new Student();
Class clazz2 = student.getClass();
System.out.println(clazz2);
//方式三
Class clazz3 = Student.class;
System.out.println(clazz3);
}
}
六、类的加载与ClassLoader
6.1 Java内存分析
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化
6.2 类的加载与ClassLoader的理解
-
加载:将.class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表该类的java.lang.Class对象存放在堆中(不能创建Class对象,只能获取)
-
链接:将Java类的二进制代码合并到JVM的运行状态之中的过程
- 验证:确保加载的类信息符合JVM规范,没有安全的问题
- 准备:为类变量(static)分配内存并设置默认数据(int为0,String为null…)并在方法区中分配内存
- 解析:JVM常量池内的常量名引用替换为直接引用(地址)的过程
-
初始化:
- 执行类构造器< clinit >()方法。自动收集类中所有静态变量的赋值动作和静态代码块中的语句合并产生< clinit >()方法并执行。(此类构造器是构造类的信息,不是构造该类的对象的构造器)
- 当初始化一个类的时候,发现父类还没有初始化,则需要先触发父类的初始化
- JVM会保证一个类的< clinit >()方法在多线程环境中加锁和保持同步
注意:静态代码块与静态变量赋值动作的执行的先后顺序根据语句的前后决定(合并为< clinit >()方法,语句有先后顺序)
//输出结果为id=100 public class TestClass { public static void main(String[] args) { Student student = new Student(); System.out.println(student); } } class Student{ static { id = 200 ; } static int id = 100 ; public Student(){ name = "李四" ; } String name = "张三" ; @Override public String toString() { return "Student{" + "name='" + name + '\'' + "id='" + id + '\'' + '}'; } } //结果输出为id=200 class Student{ static int id = 100 ; String name = "张三" ; static { id = 200 ; } public Student(){ name = "李四" ; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + "id='" + id + '\'' + '}'; } }
6.3 什么时候会发生类的初始化
- 类的主动引用(一定会发生类的初始化)
- 当JVM启动,先初始化main方法所在的类
- new一个类的对象
- 调用类的静态成员(除了final常量)和静态方法
- 反射调用
- 初始化一个类,其父类若没有初始化则会先初始化
- 类的被动引用(不会发生类的初始化)
- 访问静态域,只有真正声明这个域的类才会被初始化(子类引用父类的静态变量,子类不会初始化)
- 通过数组定义类的引用,不会触发类的初始化
- 引用常量不会触发类的初始化(常量在链接阶段就存入常量池中了)
会初始化
public class TestInit {
static {
System.out.println("main类被初始化");
}
public static void main(String[] args) throws ClassNotFoundException {
//会初始化
Son son = new Son();
Class clazz = Class.forName("com.json.classLoader.Son");
System.out.println(Son.number);
}
}
class Parent{
static String parent = "爷爷" ;
static {
System.out.println("父类被初始化");
}
}
class Son extends Parent {
static final String NAME = "张三";
static int number = 100 ;
static {
System.out.println("子类被初始化");
number = 200 ;
}
}
不会初始化
public class TestInit {
static {
System.out.println("main类被初始化");
}
public static void main(String[] args) {
//不会初始化
Son[] sons = new Son[10];
System.out.println(Son.parent);
System.out.println(Son.NAME);
}
}
class Parent{
static String parent = "爷爷" ;
static {
System.out.println("父类被初始化");
}
}
class Son extends Parent {
static final String NAME = "张三";
static int number = 100 ;
static {
System.out.println("子类被初始化");
number = 200 ;
}
}
6.4 类加载器的作用
类加载器的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆内容在生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象
简而言之,类加载器作用就是把类(class)装载到内存中。
JVM规范定义了如下类型的类加载器
- 自顶向下尝试加载类
- 自底向上尝试检查是否已装载
public static void main(String[] args) throws ClassNotFoundException {
//获取系统类的加载器
ClassLoader classLoader1 = TestInit.class.getClassLoader();
//获取系统类加载器的父类加载器(扩展加载器)
ClassLoader classLoader2 = classLoader1.getParent();
//获取扩展类加载器的父类加载器-->根加载器(c/c++编写,无法获取)
ClassLoader classLoader3 = classLoader2.getParent();
System.out.println("获取系统类的加载器");
System.out.println(classLoader1);
System.out.println("获取系统类加载器的父类加载器");
System.out.println(classLoader2);
System.out.println("获取扩展类加载器的父类加载器");
System.out.println(classLoader3);
//获取当前类的加载器
System.out.println("获取当前类的加载器");
Class<?> init = Class.forName("com.json.classLoader.TestInit");
ClassLoader initClassLoader = init.getClassLoader();
System.out.println(initClassLoader);
//获取java内置的类的加载器(根加载器为null)
System.out.println("获取java内置的类的加载器");
Class<?> clazz = Class.forName("java.util.ArrayList");
ClassLoader classLoader = clazz.getClassLoader();
System.out.println(classLoader);
//获取类加载可以加载的路径
String property = System.getProperty("java.class.path");
System.out.println(property);
/**
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\charsets.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\deploy.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\access-bridge-64.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\cldrdata.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\dnsns.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jaccess.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jfxrt.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\localedata.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\nashorn.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunec.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunjce_provider.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunmscapi.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunpkcs11.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\zipfs.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\javaws.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\jce.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\jfr.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\jfxswt.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\jsse.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\management-agent.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\plugin.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\resources.jar;
* D:\Program Files\Java\jdk1.8.0_191\jre\lib\rt.jar;
* F:\idea\SpringBootApp\hello_world\target\classes;
* F:\mvnLocalRepository\org\springframework\boot\spring-boot-starter\2.2.5.RELEASE\spring-boot-starter-2.2.5.RELEASE.jar;
* F:\mvnLocalRepository\org\springframework\boot\spring-boot\2.2.5.RELEASE\spring-boot-2.2.5.RELEASE.jar;
* F:\mvnLocalRepository\org\springframework\spring-context\5.2.4.RELEASE\spring-context-5.2.4.RELEASE.jar;
* F:\mvnLocalRepository\org\springframework\boot\spring-boot-autoconfigure\2.2.5.RELEASE\spring-boot-autoconfigure-2.2.5.RELEASE.jar;
* F:\mvnLocalRepository\org\springframework\boot\spring-boot-starter-logging\2.2.5.RELEASE\spring-boot-starter-logging-2.2.5.RELEASE.jar;
* F:\mvnLocalRepository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;
* F:\mvnLocalRepository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;
* F:\mvnLocalRepository\org\apache\logging\log4j\log4j-to-slf4j\2.12.1\log4j-to-slf4j-2.12.1.jar;
* F:\mvnLocalRepository\org\apache\logging\log4j\log4j-api\2.12.1\log4j-api-2.12.1.jar;
* F:\mvnLocalRepository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;
* F:\mvnLocalRepository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;
* F:\mvnLocalRepository\org\springframework\spring-core\5.2.4.RELEASE\spring-core-5.2.4.RELEASE.jar;
* F:\mvnLocalRepository\org\springframework\spring-jcl\5.2.4.RELEASE\spring-jcl-5.2.4.RELEASE.jar;
* F:\mvnLocalRepository\org\yaml\snakeyaml\1.25\snakeyaml-1.25.jar;
* F:\mvnLocalRepository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;
* F:\mvnLocalRepository\org\springframework\boot\spring-boot-starter-web\2.2.5.RELEASE\spring-boot-starter-web-2.2.5.RELEASE.jar;
* F:\mvnLocalRepository\org\springframework\boot\spring-boot-starter-json\2.2.5.RELEASE\spring-boot-starter-json-2.2.5.RELEASE.jar;
* F:\mvnLocalRepository\com\fasterxml\jackson\core\jackson-databind\2.10.2\jackson-databind-2.10.2.jar;
* F:\mvnLocalRepository\com\fasterxml\jackson\core\jackson-annotations\2.10.2\jackson-annotations-2.10.2.jar;
* F:\mvnLocalRepository\com\fasterxml\jackson\core\jackson-core\2.10.2\jackson-core-2.10.2.jar;
* F:\mvnLocalRepository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.10.2\jackson-datatype-jdk8-2.10.2.jar;
* F:\mvnLocalRepository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.10.2\jackson-datatype-jsr310-2.10.2.jar;
* F:\mvnLocalRepository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.10.2\jackson-module-parameter-names-2.10.2.jar;
* F:\mvnLocalRepository\org\springframework\boot\spring-boot-starter-tomcat\2.2.5.RELEASE\spring-boot-starter-tomcat-2.2.5.RELEASE.jar;
* F:\mvnLocalRepository\org\apache\tomcat\embed\tomcat-embed-core\9.0.31\tomcat-embed-core-9.0.31.jar;
* F:\mvnLocalRepository\org\apache\tomcat\embed\tomcat-embed-el\9.0.31\tomcat-embed-el-9.0.31.jar;
* F:\mvnLocalRepository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.31\tomcat-embed-websocket-9.0.31.jar;
* F:\mvnLocalRepository\org\springframework\boot\spring-boot-starter-validation\2.2.5.RELEASE\spring-boot-starter-validation-2.2.5.RELEASE.jar;
* F:\mvnLocalRepository\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;
* F:\mvnLocalRepository\org\hibernate\validator\hibernate-validator\6.0.18.Final\hibernate-validator-6.0.18.Final.jar;
* F:\mvnLocalRepository\org\jboss\logging\jboss-logging\3.4.1.Final\jboss-logging-3.4.1.Final.jar;
* F:\mvnLocalRepository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;
* F:\mvnLocalRepository\org\springframework\spring-web\5.2.4.RELEASE\spring-web-5.2.4.RELEASE.jar;
* F:\mvnLocalRepository\org\springframework\spring-beans\5.2.4.RELEASE\spring-beans-5.2.4.RELEASE.jar;
* F:\mvnLocalRepository\org\springframework\spring-webmvc\5.2.4.RELEASE\spring-webmvc-5.2.4.RELEASE.jar;
* F:\mvnLocalRepository\org\springframework\spring-aop\5.2.4.RELEASE\spring-aop-5.2.4.RELEASE.jar;
* F:\mvnLocalRepository\org\springframework\spring-expression\5.2.4.RELEASE\spring-expression-5.2.4.RELEASE.jar;
* E:\ideaIU-2019.3.1.win\lib\idea_rt.jar
*/
}
双亲委派机制:类加载器检测类(全类名)是否与java内置类相同,如果相同则不会加载该类,保证java的安全性
七、创建运行时类的对象
反射获取Class对象,实例化该对象
public static void demo1() {
Class<?> studentClazz = Class.forName("org.com.junjie.reflect.Student");
//newInstance()创建Student对象
Student stduent =(Student) studentClazz.newInstance();
System.out.println(stduent);
}
八、获取运行时类的完整结构
反射获取对象的方法
public static void demo2() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class<?> studentClazz = Class.forName("org.com.junjie.reflect.Student");
//newInstance()创建Student对象
Student stduent =(Student) studentClazz.newInstance();
System.out.println(stduent);
//获取名为setName,参数为String类型的方法(private不能获取)
Method setNameMethod = studentClazz.getMethod("setName", String.class);
System.out.println(setNameMethod);
//获取该类与所有父类的所有方法(private不能获取)
Method[] methods = studentClazz.getMethods();
//只获取该类的所有方法(private可以获取)
Method[] declaredMethods = studentClazz.getDeclaredMethods();
for (Method method:methods) {
System.out.println(method);
}
System.out.println("================");
for (Method declaredMethod:declaredMethods) {
System.out.println(declaredMethod);
}
}
反射获取类的成员变量
public static void demo3() {
Class<?> studentClazz = Class.forName("org.com.junjie.reflect.Student");
//获取该类名为name成员变量(private可以获取)
Field nameField = studentClazz.getDeclaredField("name");
System.out.println(nameField);
//获取该类和所有父类的所有的成员变量(private不能获取)
Field[] fields =studentClazz.getFields();
for (Field filed : fields) {
System.out.println(filed);
}
System.out.println("----------------");
//只获取该类所有的成员变量(private可以获取)
Field[] declaredFields = studentClazz.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field);
}
}
反射获取类的构造器
public static void demo4(){
Class<?> studentClazz = Class.forName("org.com.junjie.reflect.Student");
//只获取该类的所有的构造器(private不能获取)
Constructor<Student>[] constructors = (Constructor<Student>[]) studentClazz.getConstructors();
for (Constructor<Student> constructor : constructors) {
System.out.println(constructor);
}
//只获取该类的所有的构造器(private可以获取)
Constructor<Student>[] declaredConstructors = (Constructor<Student>[]) studentClazz.getDeclaredConstructors();
for (Constructor<Student> constructor : declaredConstructors) {
System.out.println(constructor);
}
}
九、调用运行时类的指定的结构
反射执行类的方法
class Student{
public void eat(String food) {
System.out.println("吃"+food);
}
private String sleep() {
return "sleep";
}
}
public static void demo5() {
Class<?> studentClazz = Class.forName("org.com.junjie.reflect.Student");
Student student =(Student) studentClazz.newInstance();
//获取sleep方法
Method sleepMethod = studentClazz.getDeclaredMethod("sleep");
//由于sleep方法权限为private,调用setAccessible方法打开权限
findMethod.setAccessible(true);
//执行student类的find方法
Object invoke = findMethod.invoke(student);
System.out.println(invoke);
//获取eat方法
Method eatMethod = studentClazz.getDeclaredMethod("eat", String.class);
invoke = eatMethod.invoke(student, "饭");
System.out.println(invoke);
}
结果:
反射给私有成员变量赋值或(取值)
public static void demo6() {
Class<?> studentClazz = Class.forName("org.com.junjie.reflect.Student");
Student student =(Student) studentClazz.newInstance();
//获取name成员变量
Field field = studentClazz.getDeclaredField("name");
//打开private的权限
field.setAccessible(true);
//给name属性赋值
field.set(student,"张三");
//取name的值
System.out.println(field.get(student));
}
反射获得构造器创建对象
public static void demo7() {
Class<?> studentClazz = Class.forName("org.com.junjie.reflect.Student");
//获取该类参数类型为int,String,int的构造器
Constructor<?> constructor = studentClazz.getConstructor(int.class,String.class,int.class);
Object obj = constructor.newInstance(1,"张三",14);
Student student = (Student) obj ;
System.out.println(student);
}
给任意类的任意变量赋值或取值
class Student {
private String name;
}
class Teacher {
private int workAge;
}
public static void demo8() {
Student student = new Student ();
//给Student类中的name属性赋值
setOjbect(student, "name", "张三");
System.out.println(student.getName());
Teacher teacher = new Teacher ();
//给Teacher类中的workAge属性赋值
setOjbect(teacher, "workAge", 12);
System.out.println(teacher.getWorkAge());
}
//赋值
private static void setOjbect(Object target,String fieldName,Object value){
Class<?> targetClazz = target.getClass();
Field field = targetClazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(target, value);
}
//取值
public static Object getObject(Object target, String name ) {
Class<?> clazz = target.getClass();
Field field = clazz.getDeclaredField(name);
if (field!=null){
field.setAccessible(true);
return field.get(target);
}else{
return null ;
}
}
在程序运行中读取properties,反射动态执行properties中的方法
public static void demo9() {
Properties prop = new Properties();
//读取properties文件
Reader reader = new FileReader("D:\\Users\\333\\eclipse-workspace\\Reflect_反射\\src\\xx.properties");
prop.load(reader);
//通过key 取value
String className = prop.getProperty("className");
String method = prop.getProperty("method");
//反射创建对象
Object clazz = Class.forName(className).newInstance();
//获取方法
Method declaredMethod = Class.forName(className).getDeclaredMethod(method);
//打开private的权限
declaredMethod.setAccessible(true);
//执行方法
declaredMethod.invoke(clazz);
}
改变泛型集合的结构(慎用)
public static void demo10() {
//创建一个Integer泛型的集合对象
List<Integer> intArr = new ArrayList<Integer>();
//添加数据
intArr.add(1);
intArr.add(2);
intArr.add(3);
System.out.println(intArr);
//反射获取ArrayList集合的Class对象
Class<?> stringClazz = intArr.getClass();
//获取add方法,并改变ArrayList中add方法的参数为Object
Method method = stringClazz.getDeclaredMethod("add",Object.class);
//打开private的权限
method.setAccessible(true);
//执行add方法,传入任意类型的参数
method.invoke(intArr, "张三");
method.invoke(intArr, true);
method.invoke(intArr, new Date());
System.out.println(intArr);
}
执行结果:
十、性能对比分析
setAccessible
- Method、Field、Constructor对象都有setAccessible()方法
- setAccessible作用是启动和禁用访问安全检查的开关
- 参数值为true则指示反射的对象在使用时应该Java语言访问检查
- 提高反射的效率,如果代码中必须用反射,而且频繁的被调用,设置为true
- 打开私有权限,使得被private修饰的成员变量和方法可以被使用
- 参数值为false则指示反射的对象应该实施Java语言访问检查
十一、反射获取注解信息
- Annotation[] getAnnotations();
- Annotation getAnnotation(Class< ? > annotationClass);
ORM对象关系映射
- Object relationship Mapping 对象关系映射
- 类与表结构对应
- 属性和字段对应
- 对象和记录对应
通过注解和反射完成类和表结构的映射关系
@Table("db_student")
class Student{
@Field(column = "db_id",type = "int",length = 10)
private int id ;
@Field(column = "db_name",type = "String",length = 20)
private String name ;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
}
public class TestAnnotationReflect {
public static void main(String[] args) {
//反射获取Student的Class对象
Class clazz = Student.class;
//获取class对象的类注解
Annotation annotationClass = clazz.getAnnotation(Table.class);
Table table = (Table) annotationClass;
//获取Table的value值
String value = table.value();
System.out.println(value);
//获取所有的属性
java.lang.reflect.Field[] declaredFields = clazz.getDeclaredFields();
//遍历,获取每一个属性对应的注解
for (java.lang.reflect.Field declaredField : declaredFields) {
Field annotation = declaredField.getAnnotation(Field.class);
//获取Field的column值
String column = annotation.column();
//获取Field的type值
String type = annotation.type();
//获取Field的length值
Integer length = annotation.length();
System.out.println("字段:"+column+",类型:"+type+",长度:"+length);
}
}
}
//定义类与数据库表对应的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
String value();
}
//定义类属性与字段对应的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field{
String column();
String type();
int length();
}
结果:
来源:CSDN
作者:junjie886
链接:https://blog.csdn.net/junjie886/article/details/104892408