泛型、泛型类、泛型方法、泛型方法、泛型通配符、泛型的限定
泛型:
集合中存储了不同类型的对象,取出时,容易在运行时期发生ClassCastException类型转换异常,为了避免这个问题的发生,如果在存储的时候就明确了集合要操作的数据类型,取出就没有任何问题了。这样在定义集合时,就需要立刻明确元素的类型,可以通过<>来明确元素的类型。
泛型的好处:
1.将运行时期出现的ClassCastException问题,转移到了编译时期;
2.避免了强制转换的麻烦。
泛型其实是JDJ1.5版本以后出现的一个安全机制,是给编译器使用的。泛型的表现形式就是<>,泛型的使用其实就是 给<>传递实际参数,而这个参数就是一个具体引用数据类型。
如下代码所示,直接避免了强制转换:
class GenericDemo2 { public static void main(String[] args) { TreeSet<Person> ts = new TreeSet<Person>(new CompareByName()); //HashSet<Person> ts = new HashSet<Person>(); ts.add(new Person("abc1",21)); ts.add(new Person("abc0",20)); ts.add(new Person("abc0",20)); ts.add(new Person("abc4",24)); ts.add(new Person("abc3",28)); Iterator<Person> it= ts.iterator(); while(it.hasNext()) { Person p = it.next(); System.out.println(p.getName()+"....."+p.getAge()); } } } class CompareByName implements Comparator<Person> { public int compare(Person p1,Person p2) { int temp = p1.getName().compareTo(p2.getName()); return temp==0?p1.getAge()-p2.getAge():temp; } } class Person implements Comparable<Person> { private String name; private int age; Person(String name,int age) { this.name = name; this.age = age; } public int compareTo(Person p) { int temp = this.age-p.age; return temp==0?this.name.compareTo(p.name):temp; } public int hashCode() { final int NUM = 34; return name.hashCode()+age*NUM; } public boolean equals(Object obj) { if(this==obj) return true; if(!(obj instanceof Person)) return false; Person p = (Person)obj; return this.name.equals(p.name) && this.age==p.age; } public String getName() { return name; } public int getAge() { return age; } public String toString() { return name+"::"+age; } }
泛型类
当类要操作的引用数据类型不确定的时候,可以使用泛型来定义,也就是定义一个类型参数。具体要操作什么类型的对象,由使用该类的使用者来明确,将具体的类型作为实际参数传递给<>,将泛型定义在雷桑,该泛型在该类范围内有效。
package Test.Test; class Student { } class Worker { } class Tool<Q> { private Q obj; public void setObj(Q obj) { this.obj = obj; } public Q getObj() { return obj; } } class GenericDemo3 { public static void main(String[] args) { Tool<Student> t = new Tool<Student>(); t.setObj(new Student()); Student s = t.getObj(); } }
泛型方法
应用场景:当方法中操作的应用数据类型不确定,而且和对应的对象执行的类型也不一定一致,这时就将泛型定义在方法上。
当泛型定义在类上,该泛型作用于整个类,当建立该对象时就明确了具体类型,那么凡是使用了类上定义的泛型方法,操作的类也就固定了。
希望类中的方法,可以操作任意类型而不受类中泛型限制,可以将泛型定义在方法上----泛型方法。
当类中定义static方法时,静态方法是不可以直接访问类上的泛型的,因为类上的泛型只有通过建立对象才可以明确具体类型。
所以静态发那个发如果操作的引用数据类型不确定,只能将泛型定义在方法上,在静态方法上定义泛型,必须定义在static关键字之后。
package Test.Test; class Student { } class Worker { } class Tool<Q> { private Q obj; public void setObj(Q obj) { this.obj = obj; } public Q getObj() { return obj; } public static<w> void show(w obj){ System.out.println(obj.toString()); } public <w> void print(w obj){ System.out.println(obj.toString()); } } class GenericDemo3 { public static void main(String[] args) { Tool<Student> t = new Tool<Student>(); t.setObj(new Student()); Student s = t.getObj(); t.print(new Worker()); Tool.show(new Worker()); } }
输出为:

泛型接口
package Test.Test; public class GenericInterfce { public static void main(String[] args){ GenericInterfaceClass<String> gIC=new GenericInterfaceClass<String>(); gIC.show("haha"); GenericInterfaceClass2 gIC2=new GenericInterfaceClass2(); gIC2.show("hehe"); } } interface GenericInterface<T>{ void show(T obj); } class GenericInterfaceClass<T> implements GenericInterface<T>{ @Override public void show(T obj) { System.out.println(obj.toString()); } } class GenericInterfaceClass2 implements GenericInterface<String>{ @Override public void show(String obj) { System.out.println(obj); } }
泛型接口的实现有两种方式:
第一种:在类实现该接口时仍然使用泛型,只有在建立类对象时才明确操作的类型,如GenericInterfaceClass 所示;
第二种:在类实现该接口时即确定类型,如 GenericInterfaceClass2 所示
泛型通配符 ?
以API文档中Collection类中的containsAll(Collection<?> c)为例:


可以看到存储有String类型的集合对象mc不能判断其是否包含存储有Integer类型的集合对象,这是因为mc存储的类型是String,其containsAll方法中对应的类型也为String,那么如何实现存储有String类型的集合对象也能够判断其是否包含存储有Integer类型的集合对象呢?
package Test.Test; import java.util.Collection; public class GenericDemo4 { public static void main(String[] args){ MyCollection<String> mc=new MyCollection<String>(); mc.containsAll(new MyCollection<Integer>()); } } class MyCollection<T>{ boolean containsAll(MyCollection <?> coll){ return false; } }
泛型的限定
package Test.Test; import java.util.*; 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 Teacher extends Person{ Teacher(String name) { super(name); } } class GenericDemo7 { public static void main(String[] args) { // ArrayList<Person> al = new ArrayList<Student>();//不允许这样定义,因为集合声明的是可以放Person及其子类对象, // 但是集合实体声明只能存放Student类型,这会导致向集合中添加Person类的其他子类对象时出错,所以不允许这样定义,会在编译时出错。 ArrayList<Person> al = new ArrayList<>(); //定义集合要保证左右两边的类型一致。 //两边只有一边定义泛型,也是可以支持,至少新老版本兼容。但是一样会出现,安全提示信息。 al.add(new Person("p1")); al.add(new Person("p2")); al.add(new Person("p3")); al.add(new Student("s1")); al.add(new Teacher("t1")); show(al); ArrayList<Student> al1 = new ArrayList<Student>(); al1.add(new Student("s1")); al1.add(new Student("s2")); al1.add(new Student("s3")); show(al1);//al1集合中存储的是Student类型,Student是Person的子类,所以可以正常调用show方法 } public static void show(Collection< ? extends Person> coll) { Iterator<? extends Person> it = coll.iterator(); while(it.hasNext()) { System.out.println(it.next().getName()); } } }
在泛型方法中,不可以使用具体类型的方法,最多只能使用Object类中的方法,
定义T只能固定一种类型;
定义?可以是任意类型;
如果泛型方法中指向操作Person或者Person的子类类型,使用泛型的限定 ? extends E:接收E类型或者E的子类型;
? super E:接收E类型或者E的父类型;
? super E 示例:

package Test.Test; import java.util.*; class Person{ private String name; Person(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return "name:" + name; } } class Student extends Person{ Student(String name) { super(name); } } class Teacher extends Person{ Teacher(String name) { super(name); } } class GenericDemo7{ public static void main(String[] args) { TreeSet<Student> treeSet=new TreeSet<Student>(new MyComparator()); treeSet.add(new Student("s1")); treeSet.add(new Student("s4")); treeSet.add(new Student("s2")); System.out.println(treeSet); } } class MyComparator implements Comparator<Person>{ public int compare(Person p1,Person p2){ return p1.getName().compareTo(p2.getName()); } }
MyComparator类对象可以比较Person类及其子类对象,因为treeSet集合中存储的是Student类对象,Student类是Person类的子类,所以可以这样构造并进行比较。
这样创建比较器的好处是创建Person类的比较器之后,其各个子类都都可以用这个比较器进行比较。
此外,例如方法containsAll()

可以向存储有父类元素的集合中添加存储有子类对象的集合。

浙公网安备 33010602011771号