java反射

本文深入讲解Java反射机制,包括Class类的多种实现方式、动态加载类的用法、获取方法和成员变量信息等内容。通过丰富的代码示例帮助理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java反射机制就是在程序运行状态中,对于任意一个类,都能知道这个类的属性和方法;对于任意一个对象,都能够调用到他的属性和方法。这种动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制。

1.Class类 (3种实现方式)
2.Class类动态加载类的用法
3.Class类的使用
4.Class类获取方法信息(返回值、方法名、参数)
5.Class类API 获取成员变量的信息
6.Class类API 获构造函数的信息
7.Class类API 获取某一个方法的反射

8.Class类API 通过反射越过泛型

9.反射与动态代理


1.Class类 (3种实现方式)

/**
 * Class类的三种实现方式
 */
public void getPersionClass(){
// Class类的三种实现方式1
Class pc = Persion.class;


// Class类的三种实现方式2
Persion persion = new Persion();
Class pc1 = persion.getClass();


try {
// Class类的三种实现方式3
Class pc2 = Class.forName("com.yz.reflect.Persion");
System.out.println(pc==pc1); //true
System.out.println(pc1==pc2);//true 一个类只有一个class实例对象
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}


/**
 * 反射获取方法
 */
public void getTest(){
// 一般方式
/*Persion persion = new Persion();
persion.get();*/


// 反射方式
Class<Persion> cp = Persion.class;
try {
Persion persion = cp.newInstance();
persion.get();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}


2.Class类动态加载类的用法

编译时加载类是"静态加载类"
运行时加载类是"动态加载类"

public interface Persion {
    void getStart();
}
public class Student implements Persion{
    public void getStart() {
        System.out.println("Student"+Student.class.toString());
    }
}
public class Teacher implements Persion{
    public void getStart() {
        System.out.println("Teacher"+Thread.class.toString());
    }
}


public class RefTest {

    public void getInstance (String url){
        try {
            Class forName = Class.forName(url);
            Persion p = (Persion) forName.newInstance();
            p.getStart();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 反射动态获取对象实例
     */
    @Test
    public void getTest(){
        /*Student student = new Student();
        student.getStart();*/

        getInstance("com.yz.reflect.Student");

    }
}


3.Class类的使用
public void test(){
Class ci = int.class;
Class cs = String.class;
// Double的类类型
Class cD = Double.class;
// 基本数据类型
Class cd = double.class;

System.out.println(ci.getName()); // int
System.out.println(cs.getName()); // java.lang.String
System.out.println(cD.getName()); // java.lang.Double
System.out.println(cs.getSuperclass().getName()); // java.lang.Object
System.out.println(cs.getSimpleName()); // String
}


4.Class类获取方法信息(返回值、方法名、参数)
public void test(){
Class cs = String.class;
// 获取所有的public修饰的方法,包括父类的
Method[] methods = cs.getMethods();
// 获取声明是所有本类的方法,不包括父类的,不常用
// cs.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
// 获取方法的返回值类类型
Class returnType = methods[i].getReturnType();
System.out.print(returnType.getName()+" ");
// 获取方法的名称
System.out.print(methods[i].getName()+"(");
// 获取参数,可能有多个参数
Class[] parameterTypes = methods[i].getParameterTypes();
for (Class cls : parameterTypes) {
System.out.print(cls.getName());
}
System.out.print(")");
System.out.println();
}
}

输出:
boolean equals(java.lang.Object)
java.lang.String toString()
int hashCode()
int compareTo(java.lang.String)
int compareTo(java.lang.Object)
int indexOf(java.lang.Stringint)
int indexOf(java.lang.String)
int indexOf(intint)
int indexOf(int)
...


5.Class类API 获取成员变量的信息

 /**
  * 获取/修改 public修饰的成员变量
  * public String name = "tom";
  */
public void test(){
Student student = new Student();
Class cs = Student.class;
try {
// 反射获取成员变量的值
field = cs.getField("name");
String str = (String) field.get(student);
System.out.println(str);

// 反射修改成员变量的值
field.set(student,"yz");
System.out.println(field.get(student));
} catch (Exception e) {
e.printStackTrace();
}
}


/**
 * 获取/修改 private修饰的成员变量
 * private String mail = "tom@qq.com";
 */
public void test(){
Student student = new Student();
Class cs = Student.class;
try {
// 反射获取成员变量的值
field = cs.getDeclaredField("mail");
// 开启私有可用
field.setAccessible(true);
String str = (String) field.get(student);
System.out.println(str);

// 反射修改成员变量的值
field.set(student,"yz@qq.com");
System.out.println(field.get(student));
} catch (Exception e) {
e.printStackTrace();
}
}

6.Class类API 获构造函数的信息
public void test(){
Class cs = String.class;
// 获取所有的public的构造函数
Constructor[] constructors = cs.getConstructors();
// 获取该类声明的构造函数
//Constructor[] declaredConstructors = cs.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.print(constructor.getName()+"(");
//获取构造函数的参数
Class[] parameterTypes = constructor.getParameterTypes();
for (Class class1 : parameterTypes) {
System.out.print(class1.getName());
}
System.out.print(")");
System.out.println();
}
}


/**
 * 获取指定的构造函数
 */
public void test(){
Class cs = Student.class;
try {
Constructor constructor = cs.getConstructor(String.class,Integer.class);
// 调用构造函数
Student student = (Student) constructor.newInstance("tom", 123);
System.out.println(student);
} catch (Exception e) {
e.printStackTrace();
}
}


public Student(String name, Integer id) {
this.name = name;
this.id = id;
System.out.println("name:"+name+" id:"+id);
}


7.Class类API 获取某一个方法的反射

/**
 * 反射获取有参数的方法
 */
public void test(){
Student student = new Student();
Class cs = student.getClass();
// 方法名,方法参数 getStart(String str,Integer id)
try {
Method method = cs.getMethod("getStart",new Class[]{String.class,Integer.class});
//Object invoke = method.invoke(student, new Object[]{"tom", 123});
Object invoke = method.invoke(student,"tom", 123);
System.out.println(invoke);
} catch (Exception e) {
e.printStackTrace();
}
}

/**
 * 反射获取无参数的方法
 */
public void test(){
Student student = new Student();
Class cs = student.getClass();
// 方法名,方法参数 getStart()
try {
Method method = cs.getMethod("getStart");
Object invoke = method.invoke(student);
System.out.println(invoke);
} catch (Exception e) {
e.printStackTrace();
}
}


8.Class类API 通过反射越过泛型
/**
 * 反射越过泛型
 */
public void test(){
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("tom");
ArrayList arrayList2 = new ArrayList();
arrayList2.add("tony");
arrayList2.add(123);

Class c1 = arrayList.getClass();
Class c2 = arrayList2.getClass();
/**
*  c1 == c2 为true 说明集合的泛型在编译的时候有效,越过编译就无效
*/
System.out.println(c1 == c2); // true

// 越过泛型
try {
Method method = c1.getMethod("add",Object.class);
method.invoke(arrayList,123);
System.out.println(arrayList);
} catch (Exception e) {
e.printStackTrace();
}
}

9.反射与动态代理

动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的原代码。动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因此Java反射机制可以生成任意类型的动态代理类。java.lang.reflect包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。

动态代理
代理模式是常用的Java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类处理消息、过滤消息,把消息转发给代理类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真实实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。


JDK动态代理中包含了一个类和一个接口:

Proxy类:
Proxy类是专门完成代理的操作类,可以通过调用此类为一个或多个接口动态的生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

参数说明:
ClassLoader loader : 类加载器
Class<?>[] interfaces : 得到全部的接口
InvocationHandler h   : 得到InvocationHandler接口的子类实例

InvocationHandler接口:

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}

参数说明:
Object proxy : 被代理的对象
Method method : 要调用的方法

Object[] args : 方法调用是所需要的参数


动态代理实例:

吃饭前洗手 ---> 吃饭中  ---> 吃饭后洗碗

规律:每次吃饭的菜都不一样,但是每次吃饭前后做的事情都一样,这样的情形适合使用动态代理,把洗手和洗碗的工作交给代理对象完成。

代码部分:

/**
 * 吃晚饭的接口
 * Created by yz on 2018/3/1.
 */
public interface Dinner {

    /**
     * 吃晚饭的方法
     */
    void haveDinner();
}
/**
 * 委托类
 * Created by yz on 2018/3/1.
 */
public class MyDinner implements Dinner{
    public void haveDinner() {
        System.out.println("今天做的晚饭真好吃...");
    }
}
package com.yz.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 代理类,需要实现InvocationHandler接口
 * Created by yz on 2018/3/1.
 */
public class MyDinnerProxy implements InvocationHandler{

    private Object originalObject; //被代理的原始对象

    /**
     * 绑定被代理对象,返回代理对象
     * @param obj
     * @return
     */
    public Object bind(Object obj){
        this.originalObject = obj;
        //返回一个代理对象
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
    }

    // 吃饭之前要执行的方法
    private void preMethod(){
        System.out.println("吃饭之前要洗手...");
    }

    // 吃饭之后要执行的方法
    private void afterMethod(){
        System.out.println("吃饭之后要洗碗...");
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        preMethod();
        result = method.invoke(this.originalObject,args);
        afterMethod();
        return result;
    }
}
/**
 * 测试类
 * Created by yz on 2018/3/1.
 */
public class MyDinnerProxyTest {
    public static void main(String[] args) {
        Dinner din = new MyDinner();
        //不使用代理对象的效果
        //din.haveDinner();

        //使用代理对象的效果
        MyDinnerProxy proxy = new MyDinnerProxy();
        din = (Dinner) proxy.bind(din);
        //执行代理对象的方法,前后增加了洗手和洗碗的方法
        din.haveDinner();
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值