zoukankan      html  css  js  c++  java
  • java编程之泛型

    java泛型实现了“参数化类型”的概念,所谓“参数化类型”是指将操作的数据类型指定为一个参数,这点在容器中用的最多,例如:List<String> strlist=new ArrayList<String>(),List<Integer> intlist=new ArrayList<Integer>();strlist可以操作的数据类型是String类型,intlist可以操作的数据类型是int类型,泛型在容器中得到了充分的应用。

    泛型是使得代码重用得到很大的提升,我们在程序中也会想一些办法设计代码重用的方法,例如输出一个内容,我们要用System.out.println(...),敲这么多东西还是麻烦,我们可以定义一个println()方法,如下:

    static void println(Object o){

      System.out.println(o);

    }

    再在程序中输出东西时,只需调用println(...)即可,这个println()方法就有了“泛化”的机制,它可以输出任何System.out.println()可以输出的东西,该方法的参数类型被设置为基类Object类型,我们知道,Java中的基本数据类型都有相对应的类类型的数据,比如int类型的数据对应的有Integer类类型的数据,java有“自动装箱”功能,也就是将对应的基本类型的数据转化为对应类类型的对象,例如上面的println(3),在编译后会变成println(Integer.valueOf(3));而所有的java类都是继承自Object类,所以当然可以用println()方法了。

    那么将数据类型都定义为Object类型不就可以设计一个泛化类型的方法,类和接口了吗?答案是可以的,但是“太泛化”了,以至于没了边界。这里先给出代码:

     1 public class gen{
     2     
     3     public static void main(String[] args){
     4         myList list=new myList();
     5         list.push("helloworld");
     6         list.push(12);
     7         Object val;
     8         while((val=list.pop())!=null){
     9             System.out.println(val.getClass());
    10         }
    11     }
    12 }
    13 
    14 class myList{    
    15     class Node{
    16         Object val=null;
    17         Node next=null;
    18         Node(Object val,Node next){
    19             this.val=val;
    20             this.next=next;
    21         }
    22         Node(){
    23             val=null;
    24             next=null;
    25         }
    26         boolean end(){
    27             return val==null && next==null;
    28         }
    29     }
    30     private Node top=null;
    31     myList(){
    32         top=new Node();
    33     }
    34     //插入新值
    35     public void push(Object val){
    36         top=new Node(val,top);
    37     }
    38     //返回头结点的值
    39     public Object pop(){
    40         Object val=top.val;
    41         if(!top.end()){
    42             top=top.next;
    43         }
    44         return val;
    45     }
    46 }
    View Code

    我们自定义了一个list链表,为了使这个链表有更好的普遍使用性,我们将链表类内部的数据定义为Object类型,这样我们可以插入String类型数据、int类型数据....。但是这个设计“太泛化”了,你甚至可以“混插”,比如上面的执行结果,int类型的数据和String类型的数据插到了一起,显然在后续的操作中可能出现错误,例如你创建了一个自以为全是int类型的链表并对它们求和,但是不小心插入了字符串类型的数字"123",程序编译也能通过,你以为你的程序是对的,结果运行的时候出错了!你深受打击,自挂东南枝,全球计算机行业从此一蹶不振.....

    为了防止上面悲剧的发生,我们还是希望错误在编译时期就能暴露出来,以便将错误及时地扼杀与萌芽状态,泛型设计的一项重大功能体现出来了:提前指定我们的链表可以插入什么样的数据类型,并由编译器验证其类型的正确性!这时,我们可以这样设计:

     1 public class gen{    
     2     public static void main(String[] args){
     3         //这里指定list2中的数据类型为String类型,也就是将T设置为String类型
     4         myList2<String> list2=new myList2<String>();
     5         list2.push("hello world");
     6         list2.push("hello code");
     7         //list2.push(23);//编译时便会提醒错误
     8         String s;
     9         while((s=list2.pop())!=null){
    10             System.out.println(s);
    11         }
    12     }
    13 }
    14 class myList2<T>{
    15     class Node<U>{
    16         U val=null;
    17         Node<U> next=null;
    18         Node(U val,Node<U> next){
    19             this.val=val;
    20             this.next=next;
    21         }
    22         Node(){
    23             val=null;
    24             next=null;
    25         }
    26         boolean end(){
    27             return val==null && next==null;
    28         }
    29     }//这里将Node中的值类型设定为U类型,也就是将U传递给T
    30     private Node<T> top=null;
    31     myList2(){
    32         top=new Node<T>();
    33     }
    34     public void push(T val){
    35         top=new Node<T>(val,top);
    36     }
    37     public T pop(){
    38         T val=top.val;
    39         if(!top.end()){
    40             top=top.next;
    41         }
    42         return val;
    43     }
    44 }
    View Code

    当我们不小心执行list2.push(23)时,编译器在编译阶段就会提醒:你错啦!于是我们很愉快地就可以将错误的代码修正过来。

    Java容器类可以说是Java代码重用设计的一个重要体现,而Java容器类设计的基础就是泛型,这就是Java泛型的重要之处。

    注:以上代码设计部分参考自《Thinking In Java》,感谢Bruce Eckel。

  • 相关阅读:
    C语言的灵魂(函数)
    GO语言测试题
    gRPC的发布订阅模式
    gRPC 介绍和简单实现
    RPC与Protobuf(五)
    RPC和Protubuf(四)
    RPC与Protobuf(三)
    JS立即执行函数的几种写法
    如何写出让人看了恶心的代码
    记录几个前端必备的库/框架
  • 原文地址:https://www.cnblogs.com/codeMedita/p/6915494.html
Copyright © 2011-2022 走看看