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);
 
     }
}
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐