02

    科技2022-07-17  122

    1 泛型的理解

    泛型是指定某种类型。通过<>的方式取标识。

    所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返 回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、 创建对象时确定(即传入实际的类型参数,也称为类型实参)。

    泛型引入的背景

    JDK1.5之前对于不确定的容器到底存储什么类型的对象,都将其设置为Object类型。

    JDK1.5,以后使用泛型来解决这一问题,对于不知道存储什么类型的对象,设计为一个参数,在实例化或者确定为什么类型的时候,再去指明其类型。

    2 泛型在集合中的使用

    2.1 泛型在集合中的总结

    集合接口或者集合类在jdk1.5时全部使用泛型在实例化对象的时候,可以指明泛型的具体类型。指明完具体类型以后,在集合中定义类或接口的时候,内部结构(比如方法,构造器,属性),使用泛型的位置,都指定为实例化的泛型类型。 比如add(E e) ----> 实例化以后:add(Integer e) 注意点,泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的时候需要用包装类替换。如果实例化的时候没有指明泛型的具体类型,默认为java.lang.Object类型

    2.2 不使用泛型时的集合

    @Test public void test1(){ ArrayList list = new ArrayList(); //需求:存放学生的成绩 list.add(78); list.add(76); list.add(89); list.add(88); //问题一:类型不安全 // list.add("Tom"); for(Object score : list){ //问题二:强转时,可能出现ClassCastException int stuScore = (Integer) score; System.out.println(stuScore); } }

    2.3 使用泛型时的集合

    @Test public void test2(){ ArrayList<Integer> list = new ArrayList<Integer>(); list.add(78); list.add(87); list.add(99); list.add(65); //编译时,就会进行类型检查,保证数据的安全 // list.add("Tom"); //方式一: // for(Integer score : list){ // //避免了强转操作 // int stuScore = score; // // System.out.println(stuScore); // // } //方式二: Iterator<Integer> iterator = list.iterator(); while(iterator.hasNext()){ int stuScore = iterator.next(); System.out.println(stuScore); } }

    2.4 泛型在HashMap的使用

    //在集合中使用泛型的情况:以HashMap为例 @Test public void test3(){ // Map<String,Integer> map = new HashMap<String,Integer>(); //jdk7新特性:类型推断 Map<String,Integer> map = new HashMap<>(); map.put("Tom",87); map.put("Jerry",87); map.put("Jack",67); // map.put(123,"ABC"); //泛型的嵌套 Set<Map.Entry<String,Integer>> entry = map.entrySet(); Iterator<Map.Entry<String, Integer>> iterator = entry.iterator(); while(iterator.hasNext()){ Map.Entry<String, Integer> e = iterator.next(); String key = e.getKey(); Integer value = e.getValue(); System.out.println(key + "----" + value); } }

    3 自定义泛型类、泛型接口;泛型方法

    3.1 举例:

    public class Order<T>{ String name; int orderId; T orderT;//类的成员变量使用泛型 //类的内部结构可以使用类的泛型 public Order(){ //编译不通过 // T[] arr = new T[10]; //编译通过 T[] arr = (T[]) new Object[10]; } public Order(String orderName,int orderId,T orderT){ this.orderName = orderName; this.orderId = orderId; this.orderT = orderT; } //如下的个方法都不是泛型方法 public T getOrderT(){ return orderT; } public void setOrderT(T orderT){ this.orderT = orderT; } @Override public String toString() { return "Order{" + "orderName='" + orderName + '\'' + ", orderId=" + orderId + ", orderT=" + orderT + '}'; } //静态方法中不能使用类的泛型。 // public static void show(T orderT){ // System.out.println(orderT); // } public void show(){ //编译不通过,异常处理语句不能使用泛型 // try{ // // // }catch(T t){ // // } } }

    3.2 泛型方法

    //泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没任何关系。 //换句话说,泛型方法所属的类是不是泛型类都没关系。 //泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。 public static <E> List<E> copyFromArrayToList(E[] arr){ ArrayList<E> list = new ArrayList<>(); for(E e : arr){ list.add(e); } return list; }

    4 泛型在继承上的体现

    4.1 子类继承泛型类

    子类继承泛型类时可以指明泛型类型。

    【SubOrder.java】 public class SubOrder extends Order<Integer> {//SubOrder:不是泛型类 public static <E> List<E> copyFromArrayToList(E[] arr){ ArrayList<E> list = new ArrayList<>(); for(E e : arr){ list.add(e); } return list; } } > //实例化时,如下的代码是错误的 SubOrder<Integer> o = new SubOrder<>();

    子类继承泛型类的时候也可以不指明具体类型,子类也可以是泛型类。

    【SubOrder1.java】 public class SubOrder1<T> extends Order<T> {//SubOrder1<T>:仍然是泛型类 }

    4.2 应用场景举例JDBC

    【DAO.java】:定义了操作数据库中的表的通用操作。 ORM思想(数据库中的表和Java中的类对应)

    public class DAO<T> {//表的共性操作的DAO //添加一条记录 public void add(T t){ } //删除一条记录 public boolean remove(int index){ return false; } //修改一条记录 public void update(int index,T t){ } //查询一条记录 public T getIndex(int index){ return null; } //查询多条记录 public List<T> getForList(int index){ return null; } //泛型方法 //举例:获取表中一共有多少条记录?获取最大的员工入职时间? public <E> E getValue(){ return null; } } 【CustomerDAO.java】: public class CustomerDAO extends DAO<Customer>{//只能操作某一个表的DAO } 【StudentDAO.java】: public class StudentDAO extends DAO<Student> {//只能操作某一个表的DAO }

    5 通配符

    5.0 泛型类型变量的上限

    当在声明类型变量时,如果不希望这个类型变量代表任意引用数据类型,而是某个系列的引用数据类型,那么可以设定类型变量的上限。

    语法格式:

    <类型变量 extends 上限>

    如果有多个上限

    <类型变量 extends 上限1 & 上限2>

    如果多个上限中有类有接口,那么只能有一个类,而且必须写在最左边。接口的话,可以多个。

    如果在声明<类型变量>时没有指定上限,默认上限是java.lang.Object。

    例如:我们要声明一个两个数求和的工具类,要求两个加数必须是Number数字类型,并且实现Comparable接口。

    5.1 通配符的使用

    通配符:?

    类A是类B的费用类,G和G是没关系的。

    二者的共同父类是G<?>

    @Test public void test3(){ List<Object> list1 = null; List<String> list2 = null; List<?> list = null; list = list1; list = list2; //编译通过 // print(list1); // print(list2);

    5.2 涉及通配符的集合的数据写入和读取

    List<String> list3 = new ArrayList<>(); list3.add("AA"); list3.add("BB"); list3.add("CC"); list = list3; //添加(写入):对于List<?>就不能向其内部添加数据。 //除了添加null之外。 // list.add("DD"); // list.add('?'); list.add(null); //获取(读取):允许读取数据,读取的数据类型为Object。 Object o = list.get(0); System.out.println(o); } public void print(List<?> list){ Iterator<?> iterator = list.iterator(); while(iterator.hasNext()){ Object obj = iterator.next(); System.out.println(obj); } }

    5.3 有限制条件的通配符的使用

    G<? extends A> 可以作为G和G的父类,其中B是A的子类

    G<? super A> 可以作为G和G的父类,其中B是A的父类

    @Test public void test4(){ List<? extends Person> list1 = null; List<? super Person> list2 = null; List<Student> list3 = new ArrayList<Student>(); List<Person> list4 = new ArrayList<Person>(); List<Object> list5 = new ArrayList<Object>(); list1 = list3; list1 = list4; // list1 = list5; // list2 = list3; list2 = list4; list2 = list5; //读取数据: list1 = list3; Person p = list1.get(0); //编译不通过 //Student s = list1.get(0); list2 = list4; Object obj = list2.get(0); 编译不通过 // Person obj = list2.get(0); //写入数据: //编译不通过 // list1.add(new Student()); //编译通过 list2.add(new Person()); list2.add(new Student()); }
    Processed: 0.011, SQL: 8