zoukankan      html  css  js  c++  java
  • Java之泛型

    1. 概述
              在引入泛型之前,Java类型分为原始类型、复杂类型,其中复杂类型分为数组和类。引入泛型后,一个复杂类型就可以在细分成更多的类型。
              例如原先的类型List,现在在细分成List<Object>, List<String>等更多的类型。
              注意,现在List<Object>, List<String>是两种不同的类型,他们之间没有继承关系,即使String继承了Object。下面的代码是非法的:

    1 List<String> ls = new ArrayList<String>();
    2 List<Object> lo = ls;

             这样设计的原因在于,根据lo的声明,编译器允许你向lo中添加任意对象(例如Integer),但是此对象是List<String>,破坏了数据类型的完整性。
             在引入范型之前,要在类中的方法支持多个数据类型,就需要对方法进行重载,在引入范型后,可以解决此问题(多态),更进一步可以定义多个参数以及返回值之间的关系。例如:

    1 public void write(Integer i, Integer[] ia);
    2 public void write(Double  d, Double[] da);

    的范型版本为:

    1 public <T> void write(T t, T[] ta);

    在看下面代码:

     1 public class GenericTest {
     2 
     3     public static void main(String[] args) {
     4         List list = new ArrayList();
     5         list.add("qqyumidi");
     6         list.add("corn");
     7         list.add(100);
     8 
     9         for (int i = 0; i < list.size(); i++) {
    10             String name = (String) list.get(i); // 1
    11             System.out.println("name:" + name);
    12         }
    13     }
    14 }

          定义了一个List类型的集合,先向其中加入了两个字符串类型的值,随后加入一个Integer类型的值。这是完全允许的,因为此时list默认的类型为Object类型。在之后的循环中,由于忘记了之前在list中也加入了Integer类型的值或其他编码原因,很容易出现类似于//1中的错误。因为编译阶段正常,而运行时会出现“java.lang.ClassCastException”异常。因此,导致此类错误编码过程中不易发现。

    通过使用泛型,解决上面异常,修改代码如下:

     1 public class GenericTest {
     2 
     3     public static void main(String[] args) {
     4         /*
     5         List list = new ArrayList();
     6         list.add("qqyumidi");
     7         list.add("corn");
     8         list.add(100);
     9         */
    10 
    11         List<String> list = new ArrayList<String>();
    12         list.add("qqyumidi");
    13         list.add("corn");
    14         //list.add(100);   // 1  提示编译错误
    15 
    16         for (int i = 0; i < list.size(); i++) {
    17             String name = list.get(i); // 2
    18             System.out.println("name:" + name);
    19         }
    20     }
    21 }

    总结: 使用泛型可以指代任意对象类型,定义的容器所放的内容是一个统一的类型;   

    java中泛型的引入主要是为了解决两个方面的问题:
    1. 集合类型元素在运行期出现类型装换异常,引入泛型增加编译时类型的检查;(即:消除强制类型转换,提高 Java 程序的类型安全)
    2. 解决开发时重复代码的编写,能够复用算法。(比如:在类中的方法支持多个数据类型,就需要对方法进行重载)

    2. 定义泛型类

    我们直接上代码:

     1 package com.learn.chap06.sec01;
     2 
     3 public class Fdemo<T> {  // 泛型类
     4     private T a;
     5 
     6     public Fdemo(T a) {
     7         super();
     8         this.a = a;
     9     }
    10 
    11     public T getA() {
    12         return a;
    13     }
    14 
    15     public void setA(T a) {
    16         this.a = a;
    17     }
    18     
    19     public void print(){
    20         System.out.println("Obeject类型为:"+a.getClass().getName());
    21     }
    22     
    23     
    24 }
     1 package com.learn.chap06.sec01;
     2 /**
     3  * 定义泛型类    (使用泛型可以指代任意对象类型)
     4  * @author Administrator
     5  *
     6  */
     7 public class Fdemotest {
     8     
     9     public static void main(String[] args) {
    10         Fdemo<Integer> test = new Fdemo<Integer>(12);
    11         test.print();
    12         System.out.println("test="+test.getA());
    13         
    14         Fdemo<String> strFdemo = new Fdemo<String>("我是中国人");
    15         strFdemo.print();
    16         System.out.println("strFdemo="+strFdemo.getA());
    17     }
    18 }

    运行结果:

    Obeject类型为:java.lang.Integer
    test=12
    Obeject类型为:java.lang.String
    strFdemo=我是中国人

    3. 限制泛型:

    我们直接上代码:

    1 package com.learn.chap06.sec02;
    2 
    3 public class Animal {
    4     public void say() {
    5         System.out.println("它是动物");
    6     }
    7 }
     1 package com.learn.chap06.sec02;
     2 
     3 public class Dog extends Animal{
     4 
     5     @Override
     6     public void say() {
     7         // TODO Auto-generated method stub
     8         System.out.println("它是一只狗");
     9     }
    10     
    11     
    12 }
     1 package com.learn.chap06.sec02;
     2 
     3 public class Cat extends Animal{
     4 
     5     @Override
     6     public void say() {
     7         // TODO Auto-generated method stub
     8         System.out.println("它是一只猫");
     9     }
    10     
    11     
    12 }
     1 package com.learn.chap06.sec02;
     2 
     3 public class Demo<T extends Animal>{
     4     private T ob;
     5 
     6     public Demo(T ob) {
     7         super();
     8         this.ob = ob;
     9     }
    10 
    11     public T getOb() {
    12         return ob;
    13     }
    14 
    15     public void setOb(T ob) {
    16         this.ob = ob;
    17     }
    18     
    19     public void print(){
    20         System.out.println("T的类型是:"+ob.getClass().getName());
    21     }
    22 }
     1 package com.learn.chap06.sec02;
     2 /**
     3  * 限制泛型
     4  * @author Administrator
     5  *
     6  */
     7 public class Test {
     8     public static void main(String[] args) {
     9         Demo<Dog> demo = new Demo<Dog>(new Dog());
    10         //demo.say(); 
    11         demo.print();
    12         
    13         //Demo<Integer> demo = new Demo<Integer>(new Dog()); // 由于泛型定义Demo类的类型必须为Animal或其子类Dog和Cat,而Integer不是Animal的子类,所以类型被限制,即:限制泛型,导致编译报错
    14         Demo<Animal> demo2 = new Demo<Animal>(new Cat());
    15         demo2.print();
    16         
    17         Demo<Cat> demo3 = new Demo<Cat>(new Cat());
    18         demo3.print();
    19         
    20     }
    21 }

    运行结果:

    T的类型是:com.learn.chap06.sec02.Dog
    T的类型是:com.learn.chap06.sec02.Cat
    T的类型是:com.learn.chap06.sec02.Cat

    4. 通配符泛型:

    我们直接上代码:

     1 package com.learn.chap06.sec03;
     2 
     3 import com.learn.chap06.sec02.Animal;
     4 import com.learn.chap06.sec02.Cat;
     5 import com.learn.chap06.sec02.Demo;
     6 import com.learn.chap06.sec02.Dog;
     7 
     8 public class Test1 {
     9     /**
    10      * 通配符泛型
    11      * @param demo
    12      */
    13     public static void take(Demo<?> demo){ // <?> 即为:通配符泛型
    14         demo.print();
    15     }
    16     
    17     public static void main(String[] args) {
    18         Demo<Dog> demo1 = new Demo<Dog>(new Dog());
    19         take(demo1);
    20         
    21         Demo<Cat> demo2 = new Demo<Cat>(new Cat());
    22         take(demo2);
    23         
    24         Demo<Animal> demo3 = new Demo<Animal>(new Animal());
    25         take(demo3);
    26     }
    27 }

    运行结果:

    T的类型是:com.learn.chap06.sec02.Dog
    T的类型是:com.learn.chap06.sec02.Cat
    T的类型是:com.learn.chap06.sec02.Animal

    5. 泛型方法:

     1 package com.learn.chap06.sec04;
     2 
     3 public class Test {
     4     
     5     /**
     6      * 泛型方法
     7      * @param t
     8      */
     9     public  static <T> void f(T t) {
    10         System.out.println("T的类型是:"+t.getClass().getName());
    11     }
    12     
    13     public static void main(String[] args) {
    14         f(1);
    15         f("hello");
    16         f(1.0f);
    17         f(new Object());
    18     }
    19 }

    运行结果:

    T的类型是:java.lang.Integer
    T的类型是:java.lang.String
    T的类型是:java.lang.Float
    T的类型是:java.lang.Object

    现在使用泛型没问题了吧!呵呵

  • 相关阅读:
    Linux开发环境必备十大开发工具
    mysql executemany与 insert ... ON DUPLICATE KEY UPDATE 一起使用
    python LD_LIBRARY_PATH 靠谱解决办法
    搭建简单ftp,满足windows和ubuntu共享文件
    用类方法作为装饰器装饰同属于本类的另一个方法
    通过类方法名调用类方法
    java将jpg文件转化为base64字节(互转)
    CSS元素居中的方式
    T-SQL语法学习一(持续更新)
    SVN的使用教程(一)
  • 原文地址:https://www.cnblogs.com/eaglezb/p/5983567.html
Copyright © 2011-2022 走看看