文章目录
- 反射
- 反射概述
- 获取Class对象的三种方法:
- 通过Class.forName()获取class对象,它会把参数指定的类加载到内存中
- 反射类class的信息
- class对象方法 - 01
- 获取反射类的代码示例
- 通过反射技术访问类的字段(属性方法)并赋值
- class对象方法 - 02
- 通过反射技术反射类的字段(属性)
- 通过反射技术反射方法
- Class对象方法 - 03
- 通过反射技术反射类的方法
反射
反射概述
反射就是根据字节码文件(Class),反射类的信息、字段、方法、构造方法等类的内容,然后根据字节码文件来创建对象,调用方法的技术
没有源码,只有字节码文件也能够运行
反射的基础前提,是Class对象!【记住这个非常非常非常重要,反射都是基于类Class对象的】
什么是Class类:
比如小猫可以抽象为Cat类,小狗抽象为Dog类,小猪抽象为Pig类,人可以抽象为Person类,字符串抽象为String类,然后在将这些抽象的Cat/Dog/Pig/Person/String等所有的类再抽象为一个Class类。
Class类描述所有类的共同特征。
获取Class对象的三种方法:
- 每个类通过class属性获取。【类名.class】
- 每个对象通过getClass()方法获取。【对象.getClass()】
- 通过**Class.forName(“类的完整名”)**获取,需要捕获异常。【Class.forName(“类的完整名”)】
/*
* 获取class对象的方法
* */
public class GetClasssObject {
public static void main(String[] args) {
//1、每个类通过class属性 获取
Class classObject1 = GetClasssObject.class;
//2、每个对象通过getClass()方法获取。
Class classObject2 = new GetClasssObject().getClass();
//通过Class.forName("类的完整名")获取 需要抛出异常
Class classObject3 = null;
try {
classObject3 = Class.forName("com.xgf.reflect.GetClasssObject");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//获取int Integer的class对象
Class intClass = int.class;
Class integerClass1 = Integer.class;
System.out.println("classObject1 : " + classObject1);
System.out.println("classObject2 : " + classObject2);
System.out.println("classObject3 : " + classObject3);
System.out.println("intClass : " + intClass);
System.out.println("integerClass1 : " + integerClass1);
}
}
运行结果:
发现三种方式都可以获取类的对象,结果相同!
通过Class.forName()获取class对象,它会把参数指定的类加载到内存中
package com.xgf.bean;
public class User {
static {
System.out.println("我是User的一个静态代码块");
}
}
/*
* 通过Class.forName()获取class对象,它会把参数指定的类加载到内存中
* 通过测试是否运行了类的static静态代码块来判断是否加载到内存中
* */
public class ClassFormName {
public static void main(String[] args) {
System.out.println(" 1、类.Class ");
Class<User> userClass = User.class;
System.out.println();//换行
System.out.println(" 2、 Class.forName(完整类名) ");
try {
Class<?> aClass = Class.forName("com.xgf.bean.User");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
运行结果(只有class.forName()方法运行了User类的静态代码块)
总结:
1. 类名.class 不将类加载到内存,Class.forName()会将类加载到内存
2. 对象.getClass()创建对象就会加载到内存中去
反射类class的信息
class对象方法 - 01
class对象方法 | 描述 |
int getModifiers() | 获取反射类的修饰符,需要通过Modifier.toString()将其转化为字符串 |
getName() | 返回完整类名(java.lang.String) |
getSimpleName() | 返回简易类名(String) |
getSuperclass() | 获取反射类的父类 |
getInterfaces() | 获取反射类的接口数组,如果没有实现接口,返回长度为0 |
获取反射类的代码示例
public class ReflectParentClass {
public static void main(String[] args) {
//1、通过类名获取Calss对象
Class<String> stringClass = String.class;
StringBuilder sb = new StringBuilder();//字符串拼接
//2、通过class对象获取反射类的信息
//2.1 getModifiers()获取反射类的修饰符
int modifiers = stringClass.getModifiers();
//Modifier.toString()将其转化为字符串,拼接到StringBuilder
sb.append(Modifier.toString(modifiers));
//2.2 getName()获取反射类的类名
sb.append(" class ");//public final class java.lang.String 需要拼接class
//getName()返回完整类名 : java.lang.String
sb.append(stringClass.getName());
//getSimpleName()返回简易类名 String
//sb.append(stringClass.getSimpleName());
//2.3 getSuperclass()获取反射类的父类
Class superclass = stringClass.getSuperclass();
sb.append(" extends ");//拼接关键字
sb.append(superclass);
//2.4 getInterfaces() 获取反射类的接口,如果没有实现接口,返回长度为0
Class<?>[] interfaces = stringClass.getInterfaces();
if( interfaces.length > 0){
sb.append(" implements ");
//遍历接口数组
for(int i = 0; i<interfaces.length; i++){
sb.append(interfaces[i].getSimpleName());//获取接口简易名
//不是最后一个接口需要用逗号,隔开
if(i != interfaces.length-1){
sb.append(",");
}
}
}
//输出拼接的类信息
System.out.println(sb);
}
}
运行结果:这里的接口我用了getSimpleName()获取的是它们的简易名
通过反射技术访问类的字段(属性方法)并赋值
class对象方法 - 02
方法名 | 描述 |
Field getField(string fields, mixed condition, string spea) | 获取反射的字段。fields 必须有,需要查询的字段名称,可以是一个或多个字段。condition 可选,查询条件,可以是字符或数组。spea 多个字段数据生成关联数组时,数据间隔符号,默认为空格。 如果输入的字段名称fields在反射类中找不到就会抛出NoSuchFieldException异常。这个方法只能访问公共字段(public),但是可以通过setAccessible(true)方法设置访问权限,就可以访问private的字段了 |
Field 、getDeclaredField() | 该方法可以访问所有的字段,包括私有字段(private) |
Object newInstance() | 通过反射对象创建类的实例,默认调用类的无参构造方法创建对象 |
Field方法 | 描述 |
field.set(对象名,字段值) | 给object对象的field字段赋值 |
field.get(对象名) | 返回字段的值 |
field.setAccessible(true) | 设置字段的访问属性,比如getField()获取的字段只能访问public的,可以通过该方法设置为true访问 |
通过反射技术反射类的字段(属性)
public class User {
static {
System.out.println("我是User的一个静态代码块");
}
public String userName;
public int userAge;
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", userAge=" + userAge +
'}';
}
}
/*
* 通过反射技术反射类的字段(属性) -- 反射User类
* 并给字段赋值
* */
public class ReflectClassField {
public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException {
//1、通过类名获取User的Calss对象 反射的前提是Class对象
Class<User> userClass = User.class;
System.out.println(" === 给user对象的userName赋值 ===");
//2、getField()获取 反射User的字段username 反射字段要与类字段一致,否自会报NoSuchFieldException
Field userNameField = userClass.getField("userName");
//getDeclaredField()方法能访问所有的字段,包括私有的
//Field declaredField = userClass.getDeclaredField("userName");
//3、设置字段的值(给字段赋值),对对象赋值,就需要创建对象
//3.1 newInstance()通过反射技术创建对象的实例,默认调用类的无参构造方法
User user = userClass.newInstance(); //相当于new User()
//3.2 field.set(对象名,字段值) 设置字段的值 赋值
userNameField.set(user,"我通过userNameField字段设置了userName的值");
System.out.println(user);
//3.3 field.get(对象名)返回字段的值
System.out.println(userNameField.get(user));
System.out.println("\n === 给user对象的setAge赋值 ===");
Field userAgeField = userClass.getField("userAge");//获取字段
userAgeField.set(user,20);//赋值
System.out.println(user);
}
}
运行结果:
通过反射技术反射方法
Class对象方法 - 03
方法名 | 描述 |
getMethod(方法名, 方法参数类型列表) | 反射指定方法签名的公共public方法 |
Method.invoke(对象实例名,方法参数列表) | 通过invoke调用方法 |
通过反射技术反射类的方法
public class User {
static {
System.out.println("我是User的一个静态代码块");
}
public String userName;
public int userAge;
/* 有参构造方法 */
public void set(String userName,int userAge){
this.userName = userName;
this.userAge = userAge;
System.out.println("调用set方法");
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", userAge=" + userAge +
'}';
}
}
public class ReflectClassMenthod {
public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//1、通过类名获取User的Calss对象 反射的前提是Class对象
Class<User> userClass = User.class;
//2、getMethod(方法名, 方法参数类型列表) 反射指定方法签名的公共public方法
//反射toString方法 -- 无参构造方法
Method toStringMethod = userClass.getMethod("toString", null);
//3、 newInstance()通过反射技术创建对象的实例,默认调用类的无参构造方法
User user = userClass.newInstance();//相当于new User()
//4、 调用方法 方法.invoke(对象实例名,方法实参列表)
toStringMethod.invoke(user,null);
//5、反射有参构造方法set
Method setMethod = userClass.getMethod("set", String.class, int.class);
setMethod.invoke(user,"set对象设置userName",21);
System.out.println(user);
}
}
运行结果