1.包装类
在Java中,由于基本类型不是继承自Object,为了在泛型代码中科一支持基本类型,Java给每个基本类型都对应了一个包装类型。
1.1基本数据类型和对应的包装类
基本数据类型 | 包装类 |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
除了Integer和Character,其余基本类型的包装类都是首字母大写。
1.2 装箱和拆箱
int i=10;
//装箱操作:新建一个Integer对象,将i的值放入对象的某个属性中
Integer ii=Integer.valueOf(i);
Integer jj=new Integer(i);
//拆箱操作:将Integer对象中的值去除,放到一个基本数据类型中
int j=ii.intValue();
1.3 自动装箱和自动拆箱
自动装箱拆箱减少了不小的代码量,减少了开发者的负担。
int i=10;
//自动装箱
Integer ii=i;
Integer jj=(Integer)i;
//自动拆箱
int j=ii;
int k=(int)ii;
2.什么是泛型
一般的类和方法,只能使用具体的类型,要么是基本类型,要么是自定义的类,如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。所以JDK1.5引入了新的语法泛型:就是适用于许多许多类型。从代码上讲,就是对类型实现了参数化。
3.引出泛型
class MyArray{
public Object[]array=new Object[10];
public Object getPos(int pos){
return this.array[pos];
}
public Object setVal(int pos,Object val){
return this.array[pos]=val;
}
}
public class Main {
public static void main(String[] args) {
MyArray myArray=new MyArray();
myArray.setVal(0,10);
myArray.setVal(1,"123");//字符串也可以存放
String ret=myArray.getPos(1);//编译报错
System.out.println(ret);
}
}
实现代码后可以看到
1.确实任何类型数据都可以存放
2.1号位下标存放的是字符串,但编译却报错,必须强制类型转换
3.1 语法
class 泛型类名称 < 类型形参列表 > {// 这里可以使用类型参数}class ClassName < T1 , T2 , ..., Tn > {}class 泛型类名称 < 类型形参列表 > extends 继承类 /* 这里可以使用类型参数 */ {// 这里可以使用类型参数}class ClassName < T1 , T2 , ..., Tn > extends ParentClass < T1 > {// 可以只使用部分类型参数}
上述代码改写如下
class MyArray<T> {
public T[] array = (T[])new Object[10];//1
public T getPos(int pos) {
return this.array[pos];
}
public void setVal(int pos,T val) {
this.array[pos] = val;
}
}
public class TestDemo {
public static void main(String[] args) {
MyArray<Integer> myArray = new MyArray<>();//2
myArray.setVal(0,10);
myArray.setVal(1,12);
int ret = myArray.getPos(1);//3
System.out.println(ret);
myArray.setVal(2,"bit");//4
}
}
代码解释:
类名后的<T>代表占位符,便是当前类是一个泛型类。
4.泛型类的使用
4.1语法
泛型类 < 类型实参 > 变量名 ; // 定义一个泛型类引用new 泛型类 < 类型实参 > ( 构造方法实参 ); // 实例化一个泛型类对象
4.2 实例
MyArray<Integer> list = new MyArray<Integer>();
注意:泛型只能接受类,所有的基本类型都必须使用包装类。
4.3 类型推导
当编译器可以根据上下文推导出类型实参时,可以省略类型实参的填写
MyArray<Integer> list = new MyArray<>();
5.泛型如何编译的
5.1 为什么不能实例化泛型类型数组
class MyArray<T> {
public T[] array = (T[])new Object[10];
public T getPos(int pos) {
return this.array[pos];
}
public void setVal(int pos,T val) {
this.array[pos] = val;
}
public T[]getArray(){
return array;
}
}
public class TestDemo {
public static void main(String[] args) {
MyArray<Integer> myArray = new MyArray<>();
Integer[] strings=myArray1.getArray();
}
}
这个程序会报错,因为替换后的方法:将Object[]分配给Integer[]引用,所以程序报错了。
通俗讲,任何数据类型都可以返回到Object数组里面,可以说String,可以是Person,上述代码中,运行时候,直接转给了Integer类型的数组,编译器认为是不安全的
正确的方法:
class MyArray<T> {
public T[] array;
public MyArray() {
}
/**
* 通过反射创建,指定类型的数组
* @param clazz
* @param capacity
*/
public MyArray(Class<T> clazz, int capacity) {
array = (T[])Array.newInstance(clazz, capacity);
}
public T getPos(int pos) {
return this.array[pos];
}
public void setVal(int pos,T val) {
this.array[pos] = val;
}
public T[] getArray() {
return array;
}
}
public static void main(String[] args) {
MyArray<Integer> myArray1 = new MyArray<>(Integer.class,10);
Integer[] integers = myArray1.getArray();
}
6.泛型的上界
在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束
7.1 语法
class 泛型类名称<类型形参 extends 类型边界>{
.....
}
举例:
public class MyArray<E extends Number>{
....
}
所以上述代码只接受Number的子类型作为E的类型实参
MyArray<Integer>l1;//正常,因为Integer时Number的子类型
MyArray<String>l2; //编译错误,因为String不是Number的子类型
如果没有指定类型边界E,那么默认为E extends Object;
7.泛型方法
7.1 定义语法
方法限定符<类型形参列表> 返回值类型 方法名称(形参列表){....}
7.2 举例
public class Util {// 静态的泛型方法 需要在 static 后用 <> 声明泛型类型参数public static < E > void swap ( E [] array , int i , int j ) {E t = array [ i ];array [ i ] = array [ j ];array [ j ] = t ;}}
7.3类型推导
可以类型推导
Integer[] a = { ... };swap(a, 0, 9);String[] b = { ... };swap(b, 0, 9);
不使用类型推导
Integer[] a = { ... };Util.<Integer>swap(a, 0, 9);String[] b = { ... };Util.<String>swap(b, 0, 9);
以上就是泛型的基本内容啦,喜欢就点个赞吧!