1.反射概述
2.获取Class类对象的三种方法
3.Class类的常用方法
4.反射获取构造方法并使用
5.反射获取类的成员属性并使用
6.反射获取类的成员方法并使用
7.反射的优缺点
8.反射的注意事项

1.反射概述

1.反射定义:

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

2.关于Class类

首先,我要给初学者或者小白定位一下对Class类的理解。常用类有String类、Math类等等,这里的Class也是一个类似于String类、Math类等等的类,和我们随便创建的类的概念是有本质区别的,Class类位于java.lang包下!Class 类的实例表示正在运行的 Java应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型) Class 没有公共构造方法。Class对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass方法自动构造的。也就是这不需要我们自己去处理创建Class对象,JVM已经帮我们创建好了。

3.了解完了反射的概念我们来看看普通类的加载过程:

熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。反射的本质理解就是得到Class对象后反向获取Student对象的各种成分信息(成分信息包括成员变量、方法、构造方法、所在包、字段属性等等),下面就以Student对象为例,图解Student类的正常加载过程~


那么我们再看看student加载的三个阶段:

对于这一张图的解释:
我们java类的代码编译后生成了字节码文件,里边包含三个比较重要的部分,分别对应成员变量,构造方法,和成员方法(当然一个字节码文件可不止这些东西,比如还有类名等等,这三个只是比较重要的部分),然后这个字节码文件存储在硬盘上,然后当我们new student()的时候,jvm就会把字节码文件加载到内存中,在内存里有描述我们加载进来的class文件的类对象:Class类对象,我们Class类对象把三个重要部分又分别封装成对象,分别为field,constructor,Method对象(这里注意一个对象只能包含一个成员变量或者一个构造方法成员方法,所以这里要用到数组的形式),然后真正的student对象是通过我们的Class类对象创建出来的

反射才体现出java是如何创建对象的。当java虚拟机(JVM)加载一个class类文件时,就创建这个类的class对象,以后的对象都是由这个class对象创建的,所以同一个类的所有对象的class对象都是一个,比如A a=new A(); A b=new A(); a.class()==b.class()返回true.

2.获取Class类对象的三种方法

1.Class.forName(“包名.类名”):将字节码文件加载进内存(注意这个方法可以加载类),返回Class类对象,当你知道该类的全路径名时,你可以使用该方法获取 Class 类对象。但可能抛出ClassNotFoundException异常
2.类名.class:通过类名的属性class获取,这种方法只适合在编译前就知道操作的 Class。直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高,这说明任何一个类都有一个隐含的静态成员变量 class
3.对象.getClass():这个getClass是在Object里边定义着所以每一个类里边都会有

代码实例:

package untl1;
public class student {private int age;private String name;public student(int age,String name){this.age=age;this.name=name;}public void study(){System.out.println("我爱学习");}public static void main(String[] args)throws Exception {Class cl1=Class.forName("untl1.student");System.out.println(cl1);Class cl2=student.class;System.out.println(cl2);student stu=new student(1,"1");Class cl3=stu.getClass();System.out.println(cl3);System.out.println(cl1==cl2);System.out.println(cl1==cl3);}
}
运行结果:
class untl1.student
class untl1.student
class untl1.student
true
true

两个true充分证明了一个类只有一个字节码文件对象

3.Class类的常用方法

(1)常用方法:

方法名 作用
getName() 一个Class对象描述了一个特定类的属性,Class类中最常用的方法getName以=String 的形式返回此 Class对象所表示的实体(类、接口、数组类、基本类型或 void)名称(简单来说就是获得类的完整路径名)。方法可以简单的理解为:获得字符串参数中指定的类,并初始化该类。
newInstance() 为类创建一个实例,但只能调用默认构造器(无参数构造器
getClassLoader() getClassLoader() 方法主要返回该类的类加载器。
getComponentType() getComponentType() 方法主要返回表示数组组件类型的 Class。
getSuperclass() getSuperclass() 返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。
isArray() isArray() 判定此 Class 对象是否表示一个数组类。

(2)在初始化一个类,生成一个实例的时候,newInstance()方法和new关键字除了一个是方法,一个是关键字外,最主要有什么区别?

newInstance: 弱类型。低效率。只能调用无参构造。使用的时候使用的类必须加载过
new: 强类型。相对高效。能调用任何public构造。使用的时候不需要必须加载过

这里的加载过,博主是这么理解的,当我们使用newInstance()的时候,如果类没加载过那么就不存在这个类的Class类对象文件,既然连这个Class类对象都没有那么怎么调用它的方法来创建对象呢,使用new的时候,我们都知道一个类的实例是必须经过Class类对象文件的,使用new的时候不需要加载类,在new的过程中再加载该类,以这种方法来创建对象就不需要提前加载

4.反射获取构造方法并使用

这里尤其注意看看每一个方法获取的构造方法的访问权限是怎样的

例子:
拿第一个举例子:

 package untl1;
import java.lang.reflect.Constructor;
public class student {private int age;private String name;public student(int age,String name){this.age=age;this.name=name;}public student(){this.name="花花";this.age=100;}public student(int age){this.name="草草";this.age=age;}public void study(){System.out.println("我爱学习");}public String toString(){return "年龄:"+age+"\n"+"名字:"+name;}public static void main(String[] args)throws Exception {Class cla1=student.class;Constructor con1=cla1.getConstructor();System.out.println("空参构造方法为"+con1);student stu1= (student) con1.newInstance();//newInstance是Constructor类里边的方法,和Class的newInstance用法类似System.out.println(stu1);Constructor con2=cla1.getConstructor(int.class,String.class);System.out.println("两个参数的构造方法为"+con2);student stu2= (student) con2.newInstance(33,"卿卿");System.out.println(stu2);}
}
运行结果:
空参构造方法为public untl1.student()
年龄:100
名字:花花
两个参数的构造方法为public untl1.student(int,java.lang.String)
年龄:33
名字:卿卿

5.反射获取类的成员属性并使用

这里有两个方法是属性对象里边的方法:

1.void set(Object obj,Object value):为获取的成员变量设置值
2.get(Object obj):获取成员变量的值

具体使用下边例子都有:

package untl1;
import java.lang.reflect.Field;
public class student {public int age;private String name;public student(int age,String name){this.age=age;this.name=name;}public student(){this.name="花花";this.age=100;}public student(int age){this.name="草草";this.age=age;}public void study(){System.out.println("我爱学习");}public String toString(){return "年龄:"+age+"\n"+"名字:"+name;}public static void main(String[] args)throws Exception {Class cla1=student.class;Field fie1= cla1.getField("age");student stu1=new student();fie1.set(stu1,88);Object value1=fie1.get(stu1);System.out.println(stu1);System.out.println(value1);Field fie2=cla1.getDeclaredField("name");student stu2=new student();fie2.setAccessible(true);fie2.set(stu2,"喵喵");Object value2=fie2.get(stu2);System.out.println(stu2);System.out.println(value2);Field fie3[]= cla1.getDeclaredFields();for (Field a:fie3) {System.out.println(a);}}
}
运行结果:
年龄:88
名字:花花
88
年龄:100
名字:喵喵
喵喵
public int untl1.student.age
private java.lang.String untl1.student.name

这里有一个fie2.setAccessible(true),这个是暴力反射,我们使用getDeclaredField()虽然可以获得私有的属性,但是不能拿来设置和获得该属性的值,这是由于访问修饰符为private,我们想要设置和获得该属性的值就必须要忽略访问修饰符的安全检查,那么使用setAccessible()方法就能解决,这里参数必须设置为true

6.反射获取类的成员方法并使用


获取的成员方法需要执行可以使用Method里边的执行方法:

Object invoke(Object obj,Object ...args):执行所在对象的指定方法

例子:

package untl1;
import java.lang.reflect.Method;
public class student {public int age;private String name;public student(int age,String name){this.age=age;this.name=name;}public student(){this.name="花花";this.age=100;}public student(int age){this.name="草草";this.age=age;}public void study(){System.out.println("我爱学习");}public  void fly(String str){System.out.println("我要飞得更高");}public String toString(){return "年龄:"+age+"\n"+"名字:"+name;}public static void main(String[] args)throws Exception {Class cla1=student.class;Method me=cla1.getMethod("study");student stu=new student();me.invoke(stu);Method me2=cla1.getMethod("fly",String.class);me2.invoke(stu,"翠花");}
}
运行结果:
我爱学习
我要飞得更高

7.反射的优缺点

1.反射优点:

使用反射机制,代码可以在运行时装配,提高了程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需硬编码目标类

2.反射缺点:

1.性能问题:使用反射基本上是一种解释操作,JVM无法对这些代码进行优化,因此,反射操作的效率要比那些非反射操作低得多。反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,对性能要求高的程序中不建议使用
2.安全限制:使用反射技术要求程序必须在一个没有安全限制的环境中运行
3.内部暴露:由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用——代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。

8.反射的注意事项

1.注意方法中带Declared的不考虑访问权限
2.在Constructor对象里的newInstance()方法,返回值需要强制类型转换,否则不能直接就等于此字节码文件对应的类的引用
3.在反射中传递参数时要在参数后边加上.class才行
4.暴力反射是在三个对象(Constructor,Field,Method)中都能用,只要涉及获取或者修改私有的成员属性
5.Method里边的getMethod方法如果有没参数就直接在参数列表里边以字符串的形式传递方法的名字,如果有参数,不仅要传递方法的名字,还要传递方法的参数
6.Method中invoke方法需要传递一个实例化对象,然后如果获得的方法有参数,海要在invoke里边加上方法的参数

Java资深反射玩家相关推荐

  1. 【Java】反射( reflection)机制 详解

    目录 1. 定义 2. 用途(了解即可) 3. 反射的基本信息 4. 反射相关的类(重要) 4.1 Class类(反射机制的起源 ) 4.2 Class类中的相关方法(方法的使用方法在后边的示例当中) ...

  2. java 泛型反射_Java使用反射来获取泛型信息示例

    本文实例讲述了Java使用反射来获取泛型信息.分享给大家供大家参考,具体如下: 一 点睛 获得了Field对象后,就可以很容易地获得该Field的数据类型,即使用如下代码即可获得指定Field的类型: ...

  3. java初反射_初始 java 反射机制 (一)

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

  4. Java中反射的三种常用方式

    Java中反射的三种常用方式 package com.xiaohao.test; public class Test{ public static void main(String[] args) t ...

  5. Java的反射机制 工厂模式综合讲解【转载自51CTO】

    2019独角兽企业重金招聘Python工程师标准>>> Java的反射机制 工厂模式综合讲解 1.什么叫反射 Java.lang.reflect包下 正常情况下我们可以通过类实例化一 ...

  6. java反射机制(三)---java的反射和代理实现IOC模式 模拟spring

    IOC(Inverse of Control)可翻译为"控制反转",但大多数人都习惯将它称为"依赖注入".在Spring中,通过IOC可以将实现类.参数信息等配 ...

  7. [Java基础] 反射机制汇总

    引言 初学Java反射机制的时候,只是感觉很神奇,但是不知道学了该怎么用,所以过了一段时间就忘得差不多了:最近接触到了框架,在学习中遇到了反射,深深体会到了反射机制的神奇,回来复习了一下反射机制,写一 ...

  8. Java 利用反射实现C#的委托

    一, 观察者模式的缺点 在之前的博文的介绍过观察者模式了. 观察者模式可以让多个观察者同时观察1个被观察者. 也就说被观察者可以1次过执行所有观察者的update()方法. 再通俗d来讲, 就是多个观 ...

  9. sqlite字段是否存在_学习廖雪峰的JAVA教程---反射(访问字段)

    对任意的一个Object实例,只要我们获取了它的Class,就可以获取它的一切信息. 我们先看看如何通过Class实例获取字段信息.Class类提供了以下几个方法来获取字段: Field getFie ...

最新文章

  1. 关肇直 automation lingjunrenwu
  2. Google Guice使用入门
  3. 【P1835】小红花
  4. ext2.0 主体皮肤 (xtheme-black)
  5. 2018-2019-1 20189204《Linux内核原理与分析》第二周作业
  6. java 6 基础_java基础(6)
  7. html css 书签,CSS实现书签图案的效果
  8. 复印机扫描仪错误怎么回事_打印机扫描后出现错误怎么处理?
  9. Windows下安装 Apache 步骤
  10. es3,es5语法记要
  11. 为Exynos4412移植2022版U-Boot(一)步骤及其原理分析
  12. 小程序源码:装B神器P图修改微信流量主小程序源码下载趣味恶搞图制作
  13. LaTeX中文字体设置
  14. 夜间模式 css,网站夜间模式的实现
  15. 微信小程序自定义组件使用阿里矢量图标库图标
  16. Vue3技术4之watch监视属性、watch时value问题
  17. 树莓派从入门到放弃之Docker上安装Jellyfin视频服务器
  18. 《部落冲突:皇室战争》——一款不能错过的游戏!
  19. 有n个结构体变量,内含学生学号、姓名和3门课程的成绩。要求输出平均成绩最高的学生的信息(包括学号、姓名、3门课程成绩和平均成绩)
  20. 使用CSS绘制几何图形(圆形、三角形、扇形、菱形等

热门文章

  1. 【奖】《密码信》破解者们,快来领奖啦!
  2. 在家点点接入云信,打造全新社区商业和社交生态
  3. Python--day46--MySQL视图
  4. Vue(五)Vue规范
  5. BZOJ3775 : 点和直线
  6. 云监控Agent指南-Linux版
  7. elementui中同时上传多个文件_2019-12-19 element-ui文件上传 一次请求上传多个文件...
  8. 【python 学习】知识点日记
  9. 推荐 7 个 Github 上近 200k Star 的计算机学习资源,练好前端内功的秘籍!
  10. goroutine sync.RWMutex读写锁RLock的使用