1. 为什么使用泛型
2. 在集合中使用泛型
package org.example;
import org.junit.Test;
import java.util.*;
/**
* 泛型的使用
* 1. jdk 5.0新增特性
* <p>
* 2. 在集合中使用泛型:
* 总结:
* 1)集合接口或集合类在jdk5.0都修改为带泛型的结构。
* 2)在实例化集合类时,可以指明具体的泛型类型。
* 3)指明完之后,在集合接口或类中凡是定义类或接口时,内部结构使用到类的泛型的位置,
* 都指定为实例化时的泛型类性
* 如:add(E e) --->实例化以后 add(Integer e)
*4) 注意点:泛型的类型必须是类,不能是基本数据类型。
* 5)如果实例化时,没有指明泛型类型,默认类型为java.lang.Object.
*
* jdk7新特性:类型推断
* Map<String, Integer> map = new Map<>();
*
* @author AmorFati
* 2020/10/5 20:04
*/
public class GenericTest {
@Test
public void test1() {
//需求:存放学生成绩
ArrayList list = new ArrayList();
list.add(33);
list.add(44);
list.add(77);
list.add(88);
//问题一:类型不安全
list.add("Tom");
for (Object score : list) {
//问题二:强转时,可能出现ClassCastException
int stuScore = (int) score;
}
}
//在集合中使用泛型的情况
@Test
public void test2() {
ArrayList<Integer> list = new ArrayList<>();
list.add(33);
list.add(44);
list.add(77);
list.add(88);
//编译时,就会进行类型检查,保证数据类型的安全
// list.add("Tom");
//方式一:
for (Integer score : list) {
//避免了强转操作
int stuScore = score;
}
//方式二:
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
//在集合中使用泛型的情况,以HashMap为例
@Test
public void test3() {
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("Tom", 88);
map.put("Jack", 55);
map.put("Sam", 78);
map.put("Amy", 54);
//泛型的嵌套
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
while (iterator.hasNext()) {
Map.Entry<String, Integer> next = iterator.next();
System.out.println(next.getKey() + "=" + next.getValue());
}
}
}
3. 自定义泛型结构
自定义泛型类或接口
public class Order<T> {
String orderName;
int orderId;
//类的内部结构可以使用类的泛型
T orderT;
public Order() {
//编译不通过
// T[] arr = new T[10];
//编译通过
T[] arr = (T[]) new Object[10];
}
public Order(String orderName, int orderId, T orderT) {
this.orderName = orderName;
this.orderId = orderId;
this.orderT = orderT;
}
public T getOrderT() {
return orderT;
}
}
//SubOrder不是泛型
public class SubOrder extends Order<Integer> {
}
//SubOrder1<T>仍然是泛型
public class SubOrder1<T> extends Order<T> {
}
package org.example;
import org.junit.Test;
import java.util.ArrayList;
/**
* 1. 关于自定义泛型类,泛型接口。
*/
public class GenericTest1 {
@Test
public void test1() {
//要求:如果大家定义了类是带泛型的,建议在实例化时要指明类的泛型。
Order<String> order = new Order<>();
}
@Test
public void test2() {
//由于子类在继承带泛型的父类时,指明了泛型类型, 则实例化子类对象时,不在需要指明泛型。
SubOrder subOrder = new SubOrder();
SubOrder1<String> subOrder1 = new SubOrder1<>();
}
@Test
public void test3() {
ArrayList<Integer> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
//泛型的不同引用不能相互赋值。
// list1 = list2;
}
}
自定义泛型方法
//泛型方法:在方法中出现了泛型结构,泛型参数与类的泛型参数没有任何关系
//换句话说,泛型方法所属的类是不是泛型类都没有关系
//泛型方法可以声明static
//原因:泛型参数是在调用方法时确定的,并非在实例化时确定的。
public <E> List<E> copyFromArrayToList(E[] arr) {
ArrayList<E> list = new ArrayList<>();
for (E e : arr) {
list.add(e);
}
return list;
}
@Test
public void test4() {
Integer[] arr = new Integer[]{1, 2, 3, 4};
List<Integer> list = copyFromArrayToList(arr);
System.out.println(list);
}
4. 泛型在继承上的体现
package org.example.java2;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
/**
* 1. 泛型在继承方面的体现
*虽然类A是类B的父类,但是G<A>和G<B>二者不具备子父类关系,二者是并列关系。如Test1
*
*类A是类B的父类,A<G>是B<G>的父类。如Test2
*
* @author AmorFati
* @create 2020/10/5 21:31
*/
public class GenericTest {
@Test
public void test1() {
Object[] arr1 = null;
String[] arr2 = null;
arr1 = arr2;//编译通过
List<Object> list1 = null;
List<String> list2 = null;
//此时list1和list2不具备子父类关系,编译不通过。
// list1 = list2;
/*
反证法:
假设list1 = list2;成立
list1.add(123);导致混入非String的数据,出错。
*/
}
@Test
public void test2() {
List<String> list1 = null;
ArrayList<String> list2 = null;
list1 = list2;
}
}
5. 通配符的使用
package org.example.java2;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* 通配符的使用
* 通配符:? (英文格式下)
* <p>
* 类A是类B的父类,G<A>和G<B>没有关系,二者共同的父类是G<?>
*
* @author AmorFati
* @create 2020/10/5 21:46
*/
public class GenericTest1 {
@Test
public void test1() {
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<?> list = null;
list = list1;
list = list2;
List<String> list3 = new ArrayList<>();
list3.add("AA");
list3.add("BB");
list3.add("CC");
list = list3;
//添加(写入),对于List<?>就不能向其内部添加数据
//除了添加null之外。
// list.add("DD");编译不通过
//获取(读取):允许读取数据,读取的数据类型为Object.
Object o = list.get(0);
}
public void print(List<?> list) {
Iterator<?> iterator = list.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println(obj);
}
}
}
有限制条件的通配符
public class Person {
}
public class Student extends Person {
}
/*
有限制条件的通配符的使用
? extends A:
G<? extends A> 可以作为G<A>和G<B>的父类,其中B是A的子类。
? super A:
G<? super A> 可以作为G<A>和G<B>的子类,其中B是A的父类。
*/
@Test
public void test2() {
List<? extends Person> list1 = null;
List<? super Person> list2 = null;
List<Student> list3 = null;
List<Person> list4 = null;
List<Object> list5 = null;
list1 = list3;
list1 = list4;
// list1 = list5;//编译不通过
// list2 = list3;//编译不通过
list2 = list4;
list2 = list5;
//读取数据
Person person = list1.get(0);
// Student student = list1.get(0);//编译不通过
Object object = list2.get(0);
// Person person1 = list2.get(0);//编译不通过
//写入数据:
// list1.add(new Student());//编译不通过
// list1.add(new Person());//编译不通过
list2.add(new Person());//通过
list2.add(new Student());//通过
// list2.add(new Object());//编译不通过
}