java 反射 基本知识

1 反射

封装代码的依据就是反射和泛型,理解反射和泛型能帮助自己更好的掌握手动封装代码的方法,减少代码量,而且对于框架的源码阅读也有帮助。
之前有接触过反射和泛型的概念,现在再系统说明一次以加强对这两个概念的认识

  • 反射和泛型属于java的机制,和web无关
  • 反射通常与泛型一起使用,因为用反射封装的方法需要适用于所有数据类型,此时数据类型是不确定的,需要用泛型“占位”
  • 反射机制最核心的源码如图
    image

1.1 获取Class对象

反射中Class.forName()和ClassLoader.loadClass()的区别 - Jerry迎风 - 博客园 (cnblogs.com)

语法 说明 静态代码块 非静态代码块
Class 变量名 = Class.forName ( 全类名 ) 通过全类名获取全类名指向的类 加载 /
Class 变量名 = 对象名.getClass() 通过对象名获取对象所属的类 加载 加载
Class 变量名 = 类名.class 通过类名获取那个类 / /
Class 变量名 = 任意自定义的类.class.getClassLoader().loadClass(全类名) 通过类的加载器获取全类名指向的类 / /

注意:

  1. 全类名即.java文件的绝对路径,外部传入
  2. 通过类的加载器获取Class时,前面的写法都是固定的,需要传入的参数和方式1相同,两者的区别在于代码块
  3. 数据库链接时,要使用Class.forName(全类名),因为JDBC Driver中有静态代码块需要被加载

1.1.1 代码块的概念

首先明确一个概念——反射不只用于实体类,也能用于工具类,比如JDBCUtil,或者第三方jar包,比如JDBC Driver
而这些工具类需要在静态代码块里实现类的初始化
因此反射这种类时,就要选择能加载静态代码块的方法。
使用static修饰的代码块即静态代码块;没有static修饰的代码就是非静态代码块,通常非静态代码块用的很少。
image

image

实例:
①通过全类名(即类的地址)获取class
可以加载静态代码块,不能加载非静态代码块
image

②通过对象名获取class
能同时加载静态和非静态代码块
image

③通过类名获取class
无法加载代码块
image

④通过类的加载器获取class
无法加载代码块
image

1.1.2 类的加载器

image

1.1.3 类的加载器的常见方法

关于类加载的loadClass()方法的讲解_Demon_T的博客-CSDN博客

①loadClass(全类名)
只要知道loadClass(全类名)能根据传入的全类名返回一个Class对象即可

②getResourceAsStream(String name)
通常与getResourceAsStream(String name)结合,用于获取配置文件的信息,返回一个输入流,常用于配置druid连接池
image

1.2 获取类的构造器

只要获取到类就能获取到类的构造器、成员变量、成员方法。
实际开发中基本只用类的无参构造器,也不需要专门获取类的构造器,因此以下内容了解即可。

语法 说明
Constructor 变量名 = Class对象 . getConstructor() 获取无参构造方法
Constructor 变量名 = Class对象 . getConstructor(String.class, String.class) 通过参数类型获取有参的构造函数,显然这得先知道想要的构造函数的具体参数表
Constructor[] 变量名 = Class对象 . getConstructors() 获取所有的构造方法,返回的是一个数组,注意方法名最后的“s”
Constructor对象 . getName() 获得构造方法的名字,是全类名
Constructor对象 . getParameterCount() 获得构造方法参数表中的参数个数
Constructor对象 . getParameterTypes() 获得一个Class对象数组,每个Class对象指向构造方法参数表中的一个参数类型
Constructor对象 . getParameters() 获得构造方法的参数表,参数类型用全类名表示,参数名用arg加下标组成
Object object = Constructor对象 . newInstance() 使用无参构造函数创建一个Object类型的对象
Object object = Constructor对象 . newInstance(参数1,参数2) 使用有参构造器创建一个Object类型的对象,JAVA会自动调用能对应上参数的构造器

注意:
newInstance()除了可以给Class对象用,也能给Constructor对象用,均是使用无参构造获得一个object对象,这也是最常用的创建对象的方法。

实例:
Class对象指向的类的构造方法
image

①获取无参构造

  1. 获得的名字是全类名
  2. 无参构造的参数个数为0
    image

②获取有参构造
在知道某个构造器需要的参数类型后,可以获取到该有参构造方法
当一个类被用来创建对象时,类中的静态代码块和非静态代码块均会被调用
imageimage

③获取所有构造方法
此时能获得一个对象数组,里面按照代码的先后顺序存放类中所有的构造方法,比如图中的信息就表明类中先写了无参构造再写了有参构造
image

1.3 获取类的方法

java.lang.reflect.Method类提供了获取类的成员函数的方法,方法通常由修饰符、方法名、返回类型、参数类型构成。

语法 说明
Method[] 变量名 = Class对象 . getMethods() 获取类中所有的公开方法,返回一个对象数组
1.包括从父类继承的(一直到Object超类)以及从父接口继承的(一直到超接口)
2.注意:JDK新特性,接口中除了抽象方法,也能存在成员函数
Method[] 变量名 = Class对象 . getDeclaredMethods() 获取类中所有的方法(包含私有,需要暴力破解),但只能是类自己的方法,返回一个对象数组
1.包括重载的父类方法以及实现的父接口方法
2.不包括从父类继承或者从父接口继承的方法
Method 变量名 = Class对象 . getMethod ("方法名", 指向参数类型的Class对象) 获取类中某个带参的方法,由于存在方法重载的可能,因此需要给定方法的参数表
Method 变量名 = Class对象 . getMethod ("方法名") 获取类中某个无参的方法
Method对象 . getName() 获得方法名,不是全类名
Method对象 . getParameterCount() 获得方法的参数个数
Method对象 . getParameterTypes() 获得一个Class对象数组,每个Class对象指向方法参数表中的一个参数类型
Method对象 . getParameters() 获得方法的参数表,参数类型用全类名表示,参数名用arg加下标组成
Method对象 . getReturnType() 获得方法的返回类型,无返回类型则返回void
Method对象 . setAccessible(true) 在调用私有的方法前需要设置暴力破解
Method对象 . invoke(对象名,参数1,参数2) 调用方法,需要设置哪个对象调用这个方法,并提供这个方法需要的所有参数,参数可以是数组

注意:
①获取到私有方法时可以直接打印该方法,但是如果希望使用该方法,必须先设置暴力破解

②invoke的第一个参数是对象,后面的是可变参数,也就是允许传入多个参数,也允许传入数组

  • invoke实现类的源码
    image

  • invoke实现类的接口源码
    image

1.3.1 获取类中某一个公开的方法 无参无返回值

image

1.3.2 获取类中某一个公开的方法 有参无返回值

指定需要从类中取出的方法名 此时可能存在方法重载 所以还要指定这个方法需要的参数 以精准指定某个方法
image

1.3.3 获取类中某一个公开的方法 有参有返回值

image

1.3.4 获取类中所有的公开的方法(包括从父类、父接口继承的)

因为会继承父类并且一直继承到超级父类,因此必定有toString、hashCode、wait、equals等方法,除此之外还会有get/set方法以及明写出来的成员函数
image

1.3.5 获取类中某一个方法

image

1.3.6 获取类中所有的方法(不包含从父类或父接口继承的)

image

1.4 获取类的变量

java.lang.reflect.Filed类提供了获取类中的成员变量(属性)的方法

语法 说明
Field 变量名 = Class对象 . getField( "变量名" ) 获取类中指定名字的公开的成员变量,返回一个对象
Field[] 变量名 = Class对象 . getFields() 获取类中所有公开的成员变量,包括从父类继承的公开的成员变量,返回一个对象数组
Field 变量名 = Class对象 . getDeclaredField( "变量名" ) 获取类中指定名字的成员变量,即便这个变量没有公开,返回一个对象
Field[] 变量名 = Class对象 . getDeclaredFields(); 获取类中所有的成员变量,但不包括从父类继承的成员变量,返回一个对象数组
Field对象 . getName() 获得成员变量的名字,不是全类名
Field对象 . getType() 返回一个Class对象,指向该成员变量的数据类型
Field对象 . set( 对象名 , 参数); 调用set方法,需要设置哪个对象调用这个方法,并提供这个方法需要的所有参数,参数可以是数组
Field对象 . get( 对象名 ) 调用get方法,需要设置哪个对象调用这个方法
Field对象 . setAccessible(true); 在操作私有的成员变量之前,需要设置暴力破解

注意:
①获取到私有变量时可以直接打印该方法,但是如果希望使用该方法,必须先设置暴力破解

②set的第一个参数是对象,后面只允许跟着一个参数。
set实现类的源码
image

下面分别列举获取属性的四种方法的实例,演示的类存在如图的属性:
image

1.4.1 获取某一个公开的属性

需要指定属性的名字
image

1.4.2 获取所有的公开的属性(包括从父类继承的)

image

1.4.3 获取某一个属性

image

1.4.4 获取所有的属性(不包含从父类继承的)

image

posted @ 2021-08-12 22:35  夏·舍  阅读(58)  评论(0编辑  收藏  举报