一、模拟实现MyArrayList
1)模拟代码及其缺陷
jdk1.5之前的版本:
class Book{}
class Person{
public void print(){
System.out.println("def");
}
}
class MyArrayList{
public MyArrayList(int capacity){
array = new Object[capacity]; //就近原则,使用参数传进来的capacity
size = 0;
this.capacity = capacity;
}
public void add(Object e){
//检测容量
array[size++] = e;
}
public int size(){
return size;
}
Object get(int index){
//检测索引越界
return array[index];
}
public boolean isEmpty(){
return size == 0;
}
Object[] array;//标准库实现的各个容器任意类型都可存放所以用Object类型
int capacity;//总大小
int size;//有效元素个数
}
public class Test5 {
public static void main(String[] args) {
MyArrayList L1 = new MyArrayList(10);
L1.add(new Person());
L1.add(new Person());
L1.add(new Person());
//向下转型:不安全
Person p = (Person)L1.get(0);
p.print();
MyArrayList L2 = new MyArrayList(10);
L2.add(new Book());
L2.add(new Book());
L2.add(new Book());
}
}
缺陷:
1、接收返回值时需要用户进行强制类型转化—》不方便
2、编译通过,但会发生向下转型不安全(运行时),所以引入泛型。
2)泛型
· 泛型:类型参数化
· 泛型分类:泛型类、泛型方法
class MyArratList<E>{//E是将来存储的对象的实际类型
}
· 优化后的代码:
//这里给成泛型类
class MyArrayList<E>{
public MyArrayList(int capacity){
array = (E[])new Object[capacity];//构造时还不知道E是什么类型,故无法直接new E[] 类型空间,只能先申请Object[]然后进行 E[]的强转
size = 0;
this.capacity = capacity;
}
public void add(E e){
//检测容量
array[size++] = e;
}
public int size(){
return size;
}
E get(int index){
//检测索引越界
return array[index];
}
public boolean isEmpty(){
return size == 0;
}
E[] array;
int capacity;
int size;
}
public class Test5 {
public static void main(String[] args) {
MyArrayList<Person> L1 = new MyArrayList(10);
L1.add(new Person());
L1.add(new Person());
L1.add(new Person());
Person p = L1.get(0);//
p.print();
MyArrayList<Book> L2 = new MyArrayList(10);
L2.add(new Book());
L2.add(new Book());
L2.add(new Book());
Book b = L2.get(2);
}
}
· java里的泛型是伪泛型,这里的L1和L2是一个类型都是MyArratList类型。
原因是为了兼容1.5之前的代码,这里发生了类型擦除,具体行为如下图:
· 注意:<>内不能是基本数据类型,因为Object是所有类的基类,可以指向所有类的对象,但基本数据类型多定义的变量并不是对象。
若有需求,需要试用其包装类型。
3)包装类
· 装箱
public class Test5{
public static void main(String[] args) {
// ArrayList<Integer> L = new ArrayList<>();
// L.add(10);
int i = 10;
Integer i1 = i;//自动装箱:编译器在编译阶段使用i构造包装类型对象,让i1引用
Integer i2 = Integer.valueOf(i);//装箱:基础类型变量转化为对应的包装类型
int i3 = i2.intValue();//拆箱:包装类型对应的数据拿出来
int i4 = i1//自动拆箱:包装类型的对象直接复制给基础类型的变量
}
}
valueOf代码实现:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);//最后返回的是new出来的一个对象
}
图解:
· 例题:
解释:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
这几自动装箱编译时调用valueOf方法,代码如上👆,我们可以看到放方法内部有一个判断,点进看到IntegerCache代码如下👇:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
我们看到low = -128,high = 127。
即Integer类在其内部维护了一段空间(为了提高效率从-127~128);当传进来的参数载low和high之间的话,直接返回空间里存储的对象,如果不在的话才会生成新的对象。
4)List
· List常用方法
· ArrayList常用方法
· LinkedList常用方法
· 练习
杨辉三角及相关知识点
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> ret = new ArrayList<>();
for (int i = 0;i<numRows;i++){
List<Integer> Row = new ArrayList<>();//构造时不给参数,会给一块默认容量的空空间,我的jdk版本默认空间为10
for (int j = 0 ; j <= i ; j++) {
if (j == 0 || j == i){
// Row.set(j,0);//set方法可以理解为更改的意思,要有元素才能更改。即set方法的index必须在size范围内,不然就越界了
Row.add(1);
}else {
Row.add(0);
}
}
ret.add(Row);
}
for (int i = 2; i < numRows; ++i) {
List<Integer> cur = ret.get(i);
List<Integer> pre = ret.get(i-1);
for (int j = 1; j < i; ++j) {
cur.set(j,pre.get(j)+pre.get(j-1));
}
}
return ret;
}
注意看本文代码中的注释哦~
加油鸭!