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类型的对象,不需要进行向上转型和向下转型操作。

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

posted @ 2018-08-26 13:54  考拉熊_12  阅读(159)  评论(0编辑  收藏  举报