数组在 Java 中具有固定大小,永远无法更改
比特 Bits
计算机中的所有信息都以 1 和 0 的序列存储在内存中
一个例子
- 72 通常存储为 01001000
- 字母 H 通常存储为 01001000(与 72 相同)
变量类型
这二者的存储值相同, 那 Java 的代码如何知道如何解释 01001000 呢?
答案是通过变量类型
Java 中的 8 种原始类型:
byte, short, int, long, float, double, boolean, char
声明变量
- 当声明某种类型的变量时, Java 会找到内存中一个连续的块, 其恰好足以容纳该类型的数据
- 留出内存之外, Java 会在内部表中创建一个条目, 将每个变量名映射到每个块中的第一位
- 感觉跟指针很像
- Java 中无法知道内存块的具体位置, 和 C 不同
- Java 中没有默认值
等号的黄金法则(GRoE)
在 Java 里,所有参数传递都是按值传递(pass-by-value)
区别在于:
- 基本类型:传递的是数值本身
- 对象类型:传递的是“对象引用”的值(即对象的地址)
引用类型 Reference Type
Java 中的 8 种原始类型:
byte, short, int, long, float, double, boolean, char
上面提到了原始类型, 任何原始类型之外的其他内容都不是原始类型, 被称为引用类型 reference type
对象实例化
当使用new
实例化一个对象时, Java 为类的每个实例变量分配一定的空间, 并用默认值填充
随后, 构造函数用输入值填充对应的空间
例如:
|
|
其中 int 占 32 bits, double 占 64bits, 一共 96bits
但是在 Java 实现中, 任意对象都会有额外开销, 因此占用空间会略多于 96bits
引用变量声明
当声明任何引用类型的变量时, Java 都会分配 64bits 的空间
但这里的 64bits 不是用来存储变量的数据, 而是用于存储变量的地址
海象之谜
其实是最开始提的一个小问题: 对 b 的更改会影响 a 吗?
|
|
b
被声明为一个Walrus
类型的变量b = a;
的意思是:把a
里面存的那个“引用地址”复制一份交给b
- 所以现在
a
和b
指向同一个Walrus
对象。堆里还是只有一只“海象” - 所以更改 b 中的变量值, a 也会跟着改动
参数传递
当把参数传递给一个函数时, 只是在复制 bits, 被称为按值传递
-
Java 永远是 值传递。
-
基本类型:复制数值 → 方法里改不影响外部
-
对象类型:复制的是引用地址 → 可以改对象内容,但不能改掉外部引用
数组的实例化
存储数组的变量与其他变量一样是引用变量
|
|
这里的两个声明创造了两个 64bits 的空间:
x
只能保存int
数组的地址planets
只能保存Planet
数组的地址
|
|
new
关键字创建 5 个框,每个框 32 位,并返回整个对象的地址以分配给 x
如果丢失了对象地址的那位, 可能导致对象丢失:
若某一个实例的地址存在 x
中, 在 x=null
后会丢失这个实例
整数列表 IntList
|
|
然而, 使用这种链表时, 代码会很丑陋:
|
|
这是在构造一个[ 5, 10, 15 ] 这样的链表, 每次通过调用 rest 方法并赋值实现延长
|
|
这是优化后的构造方法, 但仍然比较麻烦
size 和 iterativeSize
递归方法
我们希望实现一个方法, 用来得到列表 L 中的元素数量
|
|
以下是使用递归实现的一种查询 size 大小的方法, 其实跟 cs61a 中的很像 hhh
关于递归: 我的想法
借着讲到递归, 梳理一下我对递归的一些认识吧, 主要是在 CS61A 的学习过程中建立的:
- 确定递归间前后状态的关系: 二者相加, 相乘, 多者相加…..
- 确定递归终止状态, 比如上面的
null
时, 并给出终止态时的返回值 - 根据 1, 设计返回值的具体迭代计算方法
其实似乎也没说啥
迭代方法
|
|
和递归最大的不同是, 迭代是通过 while
来实现的, 虽然判断条件相同
但是递归就是通过嵌套, 调用函数实现的
这里需要先把 this
赋值给 p
, 然后后续通过让 p
自己赋值为p.rest
实现不断迭代
get
这里我们想再实现一个功能: 根据 index , 获得列表中对应的元素
|
|
这里用递归的方法实现