包装类+泛型
- 一、包装类
- (1)基本数据类型和对应的包装类
- (2)装箱和拆箱
- 二、泛型
- (1)什么是泛型
- (2)引出泛型
- (3)语法
- (4)泛型类的使用
- 1.语法
- 2.示例
- 3.类型推导
- (5)裸类型
- (6)泛型是如何编译的
- 1.擦除机制
- 2.为什么不能实例化泛型类数组?
- (7)泛型的上界
- 1.语法
- 2.示例
- 3.复杂示例
- (8)泛型方法
- 1.语法
- 2.示例
一、包装类
在Java中,由于基本类型不是继承自Object
,为了在泛型代码中可以支持基本类型,Java给每个基本类型都对应了一个包装类型
(1)基本数据类型和对应的包装类
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
- 除了
Integer
和character
,其余基本类型的包装类都是首字母大写
(2)装箱和拆箱
- 装箱:把一个基本数据类型转化为包装类型的过程
- 拆箱:将一个包装类中的值取出,放到一个基本类型中
自动装箱与自动拆箱
java">public class demo {
public static void main(String[] args) {
//自动装箱
int i = 10;
Integer a = i;
//自动拆箱
int b = a;
}
}
显示装箱和显示拆箱
java"> //显示装箱
int c = 20;
Integer d = Integer.valueOf(c);
//显示拆箱:拆箱为自己指定的元素
int e = d.intValue();
double e1 = d.doubleValue();
二、泛型
(1)什么是泛型
一般的类和方法,只能使用具体的类型,要么是基本类型,要么是自定义的类,如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。—— 《Java编程思想》
泛型是在jdk1.5引入的新语法,通俗讲,泛型:就是适用于许多许多类型,从代码上将,就是对类型实现了参数化
(2)引出泛型
实现一个类,类中包含一个数组成员,使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个下标的值?
思路:
- 我们以前学过的数组,只能存放指定类型的数据,例如
String[]
、int[]
- 所有类的父类,默认为
Object
类,数组是否可以创建为Object
?
java">class MyArray{
Object[] array = new Object[10];
public void set(int pos,Object val){
this.array[pos] = val;
}
public Object get(int pos){
return this.array[pos];
}
}
public class demo1 {
public static void main(String[] args) {
MyArray myArray = new MyArray();
myArray.set(0,10000);
myArray.set(1,"hello");
String ret = myArray.get(1);//编译报错
String ret = (String) myArray.get(1);
}
}
以上代码实现后发现
- 任何类型数据都可以存放
- 1号下标本身就是字符串,但是却编译报错,必须进行强制类型转换才可以
虽然在这种情况下,当前数组任何数据都可以存放,但是,更多情况下,我们还是希望他只能够持有一种数据类型,而不是同时持有这么多类型,所以,泛型的主要目的:指定当前的容器,要持有什么类型的对象,让编译器去做检查,此时,就需要把类型作为参数传递,需要什么类型,就传入什么类型
(3)语法
java">class 泛型类名称<类型形参列表>{
//这里可以使用类型参数
}
class ClassName<T1,T2……Tn>{
}
java">class 泛型类名称<类型形参列表> extends 继承类{
//这里可以使用类型参数
}
class ClassName<T1,T2……Tn> extends ParentClass<T1>{
//可以只使用部分类型参数
}
上述代码进行改写如下
java">class Myarray<T>{
Object[] array = new Object[10];
public void set(int pos,T val){
this.array[pos] = val;
}
public T get(int pos) {
return (T)this.array[pos];
}
}
public class demo2 {
public static void main(String[] args) {
Myarray<String> myArray = new Myarray<>();
myArray.set(0,"sadfklsajdfs");
myArray.set(1,"qwe");
String ret = myArray.get(0);
String ret1 = myArray.get(1);
System.out.println(ret);
System.out.println(ret1);
Myarray<Integer> myarray = new Myarray<>();
myarray.set(0,3);
Integer ret2 = myarray.get(0);
System.out.println(ret2);
}
}
//输出结果
sadfklsajdfs
qwe
3
Process finished with exit code 0
代码解释:
- 类名后的代表占位符,表示当前类是一个泛型类
类型形参一般使用一个大写字母来表示,常用的名称有
- E表示
Element
- K表示
Key
- V表示
Value
- N表示
Number
- T表示
Type
- 不能new泛型类型的数组
java">T[] ts = new T[5];//是不对的
- 类型后需要加入包装类指定当前类型
java">Myarray<String> myArray = new Myarray<>();
- 存放元素的时候会帮我们检查,如果和包装类不同,会报错提示
(4)泛型类的使用
1.语法
java">泛型类<类型实参> 变量名 = new 泛型类<类型实参>(构造方法实参);
2.示例
尖括号中只能是引用类型,不能是基本类型
java">Myarray<String> myArray = new Myarray<String>();
注意:泛型只能接受类,所有的基本数据类型必须使用包装类
3.类型推导
当编译器可以根据上下文推导出类型实参时,可以省略类型实参的填写,但是尖括号不能省略
java">Myarray<String> myArray = new Myarray<>();
(5)裸类型
裸类型是一个泛型类但是没有带着类型实参
java">Myarray list = new Myarray();
注意:我们不要自己去使用裸类型,裸类型是为了兼容老版本的API保留的机制
(6)泛型是如何编译的
1.擦除机制
那么,泛型到底是怎么编译的呢?这个问题也是曾经的一个面试问题,泛型本质是一个非常难的语法,要理解好它还是需要一定的时间打磨
我们先察看字节码文件,发现所有的T
都是Object
- 在编译的过程中,将所有的
T
替换为Object
这种机制,我们称为擦除机制 - 运行的时候没有泛型这样的概念,泛型的擦除机制,只存在于编译期间
2.为什么不能实例化泛型类数组?
原因:替换后的方法为:将Object[]
分给Integer[]
引用,程序报错
不能证明所有类型都是Integer
类型
通俗讲就是:返回的Object
数组里面,可能存放的是任何的数据类型,可能是String
,可能是Integer
,运行的时候,直接传给Integer
类型的数组,编译器认为是不安全的
(7)泛型的上界
在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束
1.语法
java">class 泛型类名称<类型实参 extends 类型边界>{
}
2.示例
java">class test<E extends Number>{
}
extends
表示拓展,只接受Number
的子类型作为E的类型实参
java">class test<E extends Number>{
}
public class demo4 {
public static void main(String[] args) {
test<Integer> a1;//正常,因为Integer是Number的子类型
test<String> a2;//编译错误,因为String不是Number的子类型
}
}
没有指定类型边界E
,可以视为E extends Object
3.复杂示例
写一个泛型类,实现一个方法,这个方法是就指定类型泛型的最大值
java">class Alg<T extends Comparable<T>>{
public T findMax(T[] array){
T max = array[0];
for (int i = 1; i < array.length; i++) {
if(array[i].compareTo(max) > 0){
max = array[i];
}
}
return max;
}
}
public class demo5 {
public static void main(String[] args) {
Alg<Integer> alg1 = new Alg<>();
Integer[] array = {1,2,3,4,5};
Integer ret = alg1.findMax(array);
System.out.println(ret);
}
}
//输出结果
5
Process finished with exit code 0
(8)泛型方法
1.语法
java">方法限定符<类型形参列表> 返回值类型 方法名称(形参列表){
}
2.示例
java">class Util{
public <T extends Comparable<T>> T findMax(T[] array){
T max = array[0];
for (int i = 1; i < array.length; i++) {
if(array[i].compareTo(max) > 0){
max = array[i];
}
}
return max;
}
}
public class demo6 {
public static void main(String[] args) {
Util util = new Util();
Integer[] array = {1,2,3,4,5};
Integer ret = util.findMax(array);
System.out.println(ret);
}
}
//输出结果
5
Process finished with exit code 0
静态方法可以直接通过类名调用
java">class Util{
public static <T extends Comparable<T>> T findMax(T[] array){
T max = array[0];
for (int i = 1; i < array.length; i++) {
if(array[i].compareTo(max) > 0){
max = array[i];
}
}
return max;
}
}
public class demo6 {
public static void main(String[] args) {
Integer[] array = {1,2,3,4,5};
Integer ret = Util.findMax(array);
System.out.println(ret);
}
}
//输出结果
5
Process finished with exit code 0