包装类
在Java中,由于基本类型不是继承自Object,为了在泛型代码中可以支持基本类型,Java给每个基本类型都给了一个包装类型
基本数据类型和对应的包装类
基本数据类型 | 包装类 |
Byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
装箱和拆箱
什么是装箱:把基本数据类型变为包装类类型的过程
public static void main1(String[] args) {
Integer a=10;
Integer i=Integer.valueOf(a);//显示装箱
Integer i2=10;
Double d =Double.valueOf(a);
什么是拆箱:把包装类型变为基本类型的过程
public static void main2(String[] args) {
Integer a =10;
int b=a;//自动拆箱
int c=a.intValue();
double d=a.doubleValue();
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
}
面试题(阿里巴巴)
判断以下代码的结果
小tips:装箱调用的值不一样
public static void main(String[] args) {
Integer a =100;
Integer b=100;
System.out.println(a==b);
Integer c =200;
Integer d =200;
System.out.println(c==d);
}
什么是泛型
一般的类和方法,只能使用具体的类型,要么是具体的类型,要么是自定义的类,如果要编写可以应用于多种类型 的代码,这种刻板的限制对代码的束缚就会很大
通俗讲,泛型就是适用于许多许多类型,从代码上讲,就是对类型实现了参数化(可以直接传入类型)
引出泛型
【实例1】
实现一个类,类中包含一个数组成员,使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个下标的值(Object类是所有类的父类)
实例代码:
class MyArray{
public Object[] array=new Object[10];
public void setvalue(int pos,Object val){
array[pos]=val;
}
public Object getVaL(int pos){
return array[pos];
}
}
public class Test {
public static void main(String[] args) {
MyArray myArray=new MyArray();
myArray.setvalue(0,10);
myArray.setvalue(1,"hello");
String str=(String) myArray.getVaL(1);
System.out.println(str);
//或者 Object str= myArray.getVaL(1);
}
}
解析:
问题:以上代码实现后发现
- 任何类型的数据都可以存放
- 1号下标本身就是字符串,但是编译报错,必须进行强制类型转换
虽然在这种情况下任何数据都可以存放,但是更多情况下,我们还是希望他只能持有一种数据类型,所以,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象,让编译器去做检查。此时就要把类型作为参数传递
语法
class 泛型类型<类型 形参列表>{
这里可以使用类型参数
}
class ClassName<T1,T2,...,Tn>{
}
实例代码:
//<E>是一个占位符,表示当前类是一个泛型
class MyArray<E>{
public Object[] array=new Object[10];
public void setvalue(int pos,E val){
array[pos]=val;
}
public E getVaL(int pos){
return (E) array[pos];
}
}
public class Test {
public static void main(String[] args) {
MyArray <Integer> myArray=new MyArray<Integer>();
//相当于给系统提供了一个限制:myArray只能是整数
myArray.setvalue(0,10);
myArray.setvalue(1,20);
Integer a =myArray.getVaL(1);//自动类型转换
System.out.println(a);
System.out.println("==========");
MyArray<String> myArray1 =new MyArray<>();
myArray1.setvalue(0,"hello");
myArray1.setvalue(1,"abc");
String str=myArray1.getVaL(0);//
System.out.println(str);
// myArray.setvalue(1,"hello");//自动类型检查
}
}
解析:
泛型存在的最大意义:可以指定放什么类型的数据,输入数据的时候会自动类型检查,取的时候会自动类型转换,把类型作为参数进行传递
类名后的<T>代表占位符,表示当前类是一个泛型类(泛型必须是包装类)
了解:【规范】类型 形参一般使用一个大写字母表示,常用的名称有:
- E表示Element
- K表示Key
- V表示Value
- N表示Number
- T表示Type
- S,U,V等等 第二,第三,第四个类型
泛型类的使用
泛型类<类型实参>变量名;//定义一个泛型类引用
new 泛型类<类型实参>(构造方法实参);//实例化一个泛型类对象
示例
MyArray <Integer> myArray=new MyArray<Integer>();
注意:泛型只能接收类,所有的基本数据类型必须使用包装类!
类型推导(Type Inference)
当编译器可以根据上下文推导出实参时,可以省略类型实参的填写
MyArray <Integer> myArray=new MyArray<>();//可以推导出实例化需要的类型实参为Integer
裸类型(Raw Type)
裸类型是一个泛型类但没有带着类型实参,例如:
MyArray myArray=new MyArray();
注意: 我们不要自己去使用裸类型,裸类型是为了兼容老版本 API 保留的机制
【实例1】代码:
public static void main(String[] args) {
MyArray myArray=new MyArray();
//相当于给系统提供了一个限制:myArray只能是整数
myArray.setvalue(0,10);
myArray.setvalue(1,20);
myArray.setvalue(1,"fadd");
Integer a =(Integer)myArray.getVaL(1);//自动类型转换
System.out.println(a);
}
实例1代码解析:
小结:
- 泛型是将数据类型参数化,进行传递(参数化意思就是可以当做参数被传递)
- 使用<T>表示当前类是一个泛型类
- 泛型目前为止的优点:数据类型参数化,编译时自动进行类型检查和转换
泛型如何编译的
泛型是编译时期的一种机制,在运行的时候,没有泛型的概念【JVM当中没有泛型的概念】
擦除机制
编译完成以后,生成的字节码中,<E>被擦除为Object类了
【实例1】代码
public static void main(String[] args) {
/* Test test=new Test();
System.out.println(test);*/
MyArray <Integer> myArray=new MyArray<Integer>();
MyArray<String> myArray1 =new MyArray<>();
System.out.println(myArray);
System.out.println(myArray1);
}
代码解析:
泛型的上界
在定义泛型类时,有时需对传入的类型变量做一定的约束,可以通过类型边界来约束
语法
class 泛型类名称<类型形参extends类型边界>{
...
}
【实例1】
public class MyArray<E extends Number>{
...
}
复杂示例
public class MyArray<E extends Comparable<E>>{
...
}
E必须是实现了Comparable接口的