Java 泛型
Posted 考拉熊_12
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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类型的对象,不需要进行向上转型和向下转型操作。
搜索微信公众号“程序员考拉”,欢迎关注!
以上是关于Java 泛型的主要内容,如果未能解决你的问题,请参考以下文章
什么意思 在HashMap之前 ? Java中的泛型[重复]