所谓泛型就是允许在定义类,接口时通过一个标志表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个参数类型将在使用时(如继承或实现这个接口,用这个类型声明变量,创建对象时)确定传入实际的类型参数,也称为类型实参。
例:
@Test
public void test() {
//在集合中使用泛型之前
ArrayList arrayList = new ArrayList();
//在集合中存放学生成绩
arrayList.add(65);
arrayList.add(80);
arrayList.add(99);
arrayList.add(59);
//类型不安全
//arrayList.add("surprise");
// for (Object o : arrayList) {
// //强转时可能出现ClassCastException
// int score = (Integer) o;
// System.out.println(score);
// }
//在集合中使用泛型 ArrayList
ArrayList arrayList1 = new ArrayList();
arrayList1.add(65);
arrayList1.add(80);
arrayList1.add(99);
arrayList1.add(59);
//会报错无法添加 保证数据安全
//arrayList1.add("surprise");
//无需强转
// for (Integer score : arrayList1) {
// System.out.println(score);
// }
// Iterator iterator = arrayList1.iterator();
// while (iterator.hasNext()) {
// System.out.println(iterator.next());
// }
//在集合中使用泛型 HashMap
HashMap hashMap = new HashMap<>();
hashMap.put(1, "GYQ");
// hashMap.put("2", 123); //会报错
hashMap.put(3, "GQ");
hashMap.put(4, "GY");
Set> entries = hashMap.entrySet();
Iterator> iterator = entries.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
总结:集合接口或集合类在jdk5.0时都修改为带泛型的结构。
在实例化集合类时,可以指明具体的泛型类型
指明完以后,在集合类或接口中凡是定义类或接口时,内部结构使用到类的泛型的位置,都指定为实例化时的泛型类型。比如:add(E e) --->实例化以后:add(Integer e)
泛型的类型必须是一个类,不能是基本数据类型(用包装类)
如果实例化时没有指明泛型的类型,则默认为java.lang.Object类型
泛型的使用
@Test
public void test() {
//TreeSet treeSet = new TreeSet();
//jdk7新特性:类型推断
TreeSet treeSet = new TreeSet<>();
treeSet.add(new Employee("gyq", 10000));
treeSet.add(new Employee("clv", 777));
treeSet.add(new Employee("uzi", 888));
treeSet.add(new Employee("zzt", 555));
treeSet.add(new Employee("hib", 999));
//自然排序的结果
Iterator iterator = treeSet.iterator();
while (iterator.hasNext())
System.out.println(iterator.next());
System.out.println("--------------------");
//定制排序
TreeSet treeSet1 = new TreeSet<>(new Comparator() {
//按salay从高到低
@Override
public int compare(Employee o1, Employee o2) {
return -Integer.compare(o1.salary, o2.salary);
}
});
treeSet1.add(new Employee("gyq", 10000));
treeSet1.add(new Employee("clv", 777));
treeSet1.add(new Employee("uzi", 888));
treeSet1.add(new Employee("zzt", 555));
treeSet1.add(new Employee("hib", 999));
//定制排序的结果
Iterator iterator1 = treeSet1.iterator();
while (iterator1.hasNext())
System.out.println(iterator1.next());
}
}
class Employee implements Comparable {
public String name;
public int salary;
public Employee(String name, int salary) {
this.name = name;
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + ''' +
", salary=" + salary +
'}';
}
//按照name排序
@Override
public int compareTo(Employee o) {
return this.name.compareTo(o.name);
}
自定义泛型结构:泛型类,泛型接口,泛型方法
public class TestClass {
@Test
public void test() {
//带泛型类的使用
Class Class1 = new Class<>(1, "软工", "gyq");
Class Class2 = new Class<>(1, "软工", 1);
System.out.println(Class1);
System.out.println(Class2);
//泛型不同的引用不能相互赋值
ArrayList list = null;
// ArrayList list1 = list; 报错
//继承带泛型类的类的使用
//由于子类在继承带泛型的父类时,指明了泛型类型,则实例化时不需要指明
// subClass subClass1 = new subClass();
// subClass1.setMonitor(10.0);
//由于子类在继承带泛型的父类时,没有指明泛型
subClass subClass2 = new subClass();
subClass2.setMonitor("wms");
}
}
class Class {
int cno;
String major;
//类内部结构就可以使用类的泛型
T monitor;
//非静态方法可以使用
public T getMonitor() {
return monitor;
}
//静态方法 无法使用类的泛型
// public static T getMonitor() {
// return monitor;
// }
public Class() {
}
public Class(int cno, String major, T monitor) {
this.cno = cno;
this.major = major;
this.monitor = monitor;
}
public void setMonitor(T monitor) {
this.monitor = monitor;
}
@Override
public String toString() {
return "Class{" +
"cno=" + cno +
", major='" + major + ''' +
", monitor=" + monitor +
'}';
}
}
//继承时指明泛型
//class subClass extends Class
//不指明泛型 此时subClass仍是泛型类
class subClass extends Class {
}
补充:
泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:
泛型的构造器如下:public GenericClass(){}; 不需要加尖括号,但在使用时需要加。
实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。
泛型不同的引用不能相互赋值。
泛型如果不指定将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。经验:泛型要使用一路都要用,要不用,一路都不用。
如果泛型结构是一个接口或抽象类,则不可创建该结构的对象
在接口/类上声明的泛型,在本类或本接口中可以作为非静态属性的类型,非静态方法的参数类型,返回值。但在静态方法中不能使用泛型。 静态方法早于对象的创建,泛型在对象创建是指定类型
异常类不能是泛型的
声明泛型类数组:
不能使用 T[ ] array = new T[capacity] 应该使用 T[ ] array = (T[ ])new Object[capacity]
父类中有泛型,子类可以选择保留泛型也可以指定泛型类型
泛型方法
不是说方法中使用了泛型就叫泛型方法,泛型方法可以是静态的
public class TestClass {
@Test
public void test() {
Integer[] iarr = new Integer[]{1, 2, 3, 4, 5, 6};
String[] sarr = new String[]{"ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX"};
HashMap map1 = toMap(sarr, iarr);
HashMap map2 = toMap(iarr, sarr);
System.out.println(map1);
System.out.println(map2);
}
//在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系
//换句话说,泛型方法所属的类是不是泛型类都没关系
public HashMap toMap(A[] key, B[] value) {
HashMap map = new HashMap();
for (int i = 0; i < key.length; i++) {
map.put(key[i], value[i]);
}
return map;
}
}
泛型在继承方面的体现
虽然类A是类B的父类,但是G 和 G 没有子父类关系,两者为并列的关系
类A是类B的父类,A
@Test
public void test() {
Object obj = null;
String str = null;
obj = str;
Object[] arr1 = null;
String[] arr2 = null;
arr1 = arr2;
List
通配符的使用
G 和 G 的公共父类 G>
public class TestClass {
@Test
public void test() {
List list1 = new ArrayList<>();
list1.add("123");
list1.add("234");
list1.add("345");
List list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
list2.add(3);
show(list1);
System.out.println("------------");
show(list2);
System.out.println("------------");
//使用通配符后添加数据和读取数据的要求
List> list = null;
list = list1;
//对于List>不能向其内部添加数据,除了添加null之外
// list.add("str");
list.add(null);
//读取
Object o = list.get(0);
System.out.println(o);
}
public void show(List> list) {
for (Object o : list) {
System.out.println(o);
}
}
}
有限制的通配符
通配符指定上限
上限extends:使用时指定的类型必须是继承某个类,或者实现某个接口,即<=
通配符指定下限
下限super:使用时指定的类型不能小于操作的类,即>=
public class TestClass {
@Test
public void test() {
List extends Person> List1 = new ArrayList<>();
List super Person> List2 = new ArrayList<>();
List


