文章目录
泛型的简介
一、什么是泛型
允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。
二、在集合中使用泛型
1、List
@Test
public void genericTest(){
ArrayList<Integer> list = new ArrayList<>();
list.add(12345);
list.add(654);
// list.add("Tom");编译时,就会进行类型检查,保证数据的安全
for (Integer score : list){
//避免了强转操作
int studentScore = score;
System.out.println(studentScore);
}
}
2、Map
@Test
public void mapUseGeneric(){
HashMap<String, Integer> map = new HashMap<>();
map.put("tom",12);
map.put("jerry",80);
Set<Map.Entry<String, Integer>> entries = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
while (iterator.hasNext()){
Map.Entry<String, Integer> entry = iterator.next();
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + " " + value);
}
}
3、总结
- 集合接口或集合类在jdk5.0时都修改为带泛型的结构。
- 在实例化集合类时,可以指明具体的泛型类型。
- 指明完以后,在集合或接口中凡是定义类或接口时,内部结构使用到类的泛型的位置都是指定的类型。
- 如果实例化时不指明泛型的类型,默认为Object。
注意:泛型的类型必须是一个类。
三、自定义泛型类/接口
1、自定泛型类/接口
package com.genericity;
import org.junit.Test;
public class MyGeneric<T> {
String orderName;
int orderId;
//类的内部结构使用类的泛型
T orderT;
public MyGeneric(){
}
public MyGeneric(String orderName, int orderId, T orderT) {
this.orderName = orderName;
this.orderId = orderId;
this.orderT = orderT;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
public T getOrderT() {
return orderT;
}
public void setOrderT(T orderT) {
this.orderT = orderT;
}
@Override
public String toString() {
return "MyGeneric{" +
"orderName='" + orderName + '\'' +
", orderId=" + orderId +
", orderT=" + orderT +
'}';
}
}
class Use{
@Test
public void use(){
//如果定义的类是带泛型的,在实例化时要指定明类的泛型
MyGeneric<Integer> myGeneric = new MyGeneric<>();
myGeneric.setOrderT(123);
}
}
2、继承泛型类/接口
//指明泛型类型,不再是泛型类
public class SubMyGeneric extends MyGeneric<Integer>{
//由于子类在继承带泛型的父类时,指明了泛型类型,则实例化子类对象时,不再需要指明泛型
public static void main(String[] args) {
SubMyGeneric subMyGeneric = new SubMyGeneric();
subMyGeneric.setOrderT(123);
}
}
//不指明泛型类型,仍然是泛型类
class SubMyGeneric2<T> extends MyGeneric<T>{
public static void main(String[] args) {
SubMyGeneric2<Integer> myGeneric2 = new SubMyGeneric2<>();
myGeneric2.setOrderT(123);
}
}
3、需要实例化泛型类对象时的方法
public class MyGeneric<T> {
String orderName;
int orderId;
//类的内部结构使用类的泛型
T orderT;
public MyGeneric(){
//实际存储的还是Object类型数据,但是数据必需是T或T的子类,否则强转会报异常
T[] ts = (T[]) new Object[10];
}
}
4、子类继承泛型父类保留或擦除父类泛型的操作
保留/擦除父类泛型
class Father<T1, T2> {
}
// 子类不保留父类的泛型
// 1)没有类型 擦除
class Son1 extends Father {// 等价于class Son extends Father<Object,Object>{
}
// 2)具体类型
class Son2 extends Father<Integer, String> {
}
// 子类保留父类的泛型
// 1)全部保留
class Son3<T1, T2> extends Father<T1, T2> {
}
// 2)部分保留
class Son4<T2> extends Father<Integer, T2> {
}
保留/擦除父类泛型,子类自己新增自己的泛型
class Father<T1, T2> {
}
// 子类不保留父类的泛型
// 1)没有类型 擦除
class Son<A, B> extends Father{//等价于class Son extends Father<Object,Object>{
}
// 2)具体类型
class Son2<A, B> extends Father<Integer, String> {
}
// 子类保留父类的泛型
// 1)全部保留
class Son3<T1, T2, A, B> extends Father<T1, T2> {
}
// 2)部分保留
class Son4<T2, A, B> extends Father<Integer, T2> {
}
四、自定义泛型方法
1、什么是泛型方法
- 在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。
- 泛型方法是可以声明为静态的,因为泛型参数是在调用方法时确定的
2、泛型方法演示
package com.genericity;
import java.util.ArrayList;
import java.util.List;
public class GenericFunction {
//泛型方法
//第一个<E>:表示E不是一个已经存在的泛型,告诉编译器这是泛型方法
//第二个E://第二个E:泛型方法的List返回值类型
//第三个E:泛型方法的参数类型
public <E> List<E> copyFromArrayToList(E[] arr) {
ArrayList<E> list = new ArrayList<>();
for (E e : arr) {
list.add(e);
}
return list;
}
//测试泛型方法
public static void main(String[] args) {
String[] strings = {"tom", "jerry", "jack"};
GenericFunction genericFunction = new GenericFunction();
//泛型方法在调用时指明泛型参数的类型
List<String> list = genericFunction.copyFromArrayToList(strings);
System.out.println(list);
}
}
五、泛型在继承方面的体现
@Test
public void extendGeneric(){
ArrayList<Object> arr1 = null;
ArrayList<String> arr2 = null;
//报错,虽然Object是String的父类,但是<Object>与<String>在泛型中不具备子父类关系,是并列关系
// arr1 = arr2;
}
六、通配符
List<?>不能写入(除了null),只能读取,读取的数据类型为Object。
1、通配符的使用
@Test
public void test() {
List<Object> list1 = null;
List<String> list2 = null;
//通配符:?,相当于二者公共的父类
List<?> list3 = null;
list3 = list1;
list3 = list2;
}
2、有限制条件的通配符
//Student extends Person
//? extends Person:?可以为Person本身或它的子类
//? super Person:?可以为Person本身或它的父类
public void test1(){
List<? extends Person> list1 = null;
List<? super Person> list2 = null;
List<Student> studentList = null;
List<Person> personList = null;
List<Object> objectList = null;
list1 = studentList;
list1 = personList;
// list1 = objectList;
// list2 = studentList;
list2 = personList;
list2 = objectList;
}