CS61b:Week3
DLList
-
Double Linked List :双向链表
-
Node组成:
- 该节点包含的元素
- 下一个节点的地址
- 上一个结点的地址
-
从SLList到DLList的改进
DLList的改进结构
- 单端循环DLList
- 双端DLList
Generic List
泛化列表
- 类似于C语言的模板,为使用多种类型的列表提供了基础,允许用户选择列表元素的类型。
- 泛化类的创建
1 | public class Classname<sometype> { |
- 泛化类的实例化
- 传入的参数类型可以是基本类型,也可以是用户自定义类型,etc.
- 要注意的是尖括号内的有些类型要全称和大写
- int -> Integer
- double -> Double
- char -> Character
- boolean -> Boolean
- long -> Long
- etc.
1 | //实例化时要确定sometype的类型 |
- 示例代码
1 | public class GenericList<pineapple> { |
Array
Java中的Array
-
Array数组的特点
- 具有连续的存储空间
- 数组具有固定的大小(必须是整数且不会改变)
- 数组的各元素具有相同类型
- 数组可以用下标访问元素,下标索引范围为
- 数组属于引用类型之一
-
数组的创建与使用
1 | // x 和 y 实际上存储的是对应数组的地址 |
2维数组
1 | //声明list是含有int[]作为元素的大小为4的int[]类型 |
Array & Class
- 数组可以通过下标
[]
访问元素(随机访问),而类使用.
来访问成员 - 数组元素类型相同,而类可以不同
- 占用的内存空间都是固定的,无法更改
- 数组的下标可以用变量代替(运行时评估)(动态索引),而类不行。
AList
- LList的随机访问效率极低,而基于数组的列表(AList)则相反。
- 组成:
- 一个储存元素的数组
- 一个记录大小的变量
- 一些可供用户交互的方法
Resizing AList
- 由于AList是基于数组的列表,而Java中的数组大小是有限的,用户想要一个没有上限的列表,于是AList需要扩大。
- 扩大思路:
- 创建一个容量更大的新列表
- 将旧列表的元素拷贝到新列表
- 将原来指向旧列表的指针指向新列表
- 可能的问题:
- 若每次只增加元素大小,在原数组元素数量极大的情况下,需要拷贝花费的时间很久。
- 可能的解决方案,将数组大小每次扩大两倍。但是同样在数量很大的情况下,可能会占用很多的内存空间,造成浪费。时间与空间二者不能兼得。
泛化数组
- 需要注意的是泛化数组类型的时候不能直接new。
- 而是要new一个新的对象。
1 | //items = new cheese[100]; -- Wrong |
代码示例
1 | public class AList<cheese> { |
Inheritance
- 创建方法时,使用一种列表类型作为参数,而要想使用另一列表类型又要重载一次函数,仅仅换了一种形参类型,把代码重复率直接拉满。
- 实际上他们都属于列表这一类型,为了避免重复,继承是必要的。
Hypernym&Hyponyms
- Hypernym表示上位关系,而Hyponym表示下位关系
- 就比如说不同种类的狗都属于狗,狗是上位词,不同种类的各种狗是下位词。
- SSList和AList都属于某种列表,假设为List61b,则List61b为上位词,SSList和AList为下位词。
Interface
- 关键字Interface,说明该类属于Hypernym
- 用法示例
1 | public interface List61b<Item>{ |
- Interface类中只声明了该类能使用的方法,而没有具体实现。(Only what but not how)
implements
- 关键字implements,说明该类属于某种Interface的Hyponym。
- 示例:
1 | public class AList<Item> implements List61B<Item>{ |
- 所有同一Interface的不同implements都为Interface类,都可以作为Interface的类型被函数形参接受,就不必重载函数了。
override & overload
- 在子类中含有在父类中的函数声明结构一样的函数,这时就发生了函数重写Overriding
- 可以使用
@Override
表明这是重写了父类的方法(就算不使用也可以重写的啦) - 使用
@Override
,可以提醒我们是否重写了方法(若未重写则会报错) - 例子
1 | public class interface Animal { |
Interface inheritance
- 使用关键字
implements
的继承也叫接口继承。 - Interface:接口包含了方法的声明
- Inheritance:表明子类从父类继承
- 子类必须重写接口父类的所有函数方法(否则不通过编译)
- 子类能作为父类的参数传递:因为父类开辟的内存空间可以存放的下子类。
Implementation Inheritance: Default Methods
- 使用关键字
default
进行实现继承Implementation Inheritance - 在接口类中使用
default
实现方法时,可以使用未实现而已声明的方法,而不用研究其具体实现。 - 子类继承时将该方法继承,若无重写,则调用父类实现的方法
- 示例
1 | public class interface List61b<Item>{ |
Static & Dynamic type
- 一个变量类型分为静态和动态两种,静态类型是编译时就确定的类型,动态类型是运行时确定的类型
Static Type (Compile-time Type)
- 编译时就确定的数据类型。
- 在声明时就已经确定,并无法改变。
Dynamic(Runtime Type)
- 运行时确定的数据类型。
- 在实例化时(使用new时)确定的数据类型,
1 | public static void main(String[] args){ |
Dynamic method selection
- 动态方法选择:
- 当静态类型与动态类型不同时,若动态类型重写了方法,则使用被重写的方法。
- DMS的两步法
- 编译时确定了被调用的方法的签名。(仅使用静态类型决定)
- 运行时,被调用对象的动态类型使用类型内的方法。
1 | public interface Animal { |