文章目录
- 一 包装类
- 1.1 包装类的概念
- 1.2 装箱/装包
- 1.3 拆箱/拆包
- 1.4 一个面试题:
- 二 泛型
- 2.1 什么是泛型?
- 2.2 泛型的使用
- 2.3 泛型的上界
- 2.4 泛型实现Comparable接口
- 2.5 擦除机制
- 另外:
一 包装类
1.1 包装类的概念
在java中基本数据类型并不继承于Object,为了在泛型代码中支持基本数据类型,对每一个基本数据类型都对应了一个包装类。
如图所示,除int类型与char类型外,其余的包装类名均是数据类型名首字母大写!
1.2 装箱/装包
装箱是指将基本数据类型的值转换成包装类类型
进行装箱的方法:valueOf
int a = 10;
//装箱成Integer类型
Integer i = Integer.valueOf(a);
System.out.println(i);
Integer i2 = 10; //隐式装箱
System.out.println(i2);
隐式装箱的原理:
如图所示:第一个valueOf方法是我们自己调用的
而第二个valueOf方法是系统默认调用的,即在隐式装箱时,系统默认调用了valueOf方法!
能否装箱成Double封装类?
int a = 10;
Double double1 = Double.valueOf(a);
总结:即使不是对应的包装类,也可以进行装箱。
1.3 拆箱/拆包
拆箱即将数据从包装类类型转换成基本数据类型
拆箱的方法:intValue()方法
Integer a3 = 10;
int i1 = a3.intValue(); //拆箱
int i2 = a3; //自动拆箱
// 观察本质实现,实际上是调用了intValue()方法.
System.out.println(i1);
System.out.println(i2);
隐式拆箱的原理:
第一个intValue方法是显式装箱,第二个intValue方法是隐式装箱,系统自动调用intValue方法!
1.4 一个面试题:
判断下面两个布尔表达式的值是什么?
Integer a4 = 100;
Integer a5 = 100;
System.out.println(a4==a5);
Integer a6 = 200;
Integer a7 = 200;
System.out.println(a6==a7);
为什么会出现这个结果?
要查看原理,就要看valueOf方法是怎样实现的!
代码解析:
如果传入的实参i值 在IntegerCache.low这个值与IntegerCache.high这个值范围之内,就返回
IntegerCache.cache这个数组中相应数组元素的内容。
如果不在这个范围之内,就新创建一个对象并返回。
二 泛型
2.1 什么是泛型?
对于一般的方法与变量,只能使用具体的类型:自定义类型与基本数据类型,但是如果要写适用于多种类型的代码,这种刻板的方式对代码的束缚就很大,我们可以通过泛型来解决这个问题,本质就是将类型参数化!
2.2 泛型的使用
举例:创建一个有数组成员的类:创建两个方法,一个为数组赋值,一个获取数组的值!
1 .我们似乎可以不使用泛型,通过Object类使用一段代码接收所有类型的数据!
//普通类
class MyArray{
public Object [] arrays = new Object[10];
//为数组设置值!
public void setValue(int pos, Object o ){
arrays[pos] = o;
}
public Object getValue(int pos){
return arrays[pos];
}
}
public class Test {
public static void main(String[] args) {
MyArray myArray = new MyArray();
myArray.setValue(0,10);
myArray.setValue(1,"hello");
System.out.println(myArray.getValue(0));
System.out.println(myArray.getValue(1));
}
}
但是这种一个数组中存储多种不同类型数据的方式太乱
我们可以通过指定参数类型来限制数据类型。
- 通过泛型类使用泛型
//泛型类:
//<E>可以看作一个占位符,代表将传入的类型
//在类名后面加<>,
class MyArray<E> {
//创建一个数组
public Object[] arrays = new Object[10];
public E [] arrays2 = (E[])new Object[5] ; //也可以这样创建一个数组!!!
//不能直接实例化E!
//为数组设置值!
public void setValue(int pos, E o) { //限定传入的参数类型
arrays[pos] = o;
}
public Object getValue(int pos) {
return (E) arrays[pos]; //将返回的数据强制转换成指定的数据类型
}
}
public class Test {
public static void main(String[] args) {
MyArray<Integer> myArray = new MyArray<>();
myArray.setValue(0,10);
// myArray.setValue(1,"zhangsan");//只能传入整型值!
System.out.println(myArray.getValue(0));
}
}
- 使用泛型方法而不是泛型类!
class MyArray {
//创建一个数组
public Object[] arrays = new Object[10];
//为数组设置值!
public <E> void setValue(int pos, E o) { //限定传入的参数类型
arrays[pos] = o;
}
public <E> Object getValue(int pos) {
return (E) arrays[pos]; //将返回的数据强制转换成指定的数据类型
}
}
public class Test {
public static void main(String[] args) {
MyArray myArray = new MyArray();
//在将<>放在调用的方法名之前,进行传参
myArray.<Integer>setValue(0,5);
System.out.println(myArray.<Integer>getValue(0));
}
}
3.2 使用静态方法,这样可以不创建对象也可以调用方法!
class MyArray {
//创建一个数组
public static Object[] arrays = new Object[10];
//为数组设置值!
public static <E> void setValue(int pos, E o) { //限定传入的参数类型
arrays[pos] = o;
}
public static <E> Object getValue(int pos) {
return (E) arrays[pos]; //将返回的数据强制转换成指定的数据类型
}
}
public class Test {
public static void main(String[] args) {
MyArray.<Integer>setValue(0,2);
}
}
2.3 泛型的上界
//泛型的上界是指:泛型中指定的类型必须是一个类本身或者这个类的子类,此时这个类即泛型的上界。
class Person<E extends Number>{
}
此时E代表的类型,必须是Number类本身或者Number的子类。
如果E 继承的是接口,则E代表的类型必须实现了此接口!
2.4 泛型实现Comparable接口
1. 泛型类型的变量不能够直接相互用关系运算符进行比较,因为不能确定是什么类型,所以需要实现Comparable口的类型
2. Object类中并没有实现Comparable接口,所以自定义的类中必须自己去实现Comparable接口!
3. 包装类自己已经实现了自动类接口
class Alg<E extends Comparable<E>> {
public E max(E[] arrays ){
E max = arrays[0];
for (int i = 1; i < arrays.length ; i++) {
if(max.compareTo(arrays[i])<0){
max = arrays[i];
}
}
return max;
}
}
public class Test {
public static void main(String[] args) {
//泛型类实现Comparable接口:
Integer [] arrays = {1,5,4,2,3,8,9,6};
//Integer实现了comparable接口
Alg<Integer> alg = new Alg<>();
System.out.println(alg.max(arrays));
}
如果换成Person类:
此时报错:是因为Person类没有实现Comparable接口,不符合作为实参的条件!
2.5 擦除机制
另外:
在泛型类中,<>中的类型不参与类型的组成!
MyArray<Integer>myArray1 = new MyArray<>();
MyArray<String> myArray2 = new MyArray<>();
System.out.println(myArray1);
System.out.println(myArray2);
结果表明,与并没有参与到类型的组成中去,myArray1与myArray2的类型依然是
MyArray类型!