【转】Java基础-反射机制详解

转载出处:http://www.cnblogs.com/lzq198754/p/5780331.html

目录

  • 反射机制是什么
  • 反射机制能做什么
  • 反射机制的相关API
  • 通过一个对象获得完整的包名和类名
  • 实例化Class对象
  • 获取一个对象的父类与实现的接口
  • 获取某个类中的全部构造函数
  • 通过反射机制实例化一个类的对象
  • 获取某个类的全部属性
  • 获取某个类的全部方法
  • 通过反射机制调用某个类的方法
  • 通过反射机制操作某个类的属性
  • 反射机制的动态代理
  • 反射机制的应用实例
  • 在泛型为Integer 的ArrayList中存放一个String类型的对象
  • 通过反射取得并修改数组的信息
  • 通过反射机制修改数组的大小
  • 将反射机制应用于工厂模式

反射机制是什么

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

反射机制能做什么

反射机制主要提供了以下功能:

  • 在运行时判断任意一个对象所属的类。
  • 在运行时构造任意一个类的对象。
  • 在运行时判断任意一个类所具有的成员变量和方法。
  • 在运行时调用任意一个对象的方法。
  • 生成动态代理。

反射机制的相关API

通过一个对象获得完整的包名和类名

package com.zhihua.reflect;

/**
 * 1.通过一个对象获得完整的包名和类名
 * @author caizh
 *
 */
public class TestReflect_1 {

    public static void main(String[] args) {

        TestReflect_1 testReflect = new TestReflect_1();
        System.out.println(testReflect.getClass().getName());
        // 结果 com.zhihua.reflect.TestReflect_1
    }

}

实例化Class类对象

package com.zhihua.reflect;

/**
 * 2.实例化Class类对象
 * 有三种方式
 * @author caizh
 *
 */
public class TestReflect_2 {

    public static void main(String[] args) throws Exception {

        Class<?> class1 = null;
        Class<?> class2 = null;
        Class<?> class3 = null;
        // 一般采用这种形式
        class1 = Class.forName("com.zhihua.reflect.TestReflect_2");
        class2 = new TestReflect_2().getClass();
        class3 = TestReflect_2.class;
        System.out.println("类名称   " + class1.getName());
        System.out.println("类名称   " + class2.getName());
        System.out.println("类名称   " + class3.getName());
        /**
         * 0.结果:
         * 1.类名称   com.zhihua.reflect.TestReflect_2
         * 2.类名称   com.zhihua.reflect.TestReflect_2
         * 3.类名称   com.zhihua.reflect.TestReflect_2
         */
    }
}

获取一个对象的父类与实现的接口

package com.zhihua.reflect;

import java.io.Serializable;

/**
 * 3.获取一个对象的父类与实现的接口
 * @author caizh
 *
 */
public class TestReflect_3 implements Serializable{

    private static final long serialVersionUID = -2862585049955236662L;

    public static void main(String[] args) throws Exception {

        Class<?> clazz = Class.forName("com.zhihua.reflect.TestReflect_3");
        // 取得父类
        Class<?> parentClass = clazz.getSuperclass();
        System.out.println("clazz的父类为:"+parentClass.getName());
        // clazz的父类为: java.lang.Object
        // 获取所有的接口
        Class<?> intes[] = clazz.getInterfaces();
        System.out.println("clazz实现的接口有:");
        for(int i=0;i<intes.length;i++) {
            System.out.println((i+1)+": "+intes[i].getName());
        }
        // clazz 实现的接口有:
        /**
         * 1: java.io.Serializable
         */
    }

}

通过反射机制实例化一个类的对象

package com.zhihua.reflect;

import java.lang.reflect.Constructor;

/**
 * 4.获取某个类中的全部构造函数 
 * @author caizh
 *
 */
public class TestReflect_4 {

    public static void main(String[] args) throws Exception {

        Class<?> class1 = null;
        class1 = Class.forName("com.zhihua.reflect.User");
        // 第一种方法,实例化默认构造方法,调用set赋值
        User user = (User) class1.newInstance();
        user.setAge(20);
        user.setName("Rollen");
        System.out.println(user);
        // 结果 User [age=20, name=Rollen]
        // 第二种方法 取得全部的构造函数 使用构造函数赋值
        Constructor<?>[] constructors =class1.getConstructors();
        // 查看每个构造方法需要的参数
        for(int i=0;i<constructors.length;i++) {
            // 获取参数
            Class<?> clazzs[] = constructors[i].getParameterTypes();
            System.out.print("cons[" + i + "] (");
            for(int j=0;j<clazzs.length;j++) {
                if(j==clazzs.length-1){
                    System.out.print(clazzs[j].getName());
                }else {
                    System.out.print(clazzs[j].getName()+",");
                }
            }
            System.out.println(")");
        }

        // 结果
        /**
         * 1.cons[0] (int,java.lang.String)
         * 2.cons[1] (java.lang.String)
         * 3.cons[2] ()
         */
        user = (User) constructors[1].newInstance("Rollen");
        System.out.println(user);
        // 结果 User [age=0, name=Rollen]
        user = (User) constructors[0].newInstance(20,"Rollen");
        System.out.println(user);
        // 结果 User [age=20, name=Rollen]
    }
}
class User {
    private int age;
    private String name;
    public User() {
        super();
    }
    public User(String name) {
        super();
        this.name = name;
    }
    public User(int age, String name) {
        super();
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User [age=" + age + ", name=" + name + "]";
    }
}

获取某个类的全部属性

package com.zhihua.reflect;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * 5.获取某个类的全部属性
 * @author caizh
 *
 */
public class TestReflect_5 implements Serializable{

    private static final long serialVersionUID = -2862585049955236662L;
    public static void main(String[] args) throws Exception {

        Class<?> clazz = Class.forName("com.zhihua.reflect.TestReflect_5");
        System.out.println("===============本类属性===============");
        // 取得本类的全部属性
        Field[] fields = clazz.getDeclaredFields();
        for(int i=0;i<fields.length;i++) {
            // 权限修饰符
            int mo = fields[i].getModifiers();
            String priv = Modifier.toString(mo);
            // 属性类型
            Class<?> type = fields[i].getType();
            // System.out.println(priv);结果  private static final
            System.out.println(priv + " " + type.getName() + " " + fields[i].getName() + ";");
            // 结果 private static final long serialVersionUID;
        }

        System.out.println("==========实现的接口或者父类的属性==========");
        // 取得实现的接口或者父类的属性
        Field[] fields2 = clazz.getFields();
        for(int j=0;j<fields2.length;j++) {
            // 权限修饰符
            int mo = fields2[j].getModifiers();
            String priv = Modifier.toString(mo);
            // 属性类型
            Class<?> type = fields2[j].getType();
            System.out.println(priv + " " + type.getName() + " " + fields2[j].getName() + ";");
        }   
    }
}

获取某个类的全部方法

package com.zhihua.reflect;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 6.获取某个类的全部方法
 * @author caizh
 *
 */
public class TestReflect_6 implements Serializable {

    private static final long serialVersionUID = -2862585049955236662L;
    public static void main(String[] args) throws Exception {

        Class<?> clazz = Class.forName("com.zhihua.reflect.TestReflect_6");
        Method[] methods = clazz.getMethods();
        for(int i=0;i<methods.length;i++) {
            Class<?> returnType = methods[i].getReturnType();
            Class<?>[] para = methods[i].getParameterTypes();
            int temp = methods[i].getModifiers();
            System.out.print(Modifier.toString(temp) + " ");
            System.out.print(returnType.getName() + "  ");
            System.out.print(methods[i].getName() + " ");
            System.out.print("(");
            for(int j=0;j<para.length;j++) {
                System.out.print(para[j].getName()+" "+"arg"+j);
                if(j<para.length-1) {
                    System.out.print(",");
                }
            }
            // 返回 方法异常类型
            Class<?>[] exce = methods[i].getExceptionTypes();
            if(exce.length>0) {
                System.out.print(") throws ");
                for(int k=0;k<exce.length;k++) {
                    System.out.print(exce[k].getName()+ " ");
                    if(k<exce.length-1) {
                        System.out.print(",");
                    }
                }
            }else {
                System.out.print(")");
            }
            System.out.println();
        }
    }
}

通过反射机制调用某个类的方法

package com.zhihua.reflect;

import java.lang.reflect.Method;

/**
 * 7.通过反射机制调用某个类的方法
 * @author caizh
 *
 */
public class TestReflect_7 {

    public static void main(String[] args) throws Exception {

        Class<?> clazz = Class.forName("com.zhihua.reflect.TestReflect_7");
        // 调用TestReflect_7的 reflect1方法
        Method method = clazz.getMethod("reflect1");
        method.invoke(clazz.newInstance());
        // Java 反射机制 - 调用某个类的方法1.

        // 调用TestReflect的reflect2方法
        method = clazz.getMethod("reflect2", int.class,String.class);
        method.invoke(clazz.newInstance(), 20,"张三");
        // Java 反射机制 - 调用某个类的方法2.
        // age -> 20. name -> 张三
    }

    public void reflect1() {
        System.out.println("Java 反射机制 - 调用某个类的方法1.");
    }
    public void reflect2(int age, String name) {
        System.out.println("Java 反射机制 - 调用某个类的方法2.");
        System.out.println("age -> " + age + ". name -> " + name);
    }
}

通过反射机制操作某个类的属性

package com.zhihua.reflect;

import java.lang.reflect.Field;

/**
 * 8.通过反射机制操作某个类的属性
 * @author caizh
 *
 */
public class TestReflect_8 {

    private String property = null;
    public static void main(String[] args) throws Exception {

        Class<?> clazz = Class.forName("com.zhihua.reflect.TestReflect_8");
        Object object = clazz.newInstance();
        // 可以直接对private 的属性赋值
        Field field = clazz.getDeclaredField("property");
         //打破封装  实际上setAccessible是启用和禁用访问安全检查的开关,
         //并不是为true就能访问为false就不能访问  
         //由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式
         //关闭安全检查就可以达到提升反射速度的目的 
        field.setAccessible(true);
        field.set(object, "java 反射机制");
        System.out.println(field.get(object));
    }
}

getDeclaredFields 和 getFields 的区别

getDeclaredFields()获得某个类的所有申明的字段,即包括publicprivate和proteced,
但是不包括父类的申明字段。

getFields()获得某个类的所有的公共(public)的字段,包括父类。

反射机制的动态代理

package com.zhihua.reflect;

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

/**
 * 9.反射机制的动态代理
 * 
 * java 中有三种类类加载器
 * 1) Bootsrtap ClassLoader 此加载器采用c++编写,一般开发中很少见。
 * 2) Extension ClassLoader 用来进行扩展类的加载,一般对应的是jrelibext目录中的类
 * 3) AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器
 * 
 * 如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。
 * @author caizh
 *
 */
public class TestReflect_9 {

    public static void main(String[] args) {

        MyInvocationHandler demo = new MyInvocationHandler();
        Subject subject = (Subject) demo.bind(new RealSubject());
        String info = subject.say("Rollen", 20);
        System.out.println(info);
    }

}
class MyInvocationHandler implements InvocationHandler{

    private Object obj = null;
    public Object bind(Object object) {
        this.obj = object;
        return Proxy.newProxyInstance(
                obj.getClass().getClassLoader(), 
                obj.getClass().getInterfaces(), 
                this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) 
            throws Throwable {
        Object temp = method.invoke(this.obj, args);
        return temp;
    }

}
// 定义项目接口
interface Subject{
    public String say(String name,int age);
}
// 定义真实项目
class RealSubject implements Subject{

    @Override
    public String say(String name, int age) {
        return name + "  " + age;
    }
}

反射机制的应用实例

在泛型为Integer的ArrayList中存放一个String类型的对象

package com.zhihua.reflect;

import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * 10.在泛型为Integer的ArrayList中存放一个String类型的对象。
 * @author caizh
 *
 */
public class TestReflect_10 {

    public static void main(String[] args) throws Exception {

        ArrayList<Integer> list = new ArrayList<>();
        Method method = list.getClass().getMethod("add", Object.class);
        method.invoke(list, "Java反射机制实现");
        System.out.println(list);
        // 结果:[Java反射机制实现]
    }
}

通过反射取得并修改数组的信息

package com.zhihua.reflect;

import java.lang.reflect.Array;

/**
 * 11.通过反射取得并修改数组的信息
 * @author caizh
 *
 */
public class TestReflect_11 {

    public static void main(String[] args) {

        int[] temp = {1,2,3,4,5};
        Class<?> demo = temp.getClass().getComponentType();
        System.out.println("数组类型:"+demo.getName());
        System.out.println("数组长度:"+Array.getLength(temp));
        System.out.println("数组的第一个元素:"+Array.get(temp, 0));
        Array.set(temp, 0, 100);
        System.out.println("修改之后数组第一个元素为: " + Array.get(temp, 0));
    }
}

通过反射机制修改数组的大小

package com.zhihua.reflect;

import java.lang.reflect.Array;

/**
 * 12.通过反射机制修改数组的大小
 * @author caizh
 *
 */
public class TestReflect_12 {

    public static void main(String[] args) {

        int[] temp = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        int[] newTemp = (int[]) arrayInc(temp, 15);
        print(newTemp);
        String[] atr = {"a","b","c"};
        String[] str1 = (String[]) arrayInc(atr, 8);
        print(str1);

    }
    // 修改数组的大小
    public static Object arrayInc(Object object,int len) {
        Class<?> arr = object.getClass().getComponentType();
        Object newArr = Array.newInstance(arr, len);
        int co = Array.getLength(object);
        System.arraycopy(object, 0, newArr, 0, co);
        return newArr;
    }
    // 打印
    public static void print(Object object) {
        Class<?> class1 = object.getClass();
        if(!class1.isArray()) {
            return;
        }
        System.out.println("数组的长度为:"+Array.getLength(object));
        for (int i = 0; i < Array.getLength(object); i++) {
            System.out.print(Array.get(object, i) + " ");
        }
        System.out.println();
    }
}

将反射机制应用于工厂模式

package com.zhihua.reflect;

/**
 * 13.将反射机制应用于工厂模式
 * @author caizh
 *
 * 对于普通的工厂模式当文明在添加一个子类的时候,就需要对应的的修改工厂类。
 * 当我们添加很多的子类的是偶,会很麻烦。
 * 现在我们利用反射机制实现工厂模式,可以在不修改工厂类的情况下添加任意多个子类。
 * 但是有一点仍然很麻烦,就是需要知道完整的包名和类名,这里可以使用properties配置文件来完成。
 * 
 */
public class TestReflect_13 {

    public static void main(String[] args) {
        Fruit fruit = Factory.getInstance("com.zhihua.reflect.Apple");
        if(fruit!=null) {
            fruit.eat();
        }
    }
}

interface Fruit{
    public abstract void eat();
}
class Apple implements Fruit{

    @Override
    public void eat() {
        System.out.println("I eat Apple");
    }
}
class Orange implements Fruit{

    @Override
    public void eat() {
        System.out.println("Orange");
    }
}
class Factory{

    public static Fruit getInstance(String className) {
        Fruit fruit = null;
        try {
            fruit = (Fruit) Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return fruit;
    }
}

总结

Class类提供了四个public方法,用于获取某个类的构造方法。

  • Constructor getConstructor(Class[] params) 根据构造函数的参数,返回一个具体的具有public属性的构造函数
  • Constructor getConstructors() 返回所有具有public属性的构造函数数组
  • Constructor getDeclaredConstructor(Class[] params) 根据构造函数的参数,返回一个具体的构造函数(不分public和非public属性)
  • Constructor getDeclaredConstructors() 返回该类中所有的构造函数数组(不分public和非public属性)

四种获取成员方法的方法

  • Method getMethod(String name, Class[] params) 根据方法名和参数,返回一个具体的具有public属性的方法
  • Method[] getMethods() 返回所有具有public属性的方法数组
  • Method getDeclaredMethod(String name, Class[] params) 根据方法名和参数,返回一个具体的方法(不分public和非public属性)
  • Method[] getDeclaredMethods() 返回该类中的所有的方法数组(不分public和非public属性)

四种获取成员属性的方法

  • Field getField(String name) 根据变量名,返回一个具体的具有public属性的成员变量
  • Field[] getFields() 返回具有public属性的成员变量的数组
  • Field getDeclaredField(String name) 根据变量名,返回一个成员变量(不分public和非public属性)
  • Field[] getDelcaredField() 返回所有成员变量组成的数组(不分public和非public属性)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值