泛型的详解
泛型:就是适用于很多类型
一、引出泛型
不使用泛型
class MyArray{
private Object[] arrays = new Object[10];
//实现两个功能
public void setValue(int pos,Object value){
arrays[pos] = value;
}
public Object getValue(int pos){
return arrays[pos];
}
}
public class Main0928_1 {
public static void main(String[] args){
MyArray myArray = new MyArray();
myArray.setValue(0,4);
myArray.setValue(1,"hello");
myArray.setValue(2,2.6);
myArray.setValue(3,new Object());
System.out.println(myArray.getValue(0));
System.out.println(myArray.getValue(1));
System.out.println(myArray.getValue(2));
System.out.println(myArray.getValue(3));
}
}
使用泛型之后
class MyArray01<T>{
private T[] arrays = (T[])new Object[10];
//实现两个功能
public void setValue(int pos,T value){
arrays[pos] = value;
}
public T getValue(int pos){
return arrays[pos];
}
}
public class Main0928_2 {
public static void main(String[] args) {
//泛型的目的是在编译阶段,让编译器去给我们做检查
MyArray01<Integer> myArray = new MyArray01<>();
myArray.setValue(0,1);
}
}
代码解释 :
1、泛型的目的是在编译阶段,让编译器去给我们做检查
2、类名后的<T>代表占位符,表示当前类是一个泛型类
3、不能new泛型类型的数组
二、泛型的上界
在定义泛型时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束
class 泛型类名称 <类型形参 extends 类型边界>{
......
}
例如:
public class MyArray<E extends Number>{
......
}
即只接受Number的子类作为E的类型实参
复杂实例:
public class Calculator<E extends Comparable<E>>{
public E findMax(E[] arr){
E max = arr[0];
if(arr.length == 0){
throw new RuntimeException("数据为空");
}
for(int i = 1;i < arr.length;i++){
if(max.compareTo(arr[i]) < 0){
max = arr[i];
}
}
return max;
}
public int findMax(int[] arr){
int max = arr[0];
if(arr.length == 0){
throw new RuntimeException("数据为空");
}
for(int i = 1;i < arr.length;i++){
if(max < arr[i]){
max = arr[i];
}
}
return max;
}
}
即E是必须实现了 Comparable 接口的
三、泛型方法
1、定义语法
方法限定符 <类型形参列表> 返回值类型 方法名称 (形参列表) {...
2、示例
class Calculator1{
//泛型方法的定义
public <E extends Comparable<E>> E findMax(E[] arr){
E max = arr[0];
if(arr.length == 0){
throw new RuntimeException("数据为空");
}
for(int i = 1;i < arr.length;i++){
if(max.compareTo(arr[i]) < 0){
max = arr[i];
}
}
return max;
}
public static <E extends Comparable<E>> E findMax1(E[] arr){
E max = arr[0];
if(arr.length == 0){
throw new RuntimeException("数据为空");
}
for(int i = 1;i < arr.length;i++){
if(max.compareTo(arr[i]) < 0){
max = arr[i];
}
}
return max;
}
}
四、通配符
?用于在泛型的使用,即为通配符
当可以接收所有的泛型类型,但是又不能够让用户随意修改,这种情况下就需要使用通配符“?”来处理
1、通配符上界
<? extends 上界>
<? extends Number>//可以传入的实参类型是Number或者Number的子类
注:通配符的上界,不能进行写入数据,只能读取数据,因为此时存储的元素应该是哪个子类无法确定
2、通配符下界
<? super 下界>
<? super Integer>//可以传入的实参类型是Integer或者Integer的父类
注:通配符的下界,不能进行读取数据,只能写入数据
五、包装类
在Java中,由于基本类型不是继承自Object,为了在泛型代码中可以支持基本类型,Java给每个基本类型都对应了一个包装类型
1、基本数据类型和对应的包装类
基本数据类型 | 包装类型 |
byte | java.lang.Byte |
short | java.lang.Short |
int | java.lang.Integer |
long | java.lang.Long |
float | java.lang.Float |
double | java.lang.Double |
boolean | java.lang.Boolean |
char | java.lang.Character |
除了Integer和Character,其余基本类型的包装类都是首字母大写
2、装箱和拆箱
public class Main0929_2 {
public static void main(String[] args) {
//Integer里面有缓存机制,范围是-128到127
Integer a1 = 127;
Integer a2 = 127;
Integer b1 = 128;
Integer b2 = 128;
System.out.println(a1 == a2);//true,a1和a2是同一个对象
System.out.println(b1 == b2);//false,b1和b2不是同一个对象
Integer aa = new Integer(127);
System.out.println(a1 == aa);//false,aa和a1不是同一个对象
}
public static void main1(String[] args) {
//自动装箱,默认自动调用Integer.valueOf(),返回一个Integer对象
Integer a = 1;
//自动拆箱,默认自动调用Integer.intValue(),返回一个int类型的数据
Integer b = new Integer(1);
int b1 = b;
System.out.println(a);
System.out.println(b);
System.out.println(b1);
}
}