为什么需要泛型
在使用java集合时,我们常常见到泛型,为什么要使用泛型呢?
先看一个列子
package dj.generic;
import java.util.ArrayList;
public class ArrayListTest {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("abc");
list.add("ff");
for (Object object : list) {
String string = (String) object;
System.out.println(string);
}
}
}
其中add方法参数为Object类型,在取出数据的时候,需要将类型强转过来,这个时候可能出错
以下是错误代码
package dj.generic;
import java.util.ArrayList;
public class ArrayListTest {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("abc");
list.add("ff");
//取出数据时,强转为String会出错
list.add(1);
for (Object object : list) {
String string = (String) object;
System.out.println(string);
}
}
}
输出信息
abc
ff
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at dj.generic.ArrayListTest.main(ArrayListTest.java:15)
为了防止这种情况的发生,我们引入泛型,修改以上错误代码,编译时候会提示报错
常见的几种泛型
泛型方法、泛型类、泛型接口
泛型方法
定义泛型方法
GenericA
package dj.generic;
public class GenericA {
public <T> void printArr(T[] arrys) {
for (T t : arrys) {
System.out.println(t);
}
System.out.println("========");
}
//T的作用域仅在方法上有效
public <T> void otherT() {
}
//26个大写字母都可以
public <E> void otherE() {
}
//可以同时声明多个泛型参数
public <K, V> void otherKV() {
}
}
测试
DriveTestA
package dj.generic;
public class DriveTestA {
public static void main(String[] args) {
// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
GenericA genericA = new GenericA();
System.out.println( "整型数组元素为:" );
genericA.printArr(intArray); // 传递一个整型数组
System.out.println( "\n双精度型数组元素为:" );
genericA.printArr(doubleArray); // 传递一个双精度型数组
System.out.println( "\n字符型数组元素为:" );
genericA.printArr(charArray); // 传递一个字符型数组
}
}
输出结果
整型数组元素为:
1
2
3
4
5
========
双精度型数组元素为:
1.1
2.2
3.3
4.4
========
字符型数组元素为:
H
E
L
L
O
========
泛型类
泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。
和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。
泛型变量作用域为整个类,变量,方法都可以使用
Box
package dj.generic;
public class Box<T> {
// 变量可使用
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
测试方法
DriveTestA
package dj.generic;
public class DriveTestA {
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("使用菜鸟教程上的列子"));
System.out.printf("整型值为 :%d\n\n", integerBox.get());
System.out.printf("字符串为 :%s\n", stringBox.get());
}
}
输出结果
整型值为 :10
字符串为 :使用菜鸟教程上的列子
个人理解,改操作相当于为类规定了某些内部变量使用类型
泛型接口
定义一个泛型接口
InterfaceGeneric
package dj.generic;
public interface InterfaceGeneric<T> {
void test(T t);
}
实现泛型接口时候,指明类型
package dj.generic;
public class ImplGeneric implements InterfaceGeneric<String> {
@Override
public void test(String t) {
System.out.println(t);
}
}
若不指明类型,该变量类型相当于Object
类型通配符
通配符一般有三种表现形式
1.一般是使用?代替具体的类型参数。
package dj.generic;
import java.util.ArrayList;
public class ArrayListTest {
//以下语句都是正确的
public static void main(String[] args) {
ArrayList<Object> list = new ArrayList<Object>();
ArrayList<?> list2 = new ArrayList<Object>();
ArrayList<?> list3 = new ArrayList<String>();
}
}
其中:通配符?与Object不能理解为互等
看一个通配符列子
List<?> 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类。而**List<Object>是与List<String>,List<Integer> 等平级**
2.上边界
类型通配符上限通过形如List来定义,如此定义就是通配符泛型值接受Number及其下层子类类型。
GenericTest
package dj.generic;
import java.util.ArrayList;
import java.util.List;
public class GenericTest {
public static void main(String[] args) {
List<String> name = new ArrayList<String>();
List<Integer> age = new ArrayList<Integer>();
List<Number> number = new ArrayList<Number>();
name.add("icon");
age.add(18);
number.add(314);
//getUperNumber(name);//错误
getUperNumber(age);// 2
getUperNumber(number);// 3
}
public static void getData(List<?> data) {
System.out.println("data :" + data.get(0));
}
public static void getUperNumber(List<? extends Number> data) {
System.out.println("data :" + data.get(0));
}
}
name变量类型为String,不属于? extends Number,属于错误类型
3.下边界
下界关键字为<? supers Number>,这里不举例说明,和上边界相反
如何理解上下边界
package dj.generic;
public class A {
}
package dj.generic;
public class B extends A {
}
package dj.generic;
public class C extends B {
}
package dj.generic;
public class D extends C {
}
<? extends T> 是定义上边界,? >= T
<? super T> 是定义下边界,? <= T
说明
<? extends T>和<? super T>的区别
<? extends T>表示该通配符所代表的类型是T类型的子类。
<? super T>表示该通配符所代表的类型是T类型的父类。