文章目录
概述
- 反射机制的作用
通过java语言的反射机制可以操作字节码文件(.class) - 相关的类
java.lang.Class
代表整个类的字节码
java.lang.reflect.Method
代表类中方法的字节码
java.lang.reflect.Constructor
代表类中构造方法的字节码
java.lang.reflect.Field
代表类中属性的字节码
获取class的三种方式
要操作类的字节码,首先要获取到类的字节码
- Class.forName(String className)
Class类中的静态方法
返回一个Class对象
className是完整的类名带上包名
forName在获取类时会运行类中的静态代码块
package com.wcy.code01;
/**
* Class.forName获取类
*/
public class GetClassTest01 {
public static void main(String[] args) {
Class<?> c1 = null;
Class<?> c2 = null;
try {
//完整的类名加上包名
c1 = Class.forName("com.wcy.code01.GetClassTest01");
c2 = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c1);
System.out.println(c2);
}
}
- obj.getClass()
通过对象来获取类
package com.wcy.code01;
import java.util.Date;
/**
1. obj.getClass()获取类
*/
public class GetClassTest02 {
public static void main(String[] args) {
String s = new String(new char[]{'1', '2', '3'});
Date d = new Date();
Class<?> sc = s.getClass();
Class<?> ds = d.getClass();
System.out.println(sc);
System.out.println(ds);
}
}
- 类型使用class属性
Java中无论什么类型都有class属性
package com.wcy.code01;
/**
* 通过class属性来获取类
*/
public class GetClassTest03 {
public static void main(String[] args) {
Class<String> c1 = String.class;
Class<Integer> c2 = int.class;
Class<GetClassTest03> c3 = GetClassTest03.class;
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
}
}
- 以上三种方式获取的类是一样的
因为只会加载一个类在方法区中,无论通过何种方式获取,获取的都是同样的结果
package com.wcy.code01;
/**
* 三种方法获取的类是一样的
*/
public class GetClassTest04 {
public static void main(String[] args) {
String s = "111";
Class<?> c1 = null;
Class<?> c2 = null;
Class<?> c3 = null;
try {
c1 = Class.forName("java.lang.String");
c2 = s.getClass();
c3 = String.class;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c1 == c2 && c2 == c3 && c1 == c3);
}
}
通过反射机制实例化对象
- newInstance() jdk8后弃用
- 调用该方法会调用类中的无参构造方法来实例化对象
package com.wcy.code01;
public class NewInstanceTest01 {
public static void main(String[] args) {
try {
Class<?> c1 = Class.forName("com.wcy.code01.User");
//使用newInstance实例化对象
Object o = c1.newInstance();
System.out.println(o);
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
}
class User {
public User() {
System.out.println("调用了无参构造方法!");
}
}
使用反射机制实现使用配置文件实例化对象
通过读取配置文件中的内容来实例化对象,这样可以不用更改代码就可以实例化不同的对象。
配置文件中的内容
# 需要实例化的类 只需要更改此处的类名即可
classname=com.wcy.code01.User
package com.wcy.code01;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
/**
* 使用配置文件实例化对象
*/
public class NewInstanceTest02 {
public static void main(String[] args) {
FileReader fileReader = null;
Properties properties = null;
try {
//字符流读取配置文件
fileReader = new FileReader("src/name.properties");
//创建属性类对象map
properties = new Properties();
//加载配置文件
properties.load(fileReader);
} catch (IOException e) {
e.printStackTrace();
}finally {
//关闭配置文件读取
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
if (properties != null) {
//获取配置文件中的类名
String className = properties.getProperty("classname");
try {
//获取类名实例化对象
Class<?> c = Class.forName(className);
Object o = c.newInstance();
System.out.println(o);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
反射机制获取属性
- 基本方法
Field getField(String name) | 返回一个 Field对象,它反映此表示的类或接口的指定公共成员字段 类对象。 |
Field[] getFields() | 返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段 类对象。 |
Field getDeclaredField(String name) | 返回一个 Field对象,它反映此表示的类或接口的指定已声明字段和类对象。 |
Field[] getDeclaredFields() | 返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象。 |
package com.wcy.code02;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* 反射机制获取属性
*/
public class ReflectField {
public static void main(String[] args) throws Exception {
Class<?> s = Class.forName("com.wcy.code02.User");
//获取类中的所有public属性
Field[] fields = s.getFields();
System.out.println("属性个数" + fields.length);
//获取名字
System.out.println("属性信息:" + fields[0].getName());
System.out.println("----------------------------------------");
//获取所有的属性
Field[] declaredFields = s.getDeclaredFields();
System.out.println("属性个数" + declaredFields.length);
for (Field field : declaredFields) {
//获取属性类型
Class<?> type = field.getType();
String typeSimpleName = type.getSimpleName();
//获取名字
String fieldName = field.getName();
//获取修饰符列表 返回的数字 需要转换
int modifiers = field.getModifiers();
//将数字代表的修饰符转换为字符串
String modifiersString = Modifier.toString(modifiers);
//打印所有的信息
System.out.println(
"属性信息:" + typeSimpleName + "-->" + fieldName + "-->" + modifiersString
);
}
}
}
通过反射机制还原java代码
- 通过类名来获取属性,并还原java代码
package com.wcy.code02;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* 通过反射机制来获取类中的属性
* 并将反编译成标准的java代码
*/
public class ReflectField01 {
public static void main(String[] args) throws Exception{
//获取类
Class<?> c = Class.forName("com.wcy.code02.User");
//拼接字符串
StringBuilder stringBuilder = new StringBuilder();
//获取所有字段
Field[] declaredFields = c.getDeclaredFields();
//拼接类修饰符,类名,大括号
stringBuilder.append(Modifier.toString(c.getModifiers()));
stringBuilder.append(" class ");stringBuilder.append(c.getSimpleName());
stringBuilder.append(" {\n");
//拼接字段名
for(Field field:declaredFields){
stringBuilder.append("\t");
stringBuilder.append(Modifier.toString(field.getModifiers()));
//没有修饰符就不加空格
if(!Modifier.toString(field.getModifiers()).equals("")) {
stringBuilder.append(" ");
}
stringBuilder.append(field.getType().getSimpleName());
stringBuilder.append(" ");
stringBuilder.append(field.getName());
stringBuilder.append(";\n");
}
//最后的大括号
stringBuilder.append("}");
System.out.println(stringBuilder);
}
}
获取String中的字段
反射机制操作属性
- 赋值和获取值
- field.set() field.get()
package com.wcy.code02;
import java.lang.reflect.Field;
/**
* 通过反射来操作属性
* 赋值
* 获取值
*/
public class ReflectField02 {
public static void main(String[] args) throws Exception{
Class<?> c = Class.forName("com.wcy.code02.User");
//实例化一个对象
Object o = c.newInstance();
//首先获取属性 通过名称获取
Field no = c.getDeclaredField("no");
//设置值
//给o对象的no属性设置值
no.set(o, 10086);
//获取值
//获取o对象的no值
System.out.println(no.get(o));
}
}
class User {
public int no;
private String name;
protected int age;
boolean sex;
public static final double PI = 3.1415926;
}
反射机制操作私有属性
用上面的方法还不能操作私有的属性会报错
Class com.wcy.code02.ReflectField02 can not access a member of class com.wcy.code02.User with modifiers "private"
需要设置field.setAccessible(true);才可以操作私有属性
package com.wcy.code02;
import java.lang.reflect.Field;
/**
* 通过反射来操作属性
* 赋值
* 获取值
*/
public class ReflectField02 {
public static void main(String[] args) throws Exception{
Class<?> c = Class.forName("com.wcy.code02.User");
//实例化一个对象
Object o = c.newInstance();
//首先获取属性 通过名称获取
Field no = c.getDeclaredField("no");
//获取私有属性
Field name = c.getDeclaredField("name");
//设置值
//给o对象的no属性设置值
no.set(o, 10086);
//要更改私有属性的值必须设置
name.setAccessible(true);
name.set(o, "wcy");
//获取值
//获取o对象的no值
System.out.println(no.get(o));
System.out.println(name.get(o));
}
}
反射机制操作方法
获取方法相关的信息
- 一系列get方法 见名知意 和获取属性基本一样
package com.wcy.code03;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
/** 反射 method
* 获取class中method的信息
*/
public class ReflectMethod01 {
public static void main(String[] args) throws Exception{
Class<?> c = Class.forName("com.wcy.code03.UserService");
Method[] methods = c.getDeclaredMethods();
//拼接字符串
StringBuilder stringBuilder = new StringBuilder();
for (Method method: methods){
//获取修饰符
String modifier = Modifier.toString(method.getModifiers());
stringBuilder.append(modifier);
stringBuilder.append(" ");
//获取返回值类型
String returnType = method.getReturnType().getSimpleName();
stringBuilder.append(returnType);
stringBuilder.append(" ");
//获取方法名称
String methodName = method.getName();
stringBuilder.append(methodName);
stringBuilder.append("(");
//获取参数类型列表
Parameter[] parameters = method.getParameters();
for (Parameter parameter: parameters) {
//参数类型
String typeName = parameter.getType().getSimpleName();
stringBuilder.append(typeName);
stringBuilder.append(" ");
//参数名称 获取不到真的名字 arg0 arg1...
String name = parameter.getName();
stringBuilder.append(name);
stringBuilder.append(",");
}
//去除空格
if(stringBuilder.charAt(stringBuilder.length()-1)==','){
stringBuilder.deleteCharAt(stringBuilder.length()-1);
}
stringBuilder.append(")\n");
}
System.out.println(stringBuilder);
}
}
/**
* 模拟登陆注销功能
*/
class UserService{
/**
* 模拟登陆方法
* @param name:用户名
* @param password:密码
* @return 是否登陆成功
*/
public boolean login(String name, String password){
return name.equals("wcy") && password.equals("123");
}
public void logout(){
System.out.println("退出登陆成功!");
}
}
反射机制调用方法
- public Object invoke(Object obj, Object… args)
- 获取方法后通过调用invoke来调用
package com.wcy.code03;
import java.lang.reflect.Method;
/**
* 反射机制调用方法 !重要
* 调用方法的四要素
* 1.对象
* 2.方法名
* 3.参数
* 4.返回值
* 无论是普通调用还是反射机制调用都是需要的四要素
*
* 可变长参数补充:
* type... args
* -可变长参数
* -必须放在参数列表的最后
* public void login(int i, String... args){}
* - 传入多个参数会变成一个数组
* - 也可以直接传入一个对应类型的数组
*/
public class ReflectMethod02 {
public static void main(String[] args) throws Exception{
//普通调用
UserService userService = new UserService();
boolean isLogin = userService.login("wcy", "123");
System.out.println(isLogin);
//反射调用
// 1 获取类实例对象
Class<?> c = Class.forName("com.wcy.code03.UserService");
Object o = c.newInstance();
// 2 获取方法 获取的方法参数类型必须一致
// java支持方法重载 所以方法名可能重复 需要用参数类型来限制
Method login = c.getMethod("login", String.class, String.class);
// 3 传参调用 获取返回值 通过invoke调用
Object isLogin1 = login.invoke(o, "wcy", "123");
System.out.println(isLogin1);
}
}
/**
* 模拟登陆注销功能
*/
class UserService{
/**
* 模拟登陆方法
* @param name:用户名
* @param password:密码
* @return 是否登陆成功
*/
public boolean login(String name, String password){
return name.equals("wcy") && password.equals("123");
}
public void logout(){
System.out.println("退出登陆成功!");
}
}
通过反射机制,极大的降低了代码的耦合性,所有需要操作的逻辑,一次书写无需改变,只需将需要改变的部分添加到配置文件中,通过资源读取即可。
反射机制操作构造函数
获取构造方法的相关信息
- 和前面大同小异
package com.wcy.code04;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
/**
* 获取构造方法
*/
public class ReflectConstructor01 {
public static void main(String[] args) throws Exception{
Class<?> c = Class.forName("com.wcy.code04.Student");
Constructor<?>[] constructors = c.getDeclaredConstructors();
for (Constructor<?> constructor: constructors){
//修饰符
String modifiers = Modifier.toString(constructor.getModifiers());
System.out.println(modifiers);
//参数列表
Parameter[] parameters = constructor.getParameters();
for(Parameter parameter:parameters){
//获取类型
String type = parameter.getType().getSimpleName();
System.out.println(type);
}
System.out.println("--------------------------");
}
}
}
class Student{
int no;
String name;
boolean sex;
int age;
public Student() {
}
public Student(int no) {
this.no = no;
}
public Student(int no, String name, boolean sex) {
this.no = no;
this.name = name;
this.sex = sex;
}
public Student(int no, String name, boolean sex, int age) {
this.no = no;
this.name = name;
this.sex = sex;
this.age = age;
}
}
通过构造方法实例化对象
package com.wcy.code04;
import java.lang.reflect.Constructor;
/**
* 通过构造方法来实例化对象
* 前面实例化对象都是通过obj.newInstance()来实例化
* 现在通过构造方法来实例化
*/
public class ReflectConstructor02 {
public static void main(String[] args) throws Exception{
Class<?> c = Class.forName("com.wcy.code04.Student");
// 通过obj.newInstance()来实例化
// 这样会默认自动调用无参构造方法来实例化一个对象
Object o1 = c.newInstance();
System.out.println(o1);
//通过构造方法来实例化
//4参数的构造方法 通过参数类型来选取
Constructor<?> constructor1 = c.getDeclaredConstructor(int.class, String.class, boolean.class, int.class);
//还是通过newInstance()方法实例化,参数就是需要初始化的参数
Object o2 = constructor1.newInstance(10086, "wcy", true, 20);
System.out.println(o2);
//1个参数构造方法
Constructor<?> constructor2 = c.getDeclaredConstructor(int.class);
Object o3 = constructor2.newInstance(10000);
System.out.println(o3);
//无参构造
Constructor<?> constructor3 = c.getDeclaredConstructor();
Object o4 = constructor3.newInstance();
System.out.println(o4);
}
}
通过反射机制获取父类相关信息
package com.wcy.code04;
/**
* 获取父类
* 只要获取到了父类
* 就可以用之前的方法获取属性方法等
*/
public class ReflectSuper01 {
public static void main(String[] args) throws Exception{
Class<?> c = Class.forName("java.lang.reflect.Method");
//获取父类
Class<?> superclass = c.getSuperclass();
//名称
String name = superclass.getName();
System.out.println(name);
//获取该类实现的接口
//Class<?>[] interfaces1 = c.getInterfaces();
//父类实现的接口
Class<?>[] interfaces = superclass.getInterfaces();
for (Class<?> in : interfaces) {
String name1 = in.getName();
System.out.println(name1);
}
}
}