JAVA泛型详解 --- 学习笔记

原文请戳此处!!!


1. 普通泛型

class Point<T>{                  //此处可以随便写标识符号,T只是Type的简称
    private T var;               // var的类型由T指定,也就是:由外部指定
    public T getVar(){           //返回值得类型也是由外部决定的
        return var;
    }
    public void setVar(T var){    //设置的类型也由外部决定
        this.var = var;
    }
}
public class GenericsDemo01{
    public static void main(String args[]){
        Point<String> p = new Point<String>();   //此处决定了类Point<T>里面的var类型为String类型
        p.setVar("forfan06");      //设置字符串
        System.out.println(p.getVar().length());  //此处分两步,一是取得字符串;二是获得字符串长度
    }
}

-----------------------------------------------------------------------------------------------------------

class Notepad<K, V>{    //指定了两个泛型类型T和V,当然,此处的T和V可以换成其他字符。但是为了方便识别,一般取一个有意义单词的大写首字母
    private K key;      // 此处的T和V均是由外部决定的
    private V value;
    public K getKey(){
        return this.key;
    }
    public V getValue(){
        return this.value;
    }
    public void setKey(K key){
        this.key = key;
    }
    public void setValue(V value){
        this.value = value;
    }
}
public class GenericsDemo02{
    public static void main(String args[]){
        Notepad<String, Integer> t = null;        //定义了两个泛型类型的对象。
        t = new Notepad<String, Integer>();       //里面的key和value分别为String和Integer类型。
        t.setKey("饭饭");                          //设置对象t的内容
        t.setValue(20);
        
        System.out.print("姓名:" + t.getKey());      //获取对象t的属性
        System.out.println(", 年龄:" + t.getValue());
    }
}

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 GenericsDemo03{
    public static void main(String args[]){
        Info<String> i = new Info<String>();  //使用String类型为泛型类型
        i.setVar("forfan06");
        fun(i);
    }
    public static void fun(Info<?> info){    //此处Info<?>里面没有明确指明泛型类型,说明可以接受任意的泛型对象。
        System.out.println("内容是:" + info);
    }
}

更好的验证通配符的作用:增加Info<Integer>如下代码:也可以正常运行!!!

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 GenericsDemo03{
    public static void main(String args[]){
        Info<String> i = new Info<String>();  //使用String类型为泛型类型
        i.setVar("forfan06");
        fun(i);
        Info<Integer> s = new Info<Integer>();
        s.setVar(28);
        fun(s);
    }
    public static void fun(Info<?> info){    //此处Info<?>里面没有明确指明泛型类型,说明可以接受任意的泛型对象。
        System.out.println("内容是:" + info);
    }
}

上面程序若修改为:

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 GenericsDemo03{
    public static void main(String args[]){
        Info<String> i = new Info<String>();  //使用String类型为泛型类型
        i.setVar("forfan06");
        fun(i);
        Info<Integer> s = new Info<Integer>();
        s.setVar(28);
        fun(s);
    }
    public static void fun(Info<T> info){    //此处Info<?>里面没有明确指明泛型类型,说明可以接受任意的泛型对象。
        System.out.println("内容是:" + info);
    }
}

则会出现编译错误!!!!!!!!!!!!

GenericsDemo03.java:22: error: cannot find symbol
    public static void fun(Info info){    
                                ^
  symbol:   class T
  location: class GenericsDemo03
1 error

编译错误


3. 受限泛型

上限:

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 GenericsDemo04{
    public static void main(String args[]){
        Info<Integer> i1 = new Info<Integer>();          //声明Integer类的泛型对象
        Info<Float> i2 = new Info<Float>();              //声明Float类的泛型对象
        i1.setVar(27);                                   //设置整数(小数), 自动装箱!!
        i2.setVar(10.53f);
        fun(i1);
        fun(i2);
    }
    public static void fun(Info<? extends Number> temp){   //只能接受Number类及其子类的实例!!!!
        System.out.print(temp + "、");
    }
}

下限:

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 GenericsDemo04{
    public static void main(String args[]){
        Info<String> i1 = new Info<String>();
        Info<Object> i2 = new Info<Object>();
        i1.setVar("forfan06");
        i2.setVar(new Object());
        
        fun(i1);
        fun(i2);
    }
    public static void fun(Info<? super String> temp){     //只能接收String类或其父类(Object类)类型的泛型
        System.out.print(temp + "、");
    }
}


4. 泛型无法向上转型

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 GenericsDemo05{
    public static void main(String args[]){
        Info<String> i1 = new Info<String>();
        Info<Object> i2 = null;
        i2 = i1;   //此句会出错:error: incompatible types
    }
}

运行得到错误:

GenericsDemo05.java:17: error: incompatible types
        i2 = i1;   //此句会出错:incompatible types
             ^
  required: Info
  found:    Info
1 error

编译错误

  • 此时Info<String> i1, Info<Object> i2中,i2已经不是i1的基类了!!!所以不存在向上转型这一说法!!!!!

5. 泛型接口

interface Info<T>{          //在接口中定义泛型
    public T getVar();      //定义抽象方法,抽象方法的返回值就是泛型类型
}
class InfoImpl<T> implements Info<T>{   //定义泛型接口的子类
    private T var;
    public InfoImpl(T var){             //通过构造方法设置属性内容
        this.var = var;
    }
    public T getVar(){
        return this.var;
    }
    public void setVar(T var){
        this.var = var;
    }
}
public class GenericsDemo06{
    public static void main(String args[]){
        Info<String> i = null;         //声明接口对象,泛型T此时为String类型
        i = new InfoImpl<String>("forfan06");     //通过子类实例化对象
        System.out.println("内容:" + i.getVar());
    }
}

interface Info<T>{          //在接口中定义泛型
    public T getVar();      //定义抽象方法,抽象方法的返回值就是泛型类型
}
class InfoImpl implements Info<String>{   //定义泛型接口的子类
    private String var;
    public InfoImpl(String var){             //通过构造方法设置属性内容
        this.var = var;
    }
    public String getVar(){
        return this.var;
    }
    public void setVar(String var){
        this.var = var;
    }
}
public class GenericsDemo06{
    public static void main(String args[]){
        Info i = null;   //声明接口对象
        i = new InfoImpl("forfan06");  //通过子类实例化对象
        System.out.println("内容:" + i.getVar());
    }
}

6. 泛型方法

声明格式:

[访问权限] <泛型标识>  泛型标识 方法名称([泛型标识 参数名称])

class Demo{
    public <T> T fun(T t){       //可以接收任意类型的数据
        return t;                //直接把参数返回
    }
}
public class GenericsDemo07{
    public static void main(String args[]){
        Demo d= new Demo();
        String str = d.fun("forfan06");
        int i = d.fun(28);    //传递数字,自动装箱
        System.out.println(str);
        System.out.println(i);
    }
}

7. 通过泛型方法返回泛型类型实例

class Info<T extends Number>{    //指定上限,只能是数字类型。(只能是Number类的子类)
    private T var;
    public T getVar(){
        return this.var;
    }
    public void setVar(T var){
        this.var = var;
    }
    public String toString(){   //覆写Object类中的toString()方法
        return this.var.toString();
    }
}
public class GenericsDemo08{
    public static void main(String args[]){
        Info<Integer> i = fun(30);
        System.out.println(i.getVar());
    }
    public static <T extends Number> Info<T> fun(T param){      //方法中传入或返回的泛型类型由调用方法时所设置的参数类型决定
        Info<T> temp = new Info<T>();    //根据传入的数据类型实例化Info
        temp.setVar(param);              //将传递的内容设置到Info对象的var属性中
        return temp;       //返回实例化对象
    }
}

8. 使用泛型统一传入的参数类型

class Info<T>{
    private T var;
    public T getVar(){
        return this.var;
    }
    public void setVar(T var){
        this.var = var;
    }
    public String toString(){
        return this.var.toString();
    }
}
public class GenericsDemo09{
    public static void main(String args[]){
        Info<String> i1 = new Info<String>();
        Info<String> i2 = new Info<String>();
        i1.setVar("forfan06");
        i2.setVar("你好!");
        add(i1,i2);
    }
    public static <T> void add(Info<T> i1, Info<T> i2){
        System.out.println(i1.getVar() + " " + i2.getVar());
    }
}

9. 泛型数组

public class GenericsDemo10{
    public static void main(String args[]){
        Integer i[] = fun1(1, 2, 3, 4, 5, 6);  //返回泛型数组
        fun2(i);
    }
    public static <T> T[] fun1(T...arg){   //接收可变参数
        return arg;                        //返回泛型数组 
    }
    public static <T> void fun2(T param[]){    //输出
        System.out.println("接收泛型数组:");
        for(T t:param){
            System.out.print(t + "、");
        }
    }
}

此时运行会得到以下警告:

GenericsDemo10.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

出现上面警告是因为用到了JAVA5.0的泛型,而5.0的泛型不做类型检查,例如ArrayList = a new ArrayList(); a.add("hello");这样会出现警告!解决方法有以下几种:

  1. 在方法的前面加上@SuppressWarnings("unchecked")
  2. 声明泛型类型,例如ArrayList<Object> a = new ArrayList<Object>();
  3. 使用1.4兼容JDK来编译, javac -source 1.4 Test.java
  4. 也可以查看警告信息,javac Xlint:unchecked Test.java。这样会显示详细的警告信息。

10. 泛型的嵌套设置

class Info<T, V>{
    private T var;
    private V value;
    public Info(T var, V value){
        this.setVar(var);
        this.setValue(value);
    }
    public void setVar(T var){
        this.var = var;
    }
    public void setValue(V value){
        this.value = value;
    }
    public T getVar(){
        return this.var;
    }
    public V getValue(){
        return this.value;
    }
}
class Demo<S>{
    private S info;
    public Demo(S info){
        this.setInfo(info);
    }
    public void setInfo(S info){
        this.info = info;
    }
    public S getInfo(){
        return this.info;
    }
}
public class GenericsDemo11{
    public static void main(String args[]){
        Demo<Info<String, Integer>> d = null;      //将Info作为Demo的泛型类型
        Info<String, Integer> i = null;            //Info指定两个泛型类型
        i = new Info<String, Integer>("forfan06", 30);    //实例化Info对象
        d = new Demo<Info<String, Integer>>(i);           //在Demo类中设置Info类的对象
        System.out.println("内容一:" + d.getInfo().getVar());
        System.out.println("内容二:" + d.getInfo().getValue());
    }
}

泛型方法不一定要通过参数来确定泛型准确类型,可以只通过返回值,比如:

public static <E> ArrayList<E> new ArrayList(){
     return new ArrayList<E>();
}

public List<PrepaidHistory> queryHistories(Long skyid, PrepaidHistoryType type, Date from, Date end){
     ...
     return Lists.newArrayList();
}

这样Lists.newArrayList();

智能的知道返回类型为PrepaidHistory


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值