一、 预备知识-泛型(Generic)
1.1、泛型的引入
比如:我们实现一个简单的顺序表
class MyArrayList{
public int[] elem;
public int usedSize;
public MyArrayList(){
this.elem = new int[10];
}
public void add(int key){
this.elem[usedSize] = key;
usedSize++;
}
public int getPos(int pos){
return this.elem[pos];
}
}
问题:此时我么发现我们实现的顺序表,只能保存 int 类型的元素,如果现在需要保存 指向 Person 类型对象的引用的顺序表,请问应该如何解决?如果又需要保存指向 Book 对象类型的引用呢?
泛型的意义
1、当我们指定数据类型之后,它会在编译器编译的时候,就帮你检查存储的数据类型是否匹配。自动对数据类型进行检查。
2、在我们获取元素的时候,发现数据类型不匹配,此时就会自动的将类型转换成相同类的数据。自动对类型进行强转类型转换。
下面顺序表的写法是不对的,只是为了暂时的用起来
class MyArrayList<E>{
public E[] elem;
public int usedSize;
public MyArrayList(){
this.elem = (E[])new Object[10];
}
public void add(E key){
this.elem[usedSize] = key;
usedSize++;
}
public E getPos(int pos){
return this.elem[pos];
}
}
面试问题:泛型是怎么编译的?
1.泛型是编译期的一种机制(擦除机制)。
擦除机制:它会把尖括号这些内容擦除掉,也就说程序运行的时候,就没有这些东西了。所以说程序运行起来,再去获取它的类型是不可能的,因为都被擦掉了。
然后我们再来看一下细节
1.2、泛型的总结
- 泛型是为了解决某些容器、算法等代码的通用性而引入,并且能在编译期间做类型检查。
- 泛型利用的是 Object 是所有类的祖先类,并且父类的引用可以指向子类对象的特定而工作。
- 泛型是一种编译期间的机制,即 MyArrayList< Person > 和 MyArrayList< Book > 在运行期间是一个类型。
- 泛型是 java 中的一种合法语法,标志就是尖括号 <>
二、预备知识-包装类(Wrapper Class)
Object 引用可以指向任意类型的对象,但有例外出现了,8 种基本数据类型不是对象,那岂不是刚才的泛型机制要
失效了?
实际上也确实如此,为了解决这个问题,java 引入了一类特殊的类,即这 8 种基本数据类型的包装类,在使用过程
中,会将类似 int 这样的值包装到一个对象中去。
2.1、基本数据类型和包装类直接的对应关系
基本就是类型的首字母大写,除了 Integer 和 Character
2.2、包装类的使用,装箱(boxing)和拆箱(unboxing)
例如:此时我们将一个字符串类型的数据转换成int类型的数据
public static void main(String[] args) {
String str = "123";
int b = Integer.valueOf(str);
System.out.println(b + 11);
}
什么是装包和拆包
- 装箱,装包: 就是将基本数据类型的数据转换成包装类类型 的数据
- 拆箱,拆包:就是将包装类类型的数据转换成基本数据类型的数据
阿里面试题,和装包和拆包有关
下面执行结果为什么会不相等???
public static void main(String[] args) {
Integer a = 129;
Integer b = 129;
System.out.println("是否相等: " + (a == b));
}
为什么???
三、List的使用
3.1、ArrayList 和 顺序表
List是一个接口,不能实例化,但是可以实例一个就提的对象,也可以通过具体的类来实例具体的对象
public static void main(String[] args) {
List<String> list = new ArrayList<>();
ArrayList<String> arrayList = new ArrayList<>();
}
下面的这张图是ArrayList实现的接口和继承的抽象类,但是这张图并不具体
下面这张图才是ArrayList具体实现的接口和类
【说明】
- ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
- ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
- ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
- 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList
- ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表
3.2、ArrayList 的构造方法
在只用java中的类库时,一定要先看一下类库中的构造方法
public static void main(String[] args) {
//不带参数的构造方法,默认大小为0
List<String> list1 = new ArrayList<>();
//带一个参数的构造方法,大小为10
List<String> list2 = new ArrayList<>(10);
//将list2作为参数传递,但是list2和list3里面存储的数据类型必须一致
List<String> list3 = new ArrayList<>(list2);
}
ArrAyList的三种打印方式
1. 直接打印
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("hello");
list1.add("word");
list1.add("!!!");
System.out.println(list1);
}
2. 使用for和for-each循环打印
ArrayList本质上是一个数组,所以可以使用for循环打印,当然也可以使用for-each打印
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("hello");
list1.add("word");
list1.add("!!!");
for (String str : list1) {
System.out.println(str + " ");
}
}
3. 迭代器打印
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("123")<