泛型(Generic)的本质是类型参数化,通俗的说就是用一个占位符来表示类型,这个类型可以是String,Integer等不确定的类型,表明可接受的类型。

泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。

1.1、为什么需要泛型

在数据结构中有一种结构叫:,它的特点是:先进后出,后进先出

如:放衣服的箱子,糖葫芦

JavaSE学习总结(十六)—— 泛型与泛型应用

现在来模拟一个栈的数据结构

JavaSE学习总结(十六)—— 泛型与泛型应用

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()+"()");
        }
    }
}

结果:

JavaSE学习总结(十六)—— 泛型与泛型应用

说明:

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

运行结果:

JavaSE学习总结(十六)—— 泛型与泛型应用

示例

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

JavaSE学习总结(十六)—— 泛型与泛型应用

六、泛型应用

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;
    }
}
View Code

相关文章:

  • 2022-01-24
  • 2021-09-03
  • 2021-12-16
  • 2021-09-26
  • 2021-07-15
  • 2022-12-23
  • 2022-12-23
  • 2021-12-29
猜你喜欢
  • 2021-06-10
  • 2021-05-06
  • 2022-12-23
  • 2022-12-23
  • 2021-10-13
  • 2021-12-19
  • 2022-12-23
相关资源
相似解决方案