首頁 >Java >java教程 >java反射 之 反射基礎

java反射 之 反射基礎

高洛峰
高洛峰原創
2016-11-21 10:54:221533瀏覽

一、反射

反射:JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態所獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。

要想解剖一個類別,必須先要取得到該類別的字節碼檔案物件。而解剖使用的就是Class類別中的方法.所以先要取得到每一個字節碼檔案對應的Class類型的物件。對於反射的操作實際上就是透過Class物件來取得:

 *a、java.lang.reflect.Field:提供有關類別或介面的單一欄位的信息,以及對它的動態存取權限。反射的欄位可能是一個類別(靜態)欄位或實例欄位。操作類別的成員變數。
 *b、java.lang.reflect.Constructor:操作類別的夠造函數。
 *c、java.lang.reflect.Method:操作類別的方法。

在學習反射基礎前先建立一個Person物件作為實例

package com.jalja.org.base.relfect;

public class Person {
    private String name;
    int age;
    public String address;

    public Person() {
    }

    private Person(String name) {
        this.name = name;
    }

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public void show() {
        System.out.println("show");
    }

    public void method(String s) {
        System.out.println("method " + s);
    }

    public String getString(String s, int i) {
        return s + "---" + i;
    }

    private void function() {
        System.out.println("function");
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", address=" + address
                + "]";
    }

}

二、取得類別的Class物件

public static void getClassObject() throws ClassNotFoundException{
        //方式一:Object的getClass()方法
        Person person1=new Person();
        Person person2=new Person();
        Class c1=person1.getClass();
        Class c2=person2.getClass();
        System.out.println(person1==person2);//false
        System.out.println(c1==c2);//true 不管JVM内存中有多少个对象,对于字节码文件来说只有一份
        //方式二:数据类型的静态class属性
        Class c3=Person.class;
        System.out.println(c1==c3);//true
        //方式三:Class 类的静态方法 
        //public static Class<?> forName(String className)throws ClassNotFoundException
        Class c4=Class.forName("com.jalja.org.base.relfect.Person");
        System.out.println(c1==c4);//true
    }

三、java.lang.reflect.Constructor:物件並使用Constructor類別。

1、取得Constructor物件

//获取Class 对象所表示的类的构造方法
    public static void getConstructorTest() throws  Exception{
        Class c4=Class.forName("com.jalja.org.base.relfect.Person");
        //1、获取Class 对象所表示的类所有公共构造方法
        //public Constructor<?>[] getConstructors() throws SecurityException
        Constructor [] cs=c4.getConstructors();
        //2、获取Class 对象所表示的类所有构造方法
        //public Constructor<?>[] getDeclaredConstructors() throws SecurityException
        Constructor[] cs2 =c4.getDeclaredConstructors();
        //3、获取Class对象所表示类的指定指定公共构造方法,  parameterTypes 参数是 Class 对象的一个数组 ,是指定数据类型的字节码
        //public Constructor<T> getConstructor(Class<?>... parameterTypes);
        Constructor cs3=c4.getConstructor();//获取公共的无参构造方法的Constructor对象
        //获取 该 构造函数  public Person(String name, int age, String address)
        Constructor cs4=c4.getConstructor(String.class,int.class,String.class);
        //4、获取Clss对象所表示类指定的构造范法官 parameterTypes 参数是 Class 对象的一个数组,它按声明顺序标识构造方法的形参类型的字节码。
        //public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes);
        //获取该构造 函数 private Person(String name)  的Constructor对象
        Constructor cs5=c4.getDeclaredConstructor(String.class);
        
    }

2、透過Constructor 物件建立Class物件所表示類別的實例

public static void createObject() throws Exception{
        Class c4=Class.forName("com.jalja.org.base.relfect.Person");
        //使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例
        //public T newInstance(Object... initargs);
        // Person person=new Person()
        Constructor cs3=c4.getConstructor();//获取公共的无参构造方法的Constructor对象
        Object obj=cs3.newInstance();
        
        //Person person=new Person("jalja", 21, "北京");
        Constructor cs4=c4.getConstructor(String.class,int.class,String.class);
        Object obj1=cs4.newInstance("jalja",21,"北京");
        System.out.println(obj1);//Person [name=jalja, age=21, address=北京]
        
        //实例化一个私有的构造函数 private Person(String name)
        //控制java的访问检查
        //public void setAccessible(boolean flag)
        //将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
        //值为 false 则指示反射的对象应该实施 Java 语言访问检查。 
        Constructor cs5=c4.getDeclaredConstructor(String.class);
        cs5.setAccessible(true);
        Object obj2=cs5.newInstance("张三丰");
        System.out.println(obj2);//Person [name=张三丰, age=0, address=null]
    }

四、java.lang.reflect.Field

1、取得Field物件

指定類別屬性賦值

//获取Class类的Field对象
    public static void getFieldTest() throws Exception{
        Class cs=Class.forName("com.jalja.org.base.relfect.Person");
        //1、public Field[] getFields() throws SecurityException
        //获取Class 对象所表示的类或接口的所有可访问公共(public修饰的)字段
        Field [] fs=cs.getFields(); 
        //2、public Field[] getDeclaredFields() throws SecurityException
        // 获取Class 对象所表示的类或接口所声明的所有字段。包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段
        Field [] fs1=cs.getDeclaredFields(); 
        //3、public Field getField(String name)throws NoSuchFieldException, SecurityException;
        //获取Class 对象所表示的类或接口的指定公共成员(public修饰)字段。name 参数是一个 String,用于指定所需字段的简称
        Field fs2=cs.getField("address");
        //public Field getDeclaredField(String name)  throws NoSuchFieldException,SecurityException
        //获取 Class 对象所表示的类或接口的指定已声明字段。name 参数是一个 String,它指定所需字段的简称
        Field fs3=cs.getDeclaredField("name");
        System.out.println(fs3);
    }

五、java.lang.reflect.Method

1、取得Method物件

//使用 Field对象
    public static void createVarValue() throws Exception{
        Class cs=Class.forName("com.jalja.org.base.relfect.Person");
        Object obj=cs.getConstructor().newInstance();
        Field addressField=cs.getField("address");
        //public void set(Object obj, Object value);
        //将指定对象变量上此 Field 对象表示的字段设置为指定的新值。如果底层字段的类型为基本类型,则对新值进行自动解包
        //obj - 应该修改其字段的对象  value - 正被修改的 obj 的字段的新值 
        addressField.set(obj, "北京");
        System.out.println(obj); //Person [name=null, age=0, address=北京]
        
        //对非public修饰的变量操作
        Field nameField=cs.getDeclaredField("name");
        //控制java的访问检查
        nameField.setAccessible(true);
        nameField.set(obj, "张三丰");
        System.out.println(obj);//Person [name=张三丰, age=0, address=北京]
    }

2、透過Method物件呼叫指定類別的方法

//获取Method对象
    public static void getMethodTest() throws Exception{
        Class cs=Class.forName("com.jalja.org.base.relfect.Person");
        //1、public Method[] getMethods() throws SecurityException
        //获取Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
        Method [] m1=cs.getMethods();
        //2、public Method[] getDeclaredMethods() throws SecurityException
        //获取Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法
        Method [] m2=cs.getDeclaredMethods();
        //3、public Method getMethod(String name, Class<?>... parameterTypes)throws NoSuchMethodException, SecurityException;
        // 获取Class 对象所表示的类或接口的指定公共成员方法。name 参数是一个 String,用于指定所需方法的简称。parameterTypes 参数是按声明顺序标识该方法形参类型的 Class 对象的一个数组
        Method m3=cs.getMethod("show");//无参的方法
        Method m4=cs.getMethod("method",String.class);//带参的方法
        //public Method getDeclaredMethod(String name, Class<?>... parameterTypes)throws NoSuchMethodException,SecurityException
        // Class 对象所表示的类或接口的指定已声明方法。name 参数是一个 String,它指定所需方法的简称,parameterTypes 参数是 Class 对象的一个数组
        Method m5=cs.getDeclaredMethod("function");//无参的方法
        System.out.println(m5);
    }


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn