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

    泛型是JDK5.0的新特性。

    我们需要知道:

    1.为什么要引入泛型?

    2.泛型语法如何实现?

    3.泛型的优点和缺点?

    我们之前学习过JDK5.0的新特性自动拆箱和自动装箱,是编译期的概念,泛型也是编译期的概念。

    先来分析一下以下程序没有使用泛型,缺点是什么?

    import java.util.*;
    public class GenericTest01{
     public static void main(String args[]){
       //创建一个集合,用来存储A,B,C
       Set s=new HashSet();
       //创建对象
       A a=new A();
       B b=new B();
       C c=new C();
       
       s.add(a);
       s.add(b);
       s.add(c);
       
       //遍历,需求:如果是A类型调用m1方法,如果是B类型,调用m2方法,如果是C类型,调用m3方法。
        Iterator it=s.iterator();
       while(it.hasNext()){
         Object o=it.next();
         //只能做大量的强制类型转换
         if(o instanceof A){
           A a1=(A)o;
             a1.m1();
         }else if(o instanceof B){
           B b1=(B)o;
             b1.m2();
         }else if(o instanceof C){
           C c1=(C)o;
             c1.m3();
         }
       }
     }
    }
    class A{
     public static void m1(){
       System.out.println("A's m1 is...");
     }
    }
    class B{
     public static void m2(){
       System.out.println("B's m2 is...");
     }
    }
    class C{
     public static void m3(){
       System.out.println("C's m3 is...");
     }
    }

    编译运行后输出:

    C's m3 is...
    A's m1 is...
    B's m2 is...

    在上面程序中,

    1.我们定义了三个类型A,B,C,并且各自定义了方法,m1( ),m2( ),m3( )。

    2.主程序中,首先利用语句Set s=new HashSet();来创建集合s,用来存储A,B,C,接着创建对象,添加到集合s中去。

    3.之后遍历,这里给出了需求,遍历集合,如果是A类型调用m1方法,如果是B类型,调用m2方法,如果是C类型,调用m3方法。iterator接口没有泛型则只能访问Object类型,即Object o=it.next();

    4.根据需求,只能做大量的强制类型转换,A a1=(A)o; 然后调用各自类型的方法。

    通过分析以上程序可以知道,如果集合不使用泛型,则集合中的元素类型不统一,在遍历集合的时候,只能拿出来Object类型,需要做大量的强制类型转换,操作起来很麻烦。

    开头提出的三个问题:

    1.为什么使用泛型?

    ①引入泛型可以统一集合中的数据类型;

    ②可以减少强制类型转换。

    3.泛型的优点和缺点?

    优点是统一类型,可以减少强制类型转换;缺点是只能存储一种数据类型。

    接下来看看第二个问题,泛型语法如何实现?看以下程序,List使用泛型:

    import java.util.*;
    public class GenericTest02{
     public static void main(String args[]){
       //创建一个List集合,只能存储字符串类型
       List<String> strs=new ArrayList();
       //添加元素
       strs.add("JACK");
       strs.add("TOM");
       strs.add("LINDA");
       strs.add("LIMING");
       //遍历
       Iterator<String> it=strs.iterator();
       while(it.hasNext()){
         System.out.println(it.next());
       }
     }
    }

    接下来看Map使用泛型,看以下例子:

    import java.util.*;
    public class GenericTest03{
     public static void main(String[] args){
       Map<String,Integer> maps=new HashMap<String,Integer>();
       maps.put("西瓜",10);
       maps.put("桃子",5);
       maps.put("樱桃",20);
       
       Set<String> keys=maps.keySet();
       Iterator<String> it=keys.iterator();
       while(it.hasNext()){
         String k=it.next();
         Integer v=maps.get(k);
         System.out.println(k+"---->"+v);
       }
     }
    }

    编译后运行输出:

    桃子---->5
    西瓜---->10
    樱桃---->20

    其中用到的两个方法重温一下,一个是keySet();另一个是get(),分别用来得到Map中的键值对。

    再来看SortedSet集合使用泛型。

    import java.util.*;
    public class GenericTest04{
     public static void main(String[] args){
                                    //创建集合
       SortedSet<Manager> ss=new TreeSet<Manager>();
       //添加元素
       Manager m1=new   Manager(1000.0);
       Manager m2=new   Manager(1500.0);
       Manager m3=new   Manager(3000.0);
       
       ss.add(m1);
       ss.add(m2);
       ss.add(m3);
       
       //遍历
       Iterator<Manager> it=ss.iterator();
       while(it.hasNext()){
         Manager m=it.next();
         System.out.println(m);
       }
     }
    }
    class Manager implements Comparable<Manager>{
    double sal;
    Manager(double sal){
     this.sal=sal;
    }
    public String toString(){
     return sal+"";
    }
    //实现接口中的方法
    public int compareTo(Manager m){
     double sal1=this.sal;
     double sal2=m.sal;
     if(sal1>sal2){
       return 1;
     }else if(sal1<sal2){
       return -1;
     }
     return 0;
    }
    }

    在上面的例子中,Manager类继承了 Comparable接口,并重写了该接口中的compareTo()方法。

    在深入了解泛型之前需要回忆一下向上转型和向下转型,结合以下代码来看:

    public class TestF{
     private Object b;
     public Object getB(){
       return b;
     }
     public void setB(Object b){
       this.b=b;
     }
     public static void main(String[] args){
       TestF t=new TestF();
       //向上转型
       t.setB(new Boolean(true));
       //向下转型:getB()方法返回的是Object类型的,却以Boolean类型返回;
       System.out.println(t.getB());
       t.setB(new Float(12.4));
       Float f=(Float)(t.getB());
       System.out.println(f);
     }
    }

    编译运行后输出:

    true
    12.4

    在上述代码中,TestF类定义了私有的成员变量b,类型为Object类,同时为其定义了getB()和setB()方法。在主方法中,将new Boolean(true)对象作为setB()方法的参数,由于setB()方法的参数类型为Object类型,而new Boolean(true)对象为Boolean类型,因此就实现了向上转型操作。同时在调用getB()方法时,将getB()方法返回的Object对象以相应的Boolean类型返回,因此实现了向下转型操作。向上转型是安全的,但是向下转型如果用错了类型,或没有执行该操作,通常会报异常,如下将上面的代码修改一下:

    public class TestF{
     private Object b;
     public Object getB(){
       return b;
     }
     public void setB(Object b){
       this.b=b;
     }
     public static void main(String[] args){
       TestF t=new TestF();
       //向上转型
       t.setB(new Boolean(true));
       //向下转型:getB()方法返回的是Object类型的,却以Boolean类型返回;
       System.out.println(t.getB());
       t.setB(new Float(12.4));
       Integer f=(Integer)(t.getB());
       System.out.println(f);
     }
    }

    编译运行后输出:

    true
    Exception in thread "main" java.lang.ClassCastException: java.lang.Float cannot be cast to java.lang.Integer

     at TestF.main(TestF.java:16)

    Object类为最上层的父类,很多程序员为了使程序更为通用,通常程序传入的值与返回的值都为Object类型,但在需要使用这些实例时,必须正确地将该实例转换为原来的类型,否则就会报ClassCastException异常。

    接下来使用泛型对第一个代码进行修改,代码如下:

    public class OverClass<T>{
     private T over;
     public T get(){
       return over;
     }
     public void set(T over){
       this.over=over;
     }
     public static void main(String[] args){
       OverClass<Boolean> over1=new OverClass<Boolean>();
       OverClass<Float> over2=new OverClass<Float>();
       over1.set(true);
       System.out.println(over1.get());
       over2.set(12.3f);
       System.out.println(over2.get());
     }
     
    }

    在上述代码中,定义OverClass类时,后面加了一个<T>,这里便引用了泛型机制,OverClass<T>便称为泛型类,同时返回和接受的参数使用T这个类型。最后在主方法中使用OverClass<Boolean>形式返回一个Boolean类型的对象,使用OverClass<Float>形式返回一个Float类型的对象,不需要进行向上转型和向下转型操作。

    搜索微信公众号“程序员考拉”,欢迎关注!

  • 相关阅读:
    2017加油
    配置SSH框架的心得
    .net 中select和where的区别
    oracle查询中文数据出现乱码
    three.js 加载 obj模型
    下载别人的3D模型文件
    关闭按钮
    桌面截屏保存成gif形式(软件)
    vue 中引入 three.js
    three.js-地球贴图-TextureLoader
  • 原文地址:https://www.cnblogs.com/naihuangbao/p/9444453.html
Copyright © 2011-2022 走看看