泛型
泛型原本是一种机制允许程序员在编译时检测到非法的类型。他通过类型参数来实现代码复用以提高代码的编写效率。
1. 泛型方法
泛型方法拥有以下几点特征:
1. 由 <E>
作为参数声明部分,此部分要放在参数返回值之前,表明这是一个泛型方法
2. 泛型方法可以接受不同类型的参数,根据泛型方法的参数类型,编译器适当处理每一个方法调用
以下就为一个简单的泛型方法演示
public class GenericMethodTest {
/**
* 泛型方法 printArray
* @param inputArray
*/
public static <E> void printArray(E[] inputArray) {
for (E element : inputArray){
System.out.printf("%s", element);
System.out.printf(" ");
}
System.out.println();
}
public static void main(String[] args) {
// 创造不同类型数组 Integer , Double 和 Character
Integer[] integers = {1,2,3,4,5,6};
Double[] doubles = {1.1,1.2,1.3,1.4,1.5};
Character[] characters = {'G','D','C','A'};
//输出不同类型是数组
System.out.println("输出Interger类型的数组");
printArray(integers);
System.out.println(" ");
System.out.println("输出Double类型的数组");
printArray(doubles);
System.out.println(" ");
System.out.println("输出Character类型的数组");
printArray(characters);
System.out.println(" ");
}
}
我们通过定义<E>
作为声明变量,这个声明变量可以理解为Integer,Double 等引用型类型的大集合。
例如:当你传入的类型为Integer时,这个<E>
就为Integer去计算printArray函数,自动替换函数中的E
。
当传入的类型不同,<E>
就不同,这样我们就可以通过不同的传入类型去实现同一段代码的重复使用了,这样做可以大大提高代码的可用性。
2. 带限制类型的泛型方法
试想一下如下情况,当我需要比较3个变量的大小时,是不是就需要3个变量都为同一类型?不然就会出现难以比较的情况。所以我们需要用到如下定义方法:
<T extends Comparable<T>>
这种定义方式就可以实现3种变量都圈定为同一类型,以下为一个简单的代码演示:
public class MaximumTest {
/**
* 第一个T 代表泛型
* 第二个T 代表与第一个 T 对比
* 第三个 T 代表返回值
*
* @param x
* @param y
* @param z
* @return
*/
public static <T extends Comparable<T>> T Maximum(T x,T y,T z){
T max = x;
/**
* compareTo()方法
* 如果指定的数与参数相等返回0。
* 如果指定的数小于参数返回 -1。
* 如果指定的数大于参数返回 1。
*/
if (y.compareTo(max) > 0) {
max = y;
}
if (z.compareTo(max) > 0) {
max = z;
}
return max;
}
public static void main(String[] args) {
//判断三个整数之间的最大数
System.out.printf("%d, %d, %d 三个数最大的数字为%d\n\n",3,4,5,Maximum(3, 4, 5));
//判断三个浮点数之间的最大值
System.out.printf("%.1f, %.1f, %.1f 三个数最大的数字为%.1f\n\n",1.1,1.2,1.3,Maximum(1.1,1.2,1.3));
//判断三个字符串的最大值
System.out.printf("%s, %s, %s 三个数最大的数字为%s\n\n","apple","pear","orange",Maximum("apple","pear","orange"));
}
}
这里的Comparable 需要理解为一个接口,通过实现其内部的compareTo()方法来判断每次输入的值是否为同一类型,如果为不同类型就不能通过编译。
3 .泛类
不仅方法内可以添加声明变量,一个类也可以通过添加声明变量成为一个泛类。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
以下是一个简单的泛类演示:
/**
*
* @author 72921
*
* 在类的后面加上<T>(类型参数声明部分) 标志即表示该类为泛类
* T 可以接受不同的类型及内容
*
* @param <T>
*/
public class Box<T> {
private T t;
public void add(T t){
this.t = t;
}
public T get(){
return t;
}
public static void main(String[] args) {
Box<Integer> intergerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
/**
* 为两个不同的类插入不同的内容
*/
intergerBox.add(10086);
stringBox.add("这是一个测试内容");
/**
* 输出结果
*/
System.out.println("intergerBox输出内容: "+intergerBox.get());
System.out.println("stringBox输出内容: "+stringBox.get());
}
}
我们通过<T>
声明变量定义了一个Box泛类,通过实现2个带不同传入类型的泛类对象说明泛类的用途和使用。
Box<Integer> intergerBox = new Box<Integer>();
Integer就限定了该类为Integer类型,T就可以用Integer替代计算。
intergerBox.add(10086);
这样插入是正确的,当你插入float 或者 String 类型的时候编译将不通过。
4 .通配符
类型通配符一般是使用?代替具体的类型参数。例如 List<?>
在逻辑上是List<String>,List<Integer>
的实现父类。
以下是简单的通配符演示:
import java.util.ArrayList;
import java.util.List;
public class GenericTest {
public static void main(String[] args) {
/**
* 类型通配符一般是使用?代替具体的类型参数。
* 例如 List<?> 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类。
*/
List<String> name = new ArrayList<String>();
List<Integer> age = new ArrayList<Integer>();
List<Number> number =new ArrayList<Number>();
name.add("这是一条测试数据");
age.add(15);
number.add(301);
/**
* 使用 getData 函数输出
*/
getData(name);
getData(age);
getData(number);
/**
* 使用 getNumberData 函数输出
* extends Number 限制了输出仅可是 Number
*/
//getNumberData(name);
getNumberData(age);
getNumberData(number);
}
public static void getData(List<?> list) {
System.out.println("data:"+list.get(0));
}
public static void getNumberData(List<? extends Number> list){
System.out.println("data:"+list.get(0));
}
}
我们定义3个不同传入类型的List,然后往里添加三条不同类型的数据。通过getData函数输出其内容。
getData的参数List<?> list
就匹配了所有的List<all>
,这样你只需要编写一个函数就可以把所有的List的内容都输出出去。
同样,我们也可以通过List<? extends Number>
的方式来限制我们想要输出的数据是否同步。
演示中getNumberData如此定义就是通配符泛型值接受Number及其下层子类类型。所以不能输出String类型的数据。