【系列】重新认识Java——泛型(通配、特性和注意点)

上一篇文章介绍了Java泛型中的基础及原理,本文将继续研究有关Java泛型的内容。本文的主要内容有:

  1. 泛型的特性
  2. 泛型通配
  3. 泛型类与普通类的不同点,也是日常开发要主要的点

泛型特性

泛型的兼容性

首先要强调的是,泛型是编译时才会检查合法性,编译后会直接擦除泛型信息。正由于这一点,所以在使用Eclipse编写源代码时,如果代码不合法,它会直接提示我们。Java编译器是向后兼容的,也就是低版本的源代码可以用高版本编译器进行编译。下面来看看那些兼容性代码。

  1. 引用和实例化都不包含泛型信息。
import java.util.ArrayList;
import java.util.List;

/**
 * @author xialei
 * @version 1.0 2016年6月28日下午9:03:44
 */
public class Compatibility {
   

    public static void main(String[] args) {
        // 下面编译通过
        List list1 = new ArrayList();
        list1.add("123");
        list1.add(1);
    }
}

上面的这段代码是可以通过编译的,这是JDK1.4之前的写法,所以可以验证JDK1.5之后的编译器是可以兼容JDK1.4之前的源代码的。不过,笔者在JDK1.8.x版本的编译器进行编译时,会抛出如下所示的警告信息。很显然,如果类被定义成泛型类,但是在实际使用时不使用泛型特性,这是不推荐的做法!

注: Compatibility.java使用了未经检查或不安全的操作。
注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
  1. 引用使用泛型,实例化不使用泛型。
import java.util.ArrayList;
import java.util.List;

/**
 * @author xialei
 * @version 1.0 2016年6月28日下午9:03:44
 */
public class Compatibility {
   

    public static void main(String[] args) {

        // 编译不通过
        List<String> list2 = new ArrayList();
        list2.add("123");
        list2.add(1); // 这里出错
    }
}

上面的代码编译不通过,由于对引用使用了泛型,其中的所能容纳的对象必须为String 类型。这种写法实际上跟完整写法的作用一致,不过Eclipse仍然会警告。

  1. 引用不使用泛型,实例化使用泛型。
import java.util.ArrayList;
import java.util.List;

/**
 * @author xialei
 * @version 1.0 2016年6月28日下午9:03:44
 */
public class Compatibility {
   

    public static void main(String[] args) {
        // 编译通过
        List list3 = new ArrayList<String>();
        list3.add("123");
        list3.add(1);
    }
}

上面的这段代码可以编译通过,其效果与1(不使用泛型)完全一致。结合2、3可以知道,编译时只能做引用的类型检查,而无法检查引用所指向对象的实际类型。

泛型与继承

在使用泛型时,引用的参数类型与实际对象的参数类型要保持一致(通配符除外),就算两个参数类型是继承关系也是不允许的。看看下面的2行代码,它们均不能通过编译。

ArrayList<String> arrayList1 = new ArrayList<Object>(); //编译错误  
ArrayList<Object> arrayList1 = new ArrayList<String>(); //编译错误  

下面来探讨一下为什么不能这么做。

  1. 第1种情况,如果这种代码可以通过编译,那么调用get()方法返回的对象应该是String,但它实际上可以存放任意Object类型的对象,这样在调用类型转换指令时会抛出ClassCastException。这样可以不是那么明显,来看看下面的代码。arrayList1中实际存放的Object对象,所以在进行类型转换时会抛出异常。这原本就是泛型想要极力避免的问题,所以Java允许这种写法。
ArrayList<Object> arrayList1 = new ArrayList<Object>();  
arrayList1.add(new Object());  
ArrayList<String> arrayList2 = arrayList1; //编译错误  
  1. 第2种情况。虽然String类型的对象转换为Object不会有任何问题,但是这有什么意义呢?我们原本想要用String对象的方法,但最终将其赋予了一个Object类型的引用。如果需要使用String中的某些方法,必须将Object强制转换为String。这样不会抛出异常,但是却违背了泛型设计的初衷。

泛型与多态

下面来考虑一下泛型中多态问题。普通类型的多态是通过继承并重写父类的方法来实现的,泛型也不例外,下面是一个泛型多态示例。

/*
 * 个人主页:http://hinylover.space
 *
 * Creation Date: 2016年7月2日 下午7:50:35
 */
package demo.blog.java.generic;

/**
 * @author xialei
 * @version 1.0 2016年7月2日下午7:50:35
 */
public class Father<T> {
   

    public void set(T t) {
        System.out.println("I am father, t=" + t);
    }

    public T get() {
        return null;
    }
}
/*
 * 个人主页:http://hinylover.space
 *
 * Creation Date: 2016年7月2日 下午7:50:57
 */
package demo.blog.java.generic;


/**
 * @author xialei
 * @version 1.0 2016年7月2日下午7:50:57
 */
public class Son extends Father<String> {
   

    @Override
    public void set(String t) {
        super.set(t);
        System.out.println("I am son.");
    }

    @Override
    public String get() {
        return super.get();
    }

    public static void main(String[] args) {
        Father<String> father = new Son();
        father.set("hello world");
  
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值