Java的反射

反射的作用

  • 程序可以访问, 检测和修改它本身状态或行为的能力, 即自描述和自控制
  • 可以在运行时加载, 探知和使用编译期间完全未知的类
  • 反射在java.lang.reflect包中,在Java2就有,在Java5得到完善

反射的功能

  • 在运行中分析类的能力
  • 在运行中查看和操作对象
  • 基于反射自由创建对象
  • 反射构建出无法直接访问的类
  • set或get到无法访问的成员变量
  • 调用不可访问的方法
  • 实现通用的数组操作代码
  • 实现类似函数指针的功能

Java中创建对象的方式

java中常用的接口
  • Comparable用于对象比较接口
  • Runnable用于对象线程化接口
  • Serializable用于对象序列化接口
  • Clonable用于对象克隆接口
方法1
public class Demo6 {
    public static void main(String[] args) {
        A a = new A();
        a.hello();
    }
}
class A {
    public void hello() {
        System.out.println("Hello from A");
    }
}
方法2
public class Demo6 {
    public static void main(String[] args) {
        // 注意clone相当于在内存中有两个该对象的副本
        B obj2 = new B();
        obj2.hello();

        B obj3 = null;
        try {
            obj3 = (B) obj2.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        obj3.hello();
    }
}
// 使用clone的方法
class B implements Cloneable {
    public void hello() {
        System.out.println("hello from B");
    }
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
方法3
public class Demo6 {
    public static void main(String[] args) {
        C obj = new C();
        // 定义文件输出流
        try {
            // 将对象信息输出到data.obj文件中
            ObjectOutputStream out = new ObjectOutputStream(
                    new FileOutputStream("data.obj"));
            out.writeObject(obj);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 定义文件输入流
        try {
            // 读取data.obj文件创建对象
            ObjectInputStream in = new ObjectInputStream(
                    new FileInputStream("data.obj"));
            C obj1 = (C) in.readObject();
            in.close();
            obj1.hello();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
// 使用序列化和反序列化
// 由于序列化就引发安全漏洞,可能在JDK未来的版本中移除掉
class C implements Serializable {
    private static final long serialVersionUID = -1383000935440370829L;

    public void hello() {
        System.out.println("hello from C");
    }
}
方法4

项目路径

在这里插入图片描述

public class Demo1 {
    public static void main(String[] args) {
        // 使用反射机制创建对象
        try {
            // 读取A.class文件并创建对象
            Object object = Class.forName("exmple.com.demo4.A").newInstance();
            // 调用对象中的方法
            Method method = Class.forName("exmple.com.demo4.A").getMethod("hello");
            method.invoke(object);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

反射关键类

  • Class:是类型的标识
  • JVM为每个对象都保留其类型标识信息
获取类型标识信息
public static void main(String[] args) {
        // 方式1
        String s1 = "abc";
        Class c1 = s1.getClass();
        // 获取类型的包全名
        System.out.println(c1.getName());// java.lang.String

        // 方式2
        try {
            Class c2 = Class.forName("java.lang.String");
            System.out.println(c2.getName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // 方式3
        Class c3 = String.class;
        System.out.println(c3.getName());
    }
getFields() / getDeclareFields()getFields()返回本类和父类所有的属性,getDeclareFields()返回本类中的属性,不包括父类
getMethods() / getDeclareMethods()getMethods()返回本类和父类所有的方法,getDeclareMethods()返回本类中的属性,不包括父类
getPackage()返回本类所在的包
getModifiers()返回本类的前缀修饰符,如public等
getInterfaces()返回本类所继承的接口,以Class的方式显示
getSuperClass()返回本类的父类
getConstructors()返回本类的所有构造函数
getAnnotation()返回本类相应的注解
获取成员变量
public class Demo2 {
    public static void main(String[] args) {
        B obj = new B(20, "Tom");
        Class c = obj.getClass();

        // 获取本类及父类所有的public字段
        Field[] fs = c.getFields();
        try {
            System.out.println(fs[0].getName() + ":"
            + fs[0].get(obj));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        // 获取本类所有声明的字段
        Field[] fs2 = c.getDeclaredFields();
        for (Field f : fs2) {
            // 将获取到的private属性设置为可以临时访问
            f.setAccessible(true);
            try {
                System.out.println(f.getName() + ":" + f.get(obj));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}
class B {
    public int age;
    private String name;
    public B(int age, String name) {
        this.age = age;
        this.name = name;
    }
}
获取成员方法
public class Demo2 {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
        B obj = new B();
        Class c = obj.getClass();

        // 获取public方法包括父类及父接口
        Method[] ms = c.getMethods();
        for (Method m : ms) {
            // 调用f1函数
            if ("f1".equals(m.getName())) {
                m.invoke(obj, null);
            }
        }

        // 获取该类的所有方法
        Method[] ms2 = c.getDeclaredMethods();
        for (Method m : ms2) {
            // 调用f2函数
            if ("f2".equals(m.getName())) {
                m.setAccessible(true);
                String result = (String) m.invoke(obj, "abc");
                System.out.println(result);
            }
        }
    }
}
class B {
    public void f1() {
        System.out.println("B f1 function");
    }
    public String f2(String s) {
        System.out.println("B f2 function");
        return s;
    }
}
运行结果

B f1 function
B f2 function
abc

获取构造函数
public class Demo2 {
    public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
        D d = new D();
        Class c = d.getClass();

        Constructor[] cons = c.getConstructors();
        for (Constructor con : cons) {
            // 调用有参构造
            if (con.getParameterCount() > 0) {
                D obj = (D) con.newInstance(100);
                obj.printNum();
            } else {
                // 无参构造
                D obj = (D) con.newInstance();
                obj.printNum();
            }
        }
    }
}
class D {
   private int num;

   public D() {
       this.num = 10;
   }

   public D(int num) {
       this.num = num;
   }
   public void printNum() {
       System.out.println(this.num);
   }
}
运行结果:

10
100

反射应用

JDBC
// 构建Java和数据库之间的桥梁
try {
    Class.forName("com.mysql.jdbc.Driver");
    System.out.prinln("注册成功");
} catch (ClassNotFoundException e) {
    System.out.prinln("注册失败");
    e.printStackTrace();
    return ;
}
数组扩充
  • Java的数组一旦创建,其长度是不再更改的
  • 新建一个大数组(相同类型),然后将旧数组的内容拷贝过去
public static void main(String[] args) {
        int[] a = { 1, 2, 3, 4, 5};
        System.out.println(a.length);
        a = (int[]) goodCopy(a, 10);
        System.out.println(a.length);
    }

    public static Object goodCopy(Object oldArray, int newLength) {
        // Array类型
        Class c = oldArray.getClass();

        // 获取数组中单个元素的类型
        Class componentType = c.getComponentType();

        // 获取数组的长度
        int oldLength = Array.getLength(oldArray);

        // 新数组
        Object newArray = Array.newInstance(componentType, newLength);

        // 拷贝旧数据
        System.arraycopy(oldArray, 0, newArray, 0 , oldLength);
        return newArray;
    }
运行结果:

5
10

动态执行方法
  • 给定类名、方法名、即可执行
  • 加上定时器,即可做定时任务执行
public class Demo3 {
    public static void main(String[] args) {
        // 创建定时器对象
        Timer timer = new Timer();
	   // 获取当前时间对象
        Calendar now = Calendar.getInstance();
        // 当前时间+1s
        now.set(Calendar.SECOND, now.get(Calendar.SECOND) + 1);
        Date runDate = now.getTime();
	    // 定时任务
        MyTesk task2 = new MyTesk();
        // 每3s执行一次
        timer.scheduleAtFixedRate(task2, runDate, 3000);
    }
}

class MyTesk extends TimerTask {

    @Override
    public void run() {
        try {
            Method m = Class.forName("exmple.com.demo4.Worker")
                            .getMethod("hello");
            // 静态方法不用new对象
            m.invoke(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Json和Java对象互转

本案例中使用的是第三方库Gson,而Gson底层是使用反射机制来实现的

Gson gson = new Gson();
String str = "{\"name\":\"jo\"" + ",\"email\":\"a@b.com\"}";
Person p = gson.formJson(str, Person.class);
System.out.println(p.getName());
Systen.out.println(p.getEmail());
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值