- 反射机制有什么用?
通过反射机制可以操作字节码文件。
反射机制让代码有很高的通用性,可变化的内容写到配置文件中,在使用中只需要修改配置文件,就能创建不同的对象,调用不同的方法,让代码有很高的重复利用率,符合OCP开发原则。
- 反射机制的相关类在哪个包? java.lang.reflect.*
- 反射机制重要的类
Java.lang.Class :代表整个类
Java.lang.reflect.Method :代表类中的方法(重要)
Java.lang.reflect.Constructor :代表类中的构造函数
Java.lang.reflect.Field : 代表类中的成员变量
2 获取Class的三种方式
- 反射机制的灵活性。
Class.forName("完整的包名+类名")方法,只要在配置文件中修改"完整的包名+类名"就能改变获得的Class。
第一种:通过Class.forName("完整的包名+类名")方法
第二种:类对象的getClass()方法。这个方法是Object类中就有的,所有的类都有这个方法
第三种:通过类的.class属性,所有的类都有.class属性,可通过类.class获取
案例
public class Reflect {
public static void main(String[] args) throws ClassNotFoundException {
// 第一种:通过类名
Class reflectClass1 = Class.forName("Reflect");
// 第二种:通过类对象
Reflect reflect = new Reflect();
Class reflectClass2 = reflect.getClass();
// 第三种:通过.Class属性
Class reflectClass3 = Reflect.class;
System.out.println(reflectClass1);
System.out.println(reflectClass2);
System.out.println(reflectClass3);
System.out.println(reflectClass1 == reflectClass2 && reflectClass2 == reflectClass3);
}
}
获取类的完整包名:
- 通过newInstance()方法实例化对象:
通过newInstance()方法实例化对象,需要调用类中的无参构造方法,假如这个类没有无参构造方法则无法通过这个方式实例化对象。
package bean;
public class User {
public User(){
System.out.println("User的无参构造方法");
}
}
package reflect;
public class Reflect2 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class> aClass = Class.forName("bean.User");
Object user = aClass.newInstance();
}
}
4 类的静态代码块执行
5 获取文件的绝对路径 以流的形式直接返回Class.forName("完整的包名+类名")方法执行,会导致类的静态代码块: static{}会执行,不需要返回值
读取配置文件,或者资源。
- 文件一定要在src目录下
- 实际查找目录是编译后的out文件夹下
- 找不到.java文件,只能找到编译后的.class 文件
- 其他不需要编译的文件,直接使用原后缀
public class AboutPath {
public static void main(String[] args) {
String path = Thread.currentThread().getContextClassLoader().getResource("bean/User.class").getPath();
System.out.println(path);
}
}
- 获得文件的数据流
InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("File");
6 通过反射机制反编译Class文件
- 获取类名、属性名等:Class.getSimpleName();
- 获取类中的属性:获得全部属性:Class.getDeclaredFields();;获取public修饰的属性:Class.getFields();
- 获取修饰符:先获取修饰符的代号:Int Class.getModifiers();,通过代号获得修饰符Modifier.toString(Int);
- 获取类中的属性:Class field.getType();得到类型,在通过类型获得类型的名字:String Class.getSimpleName();
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
//通过反射将Class文件反编译
public class Reflect3 {
public static void main(String[] args) throws ClassNotFoundException {
StringBuilder stringBuilder = new StringBuilder();
Class c = Class.forName("java.lang.Thread");
String className = c.getSimpleName();//获得类名
int modifiers = c.getModifiers();//类修饰符的代号
String s = Modifier.toString(modifiers);//通过代号获得修饰符
stringBuilder.append(s+" class "+className+"{n");
// Field[] fields = c.getFields();//类中public修饰的属性
Field[] fields = c.getDeclaredFields();//类中所有的属性
System.out.println("类共有"+fields.length+"个属性");
for (Field field : fields) {
int modifiers1 = field.getModifiers();//属性修饰符的代号
String s1 = Modifier.toString(modifiers1);//通过代号获得修饰符
Class> type = field.getType();//属性的类型
String typeName = type.getSimpleName();//获得该类型的名字
String name = field.getName();
stringBuilder.append("t"+s1+" "+typeName+" "+name+";n");
}
stringBuilder.append("}n");
System.out.println(stringBuilder);
}
}
7 Field 给属性赋值
import java.lang.reflect.Field;
public class Reflact4 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
Class> userClass = Class.forName("bean.User");
// 使用newInstance()创建对象
Object userObj = userClass.newInstance();
Field number = userClass.getField("number");//如果要给属性赋值,属性的必须是public修饰的属性
// 给userObj对象的number属性赋值
number.set(userObj,123);
System.out.println(number.get(userObj));
//给私有属性赋值
Field nameField = userClass.getDeclaredField("name");
nameField.setAccessible(true);// 打破封装,name属性不是私有的了
nameField.set(userObj,"jack");
System.out.println(nameField.get(userObj));
}
}
public class User {
public int number;
private String name;
boolean sex;
public boolean login(String name,int number){
if (name.equals("admin") && number==123)
return true;
else return false;
}
}
8 Method 的调用(重要)
调用哪个方法,第一需要方法名,第二需要参数
- 获取到Class
- 创建对象
- 获得该方法
- 调用方法,由于参数的不同,类中可能会有重构的方法,所以参数很重要
Object 返回的值 = 获取的方法.invoke(对象,参数(可变长度的参数))
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Reflect5 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
Class> userClass = Class.forName("bean.User");
// 实例化对象
Object userObj = userClass.newInstance();
// 获得方法
Method loginMethod = userClass.getDeclaredMethod("login", String.class, int.class);
//执行方法,参数很重要(对象,方法的所有参数作为可变长度参数传入)
Object result = loginMethod.invoke(userObj, "admin", 123);
System.out.println(result);
}
}
public class User {
public int number;
private String name;
boolean sex;
public boolean login(String name,int number){
if (name.equals("admin") && number==123)
return true;
else return false;
}
}
9 Constructor 构造方法
获得哪个构造方法,靠参数来区别.getDeclaredConstructor(参数);
import java.lang.reflect.Constructor;
public class Reflect6 {
public static void main(String[] args) throws Exception {
Class> UserClass = Class.forName("bean.User");
// 无参构造方法,参数为空
Constructor> constructor1 = UserClass.getDeclaredConstructor();
Object user1 = constructor1.newInstance();
System.out.println(user1);
// 有参数的构造方法
Constructor> constructor2 = UserClass.getDeclaredConstructor(int.class, String.class, boolean.class);
Object user2 = constructor2.newInstance(123, "jack", true);
System.out.println(user2);
}
}
10 获取父类和接口
获取父类:类.getSuperclass();
获取接口:类.getInterfaces()
public class Reflect7 {
public static void main(String[] args) throws Exception {
Class> StringClass = Class.forName("java.lang.String");
// 获取父类
Class> superclass = StringClass.getSuperclass();
System.out.println("String类的父类:"+ superclass.getName());
// 获取接口
Class>[] interfaces = StringClass.getInterfaces();
System.out.println("String类的接口:");
for (Class> anInterface : interfaces) {
System.out.println(anInterface.getName());
}
}
}



