Java的泛型和通配符

泛型:
1.泛型类
    class A<T>{
    }
2.在创建实例时,需要为其类型变量赋值

3.泛型方法
    class A<T>{
        public T fun1(){}
        public void fun2(T t){}
        //以上两个都不是泛型方法,他们是泛型类里面的一个方法
        //发现方法要求需要在方法上有泛型的定义
        public <T> T fun3(){}//此为泛型方法
    }

class B{
        public <T> fun1(){}//也为泛型方法,泛型方法不一定要在泛型类中
    }
*泛型方法和泛型类并没有直接的关系,

4.泛型类的使用
    *泛型类中定义的泛型
        >可以在方法的返回值中使用
        >可以在方法的参数中使用
        >可以在局部变量是使用
    class C<T>{
        public T fun1(){
            T t = ...//可以的
            new T()//不可以的,会报错
        }
        public void fun2(T t){}
    }
简单来记:泛型可以在左边使用而不可以在右边使用。

5.泛型的继承和实现
    *子类不是泛型类:需要给父类传递一个具体的类型常量
        >此时父类中所有的泛型参数都会被此类型常量给替换掉
    *子类是泛型类:可以给父类传递一个具体的类型参数,也传递一个泛型参数
    class AA1 extends A<String>{}
    class AA2<E> extends A<E>{}

=========================================
=========================================
=========================================

泛型的通配符

1. 通配符使用的场景

方法的形参!

2. 通配符的优点
  使方法更加通用!

3. 通配符分类
  无界通配:?
  子类限定:? extends Object
  父类限定:? super Integer

4. 通配符缺点
  使变量使用上不再方便
  无界:参数和返回值为泛型的方法,不能使用!
  子类:参数为泛型的方法不能使用
  父类:返回值为泛型的方法不能使用

5. 比较通配符
boolean addAll(Collection<E> c)

List<Number> numList = new ArrayList<Number>();
List<Integer> intList = new ArrayList<Integer>();
numList.addAll(intList);//addAll(Collection<Number> c), 传递的是List<Integer>,报错

boolean addAll(Collection<? extends E> c)

List<Number> numList = new ArrayList<Number>();
List<Integer> intList = new ArrayList<Integer>();
numList.addAll(intList);//addAll(Collection<? extends Number> c), 传递的是List<Integer>,通过

代码演示

 1 package genericity;
 2
 3 public class Demo1 {
 4
 5    class A<T>{
 6        private T t;
 7        public T fun1(){
 8            return t;
 9        }
10
11        public void fun2(T t){
12
13        }
14
15    }//是泛型类
16
17    class B extends A<String>{}//B就不是泛型类
18
19    class C<E> extends A<Integer>{}//也是泛型类
20
21    class D<E> extends A<E>{}//也是泛型类
22
23    public void fun1(){
24        D<String> d = new D<String>();//此时class D 和 class E 中的泛型都被String给替换了
25    }
26 }
  1 package genericity;
  2
  3 import java.util.ArrayList;
  4 import java.util.List;
  5
  6 import org.junit.Test;
  7
  8 public class Demo2 {
  9
 10     @Test
 11     public void fun1(){//集合和数组的较量
 12         /*
 13          * 第一次较量
 14          * 数组:我可以创建一个什么都可以存在的10空间
 15          * 集合:我可以创建一个什么都放而且无限的空间
 16          */
 17         Object[] arr1 = new Object[10];
 18         List list1 = new ArrayList();
 19
 20         /*
 21          * 第二次较量
 22          * 数组:我可以创建一个只存放String类型的10空间
 23          * 集合:在以前我不行,不过现在我也可以,我可以创建一个只存放String类型的无限空间。
 24          */
 25         String[] arr2 = new String[10];
 26         List<String> list2 = new ArrayList<String>();
 27
 28         /*
 29          * 第三次较量
 30          * 数组:我可以使用Object[]来存在String[],但是arr3[0] = new Integer(100);//编程不报错,运行报:ArrayStoreException
 31          * 集合:因为泛型的擦除,直接不给我编译通过 List<Object> list3 = new ArrayList<String>()
 32          */
 33         Object[] arr3 = new String[10];
 34         arr3[0] = new Integer(100);//编程不报错,运行报:ArrayStoreException
 35
 36 //        List<Object> list3 = new ArrayList<String>();
 37           /**
 38            * 上面的代码报错,因为泛型只有编译器认识,而JVM对泛型根本不识别,泛型会在
 39            * 运行时擦除,如果上面代码不报错,而且运行时泛型又会擦除,那么就好出现下面的笑话
 40            * list.add(new Integer(100)),那么数组就好笑话集合,你什么东西都能放,
 41            * 还有什么限制,笑话。
 42            *
 43            * 然后我们把这个问题放大,对一个打印集合里面数据的方法,
 44            */
 45     }
 46
 47     public void fun2(){
 48         List<Integer> intList = new ArrayList<Integer>();
 49
 50         List<String> strList = new ArrayList<String>();
 51 //        print1(intList);//直接报错,原因和上面的一样,因为有一个实参向形参赋值的过程,编译器直接不让通过 List<Object> list= intList=new ArrayList<Integer>();
 52         //思考:那每个不同类型的集合都需要不同的打印方法,那方法是也太多了,所以就有了通配符的出现
 53
 54         //这样就可以使用通用的打印方法了
 55         print2(intList);
 56         print2(strList);
 57     }
 58
 59     public void print1(List<Object> list){
 60
 61     }
 62
 63     /**
 64      * 这里的?就是通配符
 65      * @param list
 66      */
 67     public void print2(List<?> list){
 68         /*
 69          * 思考:虽然都可以调用了,但是却带来了一些参数使用上面的限制
 70          */
 71 //        list.add(new Integer(100));//报错,因为并不知道传递进来的到底是上面,如果是String,那编程通过就笑话了,add()作废
 72         Object obj = list.get(0);//其实这个参数可以使用的原因是因为Object为所有类的父类,不让这个get()方法也作废
 73
 74         /*
 75          * 小结:
 76          *      1、当使用通配符时,对泛型类中的参数为泛型的方法起到了副作用,不能再使用!
 77          *      2、当使用通配符时,泛型类中返回值为泛型的方法,也作废了!
 78          * 通配符的好处:可以使泛型类型更加通用!尤其是在方法调用时形参使用通配符!
 79          */
 80     }
 81
 82     public void fun3(){
 83         List<Integer> intList = new ArrayList<Integer>();
 84         List<Long> longList = new ArrayList<Long>();
 85         print3(intList);
 86         print3(longList);
 87     }
 88
 89     /**
 90      * 子类统配,必须是Number及Number的子类才可以传参
 91      * 这样的缺点是:降低了参数的灵活性,但是关闭一扇大门就会打开一扇大门
 92      * 因为所有累都是Number的子类,所有返回值可以使用Number来接受,get()方法获得解放,即返回值为泛型的方法可以使用了
 93      * @param list
 94      */
 95     public void print3(List<? extends Number> list){
 96         Number nu = list.get(0);//正确
 97 //        list.add(new Integer(100));//但add()方法还是被废,以为不知道具体传入的哪一个子类,如果传入的是Long,加入Integer就笑话了
 98     }
 99
100     /**
101      * 父类统配,只允许Integer传递参数
102      * 这样的缺点是:降低了参数的灵活性,但是关闭一扇大门就会打开一扇大门
103      * 好处是因为所有类都是Integer的父类,参数为泛型的所有方法都可以使用了
104      * 但是相反的,返回值为泛型类型的方法就不能使用,因为子类不能接收父类的值
105      * @param list
106      */
107     public void print4(List<? super Integer> list){
108         list.add(new Integer(100));//正确
109         /*
110          * 但返回值为泛型的方法就不能使用了
111          */
112 //        Integer nu = list.get(0);//报错
113     }
114
115
116 }
时间: 2024-11-16 12:03:40

Java的泛型和通配符的相关文章

java 16-8 泛型高级之通配符

泛型高级(通配符) ?:任意类型,如果没有明确,那么就是Object以及任意的Java类了 ? extends E:向下限定,E及其子类 ? super E:向上限定,E极其父类 1 import java.util.ArrayList; 2 import java.util.Collection; 3 public class GenericDemo { 4 public static void main(String[] args) { 5 // 泛型如果明确的写的时候,前后必须一致 6 C

java 泛型详解(普通泛型、 通配符、 泛型接口,泛型数组,泛型方法,泛型嵌套)

JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0.这说明Java已经有大幅度的变化.本文将讲解JDK5.0支持的新功能-----Java的泛型. 1.Java泛型  其实Java的泛型就是创建一个用类型作为参数的类.就象我们写类的方法一样,方法是这样的method(String str1,String str2 ),方法中参数str1.str2的值是可变的.而泛型也是一样的,这样写class Java_Generics<K,V>,这里边的K和V就象方法中的参数str1和st

java 泛型实例详解(普通泛型、 通配符、 泛型接口)

java 泛型详解(普通泛型. 通配符. 泛型接口) 2013-02-04 19:49:49| 分类: JAVA | 标签:java |举报|字号 订阅 下载LOFTER客户端 JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0.这说明Java已经有大幅度的变化.本文将讲解JDK5.0支持的新功能-----Java的泛型. 1.Java泛型 其实Java的泛型就是创建一个用类型作为参数的类.就象我们写类的方法一样,方法是这样的method(String str1,String

java 泛型详解(普通泛型、 通配符、 泛型接口)

java 泛型详解(普通泛型. 通配符. 泛型接口) JDK1.5 令我们期待很久,可是当他发布的时候却更换版本号为5.0.这说明Java已经有大幅度的变化.本文将讲解JDK5.0支持的新功能-----Java的泛型. 1.Java泛型 其 实Java的泛型就是创建一个用类型作为参数的类.就象我们写类的方法一样,方法是这样的method(String str1,String str2 ),方法中参数str1.str2的值是可变的.而泛型也是一样的,这样写class Java_Generics<K

Java泛型中通配符的使用

学习目标 掌握通配符"?" 的使用 掌握受限泛型的设置 掌握泛型与子类继承的限制 匹配任意类型的通配符 在开发中对象的引用传递是最常见的,但是如果在泛型类的操作中,在进行传递的时候泛型类型必须匹配才可以传递.否则是无法传递的. class Info<T>{ private T var ; // 定义泛型变量 public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; }

JAVA泛型-通配符

黑马程序员:Java培训.Android培训.iOS培训..Net培训 JAVA泛型-通配符 一.泛型与继承 有如下的继承关系和以它们为类型参数的泛型: public class Holder<T>{ T t; public Holder(){} public Holder(T at){ t = at;} public void set(T at){ t = at;} public T get(){return t; } } //有如下代码: Holder<Apple> apple

Java泛型之通配符

原文点此链接 使用通配符的原因:Java中的数组是协变的,但是泛型不支持协变. 数组的协变 首先了解下什么是数组的协变,看下面的例子: Number[] nums = new Integer[10]; // OK 因为Integer是Number的子类,一个Integer对象也是一个Number对象,所以一个Integer的数组也是一个Number的数组,这就是数组的协变. Java把数组设计成协变的,在一定程度上是有缺陷的.因为尽管把Integer[]赋值给Number[],Integer[]

JAVA 泛型与通配符的使用

泛型的本质是参数化类型.即所操作的数据类型被指定为一个参数. 1.jdk 1.5/1.6 必须显式的写出泛型的类型. 2.jdk 1.7/1.8 不必显式的写出泛型的类型. 一.泛型声明 可以用<T>.<K,V>.<T  extends  Number>等进行泛型的声明.其中,<T  extends  Number>的声明方式限定了T的范围,T只能为 Number的子类. 1.参数类型用在类的创建中,泛型类. 2.参数类型用在接口的创建中,泛型接口. 3.参

java面向对象 泛型

这个第一篇知识梳理的博客,希望我可以坚持下去将知识进行总结. 这是在极客学院里看到的视频,目录如下,蛮清晰的.然后我将视频中所说再记忆下. java面向对象之泛型:认识泛型 Java SE 1.5的新特性,泛型的本质是参数化类型,可以代表任何数据类型. java面向对象之泛型:构造函数中使用 class Gen<T>{ private T value; Gen(T value){//构造函数中就泛型就不需要用尖括号了 this.value=value; } public void setVal