Java基础01-泛型详解
一、为什么要使用泛型
在java1.5之前,如果想通过一种通用的方法完成对不同参数的调用,那么只能通过创建Object数组来加入不同类型的参数变量。
Object[] element=new Object[10];
添加数字:
element.add(1);
添加字符串:
element.add("abc");
但是这样就会出现几个问题
1.元素加入object数组后,元素将以object类型存放在数组中,这时如果我们需要取出使用该元素,就必须对其进行强制类型转换。
2.由于任何类型的元素都可以存入object数组,因此在我们无法确定存入元素类型的情况下,取出时就需要进行类型转换。但这样会出现一个问题,当我们忘记进行类型转换时,编译器不会报错,但在运行时却会出现异常。我们希望在编译时就能发现错误,来提高效率,因此泛型便诞生了。
二、泛型的使用
泛型可以分为以下几种
1.泛型类
class Example<T>{
private T key;
public Example(T key){
this.key=key;
}
public T getKey(){
return key;
}
}
Example <Integer> exInt=new Example <Integer>(123);
Example <String> exStr=new Example <String>("qwe");
System.out.println(exInt.getKey());
System.out.println(exStr.getKey());
注:泛型的类型参数只能是类类型而不能是基本数据类型,原因在于泛型要求包容的是对象类型,而基本数据类型不属于。不过我们可以通过基本类型的封装类来存放基本类型,八大基本类型的封装类如下:
简单类型 | boolean | byte | char | short | int | long | float | double |
---|---|---|---|---|---|---|---|---|
二进制位数 | 1 | 8 | 16 | 16 | 32 | 64 | 32 | 64 |
封装器类 | Boolean | Byte | Character | Short | Integer | Long | Float | Double |
2.泛型接口
interface a1<T>{
public T next();
}
关于接口的实现:
1.当无泛型实参时
class a2<T> implements a1<T>{}
2.当有泛型实参时
class a3 implements a1<String>{}
3.类型通配符
(1).提出
假如我们需要定义一个方法,方法中有一个集合形参,而我们不知道其数据类型,这时就需要用到类型通配符了。
(2).使用
通配符包括:
a.无限定通配符
<?>
例如 List<?>,“?”可以表示任何类型,即也可以表示未知类型。
区别 List<?>和List,二者并不等同:
List<?>是所有泛型类型的父类,任何引用类型的List都可以传入,其类型是Object。但不能向其中添加对象,除了null。
为什么不能添加对象?
举个栗子:
List<String> l1=new ArrayList<String>();
List<?> l2=l1;
l1.add("abc"); //正确
l2.add("abc"); //错误
现在我们假设l2.add("abc"); 是正确的
那么 l2.add(123); 也是正确的
由于把l1赋值给了l2,那么l1和l2便指向了同一块内存地址,但是l1只能存放String类型的对象,如果l2可以存放String类型,那么l2也可以存放Integer类型,这和l1定义的类型发生了冲突。
List是具体化的泛型,只能是引用数据类型,可以在其中添加Object类及其子类对象。
b.上边界通配符
Vector<? extends 类型1> x=new Vector<类型2>();
其中,类型2和类型1一致或类型2为类型1子类。
c.下边界通配符
Vector <? super 类型1> x=new Vector<类型2>();
其中,类型2和类型1一致或类型2为类型1父类。
4.泛型方法
(1).无返回值类型
public <T> void text(T t3){
T t3=t3;
}
(2).有返回值类型
public <T> text(T t3){
T t3=t3;
return t3;
}
注:泛型方法必须要有public 标识符
举个栗子
public class Test {
static class Fruit{
public String toString(){
return "Fruit";
}
}
static class Apple extends Fruit{
public String toString(){
return "Apple";
}
}
static class Person{
public String toString(){
return "Person";
}
}
static class Test1<T>{
//这不是泛型方法
public void show(T t){
System.out.println(t.toString());
}
//这是泛型方法
public <T> void show2(T t){
System.out.println(t.toString());
}
}
public static void main(String[] args) {
Apple apple=new Apple();
Person person=new Person();
Test1<Fruit> test=new Test1<Fruit>();
test.show(apple); //正确,因为apple是Fruit的子类
test.show(person); //错误
test.show2(apple);
test.show2(person); //二者都正确
}
}