泛型与包装类密切相关,在学习泛型前先了解了解包装类吧
包装类
包装类是对应着各种基本数据类型进行包装后产生的引用数据类型 ,是基本数据类型的plus版本。
为什么要设计包装类
因为 Java是一个面向对象的编程语言,但是Java中的八种基本数据类型却是不面向对象的,为了使用方便和解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八种基本数据类型对应的类统称为包装类(Wrapper Class),包装类均位于java.lang包。
包装类的用处
对于包装类说,用途主要包含两种:
- 作为基本数据类型对应的类 类型存在,方便涉及到对象的操作。
- 包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法。
1、基本数据类型和对应的包装类
基本数据类型 | 包装类 |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
除了 Integer 和 Character, 其余基本类型的包装类都是首字母大写。
2、包装类的使用
(1)装箱和拆箱
装箱:建立包装类对象,将对应基本数据类型放入对象属性中
int i=10;
Integer i1=Integer.valueOf(i);
Integer i2=new Integer(100);
拆箱:将包装类对象的属性值取出放入对应基本数据类型中
int j=i1.intValue();
自动装箱和自动拆箱
int i = 10;
Integer ii = i; // 自动装箱
Integer ij = (Integer)i; // 自动装箱
int j = ii; // 自动拆箱
int k = (int)ii; // 自动拆箱
(2)类内部常用方法
包装类作为类,有非常多的方法。下面以int-Integer为例,
//parseInt方法: 数字字符串类型转成int类型
String s="123";
int i = Integer.parseInt(s);
System.out.println("字符类型转成整型:"+i);
//toString方法:int类型转成数字字符串类型
int ii=123;
String s2 = Integer.toString(ii);
System.out.println("int类型转成数字字符串类型:"+s2);
细说valueOf ( ) 源码分析
public static Integer valueOf(int i) {
assert IntegerCache.high>= 127;
if (i >= IntegerCache.low&& i <= IntegerCache.high)
return IntegerCache.cache[i+ (-IntegerCache.low)];
return new Integer(i);
}
注意方法体中,在返回之前对 int 作判断,IntegerCache.low=-128,IntegerCache.high=127.
当 127 >= i >= -128,直接返回数组下标为i-(-128)的值,而不在这个范围时,返回新的对象
来两道常见面试题练练手吧
1、Java中 int 和 Intrger 的区别
- int 是基本类型,直接存数值;而integer引用数据类型。
- Int的声明不需要实例化,且变量声明后的初始值为0;Integer的是一个类,初始值为null,需要进行实例化,才能对变量数据进行处理。
- Integer类是int的包装类,实际开发中Integer被看成一个对象,可以进行数据转换等操作。
2、代码输出结果是?
Integer a=100; Integer b=100; System.out.println(a==b); Integer m=200; Integer n=200; System.out.println(m==n);
答案是 true false
泛型
1、概述
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
2、引出泛型
举个例子
class MyArray {
public Object[] array = new Object[10];
public Object getPos(int pos) {
return this.array[pos];
}
public void setVal(int pos, Object val) {
this.array[pos] = val;
}
}
MyArray myArray = new MyArray();
myArray.setVal(0, 10);
myArray.setVal(1, "hello");//字符串也可以存放
String ret1=myArray.getPos(1);//error
String ret2=(String) myArray.getPos(1);//运行正确
System.out.println(myArray.array[0]);//打印10
System.out.println(myArray.array[1]);//打印hello
MyArray类中定义一个数组,类型为Object。
- 在调用getPos与setPos时,参数既可以传入Integer类型也可以传入String等包装类。
- 调用getPos取出结果,必须先强制类型转换。
3、语法
class 泛型类名称 < 类型形参列表 > {// 这里可以使用类型参数}
注意:泛型只能接受类,所有的基本数据类型必须使用包装类
代码举例
public class Test {
public static void main(String[] args) {
MyArray<Integer> myArray = new MyArray<>();
myArray.set(0, 20);
myArray.set(1, "hello");//error
int ret=myArray.get(0);
System.out.println(ret);
}
}
public class MyArray <E>{
Object[]arr=new Object[10];
void set(int pos,E val){
arr[pos]=val;
}
E get(int pos){
return (E) arr[pos];
}
}
了解: 【规范】类型形参一般使用一个大写字母表示,常用的名称有:E 表示 ElementK 表示 KeyV 表示 ValueN 表示 NumberT 表示 TypeS, U, V 等等 - 第二、第三、第四个类型
4、泛型的上界
占位符后extends 类(泛型的上界)表示参数既可以放父类,也可以放当前类的子类。
没有指定类型边界 E,可以视为 E extends Object
class 泛型类名称 < 类型形参列表 > extends 继承类 /* 这里可以使用类型参数 */ {// 这里可以使用类型参数}
public class Test {
public static void main(String[] args) {
MyArray<People> myArray = new MyArray<>();
People p1=new People();
Student s1=new Student();
myArray.set(0,p1);
myArray.set(1,s1);
}
}
public class MyArray <E extends People>{
Object[]arr=new Object[10];
void set(int pos, E val){
arr[pos]=val;
}
E get(int pos){
return (E) arr[pos];
}
}
public class People {
}
public class Student extends People{
}
5、擦除机制
6、泛型方法
方法限定符 < 类型形参列表 > 返回值类型 方法名称 ( 形参列表 ) { ... }
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;
}
}
包装类与泛型学习到这里。