Java反射機制及單利模式、工廠方法

Java的反射機制是Java特性之一,反射機制是構建框架技術的基礎所在。靈活掌握Java反射機制,對大家以後學習框架技術有很大的幫助。

 

 

那麼什麼是Java的反射呢?

       大家都知道,要讓Java程序能夠運行,那麼就得讓Java類要被Java虛擬機加載。Java類如果不被Java虛擬機加載,是不能正常運行的。現在我們運行的所有的程序都是在編譯期的時候就已經知道了你所需要的那個類的已經被加載了。

Java的反射機制是在編譯並不確定是哪個類被加載了,而是在程序運行的時候才加載、探知、自審。使用在編譯期並不知道的類。這樣的特點就是反射。

 

那麼Java反射有什麼作用呢?

假如我們有兩個程序員,一個程序員在寫程序的時候,需要使用第二個程序員所寫的類,但第二個程序員並沒完成他所寫的類。那麼第一個程序員的代碼能否通過編譯呢?這是不能通過編譯的。利用Java反射的機制,就可以讓第一個程序員在沒有得到第二個程序員所寫的類的時候,來完成自身代碼的編譯。

 

Java的反射機制它知道類的基本結構,這種對Java類結構探知的能力,我們稱爲Java類的“自審”。大家都用過Jcreator和eclipse。當我們構建出一個對象的時候,去調用該對象的方法和屬性的時候。一按點,編譯工具就會自動的把該對象能夠使用的所有的方法和屬性全部都列出來,供用戶進行選擇。這就是利用了Java反射的原理,是對我們創建對象的探知、自審。

 

 

Class類

       要正確使用Java反射機制就得使用java.lang.Class這個類。它是Java反射機制的起源。當一個類被加載以後,Java虛擬機就會自動產生一個Class對象。通過這個Class對象我們就能獲得加載到虛擬機當中這個Class對象對應的方法、成員以及構造方法的聲明和定義等信息。

 

 

反射API

 

       反射API用於反應在當前Java虛擬機中的類、接口或者對象信息功能

  —獲取一個對象的類信息.

       —獲取一個類的訪問修飾符、成員、方法、構造方法以及超類的信息.

       —檢獲屬於一個接口的常量和方法聲明.

       —創建一個直到程序運行期間才知道名字的類的實例.

       —獲取並設置一個對象的成員,甚至這個成員的名字是 在程序運行期間才知道.

       —檢測一個在運行期間才知道名字的對象的方法

常用方法:

  Class c=Class.forName("className");註明:className必須爲全名,也就是得包含包名,比如,cn.netjava.pojo.UserInfo; 
    Object obj=c.newInstance();//創建對象的實例 
    OK,有了對象就什麼都好辦了,想要什麼信息就有什麼信息了。   
    獲得構造函數的方法 
    Constructor getConstructor(Class[] params)//根據指定參數獲得public構造器

    Constructor[] getConstructors()//獲得public的所有構造器

    Constructor getDeclaredConstructor(Class[] params)//根據指定參數獲得public和非public的構造器

    Constructor[] getDeclaredConstructors()//獲得public的所有構造器 
    獲得類方法的方法 
    Method getMethod(String name, Class[] params),根據方法名,參數類型獲得方法

    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[] getDeclaredFields()//獲得類中所有的public和非public方法 

 

       利用Java反射機制我們可以很靈活的對已經加載到Java虛擬機當中的類信息進行檢測。當然這種檢測在對運行的性能上會有些減弱,所以什麼時候使用反射,就要靠業務的需求、大小,以及經驗的積累來決定。

 

       那麼如何利用反射API在運行的時候知道一個類的信息呢?

 

代碼示例:

 

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import javax.swing.JOptionPane;

/**

  *本類用於測試反射API,利用用戶輸入類的全路徑,

*找到該類所有的成員方法和成員屬性

  */

public classMyTest {

 

    /**

     *構造方法

     */

    publicMyTest(){

      

       StringclassInfo=JOptionPane.showInputDialog(null,"輸入類全路徑");//要求用戶輸入類的全路徑

      

       try {

           Classcla=Class.forName(classInfo);//根據類的全路徑進行類加載,返回該類的Class對象

          

           Method[]method=cla.getDeclaredMethods();//利用得到的Class對象的自審,返回方法對象集合

          

           for(Methodme:method){//遍歷該類方法的集合

              System.out.println(me.toString());//打印方法信息

           }

          

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

          

           Field[]field=cla.getDeclaredFields();//利用得到的Class對象的自審,返回屬性對象集合

           for(Fieldme:field){ //遍歷該類屬性的集合

              System.out.println(me.toString());//打印屬性信息

           }

       } catch(ClassNotFoundException e) {

           e.printStackTrace();

       }

    }

    public static voidmain(String[] args) {

       newMyTest();

    }

}

 

運行的時候,我們輸入javax.swing.JFrame,那麼運行結果如下:

 

public void javax.swing.JFrame.remove(java.awt.Component)

public void javax.swing.JFrame.update(java.awt.Graphics)

…………

 

********

public static final int javax.swing.JFrame.EXIT_ON_CLOSE

private int javax.swing.JFrame.defaultCloseOperation

 

…………

 

    大家可以發現,類的全路徑是在程序運行的時候,由用戶輸入的。所以虛擬機事先並不知道所要加載類的信息,這就是利用反射機制來對用戶輸入的類全路徑來對類自身的一個自審。從而探知該類所擁有的方法和屬性。

 

通過上面代碼,大家可以知道編譯工具爲什麼能夠一按點就能列出用戶當前對象的屬性和方法了。它是先獲得用戶輸入對象的字符串,然後利用反射原理來對這樣的類進行自審,從而列出該類的方法和屬性。

 

 

 

使用反射機制的步驟:

u導入java.lang.relfect 包

 

u遵循三個步驟
第一步是獲得你想操作的類的java.lang.Class 對象
第二步是調用諸如getDeclaredMethods 的方法
第三步使用反射API 來操作這些信息

 

 

 

 

 

獲得Class對象的方法

 

u如果一個類的實例已經得到,你可以使用

       【Class c = 對象名.getClass(); 】

      例: TextField t = new TextField();

              Classc = t.getClass();

              Classs = c.getSuperclass();

 

u如果你在編譯期知道類的名字,你可以使用如下的方法

Class c = java.awt.Button.class;
或者

         Class c = Integer.TYPE;

 

 

u如果類名在編譯期不知道, 但是在運行期可以獲得, 你可以使用下面的方法

          Class c = Class.forName(strg);

 

   這樣獲得Class類對象的方法,其實是利用反射API把指定字符串的類加載到內存中,所以也叫類加載器加載方法。這樣的話,它會把該類的靜態方法和靜態屬性,以及靜態代碼全部加載到內存中。但這時候,對象還沒有產生。所以爲什麼靜態方法不能訪問非靜態屬性和方法。因爲靜態方法和屬性產生的時機在非靜態屬性和方法之前。

 

 

代碼示例:

package  com;

 

public classMyTest {

    public static void main(String[]args) {

       TestOne  one=null;

       try{

       Class  cla=Class.forName("com.TestOne");//進行com.TestOne類加載,返回一個Class對象

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

       one=(TestOne)cla.newInstance();//產生這個Class類對象的一個實例,調用該類無參的構造方法,作用等同於new TestOne()

       }catch(Exception e){

           e.printStackTrace();

       }

       TestOne two=newTestOne();

  System.out.println(one.getClass()== two.getClass());//比較兩個TestOne對象的Class對象是否是同一個對象,在這裏結果是true。說明如果兩個對象的類型相同,那麼它們會有相同的Class對象

    }

}

 

class TestOne{

    static{

       System.out.println("靜態代碼塊運行");

    }

    TestOne(){

       System.out.println("構造方法");

    }

}

  以上代碼過行的結果是:

靜態代碼塊運行

***********

構造方法

構造方法

 

代碼分析:

 

在進行Class.forName("com.TestOne")的時候,實際上是對com.TestOne進行類加載,這時候,會把靜態屬性、方法以及靜態代碼塊都加載到內存中。所以這時候會打印出"靜態代碼塊運行"。但這時候,對象卻還沒有產生。所以"構造方法"這幾個字不會打印。當執行cla.newInstance()的時候,就是利用反射機制將Class對象生成一個該類的一個實例。這時候對象就產生了。所以打印"構造方法"。當執行到TestOnetwo=new TestOne()語句時,又生成了一個對象。但這時候類已經加載完畢,靜態的東西已經加載到內存中,而靜態代碼塊只執行一次,所以不用再去加載類,所以只會打印"構造方法",而"靜態代碼塊運行"不會打印。

 

 

 

 

反射機制不但可以列出該類對象所擁有的方法和屬性,還可以獲得該類的構造方法及通過構造方法獲得實例。也可以動態的調用這個實例的成員方法。

 

 

代碼示例:

 

package reflect;

 

importjava.lang.reflect.Constructor;

 

 

/**

 *

 * 本類測試反射獲得類的構造器對象,

 * 並通過類構造器對象生成該類的實例

 *

 */

public classConstructorTest {

 

    public static voidmain(String[] args) {

       try {

           //獲得指定字符串類對象

           Classcla=Class.forName("reflect.Tests");

           //設置Class對象數組,用於指定構造方法類型

           Class[]cl=new Class[]{int.class,int.class};

          

           //獲得Constructor構造器對象。並指定構造方法類型

           Constructorcon=cla.getConstructor(cl);

          

           //給傳入參數賦初值

           Object[]x={new Integer(33),newInteger(67)};

          

           //得到實例

           Objectobj=con.newInstance(x);

       } catch (Exception e) {

           e.printStackTrace();

       }

    }

 

}

 

class Tests{

    publicTests(int x,int y){

       System.out.println(x+"    "+y);

    }

}

 

 

運行的結果是” 33    67”。說明我們已經生成了Tests這個類的一個對象。

 

 

同樣,也可以通過反射模式,來執行Java類的方法

 

 

 

 

代碼示例:

package reflect;

 

import java.lang.reflect.Method;

 

/**

 *

 * 本類測試反射獲得類的方法對象,

 * 並通過類對象和類方法對象,運行該方法

 *

 */

public classMethodTest {

 

    public static voidmain(String[] args) {

       try {

           //獲得窗體類的Class對象

           Classcla=Class.forName("javax.swing.JFrame");

          

           //生成窗體類的實例

           Objectobj=cla.newInstance();

          

       //獲得窗體類的setSize方法對象,並指定該方法參數類型爲int,int

           MethodmethodSize=cla.getMethod("setSize", newClass[]{int.class,int.class});

          

           /*

            * 執行setSize()方法,並傳入一個Object[]數組對象,

            * 作爲該方法參數,等同於  窗體對象.setSize(300,300);

            */

           methodSize.invoke(obj,new Object[]{newInteger(300),new Integer(300)});

          

       //獲得窗體類的setSize方法對象,並指定該方法參數類型爲boolean

           MethodmethodVisible=cla.getMethod("setVisible", newClass[]{boolean.class});

          

           /*

            * 執行setVisible()方法,並傳入一個Object[]數組對象,              *作爲該方法參數。等同於  窗體對象.setVisible(true);

            */

           methodVisible.invoke(obj,new Object[]{newBoolean(true)});

          

       } catch(Exception e) {

           e.printStackTrace();

       }

    }

}

 

 

 

反射技術大量用於Java設計模式和框架技術,最常見的設計模式就是工廠模式(Factory)和單例模式(Singleton)。

 

單例模式(Singleton)

 

       這個模式主要作用是保證在Java應用程序中,一個類Class只有一個實例存在。在很多操作中,比如建立目錄 數據庫連接都需要這樣的單線程操作。這樣做就是爲了節省內存空間,保證我們所訪問到的都是同一個對象。

 

       單例模式要求保證唯一,那麼怎麼樣才能保證唯一性呢?對了,這就是靜態變量。單例模式有以下兩種形式:

 

第一種形式:

package reflect;

 

public classSingleton {

    /*

     * 注意這是private私有的構造方法, 只供內部調用

     * 外部不能通過new的方式來生成該類的實例

     */

    privateSingleton() {

    }

 

    /*

     * 在自己內部定義自己一個實例,是不是很奇怪?

     * 定義一個靜態的實例,保證其唯一性

     */

    private staticSingleton instance = newSingleton();

 

    // 這裏提供了一個供外部訪問本class的靜態方法,可以直接訪問

    public staticSingleton getInstance() {

           return instance;

    }

   

}

 

 

 

/**

 *測試單例模式

 */

class SingRun{

    public static voidmain(String[] args){

       //這樣的調用不被允許,因爲構造方法是私有的。

       //Singletonx=new Singleton();

      

       //得到一個Singleton類實例

       Singletonx=Singleton.getInstance();

      

       //得到另一個Singleton類實例

       Singletony=Singleton.getInstance();

      

       //比較x和y的地址,結果爲true。說明兩次獲得的是同一個對象

       System.out.println(x==y);

    }

}

 

 

第二種形式:

 

public classSingleton {

 

    //先申明該類靜態對象

    private staticSingleton instance = null;

   

    //創建一個靜態訪問器,獲得該類實例。加上同步,表示防止兩個線程同時進行對象的創建

    public static synchronizedSingleton getInstance() {

      

       //如果爲空,則生成一個該類實例

       if (instance == null){

           instance = newSingleton();

       }

       return instance;

    }

 

}

 

 

 

 

 

工廠模式(Factory)

 

       工廠模式是我們最常用的模式了,著名的Jive論壇 ,就大量使用了工廠模式,工廠模式在Java程序系統可以說是隨處可見。

 

爲什麼工廠模式是如此常用?是因爲工廠模式利用Java反射機制和Java多態的特性可以讓我們的程序更加具有靈活性。用工廠模式進行大型項目的開發,可以很好的進行項目並行開發。就是一個程序員和另一個程序員可以同時去書寫代碼,而不是一個程序員等到另一個程序員寫完以後再去書寫代碼。其中的粘合劑就是接口和配置文件。

之前說利用接口可以將調用和實現相分離。

 

 

 

那麼這是怎麼樣去實現的呢?工廠模式可以爲我們解答。

 

我們先來回顧一下軟件的生命週期,分析、設計、編碼、調試與測試。其中分析就是指需求分析,就是知道這個軟件要做成什麼樣子,要實現什麼樣的功能。功能知道了,這時就要設計了。設計的時候要考慮到怎麼樣高效的實現這個項目,如果讓一個項目團隊並行開發。這時候,通常先設計接口,把接口給實現接口的程序員和調用接口的程序員,在編碼的時候,兩個程序員可以互不影響的實現相應的功能,最後通過配置文件進行整合。

 

 

代碼示例:

 

 

/**

 *

 *定義接口

 */

interface InterfaceTest{

    public voidgetName();//定義獲得名字的方法

}

 

 

接口有了,那麼得到這個接口,進行實現編碼的程序員應該怎麼做呢?對了,實現這個接口,重寫其中定義的方法

 

接口實現方:

/**

 *第一個程序員書寫的,實現這個接口的類

 */

class Test1 implementsInterfaceTest{

   

    /*

     * 根據業務,重寫方法

     */

    public voidgetName() {

       System.out.println("test1");

    }

   

}

 

/**

 *第二個程序員書寫的,實現這個接口的類

 */

class Test2 implementsInterfaceTest{

   

    /*

     * 根據業務,重寫方法

     */

    public voidgetName() {

       System.out.println("test2");

    }

   

}

 

大家可以發現,當接口定義好了以後,不但可以規範代碼,而且可以讓程序員有條不紊的進行功能的實現。實現接口的程序員根本不用去管,這個類要被誰去調用。

 

那麼怎麼能獲得這些程序員定義的對象呢?在工廠模式裏,單獨定義一個工廠類來實現對象的生產,注意這裏返回的接口對象。

 

工廠類,生產接口對象:

/**

 * 本類爲工廠類,用於生成接口對象

 */

class Factory{

    //創建私有的靜態的Properties對象

    private staticProperties pro=new Properties();

   

    //靜態代碼塊

    static{

       try {

          

           //加載配置文件

           pro.load(newFileInputStream("file.txt"));

       } catch (Exception e) {

           e.printStackTrace();

       }

    }

   

    /**

     * 單例模式,保證該類只有一個對象

     */

    private staticFactory factory=new Factory();

    privateFactory(){}

   

    public staticFactory getFactory(){

       return factory;

    }

   

    /**

     * 本方法爲公有方法,用於生產接口對象

     * @return InterfaceTest接口對象

     */

    public  InterfaceTest getInterface(){

       InterfaceTestinterfaceTest=null;//定義接口對象

      

       try {

           //根據鍵,獲得值,這裏的值是類的全路徑

           StringclassInfo=pro.getProperty("test");

          

           //利用反射,生成Class對象

           Classc=Class.forName(classInfo);

          

           //獲得該Class對象的實例

           Objectobj=c.newInstance();

          

           //將Object對象強轉爲接口對象

           interfaceTest=(InterfaceTest)obj;

       } catch (Exception e) {

           e.printStackTrace();

       }

      

       //返回接口對象

       returninterfaceTest;

    }

}

 

配置文件內容:

test=factory.Test2

 

通過這個類,大家可以發現,在調用的時候,得到的是個接口對象。而一個接口變量可以指向實現了這個接口的類對象。在利用反射的時候,我們並沒有直接把類的全路徑寫出來,而是通過鍵獲得值。這樣的話,就有很大的靈活性,只要改變配置文件裏的內容,就可以改變我們調用的接口實現類,而代碼不需做任何改變。在調用的時候,我們也是通過接口調用,甚至我們可以連這個接口實現類的名字都不知道。

 

調用方:

 

public classFactoryTest {

 

    public static voidmain(String[] args) {

       //獲得工廠類的實例

        Factory factory=Factory.getFactory();

       //調用獲得接口對象的方法,獲得接口對象

       InterfaceTestinter=factory.getInterface();

       //調用接口定義的方法

       inter.getName();

    }

}

 

 

上面的代碼就是調用方法。大家可以發現,在調用的時候,我們根本沒有管這個接口定義的方法要怎麼樣去實現它,我們只知道這個接口定義這個方法起什麼作用就行了。上面代碼運行結果要根據配置文件來定。如果配置文件裏的內容是test=factory.Test2。那麼表示調用factory.Test2這個類裏實現接口的方法,這時候打印“test2”。如果配置文件裏的內容是test=factory.Test1。那麼表示調用factory.Test1這個類裏實現接口的方法,這時候打印“test1”。

 

 

 

 

 

反射機制是框架技術的原理和核心部分。通過反射機制我們可以動態的通過改變配置文件(以後是XML文件)的方式來加載類、調用類方法,以及使用類屬性。這樣的話,對於編碼和維護帶來相當大的便利。在程序進行改動的時候,也只會改動相應的功能就行了,調用的方法是不用改的。更不會一改就改全身。

 

 

 

 

 

用反射機制實現對數據庫數據的增、查例子 

 

 1)數據庫的每一個表對象一個pojo類,表中的每一個字段對應pojo類的中的一個屬性。  並且pojo類的名字和表的名字相同,屬性名和字段名相同,大小寫沒有關     系,因爲數據庫一般不區分大小寫  
 2)爲pojo類中的每一個屬性添加標準的set和get方法。 

首先數據庫的有一個表,假設數據庫名稱爲:blogsystem,裏面的一個表名userinfo。

 

1、創建對應的pojo類:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package cn.netjava.pojo;
 
public class UserInfo {
private int id;
private String name;
private String pwd;
private int age;
 
@Override
public String toString() {
    return "UserInfo [id=" + id + ", name=" + name + ", pwd=" + pwd + ", age="
            + age + "]";
}
public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public String getPwd() {
    return pwd;
}
public void setPwd(String pwd) {
    this.pwd = pwd;
}
public int getAge() {
    return age;
}
public void setAge(int age) {
    this.age = age;
}
 
}

 


2、編寫獲得數據庫連接的工廠類: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package cn.netjava.factory;
 
import java.sql.Connection;
import java.sql.DriverManager;
 
public class Connect2DBFactory {
    public static Connection getDBConnection() {
        Connection conn = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/blogsystem";
            String user = "root";
            String password = "netjava";
            conn = DriverManager.getConnection(url, user, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
 
        return conn;
    }
}

3、編寫操作數據庫的dao類

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package cn.netjava.session;
 
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
 
import cn.netjava.factory.Connect2DBFactory;
import cn.netjava.pojo.UserInfo;
 
public class NetJavaSession {
    /**
     * 解析出保存對象的sql語句
     *
     * @param object
     *            :需要保存的對象
     * @return:保存對象的sql語句
     */
    public static String getSaveObjectSql(Object object) {
        // 定義一個sql字符串
        String sql = "insert into ";
        // 得到對象的類
        Class c = object.getClass();
        // 得到對象中所有的方法
        Method[] methods = c.getMethods();
        // 得到對象中所有的屬性
        Field[] fields = c.getFields();
        // 得到對象類的名字
        String cName = c.getName();
        // 從類的名字中解析出表名
        String tableName = cName.substring(cName.lastIndexOf(".") + 1,
                cName.length());
        sql += tableName + "(";
        List<String> mList = new ArrayList<String>();
        List vList = new ArrayList();
        for (Method method : methods) {
            String mName = method.getName();
            if (mName.startsWith("get") && !mName.startsWith("getClass")) {
                String fieldName = mName.substring(3, mName.length());
                mList.add(fieldName);
                System.out.println("字段名字----->" + fieldName);
                try {
                    Object value = method.invoke(object, null);
                    System.out.println("執行方法返回的值:" + value);
                    if (value instanceof String) {
                        vList.add("\"" + value + "\"");
                        System.out.println("字段值------>" + value);
                    } else {
                        vList.add(value);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        for (int i = 0; i < mList.size(); i++) {
            if (i < mList.size() - 1) {
                sql += mList.get(i) + ",";
            } else {
                sql += mList.get(i) + ") values(";
            }
        }
        for (int i = 0; i < vList.size(); i++) {
            if (i < vList.size() - 1) {
                sql += vList.get(i) + ",";
            } else {
                sql += vList.get(i) + ")";
            }
        }
 
        return sql;
    }
 
    public static List getDatasFromDB(String tableName, int Id) {
 
        return null;
 
    }
 
    /**
     * 將對象保存到數據庫中
     *
     * @param object
     *            :需要保存的對象
     * @return:方法執行的結果;1:表示成功,0:表示失敗
     */
    public int saveObject(Object object) {
        Connection con = Connect2DBFactory.getDBConnection();
        String sql = getSaveObjectSql(object);
        try {
            // Statement statement=(Statement) con.createStatement();
            PreparedStatement psmt = con.prepareStatement(sql);
            psmt.executeUpdate();
            return 1;
        } catch (SQLException e) {
            e.printStackTrace();
            return 0;
        }
    }
 
    /**
     * 從數據庫中取得對象
     *
     * @param arg0
     *            :對象所屬的類
     * @param id
     *            :對象的id
     * @return:需要查找的對象
     */
    public Object getObject(String className, int Id) {
        // 得到表名字
        String tableName = className.substring(className.lastIndexOf(".") + 1,
                className.length());
        // 根據類名來創建Class對象
        Class c = null;
        try {
            c = Class.forName(className);
 
        } catch (ClassNotFoundException e1) {
 
            e1.printStackTrace();
        }
        // 拼湊查詢sql語句
        String sql = "select * from " + tableName + " where Id=" + Id;
        System.out.println("查找sql語句:" + sql);
        // 獲得數據庫鏈接
        Connection con = Connect2DBFactory.getDBConnection();
        // 創建類的實例
        Object obj = null;
        try {
 
            Statement stm = con.createStatement();
            // 得到執行查尋語句返回的結果集
            ResultSet set = stm.executeQuery(sql);
            // 得到對象的方法數組
            Method[] methods = c.getMethods();
            // 遍歷結果集
            while (set.next()) {
                obj = c.newInstance();
                // 遍歷對象的方法
                for (Method method : methods) {
                    String methodName = method.getName();
                    // 如果對象的方法以set開頭
                    if (methodName.startsWith("set")) {
                        // 根據方法名字得到數據表格中字段的名字
                        String columnName = methodName.substring(3,
                                methodName.length());
                        // 得到方法的參數類型
                        Class[] parmts = method.getParameterTypes();
                        if (parmts[0] == String.class) {
                            // 如果參數爲String類型,則從結果集中按照列名取得對應的值,並且執行改set方法
                            method.invoke(obj, set.getString(columnName));
                        }
                        if (parmts[0] == int.class) {
                            method.invoke(obj, set.getInt(columnName));
                        }
                    }
 
                }
            }
 
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }
}

4、測試效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package cn.netjava.tester;
 
import cn.netjava.pojo.UserInfo;
import cn.netjava.session.NetJavaSession;
 
public class Tester {
    public static void main(String args[]) {
        //獲得NetJavaSession對象
        NetJavaSession session = new NetJavaSession();
        //創建一個UserInfo對象
        UserInfo user = new UserInfo();
        //設置對象的屬性
        user.setId(6988);
        user.setAge(44);
        user.setPwd("pwd");
        user.setName("champion");
        //將對象保存到數據庫中
        String sql = session.getSaveObjectSql(user);
        System.out.println("保存對象的sql語句:" + sql);
        //查找對象
        UserInfo userInfo = (UserInfo) session.getObject(
                "cn.netjava.pojo.UserInfo", 6988);
        System.out.println("獲取到的信息:" + userInfo);
 
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章