您的位置:首页 > 职场人生

黑马程序员学习笔记之五(java中的泛型)

2012-03-07 14:38 681 查看
---------------------- android培训java培训、期待与您交流! ----------------------

泛型的概念

泛型(Generic type 或者 generics)是对java语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。

可以在集合框架(Collection framework)中看到泛型的动机。例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象。

因为 Map.get() 被定义为返回 Object,所以一般必须将 Map.get() 的结果强制类型转换为期望的类型,如下面的代码所示:

Map m = new HashMap();

m.put("key", "blarg");

String s = (String) m.get("key");

要让程序通过编译,必须将 get() 的结果强制类型转换为 String,并且希望结果真的是一个 String。但是有可能某人已经在该映射中保存了不是 String 的东西,这样的话,上面的代码将会抛出 ClassCastException。

理想情况下,您可能会得出这样一个观点,即 m 是一个 Map,它将 String 键映射到 String 值。这可以让您消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。

泛型的好处

Java语言中引入泛型是一个较大的功能增强。不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了。这带来了很多好处:

类型安全。泛型的主要目标是提高Java程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。

示例:

import java.util.*;
class GenericDemo2
{
public static void main(String[] args)
{
TreeSet<String> ts = new TreeSet<String>(new LenComparator());

ts.add("abcd");
ts.add("cc");
ts.add("cba");
ts.add("aaa");
ts.add("z");
ts.add("hahaha");

Iterator<String> it = ts.iterator();

while(it.hasNext())
{
String s = it.next();
System.out.println(s);
}
}
}

class LenComparator implements Comparator<String>
{
public int compare(String o1,String o2)
{
int num = new Integer(o2.length()).compareTo(new Integer(o1.length()));

if(num==0)
return o2.compareTo(o1);
return num;
}
}


泛型类

泛型类最常见的用例是容器类(比如集合框架)。编写一个类,用来接收或者返回一个Worker或者Student类型的对象,我们采用两种方式来实现,一种不使用泛型,一种使用泛型,进行对比。

/*
class Tool
{
private Worker w;
public void setWorker(Worker w)
{
this.w = w;
}
public Worker getWorker()
{
return w;
}
}
*/

class Worker
{

}
class Student
{
}
//泛型前做法。
class Tool
{
private Object obj;
public void setObject(Object obj)
{
this.obj = obj;
}
public Object getObject()
{
return obj;
}
}

//泛型类。
/*
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候,
早期定义Object来完成扩展。
现在定义泛型来完成扩展。
*/
class Utils<T>
{
private T t;
public void setObject(T t)
{
this.t = t;
}
public T getObject()
{
return t;
}
}

class  GenericDemo3
{
public static void main(String[] args)
{

Utils<Worker> u = new Utils<Worker>();

u.setObject(new Student());
Worker w = u.getObject();;
/*
Tool t = new Tool();
t.setObject(new Student());
Worker w = (Worker)t.getObject();
*/
}
}


泛型方法

通过在类的定义中添加一个形式类型参数列表,可以将类泛型化。方法也可以被泛型化,不管它们定义在其中的类是不是泛型化的。

泛型类在多个方法签名间实施类型约束。在 List<V> 中,类型参数 V 出现在 get()、add()、contains() 等方法的签名中。当创建一个 Map<K, V> 类型的变量时,您就在方法之间宣称一个类型约束。您传递给 add() 的值将与 get() 返回的值的类型相同。

类似地,之所以声明泛型方法,一般是因为您想要在该方法的多个参数之间宣称一个类型约束。如下:

//泛型类定义的泛型,在整个类中有效。如果被方法使用,
//那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
//
//为了让不同方法可以操作不同类型,而且类型还不确定。
//那么可以将泛型定义在方法上。

/*
特殊之处:
静态方法不可以访问类上定义的泛型。
如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。

*/

class Demo<T>
{
public  void show(T t)
{
System.out.println("show:"+t);
}
public <Q> void print(Q q)
{
System.out.println("print:"+q);
}
public  static <W> void method(W t)
{
System.out.println("method:"+t);
}
}
class GenericDemo4
{
public static void main(String[] args)
{
Demo <String> d = new Demo<String>();
d.show("haha");
//d.show(4); // show方法接受的参数类型已经声明为String类型了,不能接受Integer
d.print(5);
d.print("hehe");

Demo.method("hahahahha");

/*
Demo d = new Demo();
d.show("haha");
d.show(new Integer(4));
d.print("heihei");
*/
/*
Demo<Integer> d = new Demo<Integer>();

d.show(new Integer(4));
d.print("hah");

Demo<String> d1 = new Demo<String>();
d1.print("haha");
d1.show(5);
*/
}
}

特殊之处:

静态方法不可以访问类上定义的泛型。

如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。

泛型接口

泛型定义在接口上面,通常在数据库的CRUD操作中比较常见,代码如下:

// 泛型定义在接口上
interface Dao<T>
{
void save(T t);
T find(id);
void delet(T t);
void update(T t);
}

class JDBCDao<T> implements Dao<T> // 使用JDBC实现CRUD操作
{
public void save(T t)
{
// ...
}
public T find(T t)
{
// ...
}
public void find(T t)
{
// ...
}
public void update(T t)
{
// ...
}
}

class HibernateDao implements Dao<T> // 使用Hibernate实现CRUD操作
{
public void save(T t)
{
// ...
}
public T find(T t)
{
// ...
}
public void find(T t)
{
// ...
}
public void update(T t)
{
// ...
}
}

class GenericDemo5
{
public static void main(String[] args)
{
Student s = new Student();
// 使用JDBC进行CRUD操作
Dao dao<Student> = new JDBCDao<Student>();
dao.add(s)
// 使用JDBC进行CRUD操作
Dao dao<Student> = new HibernateDao<Student>();
dao.delete(s);
}
}


泛型通配符与泛型限定

在前面的泛型的例子中,类型参数 T是无约束的或无限制的 类型。有时在还没有完全指定类型参数时,需要对类型参数指定附加的约束。

import java.util.*;
/*
? 通配符。也可以理解为占位符。
泛型的限定;
? extends E: 可以接收E类型或者E的子类型。上限。
? super E: 可以接收E类型或者E的父类型。下限

*/

class  GenericDemo6
{
public static void main(String[] args)
{
/*
ArrayList<String> al = new ArrayList<String>();

al.add("abc1");
al.add("abc2");
al.add("abc3");

ArrayList<Integer> al1 = new ArrayList<Integer>();
al1.add(4);
al1.add(7);
al1.add(1);

printColl(al);  // 此处调用的是 printColl(ArrayList<?> al)方法,ArrayList中可以存放任何类型的对象
printColl(al1);
*/

ArrayList<Person> al = new ArrayList<Person>();
al.add(new Person("abc1"));
al.add(new Person("abc2"));
al.add(new Person("abc3"));
//printColl(al);

ArrayList<Student> al1 = new ArrayList<Student>();
al1.add(new Student("abc--1"));
al1.add(new Student("abc--2"));
al1.add(new Student("abc--3"));
printColl(al1);  //ArrayList<? extends Person> al = new ArrayList<Student>();error

}
public static void printColl(Collection<? extends Person> al) // Collection 中可以是Person类及其子类对象
{
Iterator<? extends Person> it = al.iterator();

while(it.hasNext())
{
System.out.println(it.next().getName());
}
}
/*
// ? 通配符,表示泛型中的参数可以是任何类型
public static void printColl(ArrayList<?> al)//ArrayList al = new ArrayList<Integer>();error
{
Iterator<?> it = al.iterator();

while(it.hasNext())
{
System.out.println(it.next().toString());
}
}
*/

}

//
class Person
{
private String name;
Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}

class Student extends Person
{
Student(String name)
{
super(name);
}

}

class Comp implements Comparator<Person> //<? super E>
{
public int compare(Person s1,Person s2)
{

//Person s1 = new Student("abc1");
return s1.getName().compareTo(s2.getName());
}
}

class  GenericDemo7
{
public static void main(String[] args)
{
TreeSet<Student> ts = new TreeSet<Student>(new Comp());
ts.add(new Student("abc1"));
ts.add(new Student("abc2"));
ts.add(new Student("abc3"));
}
}


上例中的Comp比较器既可以接受Person对象,也可以接受Student对象。

---------------------- android培训java培训、期待与您交流! ----------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: