泛型:jdk1.5之后出现的新特性,用于解决安全问题,是一个安全机制
好处:1 将运行时期的问题转移到编译时期,方便程序员解决问题
2 避免的强制转换的麻烦
3 提高了编译时期的安全性。
<>:什么时用?当操作的引用数据类型不确定的时候,就用<>将要操作的引用数据类型传入
<>就是一个用于接收具体引用数据类型的参数范围。
在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型。
class Tool<e1,e2,e3,e4>//<>中可以接收多个类型参数;
Tool<String,Demo,Person,Man> t = new Tool<String,Demo,Person,Man>();
注释:泛型技术是给编译器使用的技术,用于编译时期。确保了类型的安全。
运行时,会将泛型去掉,生成的class文件中时不带泛型的,这个称之为泛型的擦除。
为什么擦除呢?为了去兼容运行时的类加载器(1.4,1.5同一个类加载器)。
泛型的补偿:在运行时通过获取元素的类型进行转换动作,不用使用者再强制转换了。
-------------------------------
泛型在集合中的应用
--------------------------------
泛型在设计时好处
当函数的具体实现不知道是使用抽象函数,
当操作的对象类型不确定时使用泛型。
1 泛型类
当类中操作的引用数据类型不确定的时候就采用泛型。
calss Tool<T>
{
private T t;
public void get()
{
return t;
}
public void set(T t)
{
this.t = t;
}
}
Tool<Person> tool = new Too<Person>();//指定tool操作的对象为Person
// 提高安全性
tool.set(new Person());
Worker w = tool.get();//会报异常 (在使用泛型前异常发生在运行时期
现在异常会出现在编译时期)
2 泛型方法
public<T>viod show(T str)
{
System .out.println(str);
}
静态方法:不能访问类上定义的泛型。
只能讲泛型定义在方法上
public static <Y> void method(Y obj)
{
System.out.println(obj);
}
3 泛型接口
interface Inter <T>
{
public void show(T t);//不明确show参数的具体类型--> 泛型?为啥不定义在方法上?而是定义在类上?
} 答:即可定义在方法上,也可定义在类上
只是作用域不同,定义在类上对整个类可见
定义在方法上:对该方法可见。
//接口实现类
class InterImp implements Inter<String>//当实现类知道该接口的方法操作的数据类型时
{
pulic void show(String t)
{
System.out.println(t)
}
}
class InterImp<Q> implements Inter<Q>//当实现类不知道该接口的方法操作的数据类型时:可继续在实现类上定义泛型
{
pulic void show(Q q)
{
System.out.println(q)
}
}
InterImp<String> inter = new InterImp<String>();//在具体使用时才传参给泛型
inter.show("dasda");
interface Inter//当泛型定义在接口方法上时:
{
public<T> void show(T t);
}
class InterImp implements Inter
{
@Override
public <T> void show(T t) {
// TODO Auto-generated method stub
System.out.println(t);
}
}
--------------------------
泛型的限定
public static void printCollection(/*Collection<String>*/Collection<?> c)//当不确定集合中所装元素类型,
//但有不调用元素类型具体方法时:可使用泛型通配符 ?
{
//Iterator<String> it = c.iterator();
Iterator<?> it = c.iterator();
while(it.hasNext())
{
//String str = it.next();
? str = it.next();
}
}
public static <T> void printCollection(Collection<T> c)//当方法上定义泛型T:是希望通过T代表的
//的具体某一类型,对元素进行一些操作。
{
Iterator<T> it = c.iterator();
while(it.hasNext())
{
T str = it.next();
}
}
限制上限:
? extends E:接收E或E的子类型
public static void printCollection(Collection<? extends Person> c)//需求:集合中装入的是一个体系的对象才能打印。
{
Iterator<? extends Person> it = c.iterator();
while(it.hasNext())
{
Person p = it.next();
System.out.println(p.getName());//因为存储的都是person的子类所有都具备person的方法
}
}
限制下限:
? super E:接收E或 E的父类型。下限
public static void printCollection(Collection<? super Student> c)//
{
Iterator<? super Student> it = c.iterator();
while(it.hasNext())
{
//Person p = it.next();
//System.out.println(p.getName());
System.out.println(it.next());
}
}
--------------------------------
上限的体现
通常对结合中的元素进行取出操作时:可以使用下限
Collection中的
addAll(Collection<? extends E> c);:E时创建Collection时传入的
// Collection<E> c = new Collection<E>;
Collection<Person> c = new Collection<Person>;: 此时E == Person
往集合中存元素时:通常定义上限。
因为这样取出时:都是按照上限类型来运算了,这样不会出现类型安全隐患。
下限的体现
TreeSet (Comparator<? super E> comparator);
class TreeSet<E>
{
TreeSet (Comparator<? super E> comparator);
}
当TreeSet中装的是学生时?要定义学生的比较器。
当TreeSet中装的是工人时?要定义工人的比较器。 这两个比较器的实现方式是相同的都是按照Person比较器内容实现的
class TreeSet<Student>
{
TreeSet (Comparator<Student> comparator);
}
class TreeSet<Worker>
{
TreeSet (Comparator<Worker> comparator);
}
class TreeSet<Student>
{
TreeSet (Comparator<? super Student> comparator);
}
class TreeSet<Worker>
{
TreeSet (Comparator<? super Worker> comparator);
}
要进行比较:得把集合中的元素取出来,所以可以用父类来接收子类的对象
定义比较器时:
class compByname implements Comparator<Person>
{
}