1. 程式人生 > >JAVA基礎知識|反射

JAVA基礎知識|反射

如果 led tac hide 行動 stat tag protected 小鳥

一、理解反射

1.1、基礎概念

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

“運行狀態”,如何理解?

"運行狀態"體現了反射的應用場景,當一些類,不需要提前加載進JVM內存,而是在運行時根據需要進行加載的時候,就可以通過反射進行動態加載

1.2、如何理解反射?

學習過java的童鞋,肯定對spring、hibernate一點也不會陌生。在進行底層配置的時候,會涉及到不同類型的數據庫問題。例如sqlserver,可能會這樣配置方言“org.hibernate.dialect.SQLServer2008Dialect”,而oracle,可以能會這樣配置“org.hibernate.dialect.OracleDialect”。不同的數據庫,只需要修改配置文件中的方言即可,這就是利用了反射的功能。程序在編譯時,並不知道會使用哪種類型的數據庫,只有在運行時,動態讀取方言的配置,加載相應的類,運行類中定義的方法和屬性,從而實現相應的功能。

其實說簡單點,反射就是一種機制,可以讓你僅知道類的名字的情況下,了解整個類的內部的結構,並且訪問內部的成員和方法等

spring中的依賴註入、反轉控制使用的都是這種機制

二、反射API及使用

反射機制的實現需要四個類:Class、Constructor、Field、Method

Class類:在程序運行期間,系統始終為所有的對象維護一個被稱為運行時的類型標識。這個信息跟蹤著每個對象所屬的類。虛擬機利用運行時類型信息選擇相應的方法執行,保存這些信息的類被稱為Class

Constructor、Field、Method:分別用於描述類的構造器、域、方法

下面我們用一個簡單的例子來演示反射的使用:

技術分享圖片
package com.my.po;

/**
 * description:{description}
 * author:jyy
 * date:2018-02-06 16:28
 * modify:{modify}
 */
public interface InterFace {
    void read();
}
View Code 技術分享圖片
package com.my.po;

/**
 * description:{description}
 * author:jyy
 * date:2018-02-03 13:20
 * modify:{modify}
 */
public class Person implements
InterFace { private String id; private String name; public String age; //構造函數1 public Person() { } //構造函數2 public Person(String id) { this.id = id; } //構造函數3 public Person(String id, String name) { this.id = id; this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } /** * 靜態方法 */ public static void update() { } @Override public void read() { } }
View Code

1)三種方式獲取Class類對象

技術分享圖片
        //第一種方法:forName
        try {
            Class<?> class1 = Class.forName("com.my.po.Person");
            System.out.println( class1 );
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //第二張方法:class
        Class<?> class2 = Person.class;
        System.out.println( class2 );

        //第三種方法:getClass
        Person person = new Person();
        Class<?> class3 = person.getClass();

        System.out.println( class3 );
View Code

執行結果:

class com.my.po.Person
class com.my.po.Person
class com.my.po.Person

2)獲取類中方法

技術分享圖片
        try {
            //創建類
            Class<?> class1 = Class.forName("com.my.po.Person");

            //getMethods()獲取當前類及其父類所有的public方法
            Method[] methods1 = class1.getMethods();
            for (Method method : methods1) {
                System.out.println(method);
            }
            System.out.println("==================");

            //getDeclaredMethods()獲取當前類所有的方法,包括private、protected修飾的方法,但不可以獲取父類的方法
            Method[] methods2 = class1.getDeclaredMethods();
            for (Method method : methods2) {
                System.out.println(method);
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
View Code

執行結果:

public static void com.my.po.Person.update()
public java.lang.String com.my.po.Person.getName()
public void com.my.po.Person.read()
public java.lang.String com.my.po.Person.getId()
public void com.my.po.Person.setName(java.lang.String)
public java.lang.String com.my.po.Person.getAge()
public void com.my.po.Person.setId(java.lang.String)
public void com.my.po.Person.setAge(java.lang.String)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
==================
public static void com.my.po.Person.update()
public java.lang.String com.my.po.Person.getName()
public void com.my.po.Person.read()
public java.lang.String com.my.po.Person.getId()
public void com.my.po.Person.setName(java.lang.String)
public java.lang.String com.my.po.Person.getAge()
public void com.my.po.Person.setId(java.lang.String)
public void com.my.po.Person.setAge(java.lang.String)

3)獲取實現的接口

技術分享圖片
        try {
            //創建類
            Class<?> class1 = Class.forName("com.my.po.Person");

            //獲取所有的接口
            Class<?>[] interfaces = class1.getInterfaces();

            for (Class<?> class2 : interfaces) {
                System.out.println(class2);
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
View Code

運行結果:

interface com.my.po.InterFace

4)獲取父類

技術分享圖片
        try {
            //創建類
            Class<?> class1 = Class.forName("com.my.po.Person");

            //獲取父類
            Class<?> superClass = class1.getSuperclass();

            System.out.println(superClass);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
View Code

運行結果:

class java.lang.Object

5)獲取構造函數

技術分享圖片
        try {
            //創建類
            Class<?> class1 = Class.forName("com.my.po.Person");

            //getConstructors()獲取當前類所有的公有構造器
            Constructor<?>[] constructors1 = class1.getConstructors() ;

            for (Constructor<?> constructor : constructors1) {
                System.out.println( constructor );
            }
            System.out.println("================");
            //getDeclaredConstructors獲取當前類所有的構造器,不包括父類構造器
            Constructor<?>[] constructors2 = class1.getDeclaredConstructors() ;
            for (Constructor<?> constructor : constructors2) {
                System.out.println( constructor );
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
View Code

public com.my.po.Person(java.lang.String,java.lang.String)
public com.my.po.Person(java.lang.String)
public com.my.po.Person()
================
public com.my.po.Person(java.lang.String,java.lang.String)
public com.my.po.Person(java.lang.String)
public com.my.po.Person()

6)獲取屬性

技術分享圖片
        try {
            //創建類
            Class<?> class1 = Class.forName("com.my.po.Person");

            //getDeclaredFields()取得當前類的全部屬性,包括private、protected修飾的屬性
            Field[] field1 = class1.getDeclaredFields();

            for (Field field : field1) {
                System.out.println( field );
            }

            System.out.println("==================");

            //getFields()取得當前類和父類所有public修飾的屬性
            Field[] field2 = class1.getFields();

            for (Field field : field2) {
                System.out.println( field );
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
View Code

運行結果:

private java.lang.String com.my.po.Person.id
private java.lang.String com.my.po.Person.name
public java.lang.String com.my.po.Person.age
==================
public java.lang.String com.my.po.Person.age

7)使用獲取到的Class對象,創建實例

技術分享圖片
        try {
            //創建類
            Class<?> class1 = Class.forName("com.my.po.Person");

            //創建實例化:相當於 new 了一個對象
            Object object = class1.newInstance();

            //向下轉型
            Person person;
            if (object instanceof Person) {
                person = (Person) object;
                person.setAge("20");
                System.out.println(person.getAge());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
View Code

運行結果:20

三、實戰項目

一個簡單的例子,使用上面所列的api

技術分享圖片
        try {
            //創建類
            Class<?> class1 = Class.forName("com.my.po.Person");

            //創建實例
            Object obj = class1.newInstance();
            Person person;
            if (obj instanceof Person) {
                person = (Person) obj;
            } else {
                person = null;
            }

            //給id,name,age賦值
            Field idField = class1.getDeclaredField("id");
            idField.setAccessible(true);//打破私有屬性封裝
            idField.set(person, "1001");
            Field nameField = class1.getDeclaredField("name");
            nameField.setAccessible(true);//打破私有屬性封裝
            nameField.set(person, "李明");
            Field ageField = class1.getDeclaredField("age");
            ageField.setAccessible(true);//打破私有屬性封裝
            ageField.set(person, "30");

            //通過執行方法給id,name,age賦值
            Method setNameMethod = class1.getDeclaredMethod("setName", String.class);
            setNameMethod.invoke(person, "王立");

            //查詢屬性值
            String id = (String) idField.get(person);
            System.out.println(id);
            String name = (String) nameField.get(person);
            System.out.println(name);


        } catch (Exception e) {
            e.printStackTrace();
        }
View Code

下面是一個模擬配置文件的例子

新建兩個類Bird、Dragonfly

技術分享圖片
public class Bird {

    public void fly() {
        System.out.println("小鳥正在飛");
    }
}
public class Dragonfly {

    public void fly() {
        System.out.println("蜻蜓正在飛");
    }
}
View Code

新建配置文件configure.properties

animal.forclass=com.my.po.Dragonfly
animal.method=fly
技術分享圖片
        try {
            //讀取配置文件
            ResourceBundle resource = ResourceBundle.getBundle("configure");
            String className = resource.getString("animal.forclass");
            String methodName = resource.getString("animal.method");

            //獲取類
            Class<?> class1 = Class.forName(className);
            //根據方法名稱,獲取方法對象
            Method m = class1.getMethod(methodName);
            //獲取構造器
            Constructor<?> constructor = class1.getDeclaredConstructor();
            //根據構造器,實例化出對象
            Object obj = constructor.newInstance();
            //調用對象的指定方法
            m.invoke(obj);

        } catch (Exception e) {
            e.printStackTrace();
        }
View Code

執行結果:

蜻蜓正在飛

修改configure.properties文件中的animal.forclass=com.my.po.Bird

執行結果:

小鳥正在飛

分享結束,如果還想對反射有更深入的理解,可以搜索ObjectAnalyzer或ReflectionToStringBuilder,試著重寫toString方法

JAVA基礎知識|反射