泛型用于解决安全问题
一、泛型的使用:
LinkedList <String> al = new LinkedList<String>(); //LinkedList 相当容器 String 说明元素的类型
类似数组的声明:
int [ ] ary = new int[ 4]; // [ ] 代表容器 ,int代表元素的类型
如果没有使用泛型
LinkedList al = new LinkedList();
al.offerLast("aa");
al.offerLast("bb");
将会报警告:Type Safety : The method offerLast(Object) belongs to the raw type LinkedList . Reference to generic type LinkedList<E >should be parametrized.(意思是为了类型的安全性,推荐使用泛型 LinkedList<E >,应该对LinkedList参数化。而不推荐使用未加工的LinkedList类型 )。
二、泛型使用的好处
1.可以将运行时出现的ClassCastException 提前的编译期间。
如果没使用泛型,从集合里取出一个元素需要对它进行强制类型转换。而如果强制的类型不是元素的实际类型,在编译时可以通过,在运行时才能发现错误。
2.集合没使用泛型前,用Object类型接收具体类型对象,会失去具体类型的特征。
3.省去强制类型转换的操作。
由于使用泛型时集合对同一类对象进行操作,保证了存入的都是同一类对象。而且知道对象的类型。所以在取出元素时不必进行强转。
三、自定义泛型
为什么要自定义泛型?
当1.5 之前没有泛型时,要对不知道操作的(对象的)类型是什么时,使用Object接受所有对象。
class Tools {
private Object obj;
public void setObject(Object obj) {
this.obj = obj;
}
public Object getObject() {
return obj;
}
class Test
{
public static void main(String[ ] args) {
Tools t = new Tools();
t.setObj(new Worker());//传入Worker对象,变成Object对象
Worker er = (Worker) t.getObj();//取出的是Object对象,需要强转成实际对象才能使用。
}
}// 1.5之前的集合操作就是采取这种思想。
class Worker {
}
理由:当类中要操作的引用数据类型不确定时,早期定义Object 来完成扩展,1.5通过泛型来完成扩展。
定义泛型:
class Tools <QQ > {// 泛型类定义的泛型在整个类中有效
private QQ q;
public void setObject(QQ q) {//在整个类中有效
this.q = q;
}
public QQ getObject ( ) {//在整个类中有效
return q;
}
泛型使用:
class Test {
public static void main(String [] args) {
Tools<Worker> tool = new Tools<Worker>();
tool.setObject(new Worker());
Worker er = tool.getObject();//不要进行强转。
}
}
问题:泛型类定义的泛型,在整个类中有效。使用方法时,泛型类对象在明确要操作的具体类型后,所有要操作的类型已经固定了。
为了让不同方法可以操作不同方法可以操作不同类型,而且类型还不确定,可以将泛型定义在方法上。
解决: 泛型方法
四、自定义泛型方法
class Demo {
public <T> display(T t) {//<T>写在返回类型之前。
System.out.println("display ::"+ t);
}
class Test {
pubic static void main(String[] args) {
Demo d = new Demo();
d.display("1234");
d.display(12);
}
}
1.可以在泛型类中定义泛型方法吗?
可以。而且这样做不是没有意义的。他的意义是:使得该方法能操作不对的对象。而不是泛型类确定的统一类型。
2.静态方法不可以使用类上的泛型。
如在泛型类中有方法
public static void method(T t){
System.out.println("method()");
}
编译会报 无法从静态上下文(ps:方法)引用非静态 类 T;
原因我想是:静态方法是在泛型类字节码加载时就被加载的,但是T 是在泛型类创建对象时Demo<String> demo = new Demo<String>;才确定的 。
解决办法:定义泛型方法在静态方法上。
public static <T> void method(T t){
System.out.println("method()");
}
在java API中可以看到很多容器接口都定义了泛型。
Interface Itr<T> {
void show(T t);
}
可以有两种方式使用泛型接口
1.实现类操作明确类型,例String
class ItrImpl implements Itr<String> {
void show(String t){
System.out.println(t);
}
}
2.实现类操作泛型
class ItrImpl2 implements Itr<T> {
void show(T t){
System.out.println(t);
}
}
六 、泛型限定
<?> :占位符 、通配符 表示被操作的具体类型不确定
<?>只能定义在方法上,不能定义在类上。
public static void main (String [] args) {
ArrayList<String> al = new ArrayList<String>();
al.add("aa");
al.add("bb");
al.add("cc");
ArrayList<Integer> al2 = new ArrayList<Integer>();
al2.add(11);
al2.add(12);
al2.add(13);
//要求:现在要遍历出al 、al2中的元素 ,该怎么做?//al al2 使用各自的遍历器。
showCon(al);
showCon(al2);
}
也可以:
方法一: 定义一个泛型方法。
<span style="font-size:14px;">static <T> void showCon (ArrayList<T> al){
for(Iterator<T> it = al.iterator();it.hasNext();){
T t = it.next();
System.out.println(t);
}
}</span>
方法二:用占位符<?>表示具体类型不确定。<span style="font-size:14px;">static void showCon(ArrayList<?> al) {
for (Iterator<?> it = al.iterator(); it.hasNext();) {
// T t = it.next(); 占位符与泛型方法的不同,泛型方法可以能接受具体类型对象并操作,而占位符不能。
System.out.println(it.next());//it.next.length(),error.不能使用类型的特有方法。
}
}</span>
七、<?>的高级应用
问题:不允许这样使用泛型
ArrayList<Person> al = new ArrayList<Student>();//Student是Person的子类
和 ArrayList<Student> al = new ArrayList<Person>();
解决 <? extends E>
<? super E>
TreeSet<E> API
addAll(Collection<? extends E> c)
操作某类及某类的子类 上限
TreeSet(Comparator<? super E> comparator)
操作某类及某类的父类 下限
使用举例
<span style="font-size:14px;"><? extends E>
/*<?>通配符的高级应用 、<? extends E>上限定。
接收E及E的子类
*/
package java5new;
import java.util.*;
public class GenericDemo1 {
public static void main(String[] args){
ArrayList<Person> al = new ArrayList<Person>();
al.add(new Person("001"));
al.add(new Person("002"));
al.add(new Person("003"));
ArrayList<Student> al2 = new ArrayList<Student>();
al2.add(new Student("01"));
al2.add(new Student("02"));
al2.add(new Student("03"));
printAl(al);
printAl(al2);
}
public static void printAl(ArrayList<? extends Person> al){//<span style="color:#FF0000;">接收Person及Person的子类</span>
for(Iterator<? extends Person> it = al.iterator();it.hasNext();){//注意Iterator与AL类型一致
System.out.println(it.next().getName());//可以使用特有方法
}
}
}
class Person {
String name;
Person(String name){
this.name = name;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}
class Student extends Person{
Student(String name){//继承中,子类要写明构造方法
super(name);
}
}</span>
<? super E >
<span style="font-size:14px;">/*
* TreeSet(Comparator<? super E> comparator)
* 可以传递E或E的父类
*/
import java.util.*;
public class XiaXianDemo {
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<Student>(new Comp()); // E:Student
ts.add(new Student("s001"));
ts.add(new Student("s002"));
ts.add(new Student("s003"));
TreeSet<Worker> ts2 = new TreeSet<Worker>(new Comp()); // E:Worker
ts2.add(new Worker("w001"));
ts2.add(new Worker("w002"));
ts2.add(new Worker("w003"));
Iterator<Student> it = ts.iterator();//注意迭代器的定义
while(it.hasNext()){
System.out.println(it.next().getName());
}
Iterator<Worker> it2 = ts2.iterator();//注意迭代器的定义
while(it2.hasNext()){
System.out.println(it2.next().getName());
}
}
}
class Worker extends Person {
Worker(String s) {
super(s);
}
}
class Comp implements Comparator<Person> { //只定义接收父类的比较器,不分别定义Worker 、Student类的比较器,<span style="color:#FF0000;"><? super E> </span>
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
}</span>
以下是自己的一点思考总结:
1.泛型定义时不能操作 T 泛型的具体方法。
2.泛型的使用时可以操作具体类型的具体方法
3.<?>不用于定义泛型类class Demo<?>{},error.