1.泛型
泛型是JDK1.5出现的安全机制。
好处:
1.将运行时期的问题ClassCastException转到了编译时期。
2.避免了强制类型转换。
2.泛型什么时候用呢?
当操作引用的数据类型不确定的时候,就用泛型<>,
将要操作的引用数据类型传入即可。
其实<>就是用于接收具体引用数据类型的参数范围。
在程序找那个,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型。
3.泛型技术是给编译器使用的技术,用于编译时期,确保了类型的安全。
4.泛型的擦除&补偿
程序运行时会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除。是为了兼容运行的类加载器。
在运行时,通过获取元素的类型进行转换动作,不用使用者在进行强制类型转换了,这个称为泛型的补偿。
5.泛型的演示
public class GenericDemo {
public static void main(String[] args){
TreeSet<Person> ts = new TreeSet(new ComparatorByAge());
//在创建集合对象时就明确了要操作的类型,只能传入引用型类。
//如果没有传入指定的类型编译不通过。
ts.add(new Person("Wang",20));
ts.add(new Person("Sun",22));
ts.add(new Person("Li",23));
for(Iterator<Person> it = al.iterator(); it.hasNext();){
//在使用迭代器时也明确了要操作的类型,就避免了下面的强制类型转换。
Person p = it.next();
//Person p = (Person)it.next;
System.out.println(p.getName()+" "+p.getAge());
}
}
}
public class ComparatorByAge implements Comparator<Person> {
//在实现接口的时候明确了操作的指定类型。
@Override
public int compare(Person o1, Person o2) {
int temp = o1.getAge()-o2.getAge();
return temp==0?o1.getName().compareTo(o2.getName()):temp;
}
}
6.泛型可以定义在类上,接口上,还有方法上。
/*泛型定义在方法上。
<>位于修饰符之后,返回符之前。
这样可以根据你调用函数时,具体传入的引用数据类型进行操作。
*/
public<W> void show(W str){
System.out.println("show:"+str);
}
//当方法静态时,不能访问类上定义的泛型,如果静态方法使用泛型,只能将泛型定义在方法上。
public static <Y> void method(Y obj){
System.out.println("method:"+obj);
}
//泛型定义在接口上
interface Inter <Y>{//在接口上定义了一个不明确要操作的引用类型
void show(Y y);
}
class imple2<W> implements Inter<W>{
//在实现接口时没有明确要操作的引用数据类型,而是在创建对象时明确。
@Override
public void show(W w) {
System.out.println("show2:"+w);
}
}
class imple implements Inter<String>{
//在实现接口时,明确了要操作的引用数据类型。
@Override
public void show(String s) {
System.out.println("show:"+s);
}
}
7.自定义泛型类
在JDK1.5之后,使用泛型来接收类中要操作的引用数据类型。
自定义泛型类,当类中操作的引用数据类型不确定时,就用泛型来表示。
public class Tool<QQ>{
private QQ q;
public QQ getObject() {
return q;
}
public void setObject(QQ q) {
this.q = q;
}
//将泛型定义方法上,当方法静态时,不能访问类上定义的泛型,如果静态方法使用泛型,只能将泛型定义在方法上。
public<W> void show(W str){
System.out.println("show:"+str);
}
public static <Y> void method(Y obj){
System.out.println("method:"+obj);
}
public void print(QQ str){
System.out.println("print:"+str);
}
}
public class Student extends Person {
public Student() {
}
@Override
public String toString() {
return "Student:"+getName()+":"+getAge();
}
public Student(String name, int age) {
super(name, age);
}
public void show(){
System.out.println("Student:"+"show");
}
}
public class GenericDefineDemo3 {
public static void main(String[] args){
Tool<Student> tool = new Tool();
//创建Tool对象时明确了要操作的类型是Student
tool.setObject(new Student());
Student stu = tool.getObject();
}
}
8.泛型的通配符:?未知类型。
可以对类型进行限定。
?extends E :接收E类型或者子类型对象,上限!
?super E: 接收E类型或者E的父类型,下限!
一般存储元素的时候用的都是上限,因为这样取出都是按照上限类型来运算的,不会出现类型安全隐患。
一般对集合中的元素进行取出操作时,用的是下限,比如比较器。
public class GenericAdvanceDemo2 {
public static void main(String[] args){
ArrayList<Worker> al = new ArrayList<>();
al.add(new Worker("Zhang",30));
al.add(new Worker("Li",20));
ArrayList<Student> al2 = new ArrayList<>();
al2.add(new Student("Wang",18));
al2.add(new Student("Zhao",18));
ArrayList<Person> al3 = new ArrayList<>();
al3.add(new Person("Huang",26));
al3.add(new Person("Dong",26));
IteratorCollection2(al);
IteratorCollection2(al2);
IteratorCollection3(al2);
IteratorCollection3(al3);
}
//迭代并打印集合中的元素。
public static void IteratorCollection2(Collection<? extends Person> al) {
//用Collection是因为可以接受任意的集合,提高了代码的复用性,
//<? extends Person>可以接受Person类型和Person的子类。
for (Iterator<? extends Person> it = al.iterator(); it.hasNext();){
Person p = it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
public static void IteratorCollection3(Collection<? super Student> al) {
//<? super Student>可以接受Student类型以及Student的父类
for (Iterator<? super Student> it = al.iterator(); it.hasNext();){
System.out.println(it.next());
}
}
}