Java基础(下)之反射
反射 idea编辑器代码提示的底层
反射允许对 对象的成员变量,成员方法和构造方法的信息进行编程访问。

获取class对象的三种方式
- 源代码阶段,获取类的字节码文件:
Class.forName("全类名")全类名 = 包名.类名,最常用 - 加载阶段:
类名.class,一般当作参数传入,例如synchronize(Student.class){} - 运行阶段:
对象.getClass()具有局限性,需要提前创建该类的对象

class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//方式一:编译时期 通过Class.forName(全类名)读取字节码文件获取Class类
Class clazz1 = Class.forName("com.example.helloworld.Student");
//方式二:加载时期 通过类名.class获取Class类
Class clazz2 = Student.class;
//方式三:运行时期 通过对象名.getClass获取Class类
Student s1 = new Student("ZJQ",24);
Class clazz3 = s1.getClass();
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz2 == clazz3);//true
}
}
获取类的构造方法

Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
- default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
- private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
- public : 对所有类可见。使用对象:类、接口、变量、方法
- protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
获取修饰符:Constructor.getModifiers
获取名字:Constructor.getName
获取形参:Constructor.getParameters
创建对象:Constructor.newInstance
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//方式一:编译时期 通过Class.forName(全类名)读取字节码文件获取Class类
Class clazz1 = Class.forName("com.example.helloworld.Student");
Constructor[] cons1 = clazz1.getConstructors();//获取所有公开的构造方法
Constructor[] cons2 = clazz1.getDeclaredConstructors();//获取所有构造方法(包括私有)
for (Constructor con : cons1) {
System.out.println(con);
}
System.out.println();
for (Constructor con : cons2) {
System.out.println(con);
}
System.out.println();
//获取单个公开的构造方法
Constructor con1 = clazz1.getConstructor(String.class,int.class);
System.out.println(con1);
System.out.println(con1.getModifiers());//获取该方法的修饰符 1:public
Student s1 = (Student) con1.newInstance("ZJQ",24);//利用构造方法创建对象
System.out.println(s1);
//获取单个任意构造方法,包括私有
Constructor con2 = clazz1.getDeclaredConstructor();
System.out.println(con2);
System.out.println(con2.getModifiers());//获取该方法的修饰符 2:private
con2.setAccessible(true);//暴力反射:临时取消权限校验,否则无法创建对象
Student s2 = (Student) con2.newInstance();//利用构造方法创建对象
System.out.println(s2);
}
获取成员变量

class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//方式一:编译时期 通过Class.forName(全类名)读取字节码文件获取Class类
Class clazz1 = Class.forName("com.example.helloworld.Student");
//获取类的所有成员变量,包括私有
Field[] fields1 = clazz1.getDeclaredFields();
for (Field field : fields1) {
System.out.println(field);
}
System.out.println();
//获取类的所有公开成员变量
Field[] fields2 = clazz1.getFields();
for (Field field : fields2) {
System.out.println(field);
}
//获取类的某个公开成员变量
Field name = clazz1.getField("gender");
System.out.println(name);
Field age = clazz1.getDeclaredField("age");
System.out.println(age);
System.out.println(name.getName());//获取成员变量的名称
System.out.println(name.getModifiers());//获取成员变量的修饰符
System.out.println(name.getType());//获取成员变量的类型
Constructor con1 = clazz1.getConstructor(String.class,int.class,String.class);
Student s1 = (Student) con1.newInstance("ZJQ",24,"男");
age.setAccessible(true);//暴力反射:临时取消权限校验,否则无法访问私有属性
int value = (int)age.get(s1);//获取对象中属性的值
age.set(s1,value + 1);//设置对象中属性的值
System.out.println(s1);
}
}
获取成员方法

class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//方式一:编译时期 通过Class.forName(全类名)读取字节码文件获取Class类
Class clazz1 = Class.forName("com.example.helloworld.Student");
//获取所有公共的方法对象(包括继承自父类的所有公共方法)
Method[] methods = clazz1.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println();
//获取此类的所有方法对象(不包括父类的,含私有方法)
Method[] methods1 = clazz1.getDeclaredMethods();
for (Method method : methods1) {
System.out.println(method);
}
//获取某个公共方法
Method method1 = clazz1.getMethod("eat", String.class);
System.out.println(method1);
//获取某个任意方法(含私有方法)
Method method2 = clazz1.getDeclaredMethod("sleep", int.class);
System.out.println(method2);
//获取方法的名称
System.out.println(method2.getName());
//获取方法的权限修饰符
System.out.println(method2.getModifiers());
//获取方法的参数
Parameter[] params = method2.getParameters();
for (Parameter param : params) {
System.out.println(param);
}
//获取方法可能会抛出的异常类型
Class[] exceptionTypes = method2.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
Constructor con1 = clazz1.getConstructor(String.class,int.class,String.class);
Student s1 = (Student)con1.newInstance("ZJQ", 24, "man");
//暴力反射:临时取消权限校验,否则无法访问私有方法
method2.setAccessible(true);
//调用某个对象的该方法
int res = (int)method2.invoke(s1, 10);
System.out.println(res);
}
}
反射到底有什么用?
- 获取某个类里面的所有信息(内部结构),根据类内部结构执行其它业务逻辑;
- 结合配置文件,动态的创建对象并调用对象;
示例一:对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去
public static void save_obj(Object o, File path) throws IOException, IllegalAccessException {
if(o == null || path == null) throw new NullPointerException();
Class clazz = o.getClass();
File file = new File(path,clazz.getName());
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String name = field.getName();
field.setAccessible(true);
Object value = field.get(o);
bw.write(name + "=" + value.toString() + '\n');
}
bw.close();
}
}
示例二:从配置文件中读取对象并调用方法
package com.example.helloworld;
import java.io.*;
import java.lang.reflect.*;
import java.util.Properties;
class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException {
//1.读取配置文件中的信息
File config_file = new File("prop.properties");
FileReader fr = new FileReader(config_file);
Properties prop = new Properties();//配置文件类
prop.load(fr);//读取文件
fr.close();
System.out.println(prop);
//2.获取全类名和方法名
String className = (String) prop.get("classname");
String methodName = (String) prop.get("method");
String param = (String) prop.get("param");
String what = (String) prop.get("what");
//3.通过反射获取类,构造方法和成员方法,创建对象,运行成员方法
Class clazz = Class.forName(className);
Method method = clazz.getMethod(methodName,param.getClass());
Constructor con1 = clazz.getDeclaredConstructor();
con1.setAccessible(true);
Object obj = con1.newInstance();
method.setAccessible(true);
method.invoke(obj,what);
}
}
动态代理
特点:无侵入的给代码增加各种额外的功能
代理中就是对象要被代理的方法,Java中通过接口实现代理,代理和对象需要实现同一个接口,接口中就是被代理的所有方法。

为Java对象创建一个代理

案例:现有BigStar类,具有sing、dance方法需要被代理,请为其创建一个代理,通过代理调用sing和dance时。
BigStar.java
package com.example.helloworld;
public class BigStar implements Star{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigStar(String name) {
this.name = name;
}
@Override
public String sing(String name){
System.out.println(this.name + "正在唱"+ name);
return "谢谢";
}
@Override
public void dance(){
System.out.println(this.name + "正在跳舞");
}
}
Star.java
package com.example.helloworld;
public interface Star {
//我们可以把所有想要被代理的方法定义在接口中
public abstract String sing(String name);
public abstract void dance();
}
ProxyUtil.java
package com.example.helloworld;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyUtil {
/// 给一个明星对象创建代理并返回
public static Star createProxy(BigStar bigStar){
// 参数一:用于指定哪个类加载器,去加载生成的代理类,一般指定为当前类的加载器即可
// 参数二:指定接口的数组,这些接口用于指定生成的代理长什么样,即有哪些方法
// 参数三:用来指定生成的代理对象要干什么事情
Star star = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
new Class[]{Star.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("sing".equals(method.getName())){
System.out.println(bigStar.getName() + "的代理准备话筒,收钱");
}else if("dance".equals(method.getName())){
System.out.println(bigStar.getName() + "的代理准备服装、场地,收钱");
}
//调用被代理的对象的方法,若方法有返回值,需要返回
return method.invoke(bigStar,args);
}
}
);
return star;
}
public static void main(String[] args) {
BigStar bigStar = new BigStar("cxk");
Star proxy = createProxy(bigStar);
String res = proxy.sing("只因你太美");
System.out.println(res);
proxy.dance();
}
}

浙公网安备 33010602011771号