------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
泛型的产生
在jdk1.5版本以后,集合中可以存储基本的数据类型,因为java可以自动的对基本数据进行装箱,这样不适当的操作就会造成程序的一些安全隐患。
请看下面的代码:
import java.util.*;
class JavaCollection1_15
{
public static void main(String[] args)
{
ArrayList al=new ArrayList();
al.add("abc");
al.add("bcd");
al.add("xt");
al.add(4);//注意java会对基本数据类型进行自动装箱,相当于al.add(new Integer(4));
for(Iterator it=al.iterator();it.hasNext();)
{
String s=(String)it.next();
System.out.println(s.length());
}
}
}
注意这段代码在编译时,能够通过,但是在运行时就会报异常,
运行结果如下:
通过提示我们可以发现,程序在运行时会报出类型转换错误,原因就是我们一开始对集合没有定义数据类型而造成。为了解决这种安全隐患,因此出现了泛型。
泛型的概述:
对集合(容器)一开始就定义了数据类型,是Jdk1.5版本后的一个新特性,用于解决安全隐患。
优点:
1 将运行时期的问题和安全隐患暴露在编译时期,减少了安全问题。
2避免了强制转换的麻烦,
上面的代码进行修改:
import java.util.*;
class JavaCollection1_15
{
public static void main(String[] args)
{
ArrayList<String> al=new ArrayList<String>();
al.add("abc");
al.add("bcd");
al.add("xt");
al.add(4);//注意java会对基本数据类型进行自动装箱,相当于al.add(new Integer(4));
for(Iterator<String> it=al.iterator();it.hasNext();)
{
//String s=(String)it.next();
String s=it.next();
System.out.println(s.length());
}
}
}
运行结果如下:
泛型的使用
其实通过上面的程序我们可以发现<>就是用来接收数据的类型的。同时<E>中E的类型必须是引用类型的。
泛型实例三:
import java.util.*;
class JavaCollection1_16
{
public static void main(String[] args)
{
TreeSet<String> ts=new TreeSet<String>(new MyComparator());
ts.add("c");
ts.add("aaa");
ts.add("b");
ts.add("bca");
for(Iterator<String> it=ts.iterator();it.hasNext();)
{
String s=it.next();//这里避免了类型强制转换
System.out.println(s);
}
}
}
class MyComparator implements Comparator<String>//泛型避免了强制转换,这里我们也可以定义泛型类型的比较器
{
public int compare(String str1,String str2)
{
int num=str1.length()-str2.length();
if(num==0)
return str1.compareTo(str2);
return num;
}
}
程序运行结果如下:
从上面的实例我们发现Comparator和Comparable都可以定义成泛型的,从而避免了类型强制转换。
泛型类
什么时候定义泛型类呢?
当类中要操作的引用数据类型不确定时,需要定义泛型类。
早期使用Object类型进行扩展,现在使用泛型更方便。
泛型实例四:
需求,定义一个工具类,用来操作不同的实例对象。
import java.util.*;
class JavaCollection1_17
{
public static void main(String[] args)
{
Tools<Student> t=new Tools<Student>();
t.setInstance(new Student());
Student s=t.getInstance();
Tools<Worker>tt=new Tools<Worker>();
tt.setInstance(new Worker());
Worker w=tt.getInstance();
}
}
/*泛型类的定义用来操作不同的对象*/
class Tools<T>
{
private T t;
public void setInstance(T t)
{
this.t=t;
}
public T getInstance()
{
return t;
}
}
class Student
{
}
class Worker
{
}
编译通过,说明上面的Tools类具有操作不同的引用类型对象的功能。
注意:泛型类定义的泛型在整个类中都有效,如果在方法中使用,那么在泛型类在创建对象时,明确了对象的操作类型,那么方法的操作类型也被局限性了
泛型方法
为了解决泛型类的局限性,定义一个方法,能够操作不同引用类型的数据,从而引进了泛型方法来解决类似的问题,泛型方法的定义是将泛型定义在方法体上,同时泛型方法也可以存在泛型类中。
实例五:
import java.util.*;
class JavaCollection1_18
{
public static void main(String[] args)
{
TextDemo<Integer> t=new TextDemo<Integer>();
t.show(new Integer("111"));
t.show("123213");
t.display(new Character('c'));
t.print(new Integer("123"));
}
}
//定义了泛型类,并在泛型类中定义了泛型方法,但是泛型类在实例化后,泛型的操作类型只能够限定print方法,而不能够限定show()和display()等类似的泛型方法。
class TextDemo<Q>
{
public <T> void show(T t)
{
System.out.println(t);
}
public <G> void display(G g)
{
System.out.println(g);
}
public void print(Q q)
{
System.out.println(q);
}
}
运行结果:
其他发型知识点:
泛型接口
泛型接口在项目中的使用频率都很小,一般都使用内置的接口,但我们还是要了解其基本用法。
泛型实例六:
class JavaCollection1_19
{
public static void main(String[] args)
{
MyGenericClass<String> mgc=new MyGenericClass<String>();
mgc.show("aaaa");
}
}
interface IText<T>
{
void show(T t);
}
class MyGenericClass<T> implements IText<T>
{
public void show(T t)
{
System.out.println(t);
}
}
运行结果:
泛型限定
提到泛型限定,不得不提java中?通配符,我们可以理解为占位符,我们可以理解为一个占位符,在泛型中可能出现这种情况,我们只知道操作的集合时泛型的,但是具体是什么样的泛型我们不知道,这时我们在写方法时就可以使用?来作为占位符:
泛型实例七:
import java.util.*;
class JavaCollection1_20
{
public static void main(String[] args)
{
ArrayList<String> al1=new ArrayList<String>();
al1.add("aaa");
al1.add("bbb");
al1.add("ccc");
ArrayList<Integer> al2=new ArrayList<Integer>();
al2.add(1);
al2.add(2);
al2.add(3);
show(al1);
show(al2);
}
public static void show(ArrayList<?> al)
{
for(Iterator<?> it=al.iterator();it.hasNext();)
{
System.out.println(it.next());
}
}
}
运行结果是:
从上面的例子中我们可以看出,?可以起到占位的作用,只有等到使用时才知道?具体代表什么泛型类型。
接下来我们再看下一种情况,有时候我们需要一个方法只能够操作子类对象及其父类对象,其它的如果作为参数传进来就会报错,也就是限定了泛型的类型
实例八:
import java.util.*;
class JavaCollection1_21
{
public static void main(String[] args)
{
ArrayList<Person> alp=new ArrayList<Person>();
alp.add(new Person("xt_1",12));
alp.add(new Person("xt_2",12));
alp.add(new Person("xt_3",12));
alp.add(new Person("xt_4",12));
ArrayList<Student> als=new ArrayList<Student>();
als.add(new Student("x",20));
als.add(new Student("t",21));
als.add(new Student("x",20));
als.add(new Student("m",24));
show(alp);
show(als);
}
//定义了一个方法,这个方法采用了泛型限定,只允许传入的泛型操作对象是Person类型或者是Person类的子类对象。
public static void show(ArrayList<? extends Person> al)
{
for(Iterator<? extends Person> it=al.iterator();it.hasNext();)
{
Person p=it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
}
class Person
{
private int age;
private String name;
Person(String name,int age)
{
this.name=name;
this.age=age;
}
public int getAge()
{
return age;
}
public String getName()
{
return name;
}
}
class Student extends Person
{
Student(String name,int age)
{
super(name,age);
}
}
通过我们查询javaAPI帮助文档我们可以发现TreeSet的构造函数中有
TreeSet(Comparator<? super E> comparator)
这样的方法,而这个方法翻译过来就是,我们可以创建一个比较器,同时我们可以限定这个比较器的操作类型,
实例九:
需求:定义一个比较器,这个比较器不仅能让存储在TreeSet中的学生进行排序,并且这个比较器能够让存储在TreeSet中的工人进行排序,代码如下:
import java.util.*;
class JavaCollection1_22
{
public static void main(String[] args)
{
//想要存储在TreeSet中的对象具备比较性,那么我们可以让TreeSet具备比较性,但是由于TreeSet中存储的对象不同,所以我们每次在初始TreeSet时,必须重新定义一个比较器,这样不利于代码的复用性,因此我们可以对比较器进行向上限定,
TreeSet<Person> alp=new TreeSet<Person>(new MyCom());
alp.add(new Person("xt_1",12));
alp.add(new Person("xt_2",12));
alp.add(new Person("xt_3",12));
alp.add(new Person("xt_4",12));
for(Iterator<Person> it=alp.iterator();it.hasNext();)
{
Person p=it.next();
System.out.println(p.getName()+":"+p.getAge());
}
TreeSet<Worker> als=new TreeSet<Worker>(new MyCom());
als.add(new Worker("wx",20));
als.add(new Worker("wt",21));
als.add(new Worker("ww",20));
als.add(new Worker("wm",24));
for(Iterator<Worker> it=als.iterator();it.hasNext();)
{
Worker p=it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
}
class MyCom implements Comparator<Person>
{
public int compare(Person p1,Person p2)
{
return p1.getName().compareTo(p2.getName());
}
}
class Person
{
private int age;
private String name;
Person(String name,int age)
{
this.name=name;
this.age=age;
}
public int getAge()
{
return age;
}
public String getName()
{
return name;
}
}
class Student extends Person
{
Student(String name,int age)
{
super(name,age);
}
}
class Worker extends Person
{
Worker(String name,int age)
{
super(name,age);
}
}
运行的结果如下:
通过上面的结果,我们发现只定义了一个比较器,由于限定了类型,Person类既是Worker类的基类,也是Student类的基类满足向上限定的条件,所以扩展了代码的复用性。