反射

1.机制
在运行状态(动态)中对于任意一个类,都能够知道这个类的所有属性和方法
对于任意一个对象都能够调用它的任意方法和属性

2.功能
1.在运行时获取任意一个对象修饰符,泛型,父类/实现的接口/注解等
2.运行时构造任意一个类的对象
3.运行时获取任意一个类所具有的构造方法,成员变量和方法
4.运行时访问任意一个对象的成员变量和方法

3.应用

(1)通过类的全名创建类实例来使用外部用户定义的类
(2)开发类浏览器和智能IDE
(3)在测试工具中检测类的内部结构
(4)在框架开发中用于实现配置信息的处理

使用反射

1.class类
java.lang.Class是所有Reflection API的切入点,是所有反射操作的入口

对于每种类型的对象java虚拟机都会实例化一个不可变的java.lang.Class实例
每个对象都是引用或者原始类型

1.java.lang.Class.java类对象
2.java.lang.reflect.Constructor.java类的构造器对象
3.java.lang.reflect.Method.java类的方法对象
4.java.lang.reflect.Field.java类的属性对象 Field字段也即成员变量

一/获取Class实例的三种方法
1.对象.getClass()
2.类型名.class
3.ClassforName()(最常用)
二/获取类的成员
java.lang.reflect.Field.java类,一个Field提供类或接口中的一个成员变量的信息,可以动态访问
public Field getDeclaredField(String name)//根据名字获取类中定义的成员变量,不包括继承父类的成员

public Field[] getDeclaredFields()//获取类中声明的所有成员变量,返回Field[]类型,不含继承父类的成员
无Declared包含继承父类的成员

访问成员变量,成员方法和构造方法的方法
1.列出所有成员的方法
2.根据名字搜索特定成员的方法
3.获取类的成员方法
4.获取类的构造方法
5.调用成员方法

//使用反射调用对象的方法
//使用反射根据方法名,和参数类型、参数数量来获取具体某个方法
Method m=c.getDeclaredMethod(methodname, Class.forName(mptypes[0]));//String.class
//方法的调用,调用o对象的m方法,方法的实际参数是mp1,mo是方法调用的返回值
Object mo=m.invoke(o,mp1);
//o.setName("xiaohong");
System.out.println(mo);
//调用了o对象名为setAge,参数有1个,类型是int型的方法,实际参数是21
m=c.getDeclaredMethod("setAge", int.class);
m.invoke(o, 21);
System.out.println(o);
/*Method m=c.getDeclaredMethod(methodname);
Object mo=m.invoke(o);
System.out.println(mo);
System.out.println(f.get(o));*/
不得不用反射
第一个参数是调用方法的类实例
	(静态方法)第一个参数为null
后面几个参数是该方法的参数

6.用反射的方式给对象的属性设置值,获取对象的属性值

//使用反射访问类对象的属性(给属性设置值,获取属性的值)
Field f=c.getDeclaredField(fieldname);//根据Field名,获得Field对象
f.setAccessible(true);
f.set(o,fvalue);//o.name=“xiaolin”;使用反射给o对象的f代表的属性设置值为发value的值
System.out.println(f.get(o));//获取o对象的f属性对应的值,并输出

1.给定类的实例
2.通常情况下是因为常规方法无法设置对象的属性值才迫不得已用反射
3.这方法违反了类的封装性的设计意图,耗费额外的系统开销

7通过Constructor实例创建对象
(1)关键字new

Object o=c.newInstance();//Student o=new Student();

(2)第二种用反射创建类对象的方法,先获取具体的Constructor,再用Constructor去创建对象

Constructor con=c.getDeclaredConstructor(String.class,int.class);
//根据构造方法参数类型来获取某个构造方法
Object o1=con.newInstance("Mary",20);
//用Constructor创建类对象,相当于Student o1=new Student("Mary",20);
System.out.println(o1);

//第一种用反射创建类对象的方法,相当于调用类的无参数构造方法
方法1调用非私有的无参构造,可以抛出构造方法的异常
方法2形参是(Object… obj)调用类的任何一个构造方法。用InnovationTargetException封装异常来抛出

1.反射增加了JVM的系统开销,
2.反射允许访问私有成员,打破了封装,可能破坏可移植性。
总结:能不用就不用

Class c=Class.forName(classname);

//根据类名字符串获得类对应的Class实例
在这里插入图片描述
包含继承父类成员

访问对象的属性(给属性设置值,获取属性的值)

//使用反射访问类对象的属性(给属性设置值,获取属性的值)
Field f=c.getDeclaredField(fieldname);//根据Field名,获得Field对象
f.setAccessible(true);
f.set(o,fvalue);//o.name="xiaolin";使用反射给o对象的f代表的属性设置值为fvalue的值
System.out.println(f.get(o));//获取o对象的f属性对应的值,并输出

在这里插入图片描述
用获取的类型来进行获取修饰符
在这里插入图片描述
这个是获取类声明所有的成员变量返回TypeVariable<?>接口类型
继承了多个接口
方法有getName()
getTypeParameters();
格式化成字符串后getName()
在这里插入图片描述super父类
类型Class在这里插入图片描述接口interfaces类型Type
getGeneritcinterfaces()c
ToString()在这里插入图片描述获取类的注解类型Annotation
getAnnotation()
toString()在这里插入图片描述
获取类的构造函数
Constructor返回类型
getDeclaredConstructor();
toGenericString()
在这里插入图片描述
获取类的成员变量
Field[]返回类型(成员变量类型)
getDeclaredFields();
ToGenericString();

在这里插入图片描述
Method[]返回类型
getMethods();
获取类的公有方法toGener
icString()

import java.lang.reflect.TypeVariable;
import java.lang.reflect.Modifier;
Modifier/TypeVariable要import才能使用
Class可以不用import
在这里插入图片描述
c.getModifiers()
%n这个参数必须是一个有符号整数的指针,它存储它出现之前打印的所有字符数。
.format(" ")格式化字符串
通过调用invoke方法来执行对象的某个方法
在这里插入图片描述

图片源于https://www.cnblogs.com/qingchen521/p/8575761.html

注解

1.概念

一个元数据形式,提供有关程序的数据,该数据不属于程序本身,注释对于对其注释的代码的操作没有直接影响

注解的语法
@注解类型名

用途:
1.编译前:为编译器提供编译检查的依据,辅助检查代码错误或抑制检查异常。
2.编译中或发布时:给编译器提供信息生成代码或给其他工具提供信息生成文档等。
3.运行时:在运行过程中提供信息给解释器,辅助程序执行。
注解经常和反射结合起来用,多用于框架中

五个基本注解
@Override
@Deprecated
@Suppress Warnings
@Safe Varargs
@FunctionalInterface

2.内置的注解

1.Override
位置:在方法前
作用:1.表示重写父类的方法
2.如果重写有错误就报错
可以强制子类必须覆盖父类的方法

2.@Deprecated过时的警告
since属性指定从哪个版本开始,forRemoval指定该API将来会被删除
在这里插入图片描述

3.@SuppressWarnings
抑制编译器警告
在这里插入图片描述
4.SafeVarargs
堆异常警告
//给一个不带泛型的对象赋给一个带泛型的变量的时候往往就会发生堆污染
堆污染警告
faltyMethod发出"堆污染警告"
1.使用@SafeVarargs修饰引发该警告的方法或构造器
2.@SuppressWarning(“unchecked”)修饰
3.编译时用-Xlint:varags选项

函数式接口
@FunctionalInterface
如果接口中只有一个抽象方法
该接口就是函数式接口
在这里插入图片描述

自定义注解

修饰符:@interface(自动继承java.lang.annotation.Annotation接口)@元注解

元注解

元注解负责注解其他注解

Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)

4个标准的meta-annotation类型:
1.@Target
修饰注解定义
Annotation所修饰的对象范围
取值(ElementType)有:
1.CONSTRUCTOR:用于描述构造器   
2.FIELD:用于描述域   
3.LOCAL_VARIABLE:用于描述局部变量   
4.METHOD:用于描述方法   
5.PACKAGE:用于描述包   
6.PARAMETER:用于描述参数   
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
8.ANNOTATION_TYPE:指定该策略的注解只能修饰构造器
2.@Retention
指定Annotation被保留的时间长短
必须为value成员变量指定值、
value成员变量的值只能是下面三个
1. RetentionPolicy.CLASS
编译器将把注解记录在class文件中,当运行java程序的时候JVM不可获取注解信息,这是默认值
2. RetentionPolicy.RUNTIME
编译器把注解记录在class文件中,当运行java程序的时候,JVM可以获取注解信息,可以通过反射获取信息。
3. RetentionPolicy.SOURCE
注解保留在源代码中,编译器直接丢掉这种注解

			如果需要通过反射获取注解信息,就需要将value的属性值设置为RetentionPolicy.RUNTIME的@Retention(value=RetionPolicy.RUNTIME)
			public interface Testable

@Retention (RetentionPolicy.SOURCE)
public @interface Testable{}

3.@Documented
用于指定被元注解修饰的注解类将被javadoc工具提取成文档
如果定义注解类的时候用了@Documented修饰,则所有使用该注解修饰的程序元素的API文档将会包含该注释说明
4.@Inherited
被修饰的注解将具有继承性

提取注解信息

SuppressWarnings(“unchecked”)忽略编译器的警告
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐