十六、反射
1、反射简介
16.1.1、反射定义
反射机制是JDK中的一套类库,这套类库可以帮助我们操作/读取 class 字节码文件
后期学习的大量的java框架底层都是基于反射机制实现的
反射机制最核心的几个类
- java.lang.Class
Class类型的实例代表硬盘上的某个class文件,或者说代表某一种类型
Class反射对象描述类语义结构,可以从Class对象中获取构造函数、成员变量、方法类等类元素的反射对象,并以编程的方式通过这些反射对象对目标类对象进行操作
- java.lang.reflect.Filed
Filed类型的实例代表类中的属性/字段
- java.lang.reflect.Constructor
Constructor类型的实例代表类中的构造方法
- java.lang.reflect.Method
Method类型的实例代表类中的方法
- java.lang.reflect.Modifier
Java反射机制核心包:java.lang.reflect.*
在运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制
通过反射机制程序员能够获得在编译期间不被知晓的类、属性、方法等信息
但是反射机制的性能较低,常常被认为是一种牺牲性能换取灵活性的实现方式
16.1.2、对象的创建方式
(1)、正常方式创建对象
【示例】
下面的Car类拥有两个构造函数、一个方法及 3个属性
package com.java.createObject;
public class Car {
/*
成员属性
*/
private String brand;
private String color;
private int maxSpeed;
//默认构造函数
public Car() {
System.out.println("init car!!");
}
//带参数构造函数
public Car(String brand, String color, int maxSpeed) {
this.brand = brand;
this.color = color;
this.maxSpeed = maxSpeed;
}
//未带参方法
public void introduce() {
System.out.println("brand:" + brand + ";color:" + color + ";maxSpeed:" + maxSpeed);
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", color='" + color + '\'' +
", maxSpeed=" + maxSpeed +
'}';
}
}
一般情况下我们会使用如下代码创建Car的实例
public static void main(String[] args) {
Car car=new Car();
Car.setBrand("红旗CA72");
}
或者
public static void main(String[] args) {
Car car=new Car("红旗CA72","黑色");
}
以上两种方法都采用传统方式直接调用目标类的方法
(2)、反射方式创建对象
下面通过Java反射机制以一种间接的方式操控目标类
package com.java.createObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectTest01 {
public static Car initByDefaultConst() throws Throwable {
//1、通过类装载器获取Car类对象
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class clazz = loader.loadClass("com.java.createObject.Car");
//2、获取类的默认构造器对象并通过它实例化Car
Constructor cons = clazz.getDeclaredConstructor((Class[]) null);
Car car = (Car) cons.newInstance();
//3、通过Car的反射类对象的getMethod(String methodName,Class paramClass)获取属性的 Setter方法对象
Method setBrand = clazz.getMethod("setBrand", String.class);
setBrand.invoke(car, "红旗CA72");
Method setColor = clazz.getMethod("setColor", String.class);
setColor.invoke(car, "黑色");
Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class);
setMaxSpeed.invoke(car, 200);
return car;
}
public static void main(String args[]) throws Throwable {
Car car = initByDefaultConst();
car.introduce();
}
}
运行以上程序,在控制台上将打印出以下信息
这说明完全可以通过编程方式调用Class的各项功能,与通过构造函数和方法直接调用类功能的效果是一致的,只不过前者是间接调用,后者是直接调用罢了
在ReflectTest中使用了几个重要的反射类,分别是ClassLoader、Class、 Constructor和Method,通过这些反射类就可以间接调用目标Class的各项功能。
在1处获取当前线程的ClassLoader类加载器,然后通过指定的全限定类名"com.java.createObject.Car"装载Car类对应的反射实例
在2处通过Car的反射类对象获取Car的构造函数对象cons,通过构造函数对象的newInstrance()方法实例化Car对象,其效果等同于new Car()
在3处通过Car的反射类对象的getMethod(String methodName,Class paramClass)获取属性的 Setter方法对象,其中第一个参数是目标Class的方法名;第二个参数是方法入参的对象类型
在获取方法反射对象后,即可通过invoke(Object obj,Object param)方法调用目标类的方法,该方法的第一个参数是操作的目标类对象实例,第二个参数是目标方法的入参
2、反射类
16.2.1、类装载器ClassLoader
(1)、类装载的过程
类装载器就是寻找类的字节码文件(.class文件)并构造出类在JVM内部表示的对象的组件
在Java中类装载器把一个类装入JVM中需要经过以下步骤
- 装载
类加载器负责将类的class文件读入内存并创建一个java.lang.Class对象
-
链接
执行校验、准备和解析步骤,其中解析步骤是可以选择的
① 校验:确保加载类的信息符合JVM规范
② 准备:为静态变量在方法区中开辟存储空间并设置默认值
public static int k = 10; 此时k会赋值0 public static final int f = 10; 此时f会赋值10
③ 解析:将虚拟机常量池内的符号引用替换为直接引用(地址)的过程
-
初始化
静态变量赋值、静态代码块执行
类装载工作由ClassLoader及其子类负责。ClassLoader是一个重要的Java运行时系统组件,它负责在运行时查找和装入Class字节码文件
(2)、类装载器的名字
-
JDK8及以前的类加载
JVM在运行时会产生3个ClassLoader(这3个类装载器之间存在父子层级关系,即根装载器是ExtClassLoader的父装载器,ExtClassLoader是AppClassLoader的父装载器)
-
根装载器
根装载器不是ClassLoader的子类,它使用C++语言编写,因而在Java中看不到它
根装载器负责装载JRE的核心类库,如JRE目标下的rt.jar、charsets.jar等
-
ExtClassLoader (扩展类装载器)
ExtClassLoader是ClassLoader的子类,负责装载JRE扩展目录ext中的JAR类包
-
AppClassLoader (应用类装载器)
AppClassLoader是ClassLoader的子类,负责装载Classpath路径下的类包
在默认情况下使用AppClassLoader装载应用程序的类
-
-
JDK9+
-
虚拟机内部提供了三种类加载器
-
启动类加载器(BootstrapClassLoader)
加载Java最核心的类
例如String
-
平台类加载器(PlatformClassLoader)
加载Java平台扩展的类库
-
应用类加载器(AppClassLoader)
加载classpath中的
-
同时我们还可以自定义一个类加载器(UserClassLoader)
获取类加载器可以通过 getParent()方法一级一级获取
-
【示例】
package com.java.classLoader;
public class ClassLoaderTest {
public static void main(String args[]){
ClassLoader loader=Thread.currentThread().getContextClassLoader();
System.out.println("current loader:"+loader);
System.out.println("parent loader:"+loader.getParent());
System.out.println("grandparent loader:"+loader.getParent().getParent());
}
}
运行结果
通过以上输出信息知道当前类的ClassLoader是AppClassLoader,其父ClassLoader 是PlatformClassLoader,祖父ClassLoader是根装载器,因为在Java中无法获得它的句柄,所以仅返回null
【示例】
package com.java.classLoader;
/*
* 虚拟机内部有三个不同的类加载器:
* 1. 启动类加载器:BootstrapClassLoader
* 负责加载核心类库
* 2. 平台类加载器:PlatformClassLoader
* 负责加载扩展类库
* 3. 应用类加载器:AppClassLoader
* 负责加载classpath
*
* 类加载器也是可以自定义的,只要符合类加载器的规范即可。
* 自定义的类加载器,我们一般称为:用户类加载器。
*/
public class ClassLoaderTest02 {
public static void main(String[] args) {
// 通过自定义的类获取的类加载器是:应用类加载器。
ClassLoader appClassLoader = ClassLoaderTest02.class.getClassLoader();
System.out.println("应用类加载器:" + appClassLoader);
// 获取应用类加载器
ClassLoader appClassLoader2 = ClassLoader.getSystemClassLoader();
System.out.println("应用类加载器:" + appClassLoader2);
// 获取应用类加载器
ClassLoader appClassLoader3 = Thread.currentThread().getContextClassLoader();
System.out.println("应用类加载器:" + appClassLoader3);
// 通过 getParent() 方法可以获取当前类加载器的 "父 类加载器"。
// 获取平台类加载器。
System.out.println("平台类加载器:" + appClassLoader.getParent());
// 获取启动类加载器。
// 注意:启动类加载器负责加载的是JDK核心类库,这个类加载器的名字看不到,直接输出的时候,结果是null。
System.out.println("启动类加载器:" + appClassLoader.getParent().getParent());
}
}
(3)、双亲委派机制
某个类加载器接收到加载类的任务时通常委托给"父类加载器"完成加载
当"父类加载器"无法加载时,一级一级向下委托加载任务
JVM装载类时使用"全盘负责委托机制","全盘负责"是指当一个ClassLoader装载一个类时(除非显式地使用另一个ClassLoader)该类所有依赖及引用的类也由这个ClassLoader 载入。"委托机制"是指某个类加载器接收到加载类的任务时通常委托给"父类加载器"完成加载,当"父类加载器"无法加载时再一级一级向下委托加载任务
这一点是从安全角度考虑的
如果有人编写了一个恶意的基础类(如java.lang.String)并装载到JVM中,将会引起多么可怕的后果。但是由于有了"全盘负责委托机制",java.lang.String永远是由根装载器来装载的,这样就避免了上述安全隐患的发生
(4)、ClassLoader的重要方法
在Java中ClassLoader是一个抽象类,位于java.lang包中
下面对该类的一些重要接口方法进行介绍
-
Class loadClass(String name)
name参数指定类装载器需要装载类的名字,必须使用全限定类名
如 “com.java.createObject.Car”
该方法有一个重载方法loadClass(String name,boolean resolve)。resolve 参数告诉类装载器是否需要解析该类。在初始化类之前应考虑进行类解析的工作,但并不是所有的类都需要解析。如JVM只需要知道该类是否存在或找出该类的超类,那么就不需要进行解析
-
Class defineClass(String name,byte[] b,int off,int len)
将类文件的字节数组转换成JVM内部的 java.lang.Class 对象
字节数组可以从本地文件系统、远程网络获取
参数 name 为字节数组对应的全限定类名
-
Cass findSystemClass(String name)
从本地文件系统载入Class文件
如果本地文件系统不存在该Class文件将抛出ClassNotFoundException异常
该方法是JVM默认使用的装载机制
-
Class findLoadedClass(String name)
调用该方法来查看ClassLoader是否己装入某个类
如果己装入那么返回java.lang.Class对象;否则返回null
如果强行装载己存在的类将会抛出链接错误
-
ClassLoader getParent():
获取类装载器的父装载器
除根装载器外所有的类装载器都有且仅有一个父装载器
除JVM默认的3个ClassLoader外,用户可以编写自己的第三方类装载器,以实现一些特殊的需求
16.2.2、Package包类
Java为包提供了Package反射类
16.2.3、AnnotatedElement枚举类
在Java5.0中为注解提供了AnnotatedElement反射类
16.2.4、Class类对象
在Java中每个".class"类都有一个相应的Class对象
每个类在JVM中都拥有一个对应的java.lang.Class对象
数组、枚举、注解及基本数据类型(如int、double等),甚至void都拥有对应的Class对象
Class文件由类装载器装载后,在JVM内部将产生一个对应的java.lang.Class类描述对象,该类的实例都拥有指向这个类描述对象的引用,而类描述对象又拥有指向关联ClassLoader的引用
如图所示
Class对象描述类语义结构,可以从Class对象中获取构造函数、成员变量、方法类等类元素的反射对象并以编程的方式通过这些反射对象对目标类对象进行操作
Class没有public的构造方法
Class对象是在装载类时由JVM通过调用类装载器中的defineClass()方法自动构造的
反射的第一步是先得到编译后的Class对象,然后就可以得到Class的全部成分
HelloWorld.java -- > javac -- > HelloWorld.class
Class c = HelloWorld.class
(1)、Class类的功能
在正常情况下需要先有一个类的完整路径引入之后才可以按照固定的格式产生实例化对象。但是在java中也允许通过一个实例化对象找到一个类的完整信息,这就是Class类的功能
(2)、获取Class实例方式
获取Class类的对象的四种方式
-
静态方法获取
通过Class.forName()方法实例化对象
Class c1 = Class.forName(“全限定类名”);
类加载时会进行初始化
-
使用"类名.class"
Class c2 = 类名.class;
-
实例方法获取
Class c3 = 对象.getClass();
-
类加载器获取
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
Class clazz = classLoader.loadClass(“全限定类名”)
这种方式进行类加载时不会进行初始化,直到第一次使用该类
【示例】
package com.java.classObject;
/*
* 1. 反射机制是JDK中的一套类库,这套类库可以帮助我们操作/读取 class 字节码文件。
* 2. 后期学习的大量的java框架,底层都是基于反射机制实现的
* 3. 反射机制可以让程序更加灵活。
* 4. 反射机制最核心的几个类:
* java.lang.Class:Class类型的实例代表硬盘上的某个class文件。或者说代表某一种类型。
* java.lang.reflect.Filed:Filed类型的实例代表类中的属性/字段
* java.lang.reflect.Constructor: Constructor类型的实例代表类中的构造方法
* java.lang.reflect.Method: Method类型的实例代表类中的方法
* 5. 在java语言中获取Class的三种方式:
* 第一种方式:Class c = Class.forName("完整的全限定类名");
* 注意:
* 1.全限定类名是带有包名的。
* 2.是lang包下的,java.lang也不能省略。
* 3.这是个字符串参数。
* 4.如果这个类根本不存在,运行时会报异常:java.lang.ClassNotFoundException
* 5.这个方法的执行会导致类的加载动作的发生。
* 第二种方式:在java语言中,任何一种类型,包括基本数据类型,都有 .class 属性。用这个属性可以获取Class实例。
* 第三种方式:Class c = obj.getClass();
* 注意:这个方法是通过引用去调用的。
*
* 第四种方式:类加载器获取
* ClassLoader classLoader = ClassLoader.getSystemClassLoader();
* Class clazz = classLoader.loadClass(“全限定类名”)
*/
public class ClassTest01 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
/*
方式1:
*/
// stringClass1 就代表 String类型
// stringClass1 就代表硬盘上的 String.class文件
Class stringClass1 = Class.forName("java.lang.String");
String s1 = "我爱中国";
Class stringClass2 = s1.getClass();
// 某种类型的字节码文件在内存当中只有一份。
// stringClass1 和 stringClass2 都代表了同一种类型:String类型
System.out.println(stringClass1 == stringClass2); // true
/*
方式2
*/
// intClass 代表的就是基本数据类型 int类型
Class intClass3 = int.class;
Class doubleClass3 = double.class;
Class stringClass3 = String.class;
Class userClass3 = User01.class;
System.out.println(stringClass3 == stringClass1); // true
/*
方式3
*/
User01 user4 = new User01("zhangsan", 20);
Class userClass4 = user4.getClass();
Class userClass = Class.forName("com.java.classObject.User01");
System.out.println(userClass4 == userClass); // true
/*
方式4
*/
// 获取类加载器对象(获取的是 系统类加载器/应用类加载器 )
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
// jdk.internal.loader.ClassLoaders$AppClassLoader@36baf30c
// 这个类加载器是负责加载 classpath 中的字节码文件的。
//System.out.println(systemClassLoader);
// 加载类:但是这个加载过程只是将类加载过程中的前两步完成了,第三步的初始化没做。
// 什么时候做初始化?在这个类真正的被第一次使用的时候。
Class<?> aClass = systemClassLoader.loadClass("com.java.classObject.User01");
System.out.println(aClass.newInstance());
// 这种方式会走完类加载的全部过程,三步齐全
//Class clazz = Class.forName("com.java.classObject.User01");
}
}
class User01 {
static {
System.out.println("User类的静态代码块执行了!");
}
private String name;
private int age;
public User01(String name, int age) {
this.name = name;
this.age = age;
}
public User01() {
System.out.println("User类的无参数构造方法执行了!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
(3)、Class常用方法
Class本身表示一个类的本身
package java.lang;
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement,
TypeDescriptor.OfField<Class<?>>,
Constable {}
通过Class可以得到一个类中的完整结构(包括此类中的方法定义、属性定义等)
序号 | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public static Class<?> forName(String className) throws ClassNotFoundException {} | 普通 | 传入完整的"包.类"名称实例化Class对象 |
2 | public Constructor<?>[] getConstructors()throws SecurityException {} | 普通 | 得到一个类中的全部构造方法 |
3 | public Field[] getDeclaredFields() throws SecurityException {} | 普通 | 得到本类中单独定义的全部属性 |
4 | public Field[] getFields() throws SecurityException {} | 普通 | 取得本类继承而来的全部属性 |
5 | public Method[] getMethods() throws SecurityException {} | 普通 | 得到一个类中的全部方法 |
6 | public Method getMethod(String name, Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException {} | 普通 | 返回一个Method对象,并设置一个方法中的所有参数类型 |
7 | public Class<?>[] getInterfaces() {} | 普通 | 得到一个类中所实现的全部接口 |
8 | public String getName() {} | 普通 | 得到一个类完整的"包.类"名称 |
9 | public Package getPackage() {} | 普通 | 得到一个类的包 |
10 | public native Class<? super T> getSuperclass() | 普通 | 得到一个类的父类 |
11 | public T newInstance() throws InstantiationException, IllegalAccessException {} | 普通 | 根据Class定义的类实例化对象,在JDK9中废弃了 |
12 | public Class<?> getComponentType() {} | 普通 | 返回表示数组类型的Class |
13 | public native boolean isArray(); | 普通 | 判断此Class是否是一个数组 |
取得全部接口
要取得一个类所实现的全部接口,则必须使用Class类的getInterfaces()方法
此方法定义如下"public Class<?>[] getInterfaces() {}"
该方法返回一个Class类的数组之后直接利用Clas类的getName()方法即可输出
【示例】
package com.java.classObject;
public interface ChinaInterfaces {
String NATION = "China";
String AUTHOR = "李兴华";
void sayChina();
String sayHello(String name, int age);
}
class PeopleInterface implements ChinaInterfaces {
private String name;
private int age;
public PeopleInterface() {
}
public PeopleInterface(String name) {
this.name = name;
}
public PeopleInterface(String name, int age) {
this.setName(name);
this.setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void sayChina() {
System.out.println("作者:" + AUTHOR + ",国籍:" + NATION);
}
public String sayHello(String name, int age) {
return name + ",你好!我今年" + age + "岁了!";
}
}
class PeopleInterfaceTest {
public static void main(String args[]) throws ClassNotFoundException {
Class<?> c = null;
try {
c = Class.forName("com.java.classObject.PeopleInterface");
} catch (ClassCastException e) {
e.printStackTrace();
}
Class<?> c1[] = null;
c1 = c.getInterfaces();
for (int i = 0; i < c1.length; i++) {
System.out.println("实现的接口名称:" + c1[i].getName());
}
}
}
取得父类
一个类可以实现多个接口,但只能继承一个父类
如果要取得一个类的父类,可以直接使用Class类中的getSuperclass()方法
此方法定义如下"public native Class<? super T> getSuperclass();"
【示例】
package com.java.classObject;
public class ChinaParent {
public String NATION = "China";
public String AUTHOR = "李兴华";
}
class PeopleParent extends ChinaParent {
private String name;
private int age;
public PeopleParent() {
}
public PeopleParent(String name) {
this.name = name;
}
public PeopleParent(String name, int age) {
this.setName(name);
this.setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void sayChina() {
System.out.println("作者:" + AUTHOR + ",国籍:" + NATION);
}
public String sayHello(String name, int age) {
return name + ",你好!我今年" + age + "岁了!";
}
}
class PeopleParentTest {
public static void main(String args[]) throws ClassNotFoundException {
Class<?> c = null;
try {
c = Class.forName("com.java.classObject.PeopleParent");
} catch (ClassCastException e) {
e.printStackTrace();
}
Class<?> c1 = null;
c1 = c.getSuperclass();
System.out.println("父类名称:" + c1.getName());
}
}
获取类对象
【示例】
package com.java.classObject;
public class Student1 {
private String name;
private int age;
}
class Student1Test {
public static void main(String[] args) throws Exception {
// 1、Class类中的一个静态方法: forName(全限名:包名+类名)
Class c0 = Class.forName("com.java.classObject.Student1");
System.out.println(c0);//Student1.class
// 2、类名.class
Class c1 = Student1.class;
System.out.println(c1);
// 3、对象.getClass()获取对象对应类的Class对象
Student1 s = new Student1();
Class c2 = s.getClass();
System.out.println(c2);
// 4、类装载器获取
// 获取类加载器对象(获取的是 系统类加载器/应用类加载器 )
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
// jdk.internal.loader.ClassLoaders$AppClassLoader@36baf30c
// 这个类加载器是负责加载 classpath 中的字节码文件的。
// 加载类:但是这个加载过程只是将类加载过程中的前两步完成了,第三步的初始化没做。
// 什么时候做初始化?在这个类真正的被第一次使用的时候。
Class<?> aClass = systemClassLoader.loadClass("com.java.classObject.Student1");
System.out.println(aClass.newInstance());
}
}
16.2.5、Constructor构造方法
构造函数反射类
要取得一个类的全部构造方法,必须使用Class类中的getConstructors()方法
-
Constructor<?>[] getConstructors()
获取所有构造器对象的数组(只能拿public的)
-
Constructor<?>[] getDeclaredConstructors()
获取所有构造器对象(存在就能拿到)
-
Constructor<?> getConstructor(Class<?>…parameterTypes)
获取单个构造器对象(只能拿public的)
-
Constructor<?> getDeclaredConstructors(Class<?>…parameterTypes)
获取单个构造器对象(存在就能拿到)
-
newInstance(Object[] initargs)
可以创建一个对象类的实例,相当于new关键字。
-
newInstance(Object… initargs)
创建一个对象类的实例,相当于new关键字
16.2.5.1、获取构造器
(1)、getConstructors()示例
【示例】
package com.java.constructor;
import java.lang.reflect.Constructor;
public class Student2 {
private String name;
private int age;
public Student2() {
System.out.println("无参构造函数");
}
public Student2(String name, int age) {
System.out.println("有参构造函数");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student2{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class Student2Test {
/*
* 1、getConstructors():获取全部的构造器,只能获取public修饰的构造器
*
* @param args
* @throws ClassNotFoundException
*/
public static void main(String[] args) {
//获取类对象
Class c = Student2.class;
//提取类中的全部的构造器对象
Constructor[] constructors = c.getConstructors();
//遍历构造器
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
}
}
}
(2)、getDeclaredConstructors()
【示例】
package com.java.constructor;
import java.lang.reflect.Constructor;
public class Student3 {
private String name;
private int age;
public Student3() {
System.out.println("无参构造函数");
}
public Student3(String name, int age) {
System.out.println("有参构造函数");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student3{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class Student3Test {
/*
* 2、获取全部的构造器,只要你敢写,这里就能获取,无所谓权限是否可及
* getDeclareConstructors()
*
* @param args
*/
public static void main(String[] args) {
//获取类对象
Class c = Student3.class;
//提取类中的全部的构造器对象
Constructor[] constructors = c.getDeclaredConstructors();
//遍历构造器
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
}
}
}
(3)、getConstructor(Class<?>…parameterTypes)
【示例】
package com.java.constructor;
import java.lang.reflect.Constructor;
public class Student4 {
private String name;
private int age;
public Student4() {
System.out.println("无参构造函数");
}
public Student4(String name, int age) {
System.out.println("有参构造函数");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student4{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class Student4Test {
/*
* 3、根据参数获取某个构造器,只能拿public修饰的某个构造器
* getConstructor(Class... parameterTypes)
*/
public static void main(String[] args) throws NoSuchMethodException {
//获取类对象
Class c = Student4.class;
//定位单个构造器对象
Constructor constructor = c.getConstructor(String.class, int.class);
//遍历构造器
System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
}
}
(4)、getDeclaredConstructors(Class<?>…parameterTypes)
【示例】
package com.java.constructor;
import java.lang.reflect.Constructor;
public class Student5 {
private String name;
private int age;
public Student5() {
System.out.println("无参构造函数");
}
public Student5(String name, int age) {
System.out.println("有参构造函数");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student5{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class Student5Test {
/*
* 4、根据参数获取某个构造器,只要你敢写这里就能获取
* getConstructor(Class... parameterTypes)
*/
public static void main(String[] args) throws NoSuchMethodException {
//获取类对象
Class c = Student5.class;
//定位单个构造器对象
Constructor constructor = c.getDeclaredConstructor(String.class, int.class);
//遍历构造器
System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
}
}
16.2.5.2、实例化对象
通过反射机制获取Constructor
Constructor constructor2 = clazz.getDeclaredConstructor(paramTypes);
通过Constructor创建对象
Class clazz = MyClass.class;
Constructor constructor = clazz.getDeclaredConstructor(paramTypes);
Object[] args = {arg1, arg2, arg3};
Object myObject = constructor.newInstance(args);
(1)、通过无参构造实例化对象
如果想要通过class类本身实例化其他类的对象,则可以使用newInstance()方法,但是必须要保证被实例化的类中存在一个无参构造方法
该方法在JDK9中被废弃了
【示例】
package com.java.constructor;
public class Animal0 {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "名字:" + this.name + "年龄:" + this.age;
}
}
class Animal0Test {
public static void main(String args[]) throws ClassNotFoundException {
Class<?> c = null;
try {
c = Class.forName("com.java.constructor.Animal0");
} catch (ClassCastException e) {
e.printStackTrace();
}
Animal0 per = null;
try {
per = (Animal0) c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
per.setAge(3);
per.setName("小狗");
System.out.println(per);
}
}
(2)、调用有参构造实例化对象
- 通过class类中的getConstructors()取得本类中的全部构造方法
- 向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数
- 之后通过Constructor实例化对象
在这里使用Constructor类表示的是构造方法
此类常用的方法
-
public native int getModifiers();
得到构造方法的修饰符
-
public String getName() {}
得到构造方法的名称
-
public String toString() {}
返回此构造方法的信息
【示例】
package com.java.constructor;
import java.lang.reflect.Constructor;
public class Animal1 {
private String name;
private int age;
public Animal1(String name, int age) {
this.setName(name);
this.setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "名字:" + this.name + "年龄:" + this.age;
}
}
class Animal1Test {
public static void main(String args[]) throws ClassNotFoundException {
Class<?> c = null;
try {
c = Class.forName("com.java.constructor.Animal1");
} catch (ClassCastException e) {
e.printStackTrace();
}
Animal1 per = null;
Constructor<?> cons[] = null;
cons = c.getConstructors();
try {
per = (Animal1) cons[0].newInstance("绵羊", 2);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(per);
}
}
16.2.5.3、综合示例
通过反射机制获取一个类中所有的构造方法
package com.java.constructor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
/**
* className:ConsZengHeTest01
* dateTime:2025/2/5 9:01
* author: 龙弟弟
* description:通过反射机制获取一个类中所有的构造方法
*/
public class ConsZengHeTest01 {
public static void main(String[] args) throws Exception {
StringBuilder sb = new StringBuilder();
// 获取类
Class clazz = Class.forName("java.lang.String");
// 类的修饰符
sb.append(Modifier.toString(clazz.getModifiers()));
sb.append(" class ");
// 类名
sb.append(clazz.getName());
sb.append(" extends ");
// 父类名
sb.append(clazz.getSuperclass().getName());
// 实现的接口
Class[] interfaces = clazz.getInterfaces();
if (interfaces.length > 0) {
sb.append(" implements ");
for (int i = 0; i < interfaces.length; i++) {
sb.append(interfaces[i].getName());
if (i != interfaces.length - 1) {
sb.append(",");
}
}
}
sb.append("{\n");
//类体
// 获取所有的构造方法
Constructor[] cons = clazz.getDeclaredConstructors();
// 遍历所有的构造方法
for (Constructor con : cons) {
sb.append("\t");
// 构造方法修饰符
sb.append(Modifier.toString(con.getModifiers()));
sb.append(" ");
// 构造方法名
sb.append(con.getName());
sb.append("(");
// 构造方法参数列表
Parameter[] parameters = con.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
sb.append(parameter.getType().getName());
sb.append(" ");
sb.append(parameter.getName());
if (i != parameters.length - 1) {
sb.append(",");
}
}
sb.append("){}\n");
}
sb.append("}");
System.out.println(sb);
}
}
16.2.6、Method成员方法类
方法的反射类
要取得一个类中的全部方法,可以使用class类中的getMethod()方法此方法返回一个Method类的对象数组
Method类的常用方法
-
获取方法相关信息
-
Annotation[] getAnnotations ()
获取方法的注解信息
-
public int getModifiers() {}
取得本方法的访问修饰符
修饰符是一个整数,不同的数字代表不同的修饰符
-
Class getReturnType()
获取方法的返回值类型
-
public String getName() {}
取得方法的名称
-
Class[] getParameterTypes()
获取方法的入参类型数组
只能获取参数类型
-
Parameter[] getParameters()
获取所有的参数
包括参数类型和参数名称
-
Class[] getExceptionTypes()
获取方法的异常类型数组
-
-
获取方法
-
Method[] getMethods()
返回所有成员方法对象数组(只能拿public的)
-
Method[] getDeclaredMethods()
返回所有成员方法对象数组(存在就能拿到)
-
Method getMethod(String name,Class<?>… parameterTypes)
返回单个成员方法对象(只能拿public的)
name为方法名
parameterTypes为方法参数
-
Method getDeclaredMethod(String name,Class<?>… parameterTypes)
返回单个成员方法对象(存在就能拿到)
name为方法名
parameterTypes为方法参数
-
-
调用方法
-
Object method.invoke(Object obj,Object[] args)
执行目标方法
method表示要执行的方法
obj 表示操作的目标对象
args为方法入参
-
Object method.invoke(Object obj,Object… args)
执行目标方法
method表示要执行的方法
obj 表示操作的目标对象
args为方法入参
-
16.2.6.1、获取方法信息
-
Annotation[] getAnnotations ()
获取方法的注解信息
-
public int getModifiers() {}
取得本方法的访问修饰符
修饰符是一个整数,不同的数字代表不同的修饰符
-
Class getReturnType()
获取方法的返回值类型
-
public String getName() {}
取得方法的名称
-
Class[] getParameterTypes()
获取方法的入参类型数组
只能获取参数类型
-
Parameter[] getParameters()
获取所有的参数
包括参数类型和参数名称
-
Class[] getExceptionTypes()
获取方法的异常类型数组
【示例】
package com.java.method;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
public class Dog {
private String name;
public Dog() {
System.out.println("无参构造方法");
}
public Dog(String name) {
System.out.println("有参构造方法");
this.name = name;
}
@Deprecated
public void run() {
System.out.println("狗跑的贼快");
}
@Deprecated
public void eat() {
System.out.println("狗吃骨头");
}
@Deprecated
public String eat(String name) {
System.out.println("狗吃" + name);
return "吃的很开心";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class DogTest {
/*
* 获取类中的所有成员方法
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//获取类对象
Class c = Dog.class;
// 获取所有的方法,包含私有的方法
Method[] methods = c.getDeclaredMethods();
//遍历
for (Method method : methods) {
// 方法的注解
Annotation[] annotationsTypes = method.getAnnotations();
for (Annotation annotationsType : annotationsTypes) {
System.out.println("方法的注解:" + annotationsType.annotationType());
}
// 方法修饰符
// 修饰符是一个整数,不同的数字代表不同的修饰符
System.out.println("方法的修饰符:" + Modifier.toString(method.getModifiers()));
// 方法返回值类型
System.out.println("方法的返回值类型:" + method.getReturnType().getName());
// 方法名
System.out.println("方法的名称:" + method.getName());
// 方法的参数列表
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class parameterType : parameterTypes) {
System.out.println("方法的参数类型列表:" + parameterType.getName());
}
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
System.out.println("方法的参数类型:" + parameter.getType().getName());
System.out.println("方法的参数名:" + parameter.getName());// arg0, arg1, arg2......
}
System.out.println(method.getName() + "==>" + method.getParameterCount());
//方法异常
Class<?>[] exceptionTypes = method.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {
System.out.println("方法的异常:" + exceptionType.getName());
}
System.out.println("=========================");
}
}
}
16.2.6.1、获取方法
-
Method[] getMethods()
返回所有成员方法对象数组(只能拿public的)
-
Method[] getDeclaredMethods()
返回所有成员方法对象数组(存在就能拿到)
-
Method getMethod(String name,Class<?>… parameterTypes)
返回单个成员方法对象(只能拿public的)
name为方法名
parameterTypes为方法参数
-
Method getDeclaredMethod(String name,Class<?>… parameterTypes)
返回单个成员方法对象(存在就能拿到)
name为方法名
parameterTypes为方法参数
(1)、获取全部方法
【示例】
package com.java.method;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
public class Dog {
private String name;
public Dog() {
System.out.println("无参构造方法");
}
public Dog(String name) {
System.out.println("有参构造方法");
this.name = name;
}
@Deprecated
public void run() {
System.out.println("狗跑的贼快");
}
@Deprecated
public void eat() {
System.out.println("狗吃骨头");
}
@Deprecated
public String eat(String name) {
System.out.println("狗吃" + name);
return "吃的很开心";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class DogTest {
/*
* 获取类中的所有成员方法
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//获取类对象
Class c = Dog.class;
// 获取所有的方法,包含私有的方法
Method[] methods = c.getDeclaredMethods();
//遍历
for (Method method : methods) {
// 方法的注解
Annotation[] annotationsTypes = method.getAnnotations();
for (Annotation annotationsType : annotationsTypes) {
System.out.println("方法的注解:" + annotationsType.annotationType());
}
// 方法修饰符
// 修饰符是一个整数,不同的数字代表不同的修饰符
System.out.println("方法的修饰符:" + Modifier.toString(method.getModifiers()));
// 方法返回值类型
System.out.println("方法的返回值类型:" + method.getReturnType().getName());
// 方法名
System.out.println("方法的名称:" + method.getName());
// 方法的参数列表
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class parameterType : parameterTypes) {
System.out.println("方法的参数类型列表:" + parameterType.getName());
}
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
System.out.println("方法的参数类型:" + parameter.getType().getName());
System.out.println("方法的参数名:" + parameter.getName());// arg0, arg1, arg2......
}
System.out.println(method.getName() + "==>" + method.getParameterCount());
//方法异常
Class<?>[] exceptionTypes = method.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {
System.out.println("方法的异常:" + exceptionType.getName());
}
System.out.println("=========================");
}
}
}
(2)、获取指定方法
根据方法名和参数列表获取指定方
【示例】
package com.java.method;
import java.lang.reflect.Method;
public class Cat {
public void eat() {
System.out.println("猫吃鱼");
}
public String eat(String name) {
System.out.println("猫吃" + name);
return "吃的很开心";
}
}
class CatTest {
/**
* 获取单个方法
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//获取类对象
Class c = Cat.class;
//提取单个方法对象
Method method1 = c.getDeclaredMethod("eat");//不带参数的方法
Method method2 = c.getDeclaredMethod("eat", String.class);//带参数的方法
//打开权限
method1.setAccessible(true);
Cat cat1 = new Cat();
//触发方法执行
Object result1 = method1.invoke(cat1);
//如果方法没有返回值,那么返回null
System.out.println(result1);
Cat cat2 = new Cat();
//触发方法执行
Object result2 = method2.invoke(cat2, "鱼");
//如果方法没有返回值,那么返回null
System.out.println(result2);
}
}
16.2.6.3、反射调用方法
调用一个方法需要四要素:调用哪个对象的哪个方法、传什么参数、返回什么值
-
Object method.invoke(Object obj,Object[] args)
执行目标方法
- method表示要执行的方法
- obj 表示操作的目标对象
- args为方法入参
-
Object method.invoke(Object obj,Object… args)
执行目标方法
- method表示要执行的方法
- obj 表示操作的目标对象
- args为方法入参
通过反射机制获取Method
Method method = clazz.getDeclaredMethod(“methodName”, paramTypes);
通过Method调用方法
Class clazz = MyClass.class;
Method method = clazz.getDeclaredMethod(“methodName”, paramTypes);
Object[] args = {arg1, arg2, arg3};
Object result = method.invoke(myObject, args);
(1)、方法调用要素
不使用反射机制调用一个方法需要几个要素的参与
【示例】
package com.java.method;
public class SystemService {
public void logout() {
System.out.println("退出系统");
}
public boolean login(String username, String password) {
if ("admin".equals(username) && "admin123".equals(password)) {
return true;
}
return false;
}
}
class SystemServiceTest {
public static void main(String[] args) {
// 创建对象
SystemService systemService = new SystemService();
// 调用方法并接收方法的返回值
boolean success = systemService.login("admin", "admin123");
System.out.println(success ? "登录成功" : "登录失败");
}
}
通过以上代码可以看出调用一个方法一般涉及到4个要素:
-
调用哪个对象的(systemService)
-
哪个方法(login)
-
传什么参数(“admin”, “admin123”)
-
返回什么值(success)
(2)、获取方法
要使用反射机制调用一个方法首先要获取到这个方法
在反射机制中Method实例代表的是一个方法
有这样一个类
package com.java.method;
public class SystemService1 {
public void logout() {
System.out.println("退出系统");
}
public boolean login(String username, String password) {
if ("admin".equals(username) && "admin123".equals(password)) {
return true;
}
return false;
}
public boolean login(String password) {
if ("110".equals(password)) {
return true;
}
return false;
}
}
class SystemService1Test {
public static void main(String[] args) {
// 创建对象
SystemService1 systemService1 = new SystemService1();
// 调用方法并接收方法的返回值
boolean success = systemService1.login("admin", "admin123");
System.out.println(success ? "登录成功" : "登录失败");
}
}
要获取方法Method,首先需要获取这个类Class
获取类Class的代码
Class clazz = Class.forName("com.java.method.SystemService1");
当拿到Class之后,调用getDeclaredMethod()方法可以获取到方法
获取login(String username, String password)
Method loginMethod = clazz.getDeclaredMethod("login", String.class, String.class);
获取login(String password)
Method loginMethod = clazz.getDeclaredMethod("login", String.class);
获取一个方法需要告诉Java程序你要获取的方法的名字是什么,这个方法上每个形参的类型是什么,这样Java程序才能给你拿到对应的方法
这样的设计也非常合理,因为在同一个类当中,方法是支持重载的,也就是说方法名可以一样,但参数列表一定是不一样的,所以获取一个方法需要提供方法名以及每个形参的类型。
假设有这样一个方法
public void setAge(int age){
this.age = age;
}
要获取这个方法的话,代码应该这样写
Method setAgeMethod = clazz.getDeclaredMethod("setAge", int.class);
其中setAge是方法名,int.class是形参的类型
如果要获取上面的logout方法,代码应该这样写
Method logoutMethod = clazz.getDeclaredMethod("logout");
因为这个方法形式参数的个数是0个,所以只需要提供方法名就行了
(3)、调用方法
要让一个方法调用的话,就关联到四要素了
-
调用哪个对象的
-
哪个方法
-
传什么参数
-
返回什么值
【示例】
package com.java.method;
import java.lang.reflect.Method;
public class SystemService2 {
public void logout() {
System.out.println("退出系统");
}
public boolean login(String username, String password) {
if ("admin".equals(username) && "admin123".equals(password)) {
return true;
}
return false;
}
public boolean login(String password) {
if ("110".equals(password)) {
return true;
}
return false;
}
}
class SystemService2Test {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.java.method.SystemService2");
Object obj = clazz.newInstance();
Method loginMethod = clazz.getDeclaredMethod("login", String.class, String.class);
Object retValue = loginMethod.invoke(obj, "admin", "admin123");
System.out.println(retValue);
}
}
假如要调用的方法是:login(String, String)
-
第一步:创建对象(四要素之首"调用哪个对象的")
Class clazz = Class.forName("com.java.SystemService2"); Object obj = clazz.newInstance();
-
第二步:获取方法login(String,String)(四要素之二"哪个方法")
Method loginMethod = clazz.getDeclaredMethod("login", String.class, String.class);
第三步:调用方法
-
Method对象的invoke()方法可以调用方法
Object retValue = loginMethod.invoke(obj, "admin", "admin123");
解说四要素
-
哪个对象:obj
-
哪个方法:loginMethod
-
传什么参数:“admin”, “admin123”
-
返回什么值:retValue
16.2.6.4、综合示例
package com.java.method;
import java.beans.JavaBean;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
/**
* className:MethodZongHeTest01
* dateTime:2025/2/5 10:03
* author: 龙弟弟
* description:反射一个类中所有的方法,然后进行拼接字符串。
*/
public class MethodZongHeTest01 {
public static void main(String[] args) throws Exception {
StringBuilder sb = new StringBuilder();
Class stringClass = Class.forName("com.java.method.LoginService");
// 类的注解
Annotation[] annotations = stringClass.getAnnotations();
if (annotations != null && annotations.length > 0) {
for (Annotation anno : annotations) {
sb.append(anno);
sb.append("\n");
}
}
// 获取类的修饰符
sb.append(Modifier.toString(stringClass.getModifiers()));
sb.append(" class ");
// 获取类名
sb.append(stringClass.getName());
// 获取父类名
sb.append(" extends ");
sb.append(stringClass.getSuperclass().getName());
// 获取父接口名
Class[] interfaces = stringClass.getInterfaces();
if (interfaces.length > 0) {
sb.append(" implements ");
for (int i = 0; i < interfaces.length; i++) {
sb.append(interfaces[i].getName());
if (i != interfaces.length - 1) {
sb.append(",");
}
}
}
sb.append("{\n");
// 类体
// 获取所有的方法
Method[] methods = stringClass.getDeclaredMethods();
for (Method method : methods) {
sb.append("\t");
// 追加修饰符
sb.append(Modifier.toString(method.getModifiers()));
// 追加返回值类型
sb.append(" ");
sb.append(method.getReturnType().getName());
// 追加方法名
sb.append(" ");
sb.append(method.getName());
sb.append("(");
// 追加参数列表
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
sb.append(parameter.getType().getName());
sb.append(" ");
sb.append(parameter.getName());
if (i != parameters.length - 1) {
sb.append(",");
}
}
Class<?> ex[] = method.getExceptionTypes();//异常列表
if (ex.length > 0) {
sb.append(" )throws ");
} else {
sb.append(" ) ");
}
for (int j = 0; j < ex.length; j++) {
sb.append(ex[j].getName());
if (j < ex.length - 1) {
sb.append(" , ");
}
System.out.println();
}
sb.append("{}\n");
}
sb.append("\n}\n");
// 输出
System.out.println(sb);
}
}
@Deprecated
@JavaBean
final class LoginService {
/**
* 登录系统的方法
*
* @param username 用户名
* @param password 密码
* @return true表示登录成功,false表示失败
*/
@Deprecated
public boolean login(String username, String password) throws IOException, NullPointerException {
return "admin".equals(username) && "123456".equals(password);
}
/**
* 退出系统的方法
*/
@Deprecated
public void logout() {
System.out.println("系统已安全退出!");
}
}
16.2.7、Field成员变量类
成员变量的反射类
-
Field[] getFields()
返回所有成员变量对象的数组(只能拿public的)
-
Field[] getDeclaredFields()
返回所有成员变量对象的数组(存在就能拿)
-
Field getField(String name)
返回单个成员变量对象(只能拿public的)
-
Field getDeclaredField(String name)
返回单个成员变量对象(存在就能拿)
-
public int getModifiers() {}
得到此属性的修饰符
-
Class<?> getType()
获取属性类型
-
public String getName() {}
获取此属性的名称
-
public Object get(Object obj){}
得到一个对象中属性的具体内容
-
public void set(Object obj, Object value){}
为Obj目标类对象的属性赋值为value
- obj表示操作的目标对象
- value为目标对象的成员变量设置值
如果成员变量为基础类型,则可以使用Field类中提供的带类型名的值设置方法
如 setBoolean(Object obj,boolean value)、setInt(Object obj,int value)等
-
public void setAccessible(boolean flag) {}
设置属性是否可以被外界访问到
-
public String toString() {}
返回此Field类的信息
16.2.7.1、获取属性信息
-
public int getModifiers() {}
得到此属性的修饰符
-
Class<?> getType()
获取属性类型
-
public String getName() {}
获取此属性的名称
package com.java.field;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
interface Ball {
public String length = "100";
}
public class China {
public String NATION = "China";
}
class People extends China implements Ball {
public String name;
private int age;
}
/*
关于反射机制中的 java.lang.reflect.Field(代表的是一个类中的字段/属性)
*/
class Demo {
public static void main(String args[]) throws ClassNotFoundException {
Class<?> c = null;
try {
c = Class.forName("com.java.field.People");
} catch (ClassCastException e) {
e.printStackTrace();
}
/*
可以拿到本类所有的属性(父类及接口中的属性拿不到)
*/
/*Field field1[] = c.getDeclaredFields();
for (int i = 0; i < field1.length; i++) {
Class<?> parameterType = field1[i].getType();
int mo = field1[i].getModifiers();
String priv = Modifier.toString(mo);
System.out.println("本类属性");
System.out.println("访问控制修饰符:" + priv + "");
System.out.println("参数类型:" + parameterType.getName() + "");
System.out.println("方法名:" + field1[i].getName());
System.out.println(";");
}
System.out.println("------------------");*/
/*
只能拿到public的属性(父类及接口中的属性可以拿到,但是也只能获取public的)
*/
Field fields2[] = c.getFields();
for (Field field : fields2) {
System.out.println("父类属性");
// 获取属性的修饰符
int mo2 = field.getModifiers();
String priv2 = Modifier.toString(mo2);
System.out.println("访问控制修饰符:" + priv2 + "");
// 获取属性类型
Class<?> parameterType2 = field.getType();
System.out.println("属性类型:" + parameterType2.getName() + "");
System.out.println("属性简单类型:" + parameterType2.getSimpleName() + "");
// 获取属性名
System.out.println("属性名:" + field.getName());
System.out.println(";");
}
}
}
16.2.7.2、获取属性
-
Field[] getFields()
返回所有成员变量对象的数组(只能拿public的)
-
Field[] getDeclaredFields()
返回所有成员变量对象的数组(存在就能拿)
-
Field getField(String name)
返回单个成员变量对象(只能拿public的)
-
Field getDeclaredField(String name)
返回单个成员变量对象(存在就能拿)
【示例】
package com.java.field;
import java.lang.reflect.Field;
public class Person {
private String name;
private int age;
private static String schoolName;
private static final String COUNTRY = "中国";
}
class PersonTest {
public static void main(String[] args) throws Exception {
//获取类对象
Class c = Person.class;
/*
* 1、getDeclaredFields():获取全部的成员变量
* 获得所有的成员变量对应的Field对象,只要声明了就可以得到
*/
//定位全部成员呢变量
Field[] fields = c.getDeclaredFields();
//遍历
for (Field field : fields) {
System.out.println(field.getName() + "===>" + field.getType());
}
System.out.println("=======================");
/*
* 2、getDeclaredFields(String name):获取指定的成员变量
*/
//根据名称定为某个成员变量对象
Field fieldSingle = c.getDeclaredField("age");
System.out.println(fieldSingle.getName() + "===>" + fieldSingle.getType());
}
}
16.2.7.3、访问属性
一方面通过反射机制获取Field
Field field = clazz.getDeclaredField(“fieldName”); // 通过属性名获取
Field[] fields = clazz.getDeclaredFields(); // 获取所有的属性,包括私有的
另一方面通过Filed访问对象的属性
Object fieldValue = field.get(myObject); // 读取某个对象的属性值
field.set(myObject, newValue); // 修改某个对象的属性值
package com.java.field;
import java.lang.reflect.Field;
/**
* className:FieldAccessTest01
* dateTime:2025/2/5 11:33
* author: 龙弟弟
* description:通过反射机制如何访问Field,如何给属性赋值,如何读取属性的值。
*/
public class FieldAccessTest01 {
public static void main(String[] args) throws Exception {
// 如果不使用反射机制,怎么访问对象的属性
Customer customer = new Customer();
// 修改属性的值(set动作)
// customer要素一
// name要素二
// "张三"要素三
customer.name = "张三";
// 读取属性的值(get动作)
// 读取哪个对象的哪个属性
System.out.println(customer.name);
// 使用反射机制访问对象的属性
// 获取类
Class clazz = Class.forName("com.java.field.Customer");
// 获取对应的Field
Field ageField = clazz.getDeclaredField("age");
// 调用方法打破封装
ageField.setAccessible(true);
// 修改属性的值
// 给对象属性赋值三要素:给哪个对象 的 哪个属性 赋什么值
ageField.set(customer, 30);
// 读取属性的值
System.out.println("年龄:" + ageField.get(customer));
// 通过反射机制给name属性赋值,和读取name属性的值
Field nameField = clazz.getDeclaredField("name");
// 修改属性name的值
nameField.set(customer, "李四");
// 读取属性name的值
System.out.println(nameField.get(customer));
}
}
class Customer {
public String name;
private int age;
}
16.2.7.4、综合示例
package com.java.field;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* className:FieldZongHeTest01
* dateTime:2025/2/5 11:36
* author: 龙弟弟
* description:反编译类中所有的属性
*/
public class FieldZongHeTest01 {
public static void main(String[] args) throws Exception {
// 获取String类
Class stringClass = Class.forName("com.java.field.Vip");
// 字符串拼接
StringBuilder sb = new StringBuilder();
// 获取类的修饰符
sb.append(Modifier.toString(stringClass.getModifiers()));
sb.append(" class ");
//sb.append(stringClass.getSimpleName());
sb.append(stringClass.getName());
sb.append(" extends ");
// 获取当前类的父类
sb.append(stringClass.getSuperclass().getName());
// 获取当前类的实现的所有接口
Class[] interfaces = stringClass.getInterfaces();
if (interfaces.length > 0) {
sb.append(" implements ");
for (int i = 0; i < interfaces.length; i++) {
Class interfaceClass = interfaces[i];
sb.append(interfaceClass.getName());
if (i != interfaces.length - 1) {
sb.append(",");
}
}
}
sb.append("{\n");
// 获取所有属性
Field[] fields = stringClass.getDeclaredFields();
for (Field field : fields) {
sb.append("\t");
sb.append(Modifier.toString(field.getModifiers()));
sb.append(" ");
sb.append(field.getType().getName());
sb.append(" ");
sb.append(field.getName());
sb.append(";\n");
}
sb.append("}");
// 输出
System.out.println(sb);
}
}
class Vip {
// Field
public String name;
private int age;
protected String birth;
boolean gender;
public static String address = "北京海淀";
public static final String GRADE = "金牌";
}
16.2.8、Type泛型
(1)、获取父类泛型
package com.java.fanxing.generic01;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* 获取父类的泛型信息
*/
public class Test {
public static void main(String[] args) {
// 获取类
Class<Cat> catClass = Cat.class;
// 获取当前类的父类泛型
Type genericSuperclass = catClass.getGenericSuperclass();
System.out.println(genericSuperclass instanceof Class);// 泛型不是类
System.out.println(genericSuperclass instanceof ParameterizedType);// 泛型是一种类型
// 如果父类使用了泛型
if (genericSuperclass instanceof ParameterizedType) {
// 转型为参数化类型
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
// 获取泛型数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
// 遍历泛型数组
for (Type a : actualTypeArguments) {
// 获取泛型的具体类型名
System.out.println(a.getTypeName());
}
}
}
}
/**
* 在类上定义泛型
*
* @param <X>
* @param <Y>
* @param <Z>
*/
class Animal<X, Y, Z> {
}
class Cat extends Animal<String, Integer, Double> {
}
(2)、获取接口上的泛型
package com.java.fanxing.generic02;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/*
获取接口上的泛型
*/
public class Test {
public static void main(String[] args) {
Class<Mouse> mouseClass = Mouse.class;
// 获取接口上的泛型
Type[] genericInterfaces = mouseClass.getGenericInterfaces();
for (Type g : genericInterfaces) {
// 使用了泛型
if (g instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) g;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type a : actualTypeArguments) {
System.out.println(a.getTypeName());
}
}
}
}
}
interface Flyable<X, Y> {
}
class Mouse implements Flyable<String, Integer>, Comparable<Mouse> {
@Override
public int compareTo(Mouse o) {
return 0;
}
}
(3)、获取属性泛型
package com.java.fanxing.generic03;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception {
// 获取这个类
Class<User> userClass = User.class;
// 获取属性上的泛型,需要先获取到属性
Field mapField = userClass.getDeclaredField("map"); // 获取公开的以及私有的
// 获取这个属性上的泛型
Type genericType = mapField.getGenericType();
// 用泛型了
if (genericType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericType;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type a : actualTypeArguments) {
System.out.println(a.getTypeName());
}
}
}
}
class User {
private Map<Integer, String> map;
}
(4)、获取方法参数泛型
package com.java.fanxing.generic04;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
/**
* 获取方法参数上的泛型信息
*/
public class Test {
public static void main(String[] args) throws Exception {
// 获取类
Class<MyClass> myClassClass = MyClass.class;
// 获取方法
Method mMethod = myClassClass.getDeclaredMethod("m", List.class, List.class);
// 获取方法参数上的泛型
Type[] genericParameterTypes = mMethod.getGenericParameterTypes();
for (Type g : genericParameterTypes) {
// 如果这个参数使用了泛型
if (g instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) g;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type a : actualTypeArguments) {
System.out.println(a.getTypeName());
}
}
}
// 获取方法返回值上的泛型
Type genericReturnType = mMethod.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type a : actualTypeArguments) {
System.out.println(a.getTypeName());
}
}
}
}
class MyClass {
public Map<Integer, Integer> m(List<String> list, List<Integer> list2) {
return null;
}
}
(5)、获取构造方法参数泛型
package com.java.fanxing.generic05;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
/**
* 获取构造方法参数的泛型
*/
public class Test {
public static void main(String[] args) throws Exception {
Class<User> userClass = User.class;
Constructor<User> con = userClass.getDeclaredConstructor(Map.class);
Type[] genericParameterTypes = con.getGenericParameterTypes();
for (Type g : genericParameterTypes) {
if (g instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) g;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type a : actualTypeArguments) {
System.out.println(a.getTypeName());
}
}
}
}
}
class User {
public User(Map<String, Integer> map) {
}
}
3、反射的作用
-
运行时得到一个类的全部成分然后操作
-
破坏封装性,即暴力打开权限
-
破坏泛型的约束性
-
做java的高级框架
(1)、泛型擦除
反射是作用在运行时的技术,此时集合的泛型将不再产生作用,此时是可以为集合中存入其它任意类型元素的
泛型只是在编译阶段可以约束集合中只能操作某种数据类型,在编译成class文件进入运行阶段的时候,其真实类型都是ArrayList了,泛型相当于被擦除了
【示例】
package com.java.use;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class FanXingCaChuTest {
/**
* 反射实现泛型擦除后,放入其它类型元素
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
ArrayList<String> list1 = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
System.out.println(list1.getClass());
System.out.println(list2.getClass());
System.out.println(list1.getClass() == list2.getClass());
System.out.println("-------------");
ArrayList<Integer> list3 = new ArrayList<>();
list3.add(23);
list3.add(22);
Class c = list3.getClass();
Method add = c.getDeclaredMethod("add", Object.class);
boolean rs = (boolean) add.invoke(list3, "北京");
System.out.println(rs);
System.out.println(list3);
}
}
(2)、绕过安全机制
Java 的反射体系保证了可以通过程序化的方式访问目标类中所有的元素,对于private或protected成员变量和方法,只要JVM的安全机制允许,也可以通过反射进行调用
【示例】
package com.java.use;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class PrivateCarReflect {
public static void main(String[] args) throws Throwable {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class clazz = loader.loadClass("com.java.use.PrivateCar");
PrivateCar pcar = (PrivateCar) clazz.newInstance();
Field colorFld = clazz.getDeclaredField("color");
//1、取消Java 语言访问检查以访问'private变量
colorFld.setAccessible(true);
colorFld.set(pcar, "红色");
Method driveMtd = clazz.getDeclaredMethod("drive", (Class[]) null);
//2、取消Java 语言访问检查以访问'protected方法
driveMtd.setAccessible(true);
driveMtd.invoke(pcar, (Object[]) null);
}
}
class PrivateCar {
private String color;
protected void drive() {
System.out.println("drive private car! the color is:" + color);
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "PrivateCar{" +
"color='" + color + '\'' +
'}';
}
}
color 变量和 drive()方法都是私有的,通过类实例变量无法在外部访问私有变量、调用私有方法,但通过反射机制则可以绕过这个限制
运行该类,打印出以下信息
在访问 private 或protected成员变量和方法时,必须通过 setAccessible(boolean access)方法取消Java语言检查,否则将抛出IllegalAccessException。如果JVM的安全管理器设置了相应的安全机制,那么调用该方法将抛出SecurityException()
(3)、通用框架的底层原理
案例1
package com.java.use;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ResourceBundle;
/**
* className:ReflectTest01
* dateTime:2025/2/5 12:37
* author: 龙弟弟
* description:模拟框架的部分代码。通过读取属性配置文件,获取类信息,方法信息,然后通过反射机制调用方法。
*/
public class ReflectTest01 {
public static void main(String[] args) throws Exception {
// 读取属性配置文件
ResourceBundle bundle = ResourceBundle.getBundle("com.java.use.config");
String className = bundle.getString("className");
String methodName = bundle.getString("methodName");
String parameterTypes = bundle.getString("parameterTypes");
String parameterValues = bundle.getString("parameterValues");
// 通过反射机制调用方法
// 创建对象(依赖无参数构造方法)
Class<?> clazz = Class.forName(className);
Constructor<?> defaultCon = clazz.getDeclaredConstructor();
Object obj = defaultCon.newInstance();
// 获取方法
// java.lang.String,java.lang.String
String[] strParameterTypes = parameterTypes.split(",");
Class[] classParameterTypes = new Class[strParameterTypes.length];
for (int i = 0; i < strParameterTypes.length; i++) {
classParameterTypes[i] = Class.forName(strParameterTypes[i]);
}
Method method = clazz.getDeclaredMethod(methodName, classParameterTypes);
// 调用方法
// parameterValues=admin,123456
Object retValue = method.invoke(obj, parameterValues.split(","));
System.out.println(retValue);
}
}
案例2
【示例】
package com.java.use;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
/**
* className:ReflectTest02
* dateTime:2025/2/5 12:44
* author: 龙弟弟
* description:
*/
public class ReflectTest02 {
public static void main(String[] args) throws Exception {
Student student10 = new Student();
student10.setName("猪八戒");
student10.setAge(1000);
student10.setHobby("吃,睡");
student10.setSex('男');
save(student10);
Teacher teacher10 = new Teacher();
teacher10.setName("波仔");
teacher10.setSex('女');
teacher10.setSalary(1000);
save(teacher10);
}
public static void save(Object obj) throws Exception {
PrintStream ps = new PrintStream(new FileOutputStream("H:\\收藏地址.txt"));
//1、提取这个对象的全部成员变量:只有反射可以做
//c.getSimple()获取当前类名
//c.getName()获取全限名
Class c = obj.getClass();
ps.println("=======" + c.getSimpleName() + "======" + c.getName());
//2、提取它的全部成员变量
Field[] fields = c.getDeclaredFields();
//3、获取成员变量信息
for (Field field : fields) {
String name = field.getName();
//提取本成员变量在obj对象中的值
field.setAccessible(true);
String value = field.get(obj) + "";
ps.println(name + "=" + value);
}
ps.close();
}
}
class Student {
private String name;
private char sex;
private int age;
private String schoolName;
private String hobby;
public Student(String name, char sex, int age, String schoolName, String hobby) {
this.name = name;
this.sex = sex;
this.age = age;
this.schoolName = schoolName;
this.hobby = hobby;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
}
class Teacher {
private String name;
private char sex;
private double salary;
public Teacher() {
}
public Teacher(String name, char sex, double salary) {
this.name = name;
this.sex = sex;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
弟弟
-
description:
*/
public class ReflectTest02 {
public static void main(String[] args) throws Exception {
Student student10 = new Student();
student10.setName(“猪八戒”);
student10.setAge(1000);
student10.setHobby(“吃,睡”);
student10.setSex(‘男’);
save(student10);Teacher teacher10 = new Teacher(); teacher10.setName("波仔"); teacher10.setSex('女'); teacher10.setSalary(1000); save(teacher10);
}
public static void save(Object obj) throws Exception {
PrintStream ps = new PrintStream(new FileOutputStream(“H:\收藏地址.txt”));//1、提取这个对象的全部成员变量:只有反射可以做 //c.getSimple()获取当前类名 //c.getName()获取全限名 Class c = obj.getClass(); ps.println("=======" + c.getSimpleName() + "======" + c.getName()); //2、提取它的全部成员变量 Field[] fields = c.getDeclaredFields(); //3、获取成员变量信息 for (Field field : fields) { String name = field.getName(); //提取本成员变量在obj对象中的值 field.setAccessible(true); String value = field.get(obj) + ""; ps.println(name + "=" + value); } ps.close();
}
}
class Student {
private String name;
private char sex;
private int age;
private String schoolName;
private String hobby;
public Student(String name, char sex, int age, String schoolName, String hobby) {
this.name = name;
this.sex = sex;
this.age = age;
this.schoolName = schoolName;
this.hobby = hobby;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
}
class Teacher {
private String name;
private char sex;
private double salary;
public Teacher() {
}
public Teacher(String name, char sex, double salary) {
this.name = name;
this.sex = sex;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
[外链图片转存中...(img-sVI9YDPI-1739150450443)]