一,反射的概念
反射是JAVA或者说是JVM的一种机制,通过反射可以使程序逆周期执行
反射机制官方定义: 在程序运行时能动态获取类的结构数据,这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制
java代码执行的三大阶段:
源代码阶段
Class对象阶段
Runtime运行时阶段
反射可以可以通过.class逆向获取信息和生成类,将类中的各个组件部分封装为其他对象
反射的重要性: 框架开发的灵魂,基本上所有的java框架都有反射的影子,如:ORM的封装产生的Mybatis,MVC封装的SpringMVC等
反射是特定场景的产物,在使用框架时基本上使用不到反射,但假如要自定义封装一套框架就必然会到,假如是在甲方公司写业务时反射也能有很多应用
注:在一些很多的资料和教程中,对注解和反射都不够深刻,它们只讲怎么通过class对象通过反射获取信息和基本的注解创建,没有讲到怎么通过反射去解析注解
二,获取Class对象三种方式
获取Class对象的三种方式:
Class.forName("类全名") :将字节码文件加载进内存,返回Class对象
类名.class: 通过类名的属性class获取
对象.getClass :getClass()方法获取,这个方法是在Object类中定义的
这三种方式是在不同阶段获取class的手段:
当class子字节码文件还保存在本地,没有加载到JVM中时通过Class.forName("类全名")
当class文件已经在内存中被解析,可以直接通过类名.class获取
当class文件已经进入RunTime执行阶段,可以直接通过对象.getClass获取
在使用上一般没有区别,但在场景中有适应区分
三种方式的应用场景:
Class.forName("类全名"):多用于配置文件,将类名定义在配置文件中,读取配置文件,加载类
类名.class:多用于参数的传递
对象.getClass:多用于对象的获取字节码的方式
例:分别通过三种方式获取
public static void main(String[] args) throws ClassNotFoundException {
//方式1
Class<?> parentClass1 = Class.forName("test.parent");
//方式2
Class<parent> parentClass2 = parent.class;
//方式3
parent parent = new parent();
Class<? extends test.parent> parentClass3 = parent.getClass();
System.out.print((parentClass1==parentClass2)?(parentClass2==parentClass3):"false");
}
注:同一个字节码文件(*.class)在一次程序运行过程中,之会被加载一次,不论通过哪一种方式获取class对象结果都是同一个
三,Class对象的功能
功能:
获取和设置成员变量Field
获取构造方法Constructor
获取成员方法Method
获取注解Annotation
获取类信息
一,获取设置成员变量
Class类获取Field的方法:
Field[] getFields() :获取所有非private的成员属性变量
Field getField(String name) :通过name获取非private的单个成员属性变量
Field[] getDeclaredFields() :获取所有的成员变量属性
Field getDeclaredField(String name):通过name获取单个成员变量
例:
public static void main(String[] args) throws NoSuchFieldException {
Class<parent> parentClass = parent.class;
//获取所有非private的成员属性变量
Field[] classFields = parentClass.getFields();
//获取所有的成员变量属性
Field[] declaredFields = parentClass.getDeclaredFields();
//通过name获取非private的单个成员属性变量,如果没有直接报错
Field sex = parentClass.getField("sex"); //获取不到报错
//通过name获取单个成员变量,如果没有直接报错
Field name = parentClass.getDeclaredField("name");
//打印
System.out.println("----------getFields-----------");
for (Field s:classFields){ System.out.println(s); }
System.out.println("----------getDeclaredFields-----------");
for (Field s:declaredFields){ System.out.println(s);}
System.out.println("----------getField-----------");
System.out.println(sex);
System.out.println("----------getDeclaredField-----------");
System.out.println(name);
}
Field类的方法:
Object get(Object obj) :返回指定对象上该所表示的字段的值
Object set(Object obj,Object value) :设置指定对象上该字段的值
Annotation[] getDeclaredAnnotations() :返回直接存在于此属性上的注解
void setAccessible(boolean flag):忽略访问权限修饰符的安全检查,如果不忽略private修饰的属性不能获取和设置
…………
Field name = parentClass.getDeclaredField("name");
//忽略访问权限修饰符的安全检查
name.setAccessible(true);//暴力反射
parent x1= new parent();
name.set(x1,"空想家");
Object o = name.get(x1);
结果:
空想家
二,获取构造方法
Class类获取构造的方法:
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes):获取指定的有参和无参构造
Constructor<?>[] getDeclaredConstructors():获取无参和有参构造列表
Constructor<T> getConstructor(类<?>... parameterTypes) :获取指定的非private的有参和无参构造
Constructor<?>[] getConstructors():获取无参构造
例:
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<parent> parentClass = parent.class;
Constructor<?>[] constructors = parentClass.getConstructors();
Constructor<parent> constructor = parentClass.getDeclaredConstructor(String.class, Integer.class);//参数实际形参的类型
Constructor<parent> constructor1 = parentClass.getConstructor();
for (Constructor a:constructors){ System.out.println(a); }
System.out.println(constructor.newInstance("空想家",100));
System.out.println(constructor1.newInstance());
}
Constructor类的常用方法:
newInstance(Object... initargs) :使用指定的初始化参数来创建和初始化构造函数的声明类的新实例
三,获取全局方法
Class类获取全局方法:
Method getMethod(String name, 类<?>... parameterTypes):通过方法名和参数类型获取指定的非private的成员方法
Method[] getMethods():获取非private的成员方法列表
Method getDeclaredMethod(String name, 类<?>... parameterTypes): 通过方法名和参数类型获取指定的成员方法
Method[] getDeclaredMethods(): 获取成员方法列表
Method getEnclosingMethod():返回内部类或匿名类的方法
Method类的方法:
Object invoke(Object obj, Object... args):执行该方法,传入类对象和参数
String getName() :获取方法名
T getAnnotation(类<T> annotationClass):获取注解
例:
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<parent> parentClass = parent.class;
Method sleep = parentClass.getMethod("sleep");
Method getup = parentClass.getDeclaredMethod("getup", String.class);
Method[] declaredMethods = parentClass.getDeclaredMethods();
System.out.println(sleep);
System.out.println(getup);
System.out.println("-----------指定获取method列表------------");
for(Method a:declaredMethods){
System.out.println(a);
}
System.out.println("-----------method的invoke方法------------");
getup.setAccessible(true);//省略权限
parent parent = parentClass.getConstructor().newInstance();
System.out.println(getup.invoke(parent,"空想家"));
System.out.println("-----------method的其他方法------------");
System.out.println(getup.getName()); //获取方法名称
}
四,案例
案例1:写一个简单的反射Dome,它可以通过properties创建任意类对象和执行任意方法
① 配置文件
Classname=test.parent
Methodname=eat
② 反射
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取配置文件路径
ClassLoader classLoader = parent.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("reflect.properties");
//将配置文件加载到properties中
Properties properties = new Properties();
properties.load(resourceAsStream); //加载
String classname = properties.getProperty("Classname"); //获取classname
String methodname = properties.getProperty("Methodname"); //获取methodname
//反射创建类
Class<?> aClass = Class.forName(classname);
Object pojo = aClass.getConstructor().newInstance();
//获取方法
Method declaredMethod = aClass.getDeclaredMethod(methodname);
//调用方法
declaredMethod.invoke(pojo);
}
案例2:整合注解写一个错误收集,把错误信息保存到文件
① 注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface mytest {
String username() default "WQL";
}
② 实例类
public class calculator {
@mytest
public void add(){
System.out.println(1+0);
}
@mytest
public void sub(){
System.out.println(1-0);
}
@mytest
public void mult(){
System.out.println(1*0);
}
@mytest
public void div(){
System.out.println(1/0);
}
@mytest(username = "fq")
public void err(){
System.out.println(1/0);
}}
③ 核心(反射)
public static void main(String[] args) throws IllegalAccessException, IOException {
//创建计算器测试对象
calculator calculator = new calculator();
//获取字节码对象
Class<? extends test.calculator> calculatorClass = calculator.getClass();
//获取方法列表
Method[] declaredMethods = calculatorClass.getDeclaredMethods();
//声明错误的次数和文件输出流
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("err.txt"));
int number = 0;
//遍历方法
for (Method meth:declaredMethods){
//判断方法是否标注了mytest方法
if(meth.isAnnotationPresent(mytest.class)){
try{
meth.invoke(calculator);
}catch (Exception e){
number++;
//解析注解
bufferedWriter.write("--------"+meth.getAnnotation(mytest.class).username()+"<-->"+meth.getName()+"--------");
bufferedWriter.newLine();
bufferedWriter.write("异常名称:"+e.getCause().getClass().getSimpleName());
bufferedWriter.newLine();
bufferedWriter.write("异常原因:"+e.getCause().getMessage());
bufferedWriter.newLine();
}
} }
bufferedWriter.write("----> 总共出现"+number+"次错误<----");
bufferedWriter.flush();
bufferedWriter.close();
}
④ 结果
Comments | 30 条评论
博主 avira getintopc
What’s more, you can sync your music with rekordbox, along with smart playlists, metadata, hot cues, loops and memory points.
博主 WQL
@avira getintopc There’s no time right now
博主 Twicsy
Bel article, je l’ai partagé avec mes amis.
博主 Twicsy
Güzel bir yazı, arkadaşlarımla paylaştım.
博主 https://twicsy.com/es/comprar-instagram-likes
Buen post, lo he compartido con mis amigos.
博主 WQL
@https://twicsy.com/es/comprar-instagram-likes Thanks
博主 https://twicsy.com/pt/comprar-curtidas-instagram
Belo post, compartilhei com meus amigos.
博主 Instagram
좋은 게시물, 나는 그것을 내 친구들과 공유했습니다.
博主 Twicsy
Fint innlegg, jeg har delt det med vennene mine.
博主 https://twicsy.com
Buen post, lo he compartido con mis amigos.
博主 Twicsy
Nice post, na-share ko na sa mga kaibigan ko.
博主 Twicsy
Posting yang bagus, saya telah membagikannya dengan teman-teman saya.
博主 WQL
@Twicsy 💕
博主 WQL
@Twicsy Thanks
博主 twicsy.com
Bel post, l’ho condiviso con i miei amici.
博主 Twicsy
Belo post, compartilhei com meus amigos.
博主 Twicsy
Гарний пост, я поділився ним із друзями.
博主 WQL
@Twicsy ❤
博主 Twicsy
Dejligt indlæg, jeg har delt det med mine venner.
博主 https://twicsy.com/ar/buy-instagram-likes
منشور جميل ، لقد شاركته مع
أصدقائي.
博主 WQL
@https://twicsy.com/ar/buy-instagram-likes Thanks
博主 Instagram
Хороший пост, поделился с друзьями.
博主 Twicsy
Bel post, l’ho condiviso con i miei amici.
博主 https://twicsy.com/no/kjop-instagram-likes
Fint innlegg, jeg har delt det med vennene mine.
博主 Twicsy
좋은 게시물, 나는 그것을 내 친구들과 공유했습니다.
博主 WQL
@Twicsy Thank You
博主 https://twicsy.com/uk/kupuyte-layky-v-instagram
Гарний пост, я поділився ним із друзями.
博主 WQL
@https://twicsy.com/uk/kupuyte-layky-v-instagram Thank You
Warning: Undefined variable $m in /www/wwwroot/wql_luoqin_ltd/wp-content/themes/Sakura/functions.php on line 1765
Warning: Trying to access array offset on value of type null in /www/wwwroot/wql_luoqin_ltd/wp-content/themes/Sakura/functions.php on line 1765
Warning: Undefined variable $m in /www/wwwroot/wql_luoqin_ltd/wp-content/themes/Sakura/functions.php on line 1765
Warning: Trying to access array offset on value of type null in /www/wwwroot/wql_luoqin_ltd/wp-content/themes/Sakura/functions.php on line 1765
博主 KwivProlf
hi opp ggeis 2022 ert go fi
博主 WQL
@KwivProlf Hi
Warning: Undefined variable $return_smiles in /www/wwwroot/wql_luoqin_ltd/wp-content/themes/Sakura/functions.php on line 1109