遇到布懂的就收藏下来,学完一遍后返回再看一遍就好了,加油!
一、Java泛型是什么
Java 泛型(generics)是 JDK 5 中引入的一个新特性,
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,然后在使用的时候/调用的时传入具体的类型。
二、泛型有什么用
泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
如下代码中,不使用泛型:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* 需求:collection集合存储字符串并遍历
*/
public class GenericDemo01 {
public static void main(String[] args) {
Collection c=new ArrayList();
//添加元素
c.add("Hello");
c.add("World");
c.add("Algorithm");
//添加不同类型的元素
c.add(100);
//遍历集合
//这样是正确的:
// Iterator it=c.iterator();
// while(it.hasNext()){
// Object obj=it.next();
// System.out.println(obj);
// }
//这样是错误的:
Iterator it=c.iterator();
while(it.hasNext()){
String s=(String)it.next();//ClassCastException
System.out.println(s);
//上面添加类型时可以任意添加,但是在我们写代码的时候可能只是以为只有String一种类型,这时就会出现类型转化异常
}
/*错误的输出:
Hello
World
Algorithm
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at com.ArrayListTest.GenericDemo01.main(GenericDemo01.java:28)
*/
}
}
使用泛型后的对比:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* 需求:collection集合存储字符串并遍历
*/
public class GenericDemo01 {
public static void main(String[] args) {
Collection<String> c=new ArrayList<>();
//添加元素
c.add("Hello");
c.add("World");
c.add("Algorithm");
//添加不同类型的元素
// c.add(100);//此时 此处会报错,在编译前就发现错误
//遍历集合
Iterator<String> it=c.iterator();
while(it.hasNext()){
String s=it.next();//此处也就不用强制类型转换
System.out.println(s);
}//这样是错误的
}
}
泛型可以用在类、方法和接口中,分别被称为泛型类、泛型方法和泛型接口。
好处: 把运行期的问题提前到编译器,避免强制类型转换。
三、泛型定义格式
<类型> :指一种类型的格式。这里的类型可以看成形参
<类型1,类型2…> :指多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成形参。
举例:
Collection<String> c=new ArrayList<String>();
HashMap<String,String> hm=new HashMap<String,String>();
泛型具体应用:
1. 泛型方法
定义格式:修饰符 <类型> 返回值类型 方法名 (类型 变量名)
eg:public <T> void show(T t){ }
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前
- 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。
- 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。
实例:
public class GenericMethodTest {
// 泛型方法 printArray
public static < E > void printArray( E[] inputArray )
{
// 输出数组元素
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
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' };
System.out.println( "整型数组元素为:" );
printArray( intArray ); // 传递一个整型数组
System.out.println( "\n双精度型数组元素为:" );
printArray( doubleArray ); // 传递一个双精度型数组
System.out.println( "\n字符型数组元素为:" );
printArray( charArray ); // 传递一个字符型数组
}
}
2. 泛型类
- 泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。
- 和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。
下面用一个实例来说明泛型类的定义格式:
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> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(11));
stringBox.add(new String("泛型类定义"));
System.out.printf("整型值为 :%d\n\n", integerBox.get());
System.out.printf("字符串为 :%s\n", stringBox.get());
}
}
3. 泛型接口
定义格式:修饰符 interface 接口名<类型>{ }
示例:public interface Generic<T>{ }
具体实现可以参照List接口的实现类
如下实例:
定义一个接口Generic
public interface Generic<T> {
void show(T t);
}
一个实现类:
public class GenericImol<T> implements Generic<T> {
@Override
public void show(T t) {
System.out.println(t);
}
}
一个测试类:
public class GenericDemo {
public static void main(String[] args) {
Generic<String> g1=new GenericImol<String>();
g1.show("泛型接口示例");
Generic<Integer> g2=new GenericImol<Integer>();
g2.show(666);
Generic<Double> g3=new GenericImol<Double>();
g3.show(66.6);
}
}
类型通配符
类型通配符: <?>
- 如:List<?> 表示类型未知的List 。它的元素可以匹配任意类型。
说明:带通配符的List仅表示是List,List 等所有List<具体类型实参>的父类。
如下实例:
import java.util.ArrayList;
import java.util.List;
public class GenericDemo02 {
public static void main(String[] args) {
List<String> name=new ArrayList<>();
List<Integer> age=new ArrayList<>();
List<Number> number=new ArrayList<>();
name.add("Generic");
age.add(666);
number.add(111);
getData(name);
getData(age);
getData(number);
}
public static void getData(List<?> data){
System.out.println("data:"+data.get(0));
}
}
getData的参数是List类型的,所以当name,age,number作为方法实参只因为通配符的作用。
- 如果不希望List<?>是任何泛型List的父类,只希望它代表一类泛型 list 的父类,可以使用类型通配符的上限
类型通配符上限:<? extends 类型>
例如:List<? extends Number> 表示的类型是Number或其子类型。
类型通配符下限: <? super 类型>
例如:List<? super Number> 表示的类型是Number或其父类型。
实例演示:
import java.util.ArrayList;
import java.util.List;
public class GenericDemo03 {
public static void main(String[] args) {
//类型通配符 <?>
List<?> list1=new ArrayList<Object>();
List<?> list2=new ArrayList<Number>();
List<?> list3=new ArrayList<Integer>();
//类型通配符上限 <?>
//List<? extends Number> list4=new ArrayList<Object>();//会报错
List<? extends Number> list5=new ArrayList<Integer>();
List<? extends Number> list6=new ArrayList<Double>();
List<? extends Number> list7=new ArrayList<Number>();
//类型通配符下限
//List<? super Number> list8=new ArrayList<Integer>();//会报错
List<? super Number> list9=new ArrayList<Number>();
List<? super Number> list10=new ArrayList<Object>();
}
}