java反射的作用及使用详解

Posted javase1085

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java反射的作用及使用详解相关的知识,希望对你有一定的参考价值。

一、反射类的概念及作用

1.什么是反射类

动态获取类或者对象的信息(属性和方法),以及动态操作对象的属性和方法的类,动态分析和使用类的信息的类

注:动态是指在java运行状态

2.反射类的作用
  • 动态获取:动态获取类或对象的属性和方法
  • 动态调用:动态调用对象的属性和方法
3.反射的使用场景
  • 操作因访问权限限制的属性和方法;
  • 实现自定义注解;
  • 动态加载第三方jar包
  • 按需加载类,节省编译和初始化时间;

二、反射技术的使用

1.反射主要涉及的类

反射技术的核心技术是Class对象,每个类在定义以后都有各自的Class对象

2.反射技术主要框架

3.定义一个实体类
1.  `package main.java.com.shixinke.java.demo.reflect;`

3.  `public  class  User  `
4.  `public  String platformNo =  "WEB";`
5.  `private  Long userId;`
6.  `private  String nickname;`
7.  `private  String password;`
8.  `private  Character gender;`
9.  `private  String email;`

11.  `public  Long getUserId()  `
12.  `return userId;`
13.  ``

15.  `public  void setUserId(Long userId)  `
16.  `this.userId = userId;`
17.  ``

19.  `public  String getNickname()  `
20.  `return nickname;`
21.  ``

23.  `public  void setNickname(String nickname)  `
24.  `this.nickname = nickname;`
25.  ``

27.  `public  String getPassword()  `
28.  `return password;`
29.  ``

31.  `public  void setPassword(String password)  `
32.  `this.password = password;`
33.  ``

35.  `public  Character getGender()  `
36.  `return gender;`
37.  ``

39.  `public  void setGender(Character gender)  `
40.  `this.gender = gender;`
41.  ``

43.  `public  String getEmail()  `
44.  `return email;`
45.  ``

47.  `public  void setEmail(String email)  `
48.  `this.email = email;`
49.  ``

51.  `private  void setGender(int gender)  `
52.  `if  (gender ==  1)  `
53.  `this.gender =  'M';`
54.  `  else  `
55.  `this.gender =  'F';`
56.  ``
57.  ``
58.  ``

4.获取类的Class对象
(1)通过Class.forName()方法来获取 在面试中被问到并发知识的时候,大多都会被问到“请你说一下自己对于AQS原理的理解”。下面给大家一个示例供大家参加,面试不是背题,大家一定要假如自己的思想,即使加入不了自己的思想也要保证自己能够通俗的讲出来而不是背出来。在此我向大家推荐一个架构学习交流圈。交流学习伪鑫:1253431195(里面有大量的面试题及答案)里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多
  • forName(类的路径)
1.  `/**`
2.  `* 1.通过Class.forName的形式来获取Class对象`
3.  `*/`
4.  `Class cls =  Class.forName("main.java.com.shixinke.java.demo.reflect.User");`

(2)通过类名.class来获取
1.  `/**`
2.  `* 2.通过类名.class来获取Class对象`
3.  `*/`
4.  `Class clz =  User.class;`

(3)通过类对象.getClass()来获取
1.  `/**`
2.  `* 3.通过类对象.getClass()方法获取Class对象`
3.  `*/`
4.  `User user =  new  User();`
5.  `Class clazz = user.getClass();`

5.通过类的Class对象获取类本身的信息
  • getName()获取类的名称
1.  `System.out.println(cls.getName());  //main.java.com.shixinke.java.demo.reflect.User`
2.  `System.out.println(cls.getSuperclass());  //class java.lang.Object`
3.  `System.out.println(cls.getCanonicalName());  //main.java.com.shixinke.java.demo.reflect.User`

6.通过类的Class对象获取类的属性信息
  • getFields() : 获取类中的所有非私有的属性
  • getDecalaredFields() : 获取类中所有的属性(包括私有和仅有属性)
1.  `Field[] fields = cls.getFields();`
2.  `for  (Field field : fields)  `
3.  `System.out.println(field.getName());  //platformNo : 只能获取非私有的属性`
4.  ``

6.  `Field[] allFields = cls.getDeclaredFields();`
7.  `for  (Field field : allFields)  `
8.  `System.out.println(field.getName());  //[platformNo userId nickname password gender email]`
9.  ``

7.通过类的Class对象获取类的方法
  • getMethods() : 获取所有的非私有方法对象数组
  • getDeclaredMethods() : 获取所有的方法对象数组
  • getMethod(methodName):获取指定方法名对应的非私有方法对象
  • getDeclaredMethod(methodName):获取指定方法名对应的方法对象
1.  `/**`
2.  `* 1.获取所有非私有方法`
3.  `*/`
4.  `Method[] methods = cls.getMethods();`
5.  `for  (Method m : methods)  `
6.  `System.out.println(m.getName());`
7.  ``

9.  `/**`
10.  `* 2.获取所有方法`
11.  `*/`
12.  `Method[] allMethods = cls.getDeclaredMethods();`
13.  `for  (Method m : allMethods)  `
14.  `System.out.println(m.getName());`
15.  ``

17.  `/**`
18.  `* 3.获取某个指定方法名的方法对象(必须是非私有方法)`
19.  `* 第1个参数为方法名,第2个参数及以后的表示方法中的参数的类型`
20.  `*/`
21.  `Method setGenderMethod = cls.getMethod("setGender",  Character.class);`
22.  `System.out.println(setGenderMethod.getParameterCount());`

24.  `/**`
25.  `* 4.获取某个指定方法名的方法对象(既可以是公有也可以是私有)`
26.  `*/`
27.  `Method setGenderAllMethod = cls.getDeclaredMethod("setGender",  int.class);`
28.  `System.out.println(setGenderAllMethod.getParameterCount());`

8.方法对象(即Method对象)
  • 获取参数相关的属性:
    • 获取参数个数:getParameterCount()
    • 获取参数数组对象:getParameters()
  • 获取返回值相关的属性
    • 获取返回值的类型:getReturnType()
1.  `Method m = cls.getMethod("setGender",  Character.class);`
2.  `/**`
3.  `* 1.获取参数个数`
4.  `*/`
5.  `System.out.println(m.getParameterCount());`

7.  `/**`
8.  `* 2.获取参数对象数组`
9.  `*/`
10.  `for  (Parameter p : m.getParameters())  `
11.  `System.out.println(p.getName());  //获取参数名称`
12.  `System.out.println(p.getType());  //获取参数的类型`
13.  `System.out.println(p.getAnnotations());  //获取参数的注解`
14.  ``

16.  `/**`
17.  `* 获取返回值类型`
18.  `*/`
19.  `System.out.println(m.getReturnType());`

9.获取类的其他属性
  • 获取实现的接口数组对象: getInterfaces()
  • 获取使用的注解数组对象: getAnnotations()
1.  `/**`
2.  `* 1.获取实现的接口数组对象`
3.  `*/`
4.  `for  (Class c : cls.getInterfaces())  `
5.  `System.out.println(c.getName());`
6.  ``

8.  `/**`
9.  `* 2.获取使用的注解数组对象`
10.  `*/`
11.  `for  (Annotation a : cls.getAnnotations())  `
12.  `System.out.println(a.getClass().getName());`
13.  ``

10.创建类的对象(实例化对象)
(1)通过Class对象的newInstance()
1.  `User user =  (User)cls.newInstance();`
2.  `user.setEmail("ishixinke@qq.com");`
3.  `System.out.println(user.getEmail());  //ishixinke@qq.com`

(2)通过Constructor对象的newInstance方法
  • 通过Class对象的getConstructor方法获取Constructor对象
  • 通过Constructor对象的newInstance方法来实例化对象
1.  `Constructor constructor = cls.getConstructor();`
2.  `User user =  (User) constructor.newInstance();`
3.  `user.setEmail("ishixinke@qq.com");`
4.  `System.out.println(user.getEmail());  //ishixinke@qq.com`

11.通过类的对象来调用属性和方法
  • 通过Class类对象创建类实现类的实例化,得到类的实例
  • 通过类的实例来操作属性和方法
1.  `User user =  (User)cls.newInstance();`
2.  `user.setEmail("ishixinke@qq.com");`
3.  `System.out.println(user.getEmail());  //ishixinke@qq.com`

三、反射的优点及缺点

1.反射的优点
  • 灵活、自由度高:不受类的访问权限限制,想对类做啥就做啥
2.反射的缺点
  • (1)使用反射的性能较低
  • (2)使用反射相对来说不安全
  • (3)破坏了类的封装性,可以通过反射获取这个类的私有方法和属性

Java反射详解:入门+使用+原理+应用场景

反射非常强大和有用,现在市面上绝大部分框架(spring、mybatis、rocketmq等等)中都有反射的影子,反射机制在框架设计中占有举足轻重的作用。

所以,在你Java进阶的道路上,你需要掌握好反射。

怎么才能学好反射,我们需要弄懂以下几个问题:

1.反射是什么?

2.反射有什么用?

3.反射的实现原理?

4.怎么用反射?

下面我就针对以上的疑问,一一来讲解。

反射是什么?

反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。

反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意方法和属性,这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

一句话总结:反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。

为什么要用反射?

Java Reflection功能非常强大,并且非常有用,比如:

  • 获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器等
  • 获取任意对象的属性,并且能改变对象的属性
  • 调用任意对象的方法
  • 判断任意一个对象所属的类
  • 实例化任意一个类的对象
  • 通过反射我们可以实现动态装配,降低代码的耦合度,动态代理等。

怎么使用反射?

一般情况下我们通过反射创建类对象主要有两种方式:

  • 通过 Class 对象的 newInstance() 方法
  • 通过 Constructor 对象的 newInstance() 方法

第一种:通过 Class 对象的 newInstance() 方法。

  1. Class clz = Class.forName("com.mikechen.reflection.JiaGou");
  2. JiaGou jg= (JiaGou)clz.newInstance();

第二种:通过 Constructor 对象的 newInstance() 方法

  1. Class clz = Class.forName("com.mikechen.reflection.JiaGou");
  2. Constructor constructor = clz.getConstructor();
  3. JiaGou jg= (JiaGou)constructor.newInstance();

通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法,下面的代码就调用了一个有参数的构造方法进行了类对象的初始化。

  1. Class clz = Class.forName("com.mikechen.reflection.JiaGou");
  2. Constructor constructor = clz.getConstructor(String.class);
  3. JiaGou jg= (JiaGou)constructor.newInstance("mikechen的互联网架构");

接下来我们就可以通过具体的API调用获取到详细的属性或者方法等详细了。

1、获取类的成员变量的信息

  1. //mikechen的互联网架构
  2. Field[] fields = cls.getDeclaredFields();

更加详细成员变量获取参考如下:

2、获得类方法

  1. //mikechen的互联网架构
  2. Method[] methods = cls.getDeclaredMethods();

更加详细方法获取参考如下:

3、获得构造函数

  1. //mikechen的互联网架构
  2. Constructor[] constructors = cls.getDeclaredConstructors();

更加详细构造函数获取参考如下:

这样通过反射就可以做在运行时获取类的完整构造,并获得类信息了。

通过以上一个小案例了解了反射的使用,但如果你想对反射掌握得更好,还需深入理解反射背后的底层实现原理。

反射工作原理?

调用反射的总体流程如下:

1、当我们编写完一个Java项目之后,每个java文件都会被编译成一个.class文件。

2、这些class文件在程序运行时会被ClassLoader加载到JVM中,当一个类被加载以后,JVM就会在内存中自动产生一个Class对象。

3、通过Class对象获取Field/Method/Construcor

我们一般平时是通过new的形式创建对象实际上就是通过这些Class来创建的,只不过这个class文件是编译的时候就生成的,程序相当于写死了给jvm去跑。

反射是什么呢?当我们的程序在运行时,需要动态的加载一些类这些类可能之前用不到所以不用加载到jvm,而是在运行时根据需要才加载。

原来使用new的时候,需要明确的指定类名,这个时候属于硬编码实现,而在使用反射的时候,可以只传入类名参数,就可以生成对象,降低了耦合性,使得程序更具灵活性。

反射的应用场景

举个例子我们的项目底层数据库有时是用mysql,有时用oracle,需要动态地根据实际情况加载驱动类,这个时候反射就有用了,假设 com.mikechen.java.myqlConnection,com.mikechen.java.oracleConnection这两个类我们要用。

这时候我们在使用 JDBC 连接数据库时使用 Class.forName()通过反射加载数据库的驱动程序,如果是mysql则传入mysql的驱动类,而如果是oracle则传入的参数就变成另一个了。

Spring 框架的 IOC(动态加载管理 Bean),Spring通过配置文件配置各种各样的bean,你需要用到哪些bean就配哪些,spring容器就会根据你的需求去动态加载,你的程序就能健壮地运行。

还有Spring AOP(动态代理)功能都和反射有关系。

除此之外还有很多框架:mybatis、dubbo、rocketmq等等都会用到反射机制。

 

作者:陈睿,英文名mikechen, 资深技术专家,曾任职阿里、淘宝、百度,分享十余年BAT架构经验以及面试心得!
 
关注个人公众号:mikechen的互联网架构,第一时间获取最新BAT架构技术干货与面试经验分享!
 
公众号后台回复 架构,还可以获取我独家秘制Java大厂架构干货视频噢。

以上是关于java反射的作用及使用详解的主要内容,如果未能解决你的问题,请参考以下文章

一文详解:java开发安卓应用

java 反射——使用详解

Java反射详解:入门+使用+原理+应用场景

java反射机制详解

Java-反射机制(超详解)

Java反射详解