泛型的使用与通配符

    技术2025-07-25  13

    泛型的使用

    1.jdk1.5新特性泛型

    把元素的类型设计成一个参数,这个参数类型叫做泛型。

    2.为什么要使用泛型?

    类型无限制,类型不安全。类型强制转换时,容易出现异常。ClassCastException

    3.在集合中使用泛型

    集合接口或类在jdk5.0时都修改为带泛型的结构。在实例化集合类时,可以指明具体的泛型类型。指明完以后,在集合类或接口中凡是定义接口或类时,内部结构使用到类的泛型位置,都指定为实例化的泛型。泛型的类型必须是一个类。使用基本数据类型时,需要转换为包装类。如果实例化时,没有指明泛型的类型,默认为Object类型。如果泛型结构是一个接口或抽象类,则不能创建泛型类的对象。jdk1.7 泛型的简化操作: ArrayList<Integer> list = new ArrayList<>(); 泛型类可以有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3>

    代码举例:

    public class GenericTest { @Test public void test1(){ //在集合中使用泛型的情况:以ArrayList为例 // ArrayList<Integer> list = new ArrayList<Integer>(); //jdk7新特性:类型推断 ArrayList<Integer> list = new ArrayList<>(); list.add(99); list.add(100); list.add(88); //方式一: for (Integer integer:list){ System.out.print(integer+" "); } System.out.println(); //方式二: Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()){ System.out.print(iterator.next()+" "); } System.out.println(); //在集合中使用泛型的情况:以ArrayList为例 HashMap<String, Integer> map = new HashMap<String, Integer>(); map.put("Tom",123); map.put("Jerry",456); map.put("Jack",789); Set<Map.Entry<String, Integer>> set = map.entrySet(); Iterator<Map.Entry<String, Integer>> iterator1 = set.iterator(); while (iterator1.hasNext()){ //System.out.print(iterator1.next()+" "); Map.Entry<String, Integer> ee = iterator1.next(); String key = ee.getKey(); Integer value = ee.getValue(); System.out.println(key + ":"+value); } } }

    自定义泛型结构:泛型类,泛型接口;泛型方法

    泛型类被某个类继承

    ①public class SubOrder extends Order//此时子类时普通类 由于子类在继承带泛型的父类时,指明了泛型类型,则实例化子类对象时,不再需要指明泛型。 ②public class SubOrder1 extends Order//此时子类也是泛型类

    自定义泛型的注意点

    ①泛型不同的引用不能相互赋值

    ArrayList<Integer>list1=null; ArrayList<String>list2=null;

    此时list1和list2不能相互赋值。

    ②类型推断

    Order<String> order1 = new Order<>();

    ③静态方法中不能使用类的泛型。

    ④异常类不能是泛型的。

    ⑤不能使用new E[]。但是可以:E[] elements = (E[]) new Object[];

    代码举例:

    //自定义泛型类 public class Order<T> { String orderName; Integer orderId; //类的内部结构就可以使用类的泛型 T orderT; public Order(){ } public Order(String orderName, Integer 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 + '}'; } } //测试自定义泛型类 @Test public void test1(){ //如果定义了泛型类,实例化没指明类的泛型,则认为此泛型类型为Object类型。 //若果定义了类是泛型类的,建议实例化时要指明类的泛型。 Order order=new Order(); order.setOrderT(123); order.setOrderT("abc"); Order<String> order1 = new Order<String>("orderAA",23,"order:AA"); order1.setOrderT("AA:hello"); }

    泛型方法

    在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。 换句话说,泛型方法所属的类是不是泛型类都没有关系。 泛型方法可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。

    public static <E> List<E> copyFromArrayToList(E[] arr){ ArrayList<E> list = new ArrayList<>(); for(E e : arr){ list.add(e); } return list; } //测试泛型方法 @Test public void test4(){ Order<String> order = new Order<>(); Integer[] arr = new Integer[]{1,2,3,4}; //泛型方法在调用时,指明泛型参数的类型。 List<Integer> list = order.copyFromArrayToList(arr); System.out.println(list); }

    泛型在继承方面的体现

    /* 虽然类A是类B的父类,但是G<A> 和G<B>二者不具备子父类关系,二者是并列关系。 补充:类A是类B的父类,A<G> 是 B<G> 的父类 */ @Test public void test1(){ Object obj = null; String str = null; obj = str; Object[] arr1 = null; String[] arr2 = null; arr1 = arr2; //编译不通过 // Date date = new Date(); // str = date; List<Object> list1 = null; List<String> list2 = new ArrayList<String>(); //此时的list1和list2的类型不具有子父类关系 //编译不通过 // list1 = list2; /* 反证法: 假设list1 = list2; list1.add(123);导致混入非String的数据。出错。 */ show(list1); show1(list2); } public void show1(List<String> list){} public void show(List<Object> list){}

    通配符的使用

    /* 通配符:? 类A是类B的父类,G<A>和G<B>是没有关系的,二者共同的父类是:G<?> */ @Test public void test3(){ List<Object> list1 = null; List<String> list2 = null; List<?> list = null; list = list1; list = list2; //编译通过 // print(list1); // print(list2); 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); } }

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

    /* ? extends A: G<? extends A> 可以作为G<A>和G<B>的父类,其中B是A的子类 ? super A: G<? super A> 可以作为G<A>和G<B>的父类,其中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.018, SQL: 9