一、泛型概要
泛型(Generic)的本質是類型參數化,通俗的說就是用一個占位符來表示類型,這個類型可以是String,Integer等不確定的類型,表明可接受的類型。
泛型是Java中一個非常重要的知識點,在Java集合類框架中泛型被廣泛應用。
1.1、為什么需要泛型
在數據結構中有一種結構叫:棧,它的特點是:先進后出,后進先出
如:放衣服的箱子,糖葫蘆

現在來模擬一個棧的數據結構

1.1.1、版本一(強類型)
package com.nf.math; public class ObjUtil { public static void main(String[] args) { Stack stack=new Stack(); stack.push(11); stack.push(22); stack.push(55); int data=stack.pop(); System.out.println(data); System.out.println(stack.pop()); System.out.println(stack.pop()); } } class Stack{ //用於存放數據的數組 private int[] data=new int[10]; //當前下標 private int i=0; //進棧 public void push(int obj){ data[i++]=obj; } //出棧 public int pop(){ return data[--i]; } }
結果:
55 22 11
缺點是不通用
1.1.2、版本二(Object弱類型)
版本一有明顯的缺點,只允許存放int類型的數據,如果需要其它類型的數據怎么辦法?
有人提議重新創建不同類型的棧,這樣不好,因為如果需要10種不同類型的棧,則需定義10個,維護也麻煩。
使用Object也許可以解決問題,代碼如下:
package com.nf.math; public class ObjUtil { public static void main(String[] args) { Stack stack=new Stack(); stack.push(1.1); stack.push(2.2); stack.push(5.5); double data=(double)stack.pop(); System.out.println(data); System.out.println(stack.pop()); System.out.println(stack.pop()); } } class Stack{ //用於存放數據的數組 private Object[] data=new Object[10]; //當前下標 private int i=0; //進棧 public void push(Object obj){ data[i++]=obj; } //出棧 public Object pop(){ return data[--i]; } }
結果:
5.5 2.2 1.1
缺點是安全隱患(類型轉換)
1.1.3、版本三(泛型)
版本二中存在類型的強制轉換,如果轉換的類型不匹配則會引起運行時異常,存在安全隱患,使用泛型可以解決該問題:
package com.nf.math; public class ObjUtil { public static void main(String[] args) { Stack<Double> stack=new Stack<Double>(); stack.push(1.1); stack.push(2.2); stack.push(5.5); double data=stack.pop(); //不需要拆箱,沒有類型轉換 System.out.println(data); System.out.println(stack.pop()); System.out.println(stack.pop()); } } class Stack<T>{ //用於存放數據的數組 private T[] data=(T[])(new Object[10]); //當前下標 private int i=0; //進棧 public void push(T obj){ data[i++]=obj; } //出棧 public T pop(){ return data[--i]; } }
結果:
5.5 2.2 1.1
因為使用了泛型,兼具了版本一與版本二的優點,沒有類型轉換,沒有安全隱患,可以適用多種不同的數據類型。
java不支持泛型數組,List或ArrayList具有泛型數組的功能。
1.2、泛型的優點
沒有泛型的情況的下,通過對類型Object的引用來實現參數的“任意化”,“任意化”帶來的缺點是要做顯式的強制類型轉換,而這種轉換是要求開發者對實際參數類型可以預知的情況下進行的。對於強制類型轉換錯誤的情況,編譯器可能不提示錯誤,在運行的時候才出現異常,這是一個安全隱患。
泛型的好處是在編譯的時候檢查類型安全,並且所有的強制轉換都是自動和隱式的,以提高代碼的重用率。
1、提高程序的安全性和可靠性
使用類型更安全,指定具體類型后,Java編譯器會對錯誤的類型在編譯時被捕獲,而不是在運行時當作ClassCastException展示出來,從而提高程序的安全性和可靠性
2、消除強制類型轉換
例如在集合里使用泛型后,從集合里取出對象后就不需要再進行強制類型轉換了,這樣使編寫程序變得更簡單,更不容易出錯
3、提高代碼重用率
在一個類里要對不同結構類型的對象進行操作時,有的對象成員和方法的邏輯都是一樣的,就是類型不一樣,就有可能會造成不必要的代碼重復,通過使用泛型,只需要一個Java類就可以表示不同類型的對象,從而可以大大提高代碼的重用率
1.3、泛型規則
1、泛型的類型參數只能是類類型(包括自定義類),不能是簡單類型。
Stack<Double> stack=new Stack<Double>();
2、同一種泛型可以對應多個版本(因為參數類型是不確定的),不同版本的泛型類實例是不兼容的。
Stack<Integer> stack2=stack; //錯誤
3、泛型的類型參數可以有多個。
class Stack<T,E,K,M,X>{ }
4、泛型的參數類型可以使用extends語句,例如<T extends superclass>。習慣上稱為“有界類型”。
泛型約束,約束T的類型只能是superclass的子類型
5、泛型的參數類型還可以是通配符類型。例如Class<?> classType = Class.forName("java.lang.String");
1.4、Java中方法的參數
java中方法參數傳遞的都是值,與C#區別很大,沒有ref與out。
java中數據類型分為基本數據類型和引用數據類型。
- 基本數據類型
- 整型:byte,short,int,long
- 浮點型:float,double
- 字符型:char
- 布爾型:boolean
- 引用數據類型
- 數組
- 類
- 接口
方法的參數分為實際參數,和形式參數。
- 形式參數:定義方法時寫的參數。
- 實際參數:調用方法時寫的具體數值。
1.4.1、基本數據類型
package com.nf.math; public class ObjUtil { public static void main(String[] args) { Util util=new Util(); int n1=100,n2=200; util.Swap(n1, n2); //副本 System.out.println("n1="+n1+",n2="+n2); } } class Util { public void Swap(int n1, int n2) { int temp = n1; n1 = n2; n2 = temp; } }
結果:
n1=100,n2=200
從上面的結果可以看出n1與n2在調用交換方法后並沒有實質交換,是因為形參是n1與n2的副本。
1.4.2、引用類型
package com.nf.math; public class ObjUtil { public static void main(String[] args) { Util util=new Util(); String n1="100",n2="200"; util.Swap(n1, n2); //形參是n1的引用副本 System.out.println("n1="+n1+",n2="+n2); } } class Util { public void Swap(String n1, String n2) { String temp = n1; n1 = n2; n2 = temp; } }
結果:
n1=100,n2=200
依然沒有交互
String對象做為參數傳遞時,走的依然是引用傳遞,只不過String這個類比較特殊。
String對象一旦創建,內容不可更改。每一次內容的更改都是重現創建出來的新對象。
1.4.3、結論
- 值傳遞的時候,將實參的值,copy一份給形參。
- 引用傳遞的時候,將實參的地址值,copy一份給形參。
也就是說,不管是值傳遞還是引用傳遞,形參拿到的僅僅是實參的副本,而不是實參本身。
二、自定義泛型類
示例:
package com.nf.math; public class BoxTest { public static void main(String[] args) { Box<Integer> boxInt = new Box<Integer>(); boxInt.setAttr(5); System.out.println(boxInt.getAttr() + 1); } } class Box<T> { private T attr; public T getAttr() { return this.attr; } public void setAttr(T attr) { this.attr = attr; } }
結果:
6
三、自定義泛型方法
在自定義泛型類中,整個類都可以使用類型占位T,有時候只需要局部用到則可以定義泛型方法
定義泛型方法,語法如下:
[訪問修飾符] <泛型列表> 返回值 方法名(參數列表) { //方法體; }
示例:
package com.nf.math; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class BoxTest { public static void main(String[] args) { Box<Integer> boxInt = new Box<Integer>(); boxInt.setAttr(5); System.out.println(boxInt.getAttr() + 1); ReflectUtil.getMethods(Box.class); } } class Box<T> { private T attr; public T getAttr() { return this.attr; } public void setAttr(T attr) { this.attr = attr; } } class ReflectUtil { public static <T> void getMethods(Class<T> type){ Method[] methods=type.getMethods(); System.out.println(type.getName()+":"); for (Method method : methods) { System.out.println(Modifier.toString(method.getModifiers())+" "+method.getReturnType()+" "+method.getName()+"()"); } } }
結果:

說明:
1)在泛型列表中聲明的泛型,可用於該方法的返回值類型聲明、參數類型聲明和方法代碼中的局部變量的類型聲明
2)類中其他方法不能使用當前方法聲明的泛型
3)使用泛型方法時,不必指明參數類型,編譯器會自己找出具體的類型;泛型方法除了定義不同,調用就像普通方法一樣。
注意:是否擁有泛型方法,與其所在的類是否泛型沒有關系。要定義泛型方法,只需將泛型參數列表置於返回值前。
四、通配符與泛型約束
4.1、類型通配符
類型通配符一般是使用 ? 代替具體的類型實參。
package com.nf.math; public class BeanTest { public static void main(String[] args) { // 同一種泛型可以對應多個版本(因為參數類型是不確定的) // 不同版本的泛型類實例是不兼容的。 Bean<String> bean1 = new Bean<String>(); Bean<Integer> bean2 = new Bean<Integer>(); System.out.println(bean1.getClass().getName()); // 類型 System.out.println(bean2.getClass().getName()); Bean<Number> bean3 = bean1; } } class Bean<T> { private T var; public T getVar() { return var; } public void setVar(T var) { this.var = var; } @Override public String toString() { return var.toString(); } }
運行結果:

示例
package com.nf.math; public class BeanTest { public static void main(String[] args) { // 同一種泛型可以對應多個版本(因為參數類型是不確定的) // 不同版本的泛型類實例是不兼容的。 Bean<String> bean1 = new Bean<String>(); bean1.setVar("one"); Bean<Integer> bean2 = new Bean<Integer>(); bean2.setVar(2); System.out.println(bean1.getClass().getName()); // 類型 System.out.println(bean2.getClass().getName()); Bean<?> bean3 = bean1; Show(bean1); //Show(bean2);錯誤 Display(bean1); Display(bean2); } public static void Show(Bean<String> p){ System.out.println("內容是:"+p.getVar()); } public static void Display(Bean<?> p){ System.out.println("內容是:"+p); } } class Bean<T> { private T var; public T getVar() { return var; } public void setVar(T var) { this.var = var; } @Override public String toString() { return var.toString(); } }
結果:
com.nf.math.Bean
com.nf.math.Bean
內容是:one
內容是:one
內容是:2
示例:
class Info<T>{ private T var ; // 定義泛型變量 public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } public String toString(){ // 直接打印 return this.var.toString() ; } }; public class GenericsDemo{ public static void main(String args[]){ Info<String> i = new Info<String>() ; // 使用String為泛型類型 i.setVar("it") ; // 設置內容 fun(i) ; } public static void fun(Info<?> temp){ // 可以接收任意的泛型對象 System.out.println("內容:" + temp) ; } };
4.2、 上界
4.2.1、通配符上界
類型通配符上限通過形如Stack<? extends Number>形式定義
class Info<T>{ private T var ; // 定義泛型變量 public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } public String toString(){ // 直接打印 return this.var.toString() ; } }; public class GenericsDemo17{ public static void main(String args[]){ Info<Integer> i1 = new Info<Integer>() ; // 聲明Integer的泛型對象 Info<Float> i2 = new Info<Float>() ; // 聲明Float的泛型對象 i1.setVar(30) ; // 設置整數,自動裝箱 i2.setVar(30.1f) ; // 設置小數,自動裝箱 fun(i1) ; fun(i2) ; } public static void fun(Info<? extends Number> temp){ // 只能接收Number及其Number的子類 System.out.print(temp + "、") ; } };
示例
package com.nf.math; public class BeanTest { public static void main(String[] args) { Bean<String> bean1 = new Bean<String>(); bean1.setVar("one"); //public final class Integer extends Number implements Comparable<Integer> { Bean<Integer> bean2 = new Bean<Integer>(); bean2.setVar(2); Bean<Number> bean3 = new Bean<Number>(); bean3.setVar(3); //Display(bean1); 錯誤,原因是T必須繼承Number或就是Number類型 Display(bean2); Display(bean3); } public static void Display(Bean<? extends Number> p){ System.out.println("內容是:"+p); } } class Bean<T> { private T var; public T getVar() { return var; } public void setVar(T var) { this.var = var; } @Override public String toString() { return var.toString(); } }
結果
內容是:2
內容是:3
4.2.2、占位符上界
package com.nf.math; public class BeanTest { public static void main(String[] args) { Bean<String> bean1 = new Bean<String>(); //錯誤,因為T有上界,要求是Number或Number的子類 //public final class Integer extends Number implements Comparable<Integer> Bean<Integer> bean2 = new Bean<Integer>(); Bean<Number> bean3 = new Bean<Number>(); } } class Bean<T extends Number> { //T必須繼承Number或就是Number private T var; public T getVar() { return var; } public void setVar(T var) { this.var = var; } @Override public String toString() { return var.toString(); } }
4.2.3、多種限制
class C<T extends Comparable<? super T> & Serializable>
我們來分析以下這句,T extends Comparable這個是對上限的限制,Comparable< super T>這個是下限的限制,Serializable是第2個上限。一個指定的類型參數可以具有一個或多個上限。具有多重限制的類型參數可以用於訪問它的每個限制的方法和域。
class Bean<T extends Number & Serializable>
4.3、下界
4.3.1、通配符下界
類型通配符下限為Stack<? super Number>形式,其含義與類型通配符上限正好相反
class Info<T>{ private T var ; // 定義泛型變量 public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } public String toString(){ // 直接打印 return this.var.toString() ; } }; public class GenericsDemo21{ public static void main(String args[]){ Info<String> i1 = new Info<String>() ; // 聲明String的泛型對象 Info<Object> i2 = new Info<Object>() ; // 聲明Object的泛型對象 i1.setVar("hello") ; i2.setVar(new Object()) ; fun(i1) ; fun(i2) ; } public static void fun(Info<? super String> temp){ // 只能接收String或Object類型的泛型 System.out.print(temp + "、") ; } };
示例:
package com.nf.math; import java.io.Serializable; public class BeanTest { public static void main(String[] args) { Bean<String> bean1 = new Bean<String>(); bean1.setVar("one"); //public abstract class Number implements java.io.Serializable Bean<Integer> bean2 = new Bean<Integer>(); bean2.setVar(2); Bean<Number> bean3 = new Bean<Number>(); bean3.setVar(3); Bean<Object> bean4 = new Bean<Object>(); bean4.setVar(4); Bean<Serializable> bean5 = new Bean<Serializable>(); bean5.setVar("5"); //Display(bean1); //錯誤 //Display(bean2); //錯誤 Display(bean3); Display(bean4); Display(bean5); } //?必是Number或Number的父類,Object,Serializable,Number public static void Display(Bean<? super Number> p){ System.out.println("內容是:"+p); } } class Bean<T> { private T var; public T getVar() { return var; } public void setVar(T var) { this.var = var; } @Override public String toString() { return var.toString(); } }
結果:
內容是:3 內容是:4 內容是:5
4.3.2、占位符下界
沒有,不存在...
五、類型擦除
5.1、類型擦除
Java中的泛型基本上都是在編譯器這個層次來實現的。在生成的Java字節代碼中是不包含泛型中的類型信息的。使用泛型的時候加上的類型參數,會被編譯器在編譯的時候去掉。這個過程就稱為類型擦除。如在代碼中定義的List<Object>和List<String>等類型,在編譯之后都會變成List。JVM看到的只是List,而由泛型附加的類型信息對JVM來說是不可見的。Java編譯器會在編譯時盡可能的發現可能出錯的地方,但是仍然無法避免在運行時刻出現類型轉換異常的情況。類型擦除也是Java的泛型實現方式與C++模板機制實現方式之間的重要區別。
Java 的泛型在編譯器有效,在運行期被刪除,也就是說所有泛型參數類型在編譯后都會被清除掉。
Java在泛型設計上是一種“偽泛型”,存在着泛型擦除。
類型擦除是Java中泛型的實現方式。泛型是在編譯器這個層次來實現的。在Java 源代碼中聲明的泛型類型信息,在編譯過程中會被擦除,只保留不帶類型參數的形式。被擦除的類型信息包括泛型類型和泛型方法聲明時的形式類型參數,以及參數化類型中的實際類型信息。經過類型擦除之后,包含泛型類型的代碼被轉換成不包含泛型類型的代碼,相當於回到了泛型被引入之前的形式,Java虛擬機在運行字節代碼時並不知道泛型類型的存在。
定義好的泛型類:
public class ObjectHolder<T> { private T obj; public T getObject() { return obj; } public void setObject(T obj) { this.obj = obj; } }
被轉譯后:
以上面代碼中的ObjectHolder泛型類為例,經過類型擦除后,由於形式類型參數T沒有上界,T的所有出現將被替換成Object類型
public class ObjectHolder { private Object obj; public Object getObject() { return obj; } public void setObject(Object obj) { this.obj = obj; } }
另外使用ObjectHolder類的代碼也要進行處理,如下列代碼所示:
ObjectHolder<String> holder = new ObjectHolder<String>(); holder.setObject("Hello"); String str = holder.getObject();
在類型擦除后,ObjectHolder類中的getObject方法的返冋值類型實際上是 Object類型,因此需要添加強制類型轉換把getObject方法的返回值轉換成String類型。 這些類型轉換操作由編譯器自動添加。由於編譯器已經確保不允許使用除String類的對象之外的其他對象調用setObject方法,因此這個強制類型轉換操作始終是合法的,如下列代碼所示:
ObjectHolder holder = new ObjectHolder(); holder.setObject("Hello"); String str = (String)holder.getObject();
泛型信息只存在於代碼編譯階段,在進入 JVM 之前,與泛型相關的信息會被擦除掉,專業術語叫做類型擦除
示例:
package com.nf.math; public class BeanTest { public static void main(String[] args) { Bean<Integer> bean1=new Bean<Integer>(); Bean<String> bean2=new Bean<String>(); System.out.println(bean1.getClass().getName()); System.out.println(bean2.getClass().getName()); } } class Bean<T> { private T var; public T getVar() { return var; } public void setVar(T var) { this.var = var; } @Override public String toString() { return var.toString(); } }
結果:
com.nf.math.Bean
com.nf.math.Bean
在JVM中的 Class 都是com.nf.math.Bean,泛型信息被擦除了。
5.2、泛型轉譯
示例:
package com.nf.math; import java.lang.reflect.Field; public class BeanTest { public static void main(String[] args) throws Exception { Bean<Integer> bean1=new Bean<Integer>(); Bean<String> bean2=new Bean<String>(); //獲得Bean中的字段var Field clazz=bean1.getClass().getDeclaredField("var"); clazz.setAccessible(true); clazz.set(bean1, "abc"); //取字段var的類型 System.out.println(clazz.getType().getSimpleName()); System.out.println(bean1.getVar()); } } class Bean<T> { private T var; public T getVar() { return var; } public void setVar(T var) { this.var = var; } @Override public String toString() { return var.toString(); } }
因為Bean沒有上界,T被轉譯成Object,生成如下代碼:
class BeanCopy { private Object var; public Object getVar() { return var; } public void setVar(Object var) { this.var = var; } @Override public String toString() { return var.toString(); } }
運行結果:
Object
abc
泛型類被類型擦除后,相應的類型就被替換成 Object 類型呢?,不一定,如果有上界,則被替換成上界:
package com.nf.math; import java.lang.reflect.Field; public class BeanTest { public static void main(String[] args) throws Exception { Bean<Integer> bean1=new Bean<Integer>(); Bean<Number> bean2=new Bean<Number>(); //獲得Bean中的字段var Field clazz=bean1.getClass().getDeclaredField("var"); //查看運行時字段var的類型 System.out.println(clazz.getType().getSimpleName()); } } class Bean<T extends Number> { //設置上界 private T var; public T getVar() { return var; } public void setVar(T var) { this.var = var; } @Override public String toString() { return var.toString(); } }
運行結果:
Number
類型被轉譯成:
class Bean{ private Number var; public Number getVar() { return var; } public void setVar(Number var) { this.var = var; } @Override public String toString() { return var.toString(); } }

六、泛型應用
6.1、泛型與反射簡化JDBCUtils工具類示例
參考:https://commons.apache.org/proper/commons-dbutils/
已經寫好的工具類:
package com.zhangguo.utils; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class JDBCUtils { public static String DRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; public static String URL = "jdbc:sqlserver://localhost:1433;databasename=pubs"; public static String USER_NAME = "sa"; public static String PASSWORD = "sa"; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } private JDBCUtils() { } /** * Get connection * * @return */ public static Connection getconnnection() { Connection con = null; try { con = DriverManager.getConnection(URL, USER_NAME, PASSWORD); } catch (SQLException e) { e.printStackTrace(); } return con; } /** * Close connection * * @param rs * @param st * @param con */ public static void close(ResultSet rs, Statement st, Connection con) { try { try { if (rs != null) { rs.close(); } } finally { try { if (st != null) { st.close(); } } finally { if (con != null) con.close(); } } } catch (SQLException e) { e.printStackTrace(); } } /** * Close connection * * @param rs */ public static void close(ResultSet rs) { Statement st = null; Connection con = null; try { try { if (rs != null) { st = rs.getStatement(); rs.close(); } } finally { try { if (st != null) { con = st.getConnection(); st.close(); } } finally { if (con != null) { con.close(); } } } } catch (SQLException e) { e.printStackTrace(); } } /** * Close connection * * @param st * @param con */ public static void close(Statement st, Connection con) { try { try { if (st != null) { st.close(); } } finally { if (con != null) con.close(); } } catch (SQLException e) { e.printStackTrace(); } } /** * insert/update/delete * * @param sql * @param args * @return */ public static int update(String sql, Object... args) { int result = 0; Connection con = getconnnection(); PreparedStatement ps = null; try { ps = con.prepareStatement(sql); if (args != null) { for (int i = 0; i < args.length; i++) { ps.setObject((i + 1), args[i]); } } result = ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { close(ps, con); } return result; } /** * query, because need to manually close the resource, so not recommended * for use it * * @param sql * @param args * @return ResultSet */ @Deprecated public static ResultSet query(String sql, Object... args) { ResultSet result = null; Connection con = getconnnection(); PreparedStatement ps = null; try { ps = con.prepareStatement(sql); if (args != null) { for (int i = 0; i < args.length; i++) { ps.setObject((i + 1), args[i]); } } result = ps.executeQuery(); } catch (SQLException e) { e.printStackTrace(); } return result; } /** * Query a single record * * @param sql * @param args * @return Map<String,Object> */ public static Map<String, Object> queryForMap(String sql, Object... args) { Map<String, Object> result = new HashMap<String, Object>(); List<Map<String, Object>> list = queryForList(sql, args); if (list.size() > 0) { result = list.get(0); } return result; } /** * Query a single record * * @param sql * @param args * @return <T> */ public static <T> T queryForObject(String sql, Class<T> clz, Object... args) { T result = null; List<T> list = queryForList(sql, clz, args); if (list.size() > 0) { result = list.get(0); } return result; } /** * Query a single record * * @param sql * @param args * @return List<Map<String,Object>> */ public static List<Map<String, Object>> queryForList(String sql, Object... args) { List<Map<String, Object>> result = new ArrayList<Map<String, Object>>(); Connection con = null; ResultSet rs = null; PreparedStatement ps = null; try { con = getconnnection(); ps = con.prepareStatement(sql); if (args != null) { for (int i = 0; i < args.length; i++) { ps.setObject((i + 1), args[i]); } } rs = ps.executeQuery(); ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); while (rs.next()) { Map<String, Object> map = new HashMap<String, Object>(); for (int i = 1; i <= columnCount; i++) { map.put(rsmd.getColumnLabel(i), rs.getObject(i)); } result.add(map); } } catch (SQLException e) { e.printStackTrace(); } finally { close(rs, ps, con); } return result; } /** * Query a single record * * @param sql * @param args * @return List<T> */ public static <T> List<T> queryForList(String sql, Class<T> clz, Object... args) { List<T> result = new ArrayList<T>(); Connection con = null; PreparedStatement ps = null; ResultSet rs = null; try { con = getconnnection(); ps = con.prepareStatement(sql); if (args != null) { for (int i = 0; i < args.length; i++) { ps.setObject((i + 1), args[i]); } } rs = ps.executeQuery(); ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); while (rs.next()) { T obj = clz.newInstance(); for (int i = 1; i <= columnCount; i++) { String columnName = rsmd.getColumnName(i); String methodName = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1, columnName.length()); Method method[] = clz.getMethods(); for (Method meth : method) { if (methodName.equals(meth.getName())) { meth.invoke(obj, rs.getObject(i)); } } } result.add(obj); } } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } finally { close(rs, ps, con); } return result; } }
數據庫:
CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '編號', `name` varchar(50) DEFAULT NULL COMMENT '姓名', `sex` varchar(20) DEFAULT NULL, `cno` varchar(50) DEFAULT NULL COMMENT '班級', `addr` varchar(50) DEFAULT NULL COMMENT '籍貫', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
示例:
package com.zhangguo.utils; import java.util.List; public class JDBCUtilsTest { public static void main(String[] args) { List<Student> students = JDBCUtils.queryForList("select * from student where id<=?", Student.class, 10); for (Student student : students) { System.out.println(student); } } } /** 學生 */ class Student { private int id; private String name; private String sex; private String cno; private String addr; 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 getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getCno() { return cno; } public void setCno(String cno) { this.cno = cno; } public String getAddr() { return addr; } public void setAddr(String addr) { this.addr = addr; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", sex=" + sex + ", cno=" + cno + ", addr=" + addr + "]"; } }
結果:

6.2、實現泛型與反射簡化JDBCUtils工具類
數據庫與表的元數據就是用於描述數據庫或表的信息,如表的字段(長度,類型,注釋),主鍵,外鍵,約束等信息,表中的數據本來是描述客觀事物的。
6.2.1、獲得表的元信息方法一
示例:
/** * 根據數據庫的連接參數,獲取指定表的基本信息:字段名、字段類型、字段注釋 * 表名 * @return Map集合 */ public static List getTableInfo(String table) { List result = new ArrayList(); Connection conn = null; DatabaseMetaData dbmd = null; try { conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD); dbmd = conn.getMetaData(); ResultSet resultSet = dbmd.getTables(null, "%", table, new String[] { "TABLE" }); while (resultSet.next()) { String tableName = resultSet.getString("TABLE_NAME"); System.out.println(tableName); if (tableName.equals(table)) { ResultSet rs = conn.getMetaData().getColumns(null, getSchema(conn), tableName.toUpperCase(), "%"); while (rs.next()) { // System.out.println("字段名:"+rs.getString("COLUMN_NAME")+"--字段注釋:"+rs.getString("REMARKS")+"--字段數據類型:"+rs.getString("TYPE_NAME")); Map map = new HashMap(); String colName = rs.getString("COLUMN_NAME"); map.put("code", colName); String remarks = rs.getString("REMARKS"); if (remarks == null || remarks.equals("")) { remarks = colName; } map.put("name", remarks); String dbType = rs.getString("TYPE_NAME"); map.put("dbType", dbType); map.put("valueType", changeDbType(dbType)); result.add(map); } } } } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } return result; } private static String changeDbType(String dbType) { dbType = dbType.toUpperCase(); switch (dbType) { case "VARCHAR": case "VARCHAR2": case "CHAR": return "1"; case "NUMBER": case "DECIMAL": return "4"; case "INT": case "SMALLINT": case "INTEGER": return "2"; case "BIGINT": return "6"; case "DATETIME": case "TIMESTAMP": case "DATE": return "7"; default: return "1"; } } // 其他數據庫不需要這個方法 oracle和db2需要 private static String getSchema(Connection conn) throws Exception { String schema; schema = conn.getMetaData().getUserName(); if ((schema == null) || (schema.length() == 0)) { throw new Exception("ORACLE數據庫模式不允許為空"); } return schema.toUpperCase().toString(); }
結果:
persons
student
[{code=id, valueType=2, name=編號, dbType=INT}, {code=name, valueType=1, name=姓名, dbType=VARCHAR}, {code=sex, valueType=1, name=sex, dbType=VARCHAR}, {code=cno, valueType=1, name=班級, dbType=VARCHAR}, {code=addr, valueType=1, name=籍貫, dbType=VARCHAR}]
6.2.2、獲得表的元信息方法二
代碼:
package com.zhangguo.utils; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class DbUtils { public static String DRIVER = "com.mysql.jdbc.Driver"; public static String URL = "jdbc:mysql://localhost:3306/studentmis?useUnicode=true&characterEncoding=utf8"; public static String USER_NAME = "mysqluser"; public static String PASSWORD = "root"; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static List<Student> getStudents(String sql, Object... params) throws Exception { List<Student> result = new ArrayList<>(); Connection conn = null; PreparedStatement pstm = null; conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD); pstm = conn.prepareStatement(sql); // 添加參數 if (params != null) { for (int i = 0; i < params.length; i++) { pstm.setObject(i + 1, params[i]); } } // 執行查詢 ResultSet rs = pstm.executeQuery(); //獲得表的元數據 ResultSetMetaData rsmd=pstm.getMetaData(); //表的列數 int metaSize=rsmd.getColumnCount(); for (int i =1; i <=metaSize; i++) { System.out.println("列名:"+rsmd.getColumnName(i)); System.out.println("長度:"+rsmd.getColumnDisplaySize(i)); System.out.println("類型:"+rsmd.getColumnType(i)); System.out.println("類型:"+rsmd.getColumnTypeName(i)); System.out.println("----------"); } while (rs.next()) { Student student=new Student(); student.setAddr(rs.getString("addr")); student.setCno(rs.getString("cno")); student.setId(rs.getInt("id")); student.setName(rs.getString("name")); student.setSex(rs.getString("sex")); result.add(student); } CloseConnection(conn, pstm, rs); return result; } public static void CloseConnection(Connection conn, PreparedStatement pstm, ResultSet rs) throws SQLException { if (rs != null) { rs.close(); } if (pstm != null) { pstm.close(); } if (conn != null) { conn.close(); } } }
測試類:
package com.zhangguo.utils; import java.util.List; public class JDBCUtilsTest { public static void main(String[] args) throws Exception { List<Student> students = JDBCUtils.queryForList("select * from student where id<=?", Student.class, 10); for (Student student : students) { System.out.println(student); } System.out.println("-------------------------------------------------------------------"); List<Student> stus =DbUtils.getStudents("select * from student where id<=?", 5); for (Student student : stus) { System.out.println(student); } System.out.println("-------------------------------------------------------------------"); System.out.println(stus); } } /** 學生 */ class Student { private int id; private String name; private String sex; private String cno; private String addr; 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 getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getCno() { return cno; } public void setCno(String cno) { this.cno = cno; } public String getAddr() { return addr; } public void setAddr(String addr) { this.addr = addr; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", sex=" + sex + ", cno=" + cno + ", addr=" + addr + "]"; } }
結果:
Student [id=1, name=張學友, sex=男, cno=S1SJ90, addr=中國香港] Student [id=2, name=黎明, sex=男, cno=S1SJ18, addr=中國上海] Student [id=3, name=張慧妹, sex=女, cno=S2SJ19, addr=中國北京] Student [id=4, name=張國立, sex=男, cno=S3J37, addr=中國廣東] Student [id=5, name=張哪啦, sex=女, cno=S3SR96, addr=中國杭州] Student [id=6, name=張鐵林, sex=男, cno=S2SJ140, addr=中國珠海] Student [id=7, name=張國榮, sex=男, cno=S1SJ111, addr=中國香港] Student [id=8, name=張果果, sex=女, cno=S3SU198, addr=中國深圳] Student [id=10, name=張小軍, sex=女, cno=S1SN196, addr=中國斗門] ------------------------------------------------------------------- 列名:id 長度:11 類型:4 類型:INT ---------- 列名:name 長度:50 類型:12 類型:VARCHAR ---------- 列名:sex 長度:20 類型:12 類型:VARCHAR ---------- 列名:cno 長度:50 類型:12 類型:VARCHAR ---------- 列名:addr 長度:50 類型:12 類型:VARCHAR ---------- Student [id=1, name=張學友, sex=男, cno=S1SJ90, addr=中國香港] Student [id=2, name=黎明, sex=男, cno=S1SJ18, addr=中國上海] Student [id=3, name=張慧妹, sex=女, cno=S2SJ19, addr=中國北京] Student [id=4, name=張國立, sex=男, cno=S3J37, addr=中國廣東] Student [id=5, name=張哪啦, sex=女, cno=S3SR96, addr=中國杭州] ------------------------------------------------------------------- [Student [id=1, name=張學友, sex=男, cno=S1SJ90, addr=中國香港], Student [id=2, name=黎明, sex=男, cno=S1SJ18, addr=中國上海], Student [id=3, name=張慧妹, sex=女, cno=S2SJ19, addr=中國北京], Student [id=4, name=張國立, sex=男, cno=S3J37, addr=中國廣東], Student [id=5, name=張哪啦, sex=女, cno=S3SR96, addr=中國杭州]]
6.3、封裝DbUtilis工具類
6.3.1.、查詢功能
package com.zhangguo.utilities; import java.lang.reflect.Field; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class DbUtils { public static String DRIVER = "com.mysql.jdbc.Driver"; public static String URL = "jdbc:mysql://localhost:3306/studentmis?useUnicode=true&characterEncoding=utf8"; public static String USER_NAME = "mysqluser"; public static String PASSWORD = "root"; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static <T> List<T> queryList(String sql,Class<T> clazz,Object... params) throws Exception { List<T> result = new ArrayList<>(); Connection conn = null; PreparedStatement pstm = null; conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD); pstm = conn.prepareStatement(sql); // 添加參數 if (params != null) { for (int i = 0; i < params.length; i++) { pstm.setObject(i + 1, params[i]); } } // 執行查詢 ResultSet rs = pstm.executeQuery(); // 獲得表的元數據 ResultSetMetaData rsmd = pstm.getMetaData(); // 表的列數 int metaSize = rsmd.getColumnCount(); while (rs.next()) { T entity = clazz.newInstance(); for (int i = 1; i <= metaSize; i++) { //獲得當前列的列名 String columnName=rsmd.getColumnName(i); //根據字段名獲得實體類中的字段 Field field=clazz.getDeclaredField(columnName); //設置字段可以被訪問 field.setAccessible(true); //給實體中的字段賦值 field.set(entity, rs.getObject(columnName)); } result.add(entity); } CloseConnection(conn, pstm, rs); return result; } public static void CloseConnection(Connection conn, PreparedStatement pstm, ResultSet rs) throws SQLException { if (rs != null) { rs.close(); } if (pstm != null) { pstm.close(); } if (conn != null) { conn.close(); } } }
測試:
package com.zhangguo.utilities; import java.util.List; public class DbUtilsTest { public static void main(String[] args) throws Exception { List<Animal> result = DbUtils.queryList("select * from animal where id<?", Animal.class, 5); System.out.println(result); List<Student> students = DbUtils.queryList("select * from student where id<?", Student.class, 5); System.out.println(students); } } /** 動物 */ class Animal { private int id; private String name; private String color; 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 getColor() { return color; } public void setColor(String color) { this.color = color; } @Override public String toString() { return "Animal [id=" + id + ", name=" + name + ", color=" + color + "]"; } } /** 學生 */ class Student { //T只允許是String或String的子類 private int id; private String name; private String sex; private String cno; private String addr; 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 getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getCno() { return cno; } public void setCno(String cno) { this.cno = cno; } public String getAddr() { return addr; } public void setAddr(String addr) { this.addr = addr; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", sex=" + sex + ", cno=" + cno + ", addr=" + addr + "]"; } }
結果:
[Animal [id=1, name=Dog, color=yellow], Animal [id=2, name=Cat, color=White], Animal [id=3, name=Duck, color=Black]]
[Student [id=1, name=張學友, sex=男, cno=S1SJ90, addr=中國香港], Student [id=2, name=黎明, sex=男, cno=S1SJ18, addr=中國上海], Student [id=3, name=張慧妹, sex=女, cno=S2SJ19, addr=中國北京], Student [id=4, name=張國立, sex=男, cno=S3J37, addr=中國廣東]]
6.3.2、增刪改功能
package com.zhangguo.utilities; import java.lang.reflect.Field; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class DbUtils { public static String DRIVER = "com.mysql.jdbc.Driver"; public static String URL = "jdbc:mysql://localhost:3306/studentmis?useUnicode=true&characterEncoding=utf8"; public static String USER_NAME = "mysqluser"; public static String PASSWORD = "root"; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static <T> List<T> queryList(String sql, Class<T> clazz, Object... params) throws Exception { List<T> result = new ArrayList<>(); Connection conn = null; PreparedStatement pstm = null; conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD); pstm = conn.prepareStatement(sql); // 添加參數 if (params != null) { for (int i = 0; i < params.length; i++) { pstm.setObject(i + 1, params[i]); } } // 執行查詢 ResultSet rs = pstm.executeQuery(); // 獲得表的元數據 ResultSetMetaData rsmd = pstm.getMetaData(); // 表的列數 int metaSize = rsmd.getColumnCount(); while (rs.next()) { T entity = clazz.newInstance(); for (int i = 1; i <= metaSize; i++) { // 獲得當前列的列名 String columnName = rsmd.getColumnName(i); // 根據字段名獲得實體類中的字段 Field field = clazz.getDeclaredField(columnName); // 設置字段可以被訪問 field.setAccessible(true); // 給實體中的字段賦值 field.set(entity, rs.getObject(columnName)); } result.add(entity); } CloseConnection(conn, pstm, rs); return result; } public static <T> T queryObject(String sql, Class<T> clazz, Object... params) throws Exception { List<T> result = queryList(sql, clazz, params); if (result != null && !result.isEmpty()) { return result.get(0); } return null; } public static int execute(String sql, Object... params) throws Exception { int rows = 0; Connection conn = null; PreparedStatement pstm = null; conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD); pstm = conn.prepareStatement(sql); // 添加參數 if (params != null) { for (int i = 0; i < params.length; i++) { pstm.setObject(i + 1, params[i]); } } // 執行 rows = pstm.executeUpdate(); CloseConnection(conn, pstm, null); return rows; } public static void CloseConnection(Connection conn, PreparedStatement pstm, ResultSet rs) throws SQLException { if (rs != null) { rs.close(); } if (pstm != null) { pstm.close(); } if (conn != null) { conn.close(); } } }
6.4、JSON返回類型封裝
package com.zhangguo.utils; import java.util.HashMap; import java.util.Map; /** * 返回類型封裝 */ public class R extends HashMap<String, Object> { private static final long serialVersionUID = 1L; public R() { put("code", 0); put("msg", "success"); } //錯誤時 public static R error() { return error(500, "未知異常,請聯系管理員"); } public static R error(String msg) { return error(500, msg); } public static R error(int code, String msg) { R r = new R(); r.put("code", code); r.put("msg", msg); return r; } //成功時 public static R ok(String msg) { R r = new R(); r.put("msg", msg); return r; } public static R ok(Map<String, Object> map) { R r = new R(); r.putAll(map); return r; } public static R ok() { return new R(); } @Override public R put(String key, Object value) { super.put(key, value); return this; } }
測試:
package com.zhangguo.controller; import java.util.*; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.zhangguo.utils.DbUtils; import com.zhangguo.utils.JsonUtils; import com.zhangguo.utils.R; @WebServlet("/StudentController") public class StudentController extends BaseServlet { private static final long serialVersionUID = 1L; public void getAllStudent(HttpServletRequest request, HttpServletResponse response) { List<Student> students=null; try { students = DbUtils.queryList("select * from student", Student.class); String json = JsonUtils.toJson(students); response.getWriter().append(json); } catch (Exception e) { e.printStackTrace(); } } public void getAllStus(HttpServletRequest request, HttpServletResponse response) { List<Student> students=null; try { students = DbUtils.queryList("select * from student", Student.class); R r=R.ok().put("data", students).put("time",new Date()); String json = JsonUtils.toJson(r); response.getWriter().append(json); } catch (Exception e) { e.printStackTrace(); } } }
運行結果:

jsonUtils:
package com.zhangguo.utils; import java.text.SimpleDateFormat; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; public class JsonUtils { /** * 序列化成json * */ public static String toJson(Object obj) { // 對象映射器 ObjectMapper mapper = new ObjectMapper(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd HH:mm:ss"); mapper.setDateFormat(sdf); String result = null; // 序列化user對象為json字符串 try { result = mapper.writeValueAsString(obj); } catch (JsonProcessingException e) { e.printStackTrace(); } return result; } /** * 反序列化成對象 * */ public static <T> T toObject(String json,Class<T> valueType) { //對象映射器 ObjectMapper mapper=new ObjectMapper(); T result=null; try { result=mapper.readValue(json,valueType); }catch (Exception e) { e.printStackTrace(); } return result; } }
baseServlet:
package com.zhangguo.controller; import java.io.IOException; import java.lang.reflect.Method; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class BaseServlet extends HttpServlet { private static final long serialVersionUID = 1L; public void init(ServletConfig config) throws ServletException { } public String commonObject; //Write once only once! protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String action = request.getParameter("act"); request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); if (action != null) { try { // 在當前Servlet實例中根據action找到方法信息 Method method = getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class); if (method != null) { // 在當前實例上調用方法method,指定參數request,response method.invoke(this, request, response); } else { response.getWriter().write("您請求的action不存在"); } } catch (Exception e) { response.getWriter().write("調用發生了錯誤,錯誤:" + e.getMessage()); e.printStackTrace(); } } else { try { response.getWriter().write("請指定參數act"); } catch (IOException e) { e.printStackTrace(); } } } }
七、視頻與示例
https://www.bilibili.com/video/av9219224/
八、作業
7.1、請定義一個泛型類,實現簡單的List功能,可變長度的數組,可以實現foreach功能。
MyList<Integer> list1=new MyList<Integer>(); list1.add(1); list1.add(2); list1.add(3); foreach(Integer i : list){ System.out.println(i); }
7.2、請定義一個泛型方法,根據指定的類型獲得方法中所有的字段、方法信息。
7.3、請使用JDBC+反射+泛型實現一個可返回強類型的方法,如:
指定SQL語句、參數與類型返回一個強類型對象
List<Student> students = JDBCUtils.queryForList("select * from student where id<=?", Student.class, 10);
for (Student student : students) {
System.out.println(student);
}
7.4、指定一個數據庫,生成數據庫下所有的表的實體類文件
7.5、JDBC+反射+泛型實現一個簡單的ORM(選作)
package model; import java.util.Date; import annotation.Column; import annotation.Entity; import annotation.Id; /** * 圖書 */ @Entity("t_book") //表名 public class Book { /** * 圖書編號 */ @Id("t_isbn") private String isbn; /** * 書名 */ @Column("t_name") private String name; /** * 作者 */ @Column("t_author") private String author; /** * 出版社 */ @Column("t_publishing") private String publishing; /** * 出版時間 */ @Column(value = "t_pubdate") private Date pubdate; /** * 價格 */ @Column(value = "t_price") private double price; public String getIsbn() { return isbn; } public void setIsbn(String isbn) { this.isbn = isbn; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getPublishing() { return publishing; } public void setPublishing(String publishing) { this.publishing = publishing; } public Date getPubdate() { return pubdate; } public void setPubdate(Date pubdate) { this.pubdate = pubdate; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "書名: " + name + " 圖書編號: " + isbn + " 作者: " + author + " 出版社: " + publishing + " 出版時間: " + pubdate + " 價格: " + price; } }
調用:
package xml; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import model.Book; import org.junit.BeforeClass; import org.junit.Test; import util.DateUtils; import dao.GenericDao; import dao.JdbcGenericDaoImpl; /** * 測試泛型DAO的CRUD操作 */ public class GenericDaoTest { private GenericDao<Book> bookDao = new JdbcGenericDaoImpl<Book>(); private static InputStream is; @BeforeClass public static void setUpBeforeClass() throws Exception { is = XmlParserTest.class.getResourceAsStream("/books.xml"); } @Test public void testSave() throws Exception { List<Book> books = SaxHelper.saxReader(is); for (Book book : books) { bookDao.save(book); } } @Test public void testStudentFindAll1() throws Exception { System.out.println("\n-------------更新、刪除前,測試查詢所有記錄--------------------"); List<Book> books = bookDao.findAllByConditions(null, Book.class); for (Book book : books) { System.out.println(book); } } @Test public void testDelete() throws Exception { System.out.println("\n-------------測試刪除一條記錄--------------------"); bookDao.delete("9787111349662",Book.class); } @Test public void testGet() throws Exception { System.out.println("\n-------------測試查詢一條記錄--------------------"); Book book = bookDao.get("9787121025389", Book.class); System.out.println(book); } @Test public void testUpdate() throws Exception { System.out.println("\n-------------測試修改一條記錄--------------------"); Book book = new Book(); book.setIsbn("9787121025389"); book.setName("JAVA面向對象編程"); book.setAuthor("孫衛琴"); book.setPublishing("電子工業出版社"); book.setPubdate(DateUtils.string2Date("yyyy-MM-dd", "2006-07-01")); book.setPrice(50.6); bookDao.update(book); } @Test public void testStudentFindAll2() throws Exception { System.out.println("\n-------------更新、刪除前,測試根據條件查詢所有記錄--------------------"); Map<String,Object> sqlWhereMap = new HashMap<String, Object>(); //sqlWhereMap.put("t_isbn", "9787111213826"); //sqlWhereMap.put("t_name", "Java"); sqlWhereMap.put("t_publishing", "機械工業出版社"); //sqlWhereMap.put("t_pubdate", new Date(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2007-01-01 12:06:00").getTime())); List<Book> books = bookDao.findAllByConditions(null, Book.class); for (Book book : books) { System.out.println(book); } } }
參考:
https://www.cnblogs.com/sunwei2012/archive/2010/10/08/1845938.html
https://www.cnblogs.com/lwbqqyumidi/p/3837629.html
