泛型定义
泛型:是一种未知类型的数据当我们不知道使用什么类型的数据时,可以使用泛型;
例如: 单列集合Arraylist
public class ArrayList<E>{
public boolean add(E e){};
public E get(int index){}
}
E代表未知的数据
在创建对象的时候会把对象类型作为参数传递给泛型对象;
ArrayList对象的创建:
ArrayLIst<String> list = new ArrayList<>();
优点:把运行时异常提升到编译时异常,避免了转换的麻烦
以下不使用泛型:类型转换有误会产生运行时异常
* @author HolyTrees
* @date 2020-10-19 下午 13:56
*/
public class Demo01Generic {
public static void main(String[] args) {
show01();
}
/**
* 创建集合对象,不使用泛型
* 好处:
* 集合不适用泛型;默认的类型就是Object类型,可以存储任意类型的数据
* 弊端:
* 不安全,会引发运行时异常
*/
private static void show01() {
//创建集合,默认是Object类型
ArrayList list = new ArrayList();
list.add("abc");
list.add(123);
/**
* 使用迭代器遍历集合list
*/
Iterator it= list.iterator();
while (it.hasNext()){
Object obj = it.next();
System.out.println(obj);
/**
* 要使用String类特有的方法,length获取字符串长度,不能使用 多态 Object obj = "abc";
* 需要向下转型;但是会抛出java.lang.ClassCastException 类型转换异常,
* 不能把Integer类型转换成String类型
*/
String s = (String) obj;
//获取字符串长度
System.out.println(s.length());
}
}
}
输出结果为:
abc
字符串长度3
123
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
使用泛型:会产生编译时异常
import java.util.ArrayList;
import java.util.Iterator;
/**
* @author HolyTrees
* @date 2020-10-19 下午 14:24
*/
public class Demo02Generic {
public static void main(String[] args) {
show02();
}
/**
* 创建对象 使用泛型
* 好处:
* 避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型
* 把运行时异常提升到编译时异常;
* 弊端:
* 泛型是什么类型,只能存储什么类型的数据
*/
private static void show02() {
ArrayList<String> list = new ArrayList<>();
list.add("abc");
list.add("bbq");
list.add(1);此处产生编译时异常
//使用迭代器遍历list集合
Iterator<String> it = list.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s+"字符串长度"+s.length());
}
}
}
泛型的使用
定义和使用含有泛型的类:
格式:public class 类名称
此处可以查看ArrayList源码来学习
定义和使用含有泛型的方法
格式:修饰符 返回值类型(参数列表(E e)){}
定义和实现含有泛型的接口
格式:public Interface 接口名称
实现方式:
- public class 类名称 Implements 接口名称 ,直接定义好实现类的泛型
- public class 类名称 Implements 接口名称 ,创建实现类对象是确定泛型类型
定义和使用含有泛型的方法
定义一个类,类中含有泛型对的普通的方法以及静态方法
/**
* 定义一个含有泛型方法:泛型定义方法的修饰符和类型之间
* 格式:
* 修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)) {
* 方法体
* }
*
* @author HolyTrees
* @date 2020-10-19 下午 14:56
*/
public class GenericMethod {
/**
* 传递什么参数,返回值就是什么类型,普通方法
* @param e
* @param <E> 定义泛型
* @return
*/
public <E> E show01(E e){
System.out.println(e);
return e;
}
/**
* 静态方法
*
* @param e
* @param <E>
* @return
*/
public static<E> E show02(E e){
System.out.println(e);
return e;
}
}
测试主方法
/**
* 测试含有泛型的方法
*
* @author HolyTrees
* @date 2020-10-19 下午 14:58
*/
public class Demo01GenericMethod {
public static void main(String[] args) {
GenericMethod gc = new GenericMethod();
/**
* 传递参数给泛型
*/
//String类型
System.out.println("普通方法");
System.out.println("传递String类型给泛型方法");
gc.show01("普通泛型方法字符串");
//Integer类型
System.out.println("传递Integer类型给泛型方法");
gc.show01(123);
System.out.println();
/**
* 使用静态泛型方法
*/
System.out.println("静态方法");
System.out.println("传递String类型给泛型方法");
GenericMethod.show02("静态泛型方法字符串");
System.out.println("传递Integer类型给泛型方法");
GenericMethod.show02(678);
}
}
输出结果为:
普通方法
传递String类型给泛型方法
普通泛型方法字符串
传递Integer类型给泛型方法
123
静态方法
传递String类型给泛型方法
静态泛型方法字符串
传递Integer类型给泛型方法
678
定义和使用含有泛型的接口
定义泛型接口
/**
* 定义泛型接口
*
* @author HolyTrees
* @date 2020-10-19 下午 15:15
*/
public interface GenericInterface<E>{
/**
* 抽象方法使用接口泛型
* @param e
*/
void method(E e);
}
使用第一种实现方式
public class 类名称 Implements 接口名称 ,直接定义好实现类的泛型,此处使用String类型
/**
* 含有泛型的接口使用方式:
* 1.定义接口的实现类,实现接口,并且指定接口的泛型
* public interface Iterator<E>{
* E next();
* }
* Scanner类实现了Iterator接口,并指定接口的泛型为String,所以重写的next方法泛型默就是String
* public final class Scanner implements Iterator<String>{
* public String next(){};
* }
*
* @author HolyTrees
* @date 2020-10-19 下午 15:17
*/
public class GenericImplOne implements GenericInterface<String>{
@Override
public void method(String s) {
System.out.println(s);
}
}
使用第二种实现方式
public class 类名称 Implements 接口名称 ,创建实现类对象是确定泛型类型
/**
* 含有泛型的接口第二种使用方式:接口使用泛型,实现类就是用什么泛型
* 相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型
* public interface list<E>{
* public boolean add(E e);
* E get(int index);
* }
* public class Arraylist<E> implements list<E>{
* public boolean add(E e);
* * E get(int index);
* }
*
* @author HolyTrees
* @date 2020-10-19 下午 15:33
*/
public class GenericImplTwo<E> implements GenericInterface<E>{
@Override
public void method(E e) {
System.out.println(e);
}
}
主方法测试
/**
* 定义主方法,测试含有泛型的接口
*
* @author HolyTrees
* @date 2020-10-19 下午 15:29
*/
public class Demo01GenericInterface {
public static void main(String[] args) {
//创建GenericImplOne的对象
GenericImplOne gc = new GenericImplOne();
gc.method("No matter how far we go");
//创建GenericImplTwo的对象
GenericImplTwo<Integer> gc2 = new GenericImplTwo<>();
gc2.method(132);
GenericImplTwo<String> gc3 = new GenericImplTwo<>();
gc3.method("String类型");
}
}
输出结果为:
No matter how far we go
132
String类型
泛型通配符
泛型通配符的高级使用—受限泛型
之前设置泛型的时候,实际上可以是任意设置的,只要是类就可以设置,但是在JAVA的泛型中可以指定一个泛型的上限和下限。
泛型的上限:
格式: 类型名称 <? Extend E> 对象名称
意义:只能接收该类型及其子类
犯下的下限:
格式:类型名称<? Super E>对象名称
意义:只能接收该类型及其父类型
import java.util.ArrayList;
import java.util.Collection;
/**
* 泛型通配符的高级使用:
* 泛型通配符的上限:
* 格式 :类型名称<? extend 类>对象名称
* 意义:只能接收该类型及其子类型
* 泛型通配符的下限:
* 格式:类型名称<? super 类>对象名称
* 意义:只能接收该类型及其父类型
*
* @author HolyTrees
* @date 2020-10-19 下午 16:20
*/
public class GenericModifierLimit {
public static void main(String[] args) {
/**
* Number是Integer父类
* Object是Number的父类
*/
Collection<Integer> list1 = new ArrayList<Integer>();
Collection<String> list2 = new ArrayList<String>();
Collection<Number> list3 = new ArrayList<Number>();
Collection<Object> list4 = new ArrayList<Object>();
getElements1(list1);
getElements1(list2); 报错String类型不属于Number泛型的上限
getElements1(list3);
getElements1(list4); 报错Object是Number的父类,属于下限
getElements2(list1); 报错 Integer是Number的子类,属于上限
getElements2(list2); 报错 String类型不属于Number泛型的下限
getElements2(list3);
getElements2(list4);
}
/**
* 泛型的上限:此时的泛型必须是Number及其子类
* @param coll
*/
public static void getElements1(Collection<? extends Number> coll){};
/**
* 泛型的下限:此时的泛型必须是Number及其父类
* @param coll
*/
public static void getElements2(Collection<? super Number> coll){}
}