JDK5新特性之泛型

时间:2022-06-15 15:16:43

概述

  泛型:是一种把类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。参数化类型,把类型当作参数一样的传递。
  格式:
        <数据类型>
        此处的数据类型只能是引用类型。
  好处:
        A:把运行时期的问题提前到了编译期间
        B:避免了强制类型转换
        C:优化了程序设计,解决了黄色警告线
  泛型在哪些地方使用呢?
        看API,如果类,接口,抽象类后面跟的有<E>就说要使用泛型。一般来说就是在集合中使用。
package cn.itcast_02;

import java.util.ArrayList;
import java.util.Iterator;

public class ArrayListDemo {
    public static void main(String[] args) {
        // 用ArrayList存储字符串元素,并遍历。用泛型改进代码
        ArrayList<String> array = new ArrayList<String>();

        array.add("hello");
        array.add("world");
        array.add("java");

        Iterator<String> it = array.iterator();
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("-----------------");

        for (int x = 0; x < array.size(); x++) {
            String s = array.get(x);
            System.out.println(s);
        }
    }
}
  早期的时候,我们使用Object来代表任意的类型。
  向上转型是没有任何问题的,但是在向下转型的时候其实隐含了类型转换的问题。
  也就是说这样的程序其实并不是安全的。所以Java在JDK5后引入了泛型,提高程序的安全性。

泛型擦除

泛型只在编译时期有效,编译后的字节码文件中不存在有泛型信息!
/* * 泛型擦除实例 */
public void save(List<Person> p){
}
public void save(List<Dept> d){    // 报错: 与上面方法编译后一样
}

泛型写法

// 泛型写法
@Test
public void testGeneric3() throws Exception {
    // 声明泛型集合,集合两端类型必须一致
    List<Object> list = new ArrayList<Object>();
    List<String> list1 = new ArrayList<String>();
    List list2 = new ArrayList<String>();
    List<Integer> list3 = new ArrayList();

    // 错误
    //List<Object> list4 = new ArrayList<String>();
    // 错误: 泛型类型必须是引用类型,不能为基本类型
    List<int> list5 = new ArrayList<int>();
}

泛型的应用

泛型类

把泛型定义在类上
格式: public class 类名<泛型类型1,…>
注意: 泛型类型必须是引用类型
package cn.itcast_04;

/* * 泛型类:把泛型定义在类上 */
public class ObjectTool<T> {
    private T obj;

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}

泛型方法

把泛型定义在方法上
格式: public <泛型类型> 返回类型 方法名(泛型类型 .)
/* * 泛型方法:把泛型定义在方法上 */
public class ObjectTool {
    public <T> void show(T t) {
        System.out.println(t);
    }
}

泛型接口

把泛型定义在接口上
格式: public  interface 接口名<泛型类型1…>
/* * 泛型接口:把泛型定义在接口上 */
public interface Inter<T> {
    public abstract void show(T t);
}

//实现类在实现接口的时候
//第一种情况:已经知道该是什么类型的了

//public class InterImpl implements Inter<String> {
//
// @Override
// public void show(String t) {
// System.out.println(t);
// }
// }

//第二种情况:还不知道是什么类型的
public class InterImpl<T> implements Inter<T> {

    @Override
    public void show(T t) {
        System.out.println(t);
    }
}

泛型高级(通配符)

  ?:  任意类型,如果没有明确,那么就是Object以及任意的Java类了
  ? extends E:  向下限定,E及其子类
  ? super E:  向上限定,E极其父类
package cn.itcast_07;

import java.util.ArrayList;
import java.util.Collection;

/* * 泛型高级(通配符) * ?:任意类型,如果没有明确,那么就是Object以及任意的Java类了 * ? extends E:向下限定,E及其子类 * ? super E:向上限定,E极其父类 */
public class GenericDemo {
    public static void main(String[] args) {
        // 泛型如果明确的写的时候,前后必须一致
        Collection<Object> c1 = new ArrayList<Object>();
        // Collection<Object> c2 = new ArrayList<Animal>(); //Error
        // Collection<Object> c3 = new ArrayList<Dog>(); //Error
        // Collection<Object> c4 = new ArrayList<Cat>(); //Error

        // ?表示任意的类型都是可以的
        Collection<?> c5 = new ArrayList<Object>();
        Collection<?> c6 = new ArrayList<Animal>();
        Collection<?> c7 = new ArrayList<Dog>();
        Collection<?> c8 = new ArrayList<Cat>();

        // ? extends E:向下限定,E及其子类
        // Collection<? extends Animal> c9 = new ArrayList<Object>(); //Error
        Collection<? extends Animal> c10 = new ArrayList<Animal>();
        Collection<? extends Animal> c11 = new ArrayList<Dog>();
        Collection<? extends Animal> c12 = new ArrayList<Cat>();

        // ? super E:向上限定,E极其父类
        Collection<? super Animal> c13 = new ArrayList<Object>();
        Collection<? super Animal> c14 = new ArrayList<Animal>();
        // Collection<? super Animal> c15 = new ArrayList<Dog>(); //Error
        // Collection<? super Animal> c16 = new ArrayList<Cat>(); //Error
    }
}

class Animal {
}

class Dog extends Animal {
}

class Cat extends Animal {
}

泛型的反射

相关知识

    |--Type  
        Type 是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、
        数组类型、类型变量和基本类型。
        |-- ParameterizedType
            ParameterizedType 表示参数化类型,如 Collection<String>。 

反射泛型案例

public class AdminDao extends BaseDao<Admin> {}
public class AccountDao extends BaseDao<Account> {}
/** * 所有dao的公用的方法,都在这里实现 */
public class BaseDao<T>{

    // 保存当前运行类的参数化类型中的实际的类型
    private Class clazz;
    // 表名
    private String tableName;



    // 构造函数: 1. 获取当前运行类的参数化类型; 2. 获取参数化类型中实际类型的定义(class)
    public BaseDao(){
        // this 表示当前运行类 (AccountDao/AdminDao)
        // this.getClass() 当前运行类的字节码(AccountDao.class/AdminDao.class)
        // this.getClass().getGenericSuperclass(); 当前运行类的父类,即为BaseDao<Account>
        // 其实就是“参数化类型”, ParameterizedType 
        Type type = this.getClass().getGenericSuperclass();
        // 强制转换为“参数化类型” 【BaseDao<Account>】
        ParameterizedType pt = (ParameterizedType) type;
        // 获取参数化类型中,实际类型的定义 【new Type[]{Account.class}】
        Type types[] =  pt.getActualTypeArguments();
        // 获取数据的第一个元素:Accout.class
        clazz = (Class) types[0];
        // 表名 (与类名一样,只要获取类名就可以)
        tableName = clazz.getSimpleName();
    }


    /** * 主键查询 * @param id 主键值 * @return 返回封装后的对象 */
    public T findById(int id){
        /* * 1. 知道封装的对象的类型 * 2. 表名【表名与对象名称一样, 且主键都为id】 * * 即, * ---》得到当前运行类继承的父类 BaseDao<Account> * ----》 得到Account.class */

        String sql = "select * from " + tableName + " where id=? ";
        try {
            return JdbcUtils.getQuerrRunner().query(sql, new BeanHandler<T>(clazz), id);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }


    /** * 查询全部 * @return */
    public List<T> getAll(){
        String sql = "select * from " + tableName ;
        try {
            return JdbcUtils.getQuerrRunner().query(sql, new BeanListHandler<T>(clazz));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}