java反射

1.反射机制是什么

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

2.反射机制能做什么

  • 在运行时判断任意一个对象所属的类;

  • 在运行时构造任意一个类的对象;

  • 在运行时判断任意一个类所具有的成员变量和方法;

  • 在运行时调用任意一个对象的方法;

  • 生成动态代理。

3.反射机制的相关API

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

//第一种,任何一个类都有一个隐含的静态成员变量class
Class c1 = Person.class;

//第二种,已经知道该类的对象,通过getClass()获得
Class c2 = person.getClass();

//第三种,Class类的forName()方法
Class c3 = Class.forName("Person");
public class TestReflect {
    public static void main(String[] args) throws Exception {
        Class<?> class1 = null;
        Class<?> class2 = null;
        Class<?> class3 = null;
        //获得类名 一般有三种方式
        class1 = Class.forName("com.yuan.TestReflect");
        class2 = new TestReflect().getClass();
        class3 = TestReflect.class;
        System.out.println("类名称   " + class1.getName());
        System.out.println("类名称   " + class2.getName());
        System.out.println("类名称   " + class3.getName());
    }
}
View Code

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

clazz.getSuperclass()

clazz.getInterfaces()

import java.io.Serializable;
public class TestReflect implements Serializable {
    private static final long serialVersionUID = -2862585049955236662L;
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
        // 取得父类
        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
    }
}
View Code

获取某个类中的全部构造函数

A.1:获取构造方法的数组:

    public Constructor<?>[] getConstructors():获得所有公共构造方法

    public Constructor<?>[] getDeclaredConstructors():获得所有构造方法

A.2:获取单个构造方法(用于非私有的构造方法)

    public Constructor<T> getConstructor(Class<?>... parameterTypes)

    参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象

A.3:获取单个构造方法(用于私有的构造方法)

    public Constructor<T> getDeclaredtConstructor(Class<?>... parameterTypes)

B.1:初始化构造方法的实例:(用于非私有的构造方法)

    public T newInstance(Object... initargs)  注意:T表示的是泛型,Object... initargs表示的是你要实例化的指定参数

    使用此 Constructor对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

B.2:初始化构造方法的实例:(用于私有的构造方法)   

    先用: public void setAccessible(boolean flag):flag的值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。

    再用: public T newInstance(Object... initargs) 

public Constructor<?>[] getConstructors():获得所有公共构造方法

Constructor[] c1 = c.getConstructors();
System.out.println(c1);// 返回的是地址值,证明得到的是个数组对象
     // 遍历这个数组
for (Constructor ct : c1) {
    System.out.println(ct);
}  //获得Person类中的所有公共构造方法
View Code

public Constructor<?>[] getDeclaredConstructors():获得所有构造方法

Constructor[] c1 = c.getDeclaredConstructors();
    //遍历数组
for(Constructor ct : c1){
    System.out.println(ct);
} //获得Person类的所有构造方法
View Code

public Constructor<T> getConstructor(Class<?>... parameterTypes):获得指定的构造方法

获得无参构造方法:

Constructor c1 = c.getDeclaredConstructor();
System.out.println(c1);
View Code

获得带参构造方法:

//获取指定的构造方法,需要该方法的参数列表
Constructor c1 = c.getDeclaredConstructor(String.class,int.class,String.class);
System.out.println(c1);
View Code

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

通过反射获取公共带参构造方法并使用:

//获取指定的构造方法,需要该方法的参数列表
        Constructor c1 = c.getDeclaredConstructor(String.class,int.class,String.class);
        System.out.println(c1);
        
        // 通过带参构造方法对象创建对象
        // public T newInstance(Object... initargs):
        //有泛型,前面没使用泛型,先用Objcet
        Object b = c1.newInstance("张三",13,"家乡");
        System.out.println(b); //Person [name=张三, age=13, address=家乡]
View Code

通过反射获取私有带参构造方法并使用:

//获取指定的私有构造方法
        Constructor c1 = c.getDeclaredConstructor(String.class);
        
        //public void setAccessible(boolean flag):
        //flag的值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
        c1.setAccessible(true);
        
        // public T newInstance(Object... initargs) 
        Object ob = c1.newInstance("张三");
        System.out.println(ob);
View Code

获取某个类的全部属性

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

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

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class TestReflect implements Serializable {
    private static final long serialVersionUID = -2862585049955236662L;
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
        System.out.println("===============本类属性===============");
        // 取得本类的全部属性
        Field[] field = clazz.getDeclaredFields();
        for (int i = 0; i < field.length; i++) {
            // 权限修饰符
            int mo = field[i].getModifiers();
            String priv = Modifier.toString(mo);
            // 属性类型
            Class<?> type = field[i].getType();
            System.out.println(priv + " " + type.getName() + " " + field[i].getName() + ";");
        }
         
        System.out.println("==========实现的接口或者父类的属性==========");
        // 取得实现的接口或者父类的属性
        Field[] filed1 = clazz.getFields();
        for (int j = 0; j < filed1.length; j++) {
            // 权限修饰符
            int mo = filed1[j].getModifiers();
            String priv = Modifier.toString(mo);
            // 属性类型
            Class<?> type = filed1[j].getType();
            System.out.println(priv + " " + type.getName() + " " + filed1[j].getName() + ";");
        }
    }
}
View Code

获取某个类的全部方法

import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class TestReflect implements Serializable {
    private static final long serialVersionUID = -2862585049955236662L;
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
        Method method[] = clazz.getMethods();
        for (int i = 0; i < method.length; ++i) {
            Class<?> returnType = method[i].getReturnType();
            Class<?> para[] = method[i].getParameterTypes();
            int temp = method[i].getModifiers();
            System.out.print(Modifier.toString(temp) + " ");
            System.out.print(returnType.getName() + "  ");
            System.out.print(method[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[] = method[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();
        }
    }
}
View Code

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

打破封装 实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问

由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的目的

共有方法

import java.lang.reflect.Method;
public class TestReflect {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
        // 调用TestReflect类中的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);
    }
}
View Code

私有方法

Object person = class1.newInstance();
Method setName = class1.getDeclaredMethod( "setName", String.class ) ;
setName.setAccessible( true );
setName.invoke( person , "jack" ) ;
View Code

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

import java.lang.reflect.Field;
public class TestReflect {
    private String proprety = null;
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
        Object obj = clazz.newInstance();
        // 可以直接对 private 的属性赋值
        Field field = clazz.getDeclaredField("proprety");
        field.setAccessible(true);
        field.set(obj, "Java反射机制");
        System.out.println(field.get(obj));
    }
}
View Code

4.综合训练

反射操作属性和方法

package com.app;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class T1 {

    public static void main(String[] args) {

        try {
            //创建类
            Class<?> class1 = Class.forName("com.app.Person");

            //创建实例
            Object person = class1.newInstance();

            //获得id 属性
            Field idField = class1.getDeclaredField( "id" ) ;

            //打破封装  实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问  
            //由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的目的  
            idField.setAccessible( true );

            //给id 属性赋值
            idField.set(  person , "100") ;

            //获取 setName() 方法
            Method setName = class1.getDeclaredMethod( "setName", String.class ) ;
            //打破封装 
            setName.setAccessible( true );

            //调用setName 方法。
            setName.invoke( person , "jack" ) ;

            //获取name 字段
            Field nameField = class1.getDeclaredField( "name" ) ;
            //打破封装 
            nameField.setAccessible( true );

            //打印 person 的 id 属性值
            String id_ = (String) idField.get( person ) ;
            System.out.println( "id: " + id_ );

            //打印 person 的 name 属性值
            String name_ = ( String)nameField.get( person ) ;
            System.out.println( "name: " + name_ );
            
            //获取 getName 方法
            Method getName = class1.getDeclaredMethod( "getName" ) ;
            //打破封装 
            getName.setAccessible( true );
            
            //执行getName方法,并且接收返回值
            String name_2 = (String) getName.invoke( person  ) ;
            System.out.println( "name2: " + name_2 );

        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace() ;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}
View Code
id: 100
name: jack
name2: jack
运行结果

静态属性、静态方法调用

package com.app;

public class Util {

    public static String name = "json" ;

    /**
     * 没有返回值,没有参数
     */
    public static void getTips(){
        System.out.println( "执行了---------1111");
    }

    /**
     * 有返回值,没有参数
     */
    public static String getTip(){
        System.out.println( "执行了---------2222");
        return "tip2" ;
    }

    /**
     * 没有返回值,有参数
     * @param name
     */
    public static void getTip( String name ){
        System.out.println( "执行了---------3333 参数: " + name );
    }

    /**
     * 有返回值,有参数
     * @param id
     * @return
     */
    public static String getTip( int id ){
        System.out.println( "执行了---------4444 参数: " + id );
        if ( id == 0 ){
            return "tip1 444 --1 " ;
        }else{
            return "tip1 444 --2" ;
        }
    }

}
View Code
package com.app;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class T1 {

    public static void main(String[] args) {

        try {
            //创建类
            Class<?> class1 = Class.forName("com.app.Util");

            //获取 nameField 属性
            Field nameField = class1.getDeclaredField( "name" ) ;
            //获取 nameField 的值
            String name_ = (String) nameField.get( nameField ) ;
            //输出值
            System.out.println( name_ );


            //没有返回值,没有参数
            Method getTipMethod1 = class1.getDeclaredMethod( "getTips"  ) ; 
            getTipMethod1.invoke( null  ) ;
            
            //有返回值,没有参数
            Method getTipMethod2 = class1.getDeclaredMethod( "getTip"  ) ; 
            String result_2 = (String) getTipMethod2.invoke( null  ) ;
            System.out.println( "返回值: "+ result_2 );
            
            //没有返回值,有参数
            Method getTipMethod3 = class1.getDeclaredMethod( "getTip" , String.class  ) ; 
            String result_3 = (String) getTipMethod3.invoke( null , "第三个方法"  ) ;
            System.out.println( "返回值: "+ result_3 );
            
            //有返回值,有参数
            Method getTipMethod4 = class1.getDeclaredMethod( "getTip" , int.class ) ; 
            String result_4 = (String) getTipMethod4.invoke( null  , 1 ) ;
            System.out.println( "返回值: "+ result_4 );
            
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace() ;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}
View Code
json
执行了---------1111
执行了---------2222
返回值: tip2
执行了---------3333 参数: 第三个方法
返回值: null
执行了---------4444 参数: 1
返回值: tip1 444 --2
运行结果

注意:

当参数是 int 类型 和 Integer 类型,反射获取方法不一样

  • 当参数是 int 类型时。获取方法的时候需要用:int.class。不能使用 Integer.class. 会报错。
  • 当参数是 Integer类型时。获取方法的时候需要用:Integer .class。不能使用 int.class. 会报错。

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

import java.lang.reflect.Method;
import java.util.ArrayList;
public class TestReflect {
    public static void main(String[] args) throws Exception {
        ArrayList<Integer> list = new ArrayList<Integer>();
        Method method = list.getClass().getMethod("add", Object.class);
        method.invoke(list, "Java反射机制实例。");
        System.out.println(list.get(0));
    }
}
View Code

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

import java.lang.reflect.Array;
public class TestReflect {
    public static void main(String[] args) throws Exception {
        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));
    }
}
View Code

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

import java.lang.reflect.Array;
public class TestReflect {
    public static void main(String[] args) throws Exception {
        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 obj, int len) {
        Class<?> arr = obj.getClass().getComponentType();
        Object newArr = Array.newInstance(arr, len);
        int co = Array.getLength(obj);
        System.arraycopy(obj, 0, newArr, 0, co);
        return newArr;
    }
    // 打印
    public static void print(Object obj) {
        Class<?> c = obj.getClass();
        if (!c.isArray()) {
            return;
        }
        System.out.println("数组长度为: " + Array.getLength(obj));
        for (int i = 0; i < Array.getLength(obj); i++) {
            System.out.print(Array.get(obj, i) + " ");
        }
        System.out.println();
    }
}
View Code

反射机制的动态代理

// 获取类加载器的方法
TestReflect testReflect = new TestReflect();
        System.out.println("类加载器  " + testReflect.getClass().getClassLoader().getClass().getName());
package net.xsoftlab.baike;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//定义项目接口
interface Subject {
    public String say(String name, int age);
}
// 定义真实项目
class RealSubject implements Subject {
    public String say(String name, int age) {
        return name + "  " + age;
    }
}
class MyInvocationHandler implements InvocationHandler {
    private Object obj = null;
    public Object bind(Object obj) {
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object temp = method.invoke(this.obj, args);
        return temp;
    }
}
/**
 * 在java中有三种类类加载器。
 * 
 * 1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。
 * 
 * 2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jrelibext目录中的类
 * 
 * 3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
 * 
 * 如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。
 * 
 * @author xsoftlab.net
 * 
 */
public class TestReflect {
    public static void main(String[] args) throws Exception {
        MyInvocationHandler demo = new MyInvocationHandler();
        Subject sub = (Subject) demo.bind(new RealSubject());
        String info = sub.say("Rollen", 20);
        System.out.println(info);
    }
}
View Code

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

interface fruit {
    public abstract void eat();
}
class Apple implements fruit {
    public void eat() {
        System.out.println("Apple");
    }
}
class Orange implements fruit {
    public void eat() {
        System.out.println("Orange");
    }
}
class Factory {
    public static fruit getInstance(String ClassName) {
        fruit f = null;
        try {
            f = (fruit) Class.forName(ClassName).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}
/**
 * 对于普通的工厂模式当我们在添加一个子类的时候,就需要对应的修改工厂类。 当我们添加很多的子类的时候,会很麻烦。
 * Java 工厂模式可以参考
 * http://baike.xsoftlab.net/view/java-factory-pattern
 * 
 * 现在我们利用反射机制实现工厂模式,可以在不修改工厂类的情况下添加任意多个子类。
 * 
 * 但是有一点仍然很麻烦,就是需要知道完整的包名和类名,这里可以使用properties配置文件来完成。
 * 
 * java 读取 properties 配置文件 的方法可以参考
 * http://baike.xsoftlab.net/view/java-read-the-properties-configuration-file
 * 
 * @author xsoftlab.net
 */
public class TestReflect {
    public static void main(String[] args) throws Exception {
        fruit f = Factory.getInstance("net.xsoftlab.baike.Apple");
        if (f != null) {
            f.eat();
        }
    }
}
View Code

总结

  • 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属性)

反射用途https://www.cnblogs.com/panxuejun/p/5874990.html

参考https://www.cnblogs.com/LZL-student/p/5965991.html

https://www.cnblogs.com/lzq198754/p/5780331.html

http://www.cnblogs.com/zhaoyanjun/p/6074887.html

原文地址:https://www.cnblogs.com/yanmingyuan/p/10574167.html