------- android培训、java培训、期待与您交流! ----------
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。
通常在集合框架中泛型很常见。在API中有<>的地方,就可以定义泛型。
规则和限制:
泛型类:
package fighting;
public class GenericClass {
/**
* 泛型类:使用了泛型的类
*
* 当类中要操作的引用数据类型不确定的时候,
* 早期定义Object来完成扩展
* jdk1.5以后定义泛型来完成扩展
*/
public static void main(String[] args) {
//未使用泛型类
Tool t1 = new Tool();
//传入的是Worker的实例对象
t1.setObj(new Worker());
//传入Worker实例,获取Farmer对象,这样在编译时不会异常,在运行时就会报java.lang.ClassCastException的异常
Farmer f = (Farmer)t1.getObj();
System.out.println(f);
//使用泛型类
Utils<Worker> u1 = new Utils<Worker>();
u1.setObj(new Worker());
//泛型优势:不需要使用强制转换类型
Worker w = u1.getObj();
//泛型优势:使用了泛型类,则传入Worker实例,获取Farmer对象,在编译时就会报错,这样
// Farmer f1 =u1.getObj();
// System.out.println(f1);
}
}
class Worker{
}
class Farmer{
}
//未使用泛型的工具类
class Tool{
private Object obj;
public void setObj(Object obj){
this.obj=obj;
}
public Object getObj() {
return obj;
}
}
//使用了泛型的工具类
class Utils<T>{
private T obj;
public void setObj(T obj){
this.obj = obj;
}
public T getObj(){
return obj;
}
}
泛型方法:
package fighting;
public class GenericMethod {
/**
* 泛型类的局限性:
* 泛型类定义的泛型整个类中有效,这个类中所有方法操作的这个类型就固定了.
* 如果想实现不同方法操作不同类型,而且类型还不确定,那么可以讲泛型定义在方法上.
*
* 泛型方法:相比较泛型类而言,泛型方法更灵活些
* 注意:泛型定义在方法上,泛型的定义要在返回值前面
*
* 特殊之处:
* 静态方法不可以访问类上定义的泛型,如果静态方法操作的引用数据类型不确定,
* 可以将泛型定义在方法上
*
*/
public static void main(String[] args) {
Demo<String> d = new Demo<String>();
d.show("haha");
// d.print(4);//由于泛型类的局限性,这句代码会报异常
Demo2 d2 = new Demo2();
d2.show("hahahaha");
d2.show(4);
d2.print("heihei");
d2.print(44);
}
}
//泛型类
class Demo<T>{
public void show(T t){
System.out.println("show:"+t);
}
public void print(T t){
System.out.println("print:"+t);
}
//静态方法不可以访问类上定义的泛型,如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上
public static <W> void method(W w){
System.out.println("method"+w);
}
}
//泛型方法
class Demo2{
public <T> void show(T t){
System.out.println("show:"+t);
}
public <E> void print(E e){
System.out.println("print:"+e);
}
}
泛型接口:
package fighting;
public class GenericInterface {
/**
* 泛型接口:
* 接口上定义了泛型,在接口的实现类上要指定要操作的数据类型
* 如果实现类要操作的数据类型也不确定,可以把实现类定义为泛型
*/
public static void main(String[] args) {
InterImpl i = new InterImpl();
i.show("ok");
InterImpl2<Integer> i2 = new InterImpl2<Integer>();
i2.show(22);
InterImpl2<String> i3 = new InterImpl2<String>();
i3.show("okok");
}
}
interface Inter<T>{
void show(T t);
}
//这个实现类只能操作String
class InterImpl implements Inter<String>{
public void show(String t){
System.out.println("show:"+t);
}
}
class InterImpl2<T> implements Inter<T>{
public void show(T t){
System.out.println("show:"+t);
}
}
泛型限定:
package fighting;
import java.util.ArrayList;
import java.util.Iterator;
public class GenericLimit {
/**
* 泛型限定:
* ?是通配符,也可以理解为占位符
* ? extends E:向上限定,可以接受E类型后者E的子类型
* ? super E:向下限定,可以接受E类型或者E的父类型
*/
public static void main(String[] args) {
ArrayList<String> a1 = new ArrayList<String>();
a1.add("abc1");
a1.add("abc2");
a1.add("abc3");
ArrayList<Integer> a12 = new ArrayList<Integer>();
a12.add(1);
a12.add(6);
a12.add(4);
printColl(a1);
printColl(a12);
//泛型限定
ArrayList<Person1> al3 = new ArrayList<Person1>();
al3.add(new Person1("aaa"));
al3.add(new Person1("bbb"));
al3.add(new Person1("ccc"));
ArrayList<Student1> al4 = new ArrayList<Student1>();
al4.add(new Student1("aaa1"));
al4.add(new Student1("bbb1"));
al4.add(new Student1("ccc1"));
//编译异常:相当于ArrayList<Student1> al4= new ArrayList<Person1>(),前后泛型类型不一致
//printColl2方法中使用泛型限定即可解决
printColl2(al4);
}
//?是占位符,这里也可以用T(代表一种数据类型TYPE),两者区别不大
public static void printColl(ArrayList<?> s1){
Iterator<?> it = s1.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
public static void printColl2(ArrayList<? extends Person1> s1){
// Iterator<Person1> it = s1.iterator();
Iterator<? extends Person1> it = s1.iterator();
while(it.hasNext()){
System.out.println(( it.next()).getName());
}
}
}
class Person1{
private String s;
public Person1(String s){
this.s=s;
}
public String getName(){
return s;
}
}
class Student1 extends Person1{
public Student1(String s){
super(s);
}
}
两个特殊的小例子:
例1:
/**
* Map的key和value的组合体用一个特定的类表示,叫Map.Entry
* 现在要用这个Entry来迭代出每个元素
*/
HashMap<String,Integer> maps =new HashMap<String,Integer> ();
maps.put("zxx", 28);
maps.put("lhm", 35);
maps.put("fix", 33);
//Map是不能直接进行迭代的,因为Map没有实现iterable接口
//要把Map编程Set,Set里面装着每个Entry,然后利用Set进行迭代
//注意=左边的参数化类型,entrySet()方法的返回值是Set<Map.Entry<K,V>>泛型类型
Set<Map.Entry<String,Integer>> entrySet = maps.entrySet();
for(Map.Entry<String, Integer> entry:entrySet){
System.out.println(entry.getKey() + ":" + entry.getValue());
}
输出结果:
fix:33
zxx:28
lhm:35
例2:
//交换的方法
//利用泛型实现交换两个元素的位置
private static <T> void swap(T[] a,int i,int j){
T temp = a[i];
a[i] = a[j];
a[j]=temp;
}
//调用交换的方法
public static void main(String[] args) throws SecurityException, Exception {
String[] swapStr = new String[]{"abc","xyz","itcast"};
swap(swapStr,1,2);
System.out.println(Arrays.asList(swapStr));
//注意下面这句会编译报错:因为泛型T的实际类型只能是对象类型,不能是基本类型,int是基本类型
// swap(new int[]{1,2,5,4,5},3,4);
//想要交换数字可以像下面这样定义成对象类型的
Integer[] swapInteger = new Integer[]{1,2,5,4,3};
swap(swapInteger,3,4);
System.out.println(Arrays.toString(swapInteger));
}
输出结果:
[abc, itcast, xyz]
[1, 2, 5, 3, 4]