Java基础之泛型

Java 1.5发行版本中增加了泛型(Generic),在没有泛型之前,从集合中读取到的每一个对象都必须进行强制类型转换,结果就是,如果在操作过程中不小心插入了类型错误的对象,在运行时转换处理就会出错,这样的错误很难发现和纠正,但是,自从有了泛型之后,就可以告诉编译器每个集合可以接受哪些对象,如果不小心插入了错的对象,编译器此时就会暴红,这样就使得程序更加安全也更加清楚。在Java List等集合中都添加了泛型方法,聪明的你也会发现,在Java中,你即可以写List list,也可以写List String>list这样的方法;这里的list叫做原型,后者叫做泛型,会什么会出现这种情况呢,是因为在泛型出现在集合以前,程序大量的使用了List原型,为了兼容性,List方法没有被取消掉,如果你在细心一点,你也许就可以发现,不管是List,还是泛型方法,最后在jvm中出现的都是List原型,并没有泛型方法,这是为什么呢?别急,我们慢慢来,集合的泛型方法相信大家早已烂熟于心,我们先学习一个自定义的方法,代码如下:

package Generic;

import java.util.List;

/**
 * Created by jiangph on 16-1-17.
 */
public class generictest {

    public static void main(String[]args)
    {
        GenericTest11<String>name=new GenericTest11<String>("jiangph");
        System.out.println("name:" + name.getData());
        /***
         * 泛型的类型擦除,作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。
         */
        GenericTest11<Integer>num=new GenericTest11<Integer>(11);
        System.out.println(name.getClass()==num.getClass()); //return true


    }

}


class GenericTest11<T>{
    private T data;
    public GenericTest11()
    {

    }
    //定义一个带参数的构造方法
    public GenericTest11(T data)
    {
        this.data=data;
    }
    //定义一个获得数据的方法
    public T getData()
    {
        return data;
    }
}

了解到泛型的好处,和自定义泛型,这里有两个东西是我们必须知道的:
一,泛型擦除
Java中的泛型只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。

public class GenericTest {
    //代码摘自互联网
    public static void main(String[] args) {

        Box<String> name = new Box<String>("corn");
        Box<Integer> age = new Box<Integer>(712);

        System.out.println("name class:" + name.getClass());      // com.qqyumidi.Box
        System.out.println("age class:" + age.getClass());        // com.qqyumidi.Box
        System.out.println(name.getClass() == age.getClass());    // true

    }

}

二,泛型继承
看这段代码

public class GenericTest {

    public static void main(String[] args) {

        Box<Number> name = new Box<Number>(99);
        Box<Integer> age = new Box<Integer>(712);

        getData(name);

        //The method getData(Box<Number>) in the type GenericTest is 
        //not applicable for the arguments (Box<Integer>)
        getData(age);   // 1

    }

    public static void getData(Box<Number> data){
        System.out.println("data :" + data.getData());
    }

}

代码在1这个地方报了错,这里编辑器告诉我们,Number和Integer逻辑上不能视为父子类;为什么呢?这不是跟多态作对么?,但是我们从反面过来看一下,如果程序是对的,那么getdata()这个函数,获得的是int?还是float?,所以我们必然是不能这样写的,那么我们要怎么做呢?第三个概念,通配符即“?”

package Generic;

/**
 * Created by jiangph on 16-1-18.
 */


public class GenericWildCard {

    public static void main(String[]args)
    {
        WildCard test1=new WildCard("111");
        WildCard test2=new WildCard(111);
        test1.getWildCardData(test1);
    }



}

class WildCard<T>{

    private T data;
    public WildCard()
    {

    }
    public WildCard(T data)
    {
        this.data=data;
    }


    public T getData()
    {
        return data;
    }

    public Object getWildCardData(WildCard<?>data)
    {
        return data.getData();
    }

}

类型通配符一般是使用 ? 代替具体的类型实参。注意了,此处是类型实参,而不是类型形参。慢慢理解代码,至于通配符上限,下限;类型通配符上限通过形如Class ? extends Number>形式定义,相对应的,类型通配符下限为Class ? super Number>形式。对类型做进一步的限制,即只能是Number及其子类或是父类。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值