学习内容:
- 一、泛型
- 二、定义和使用含有泛型的类
- 三、定义和使用含有泛型的方法
- 四、定义和使用含有泛型的接口
- 五、泛型的通配符
一、泛型
一、概述
泛型:是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型
泛型也可以看成是一个变量,用来接收数据类型
- E e:Element 元素
- T t:Type 类型
ArrayList集合在定义的时候,不知道集合中都会存储什么类型的数据,所以类型使用泛型。
二、使用泛型的好处
- 将运行时期的ClassCastException,转移到了编译时期变成了编译失败。
- 避免了类型强转的麻烦。
下面用一段代码简单说明:
import java.util.ArrayList;
import java.util.Iterator;
public class Demo01Generic {
public static void main(String[] args) {
//show01();
show02();
}
/*
创建集合对象不使用泛型
好处:
集合不使用泛型,默认的类型就是Object类型,可以存储任意类型的数据
弊端:
不安全,会引发异常
*/
private static void show01() {
ArrayList list = new ArrayList();
list.add("nxy");
list.add(1);
// 使用迭代器遍历list集合
// 获取迭代器
Iterator it = list.iterator();
// 使用迭代器中的方法hasNext遍历集合
while(it.hasNext()) {
// 取出元素也是Object类型
Object obj = it.next();
System.out.println(obj);
// 想要使用String类特有的方法,length获取字符串的长度;不能使用 多态 Object obj = "abc";
// 需要向下转型
// 会抛出ClassCastException类型转换异常,不能把Integer类型转换为String类型
String s = (String)obj;
System.out.println(s.length());
}
}
/*
创建集合对象,使用泛型
好处:
1. 避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型
2. 把运行期异常(代码运行之后会抛出的异常),提升到了编译期
弊端:
泛型是什么类型,就只能存储什么类型的数据
*/
private static void show02() {
ArrayList<String> list = new ArrayList<>();
list.add("rxz");
// list.add(1); 编译时就会报错
// 使用迭代器遍历list集合
Iterator<String> it = list.iterator();
while(it.hasNext()) {
String s = it.next();
System.out.println(s + "->" + s.length());
}
}
}
二、定义和使用含有泛型的类
一、概述
定义一个含有泛型的类,模拟ArrayList集合
- 泛型是一个未知的数据类型,当我们不确定什么数据类型的时候,可以使用泛型
- 泛型可以接收任意的数据类型,可以使用Integer,String,Student…
- 创建对象的时候确定泛型的数据类型
二、定义含有泛型的类
代码如下:
public class GenericClass<E> {
private E name;
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
}
三、使用含有泛型的类
编写测试类如下:
public class Demo02GenericClass {
public static void main(String[] args) {
// 不写泛型,默认为Object类型
GenericClass gc = new GenericClass();
// 创建GenericClass对象,泛型使用Integer类型
GenericClass<Integer> gc2 = new GenericClass<>();
gc2.setName(1);
Integer name = gc2.getName();
System.out.println(name); // 1
//创建GenericClass对象,泛型使用String类型
GenericClass<String> gc3 = new GenericClass<>();
gc3.setName("nxy");
String name1 = gc3.getName();
System.out.println(name1); // nxy
}
}
三、定义和使用含有泛型的方法
一、概述
定义含有泛型的方法:泛型定义在方法的修饰符和返回值类型之间。
格式:
修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)) {
方法体;
}
含有泛型的方法,在调用方法的时候确定泛型的数据类型,传递什么类型的参数,泛型就是什么类型。
二、定义含有泛型的方法
代码如下:
public class GenericMethod {
// 定义一个含有泛型的方法
public <M> void method01(M m) {
System.out.println(m);
}
// 定义一个含有泛型的静态方法
public static <S> void method02(S s) {
System.out.println(s);
}
}
三、使用含有泛型的方法
代码如下:
/*
测试含有泛型的方法
*/
public class Demo03GenericMethod {
public static void main(String[] args) {
//创建GenericMethod对象
GenericMethod gm =new GenericMethod();
/*
调用含有泛型的方法method01
传递什么类型,泛型就是什么类型
*/
gm.method01(10); // 10
gm.method01("nxy"); // nxy
gm.method01(true); // true
gm.method02("静态方法,不建议创建对象使用"); // 静态方法,不建议创建对象使用
// 静态方法,通过类名.方法名(参数),可以直接使用
GenericMethod.method02("nxy"); // nxy
}
}
四、定义和使用含有泛型的接口
含有泛型的接口有两种使用方式。下面分开讨论。
先定义一个含有泛型的接口:
/*
定义含有泛型的接口,接口中定义一个抽象方法
*/
public interface GenericInterface<I> {
public abstract void method(I i);
}
一、第一种使用方式
含有泛型的接口,第一种使用方式:定义接口的实现类,实现接口,指定接口的泛型,代码如下:
public class GenericInterfaceImpl1 implements GenericInterface<String> {
@Override
public void method(String s) {
System.out.println(s);
}
}
二、第二种使用方式
含有泛型的接口,第二种使用方式:接口使用什么泛型,实现类就是用什么泛型,类跟着接口走。就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型。实现类代码如下:
public class GenericInterfaceImpl2<I> implements GenericInterface<I>{
@Override
public void method(I i) {
System.out.println(i);
}
}
三、编写测试类进行测试
/*
测试含有泛型的接口
*/
public class Demo04GenericInterface {
public static void main(String[] args) {
// 创建GenericInterfaceImpl1对象
GenericInterfaceImpl1 gi1 = new GenericInterfaceImpl1();
gi1.method("实现类1指定了泛型为String类型,所以只能有字符串");
// 创建GenericInterfaceImpl2对象
GenericInterfaceImpl2<Integer> gi2 = new GenericInterfaceImpl2<>();
gi2.method(10); // 在创建对象的时候才指定泛型的类型为Integer
GenericInterfaceImpl2<Double> gi3 = new GenericInterfaceImpl2<>();
gi3.method(8.8); // 在创建对象的时候才指定泛型的类型为Double
}
}
五、泛型的通配符
一、概述
泛型的通配符:?,代表任意的数据类型
使用方式:
不能创建对象使用
只能作为方法的参数使用
二、使用
定义一个方法,能遍历所有类型的ArrayList集合
这时候我们不知道ArrayList集合使用什么数据类型,可以使用泛型的通配符?来接收数据类型
注意:
泛型没有继承的概念
代码示例如下:
import java.util.ArrayList;
import java.util.Iterator;
public class Demo05Generic {
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(1);
list01.add(2);
ArrayList<String> list02 = new ArrayList<>();
list02.add("a");
list02.add("b");
printArray(list01);
System.out.println("============");
printArray(list02);
}
// 定义方法
public static void printArray(ArrayList<?> list) {
// 使用迭代器遍历集合
Iterator<?> it = list.iterator();
while (it.hasNext()) {
// it.next()方法,取出的元素是Object类型,Object类型可以接收任意的数据类型
Object o = it.next();
System.out.println(o);
}
}
}