0%

第六章 访问权限控制

1、类库 library:将不变的内容和重构的代码内容区分开

2、访问权限修饰词:public protected private

  • 无关键字则默认包访问权限,其包内成员相对于外部的所有类均为 private

  • 取得访问权的方式

    • 使该成员成为 public
    • 不加修饰词,并将其他类放置于同一个包
    • 继承
    • 使用访问器和变异器(mutator)读取和改变数值

3、包 package:库单元

  • 功能:将构件捆绑至一个内聚的类库单元中

  • 默认(未命名)包:包含本地源代码文件

  • 编译单元:正在编写的文件

4、代码组织

  • package:群组,对每个文件,需声明该编译单元的类库

  • 分割单一的全局名字空间,避免名称冲突的可能性

  • 创建独一无二的包名

    • 层次化组织
    • 反序因特网域名 / 分解包名为机器目录

5、定制工具库

  • 输出:

1
2
3
4
5
import java.io.*;
System.out.println(123); //换行打印
System.out.print(123); //不换行打印
System.out.write(234); //字节输出
System.out.printf("%+8.5f\n", 3.14); //按格式输出
  • range()

6、接口和实现

  • 访问控制基本思想:将接口与具体实现分离

  • 可采用的形式(注:接口与实现仍混合,仅易于阅读)

1
2
3
4
5
6
public OrganizedByAccess {
public ...;
public ...;
// 阅读到此处结束
private ...;
}

7、类的访问权限

  • 每个编译单元都只能有一个公共接口,以 public 关键字修饰

  • 类仅可为默认(包访问权限)或 public 修饰,其他修饰词不可用

第五章 初始化与清理

一、初始化

1、构造器 constructor

  • 自动调用对应构造器保证初始化

  • 构造器采用与类相同的名称(因此构造器方法首字母无需小写)

  • 绑定初始化和创建

  • 不返回任何值

2、方法重载:不同构造器,参数列表独一无二

3、默认构造器(无参)

  • 创建默认对象

  • this 关键字

    • 表:对调用方法的按个对象的应用
    • 若为同一个类的另一个方法,不使用 this 关键字,精简
    • 若要明确指出对当前对象的引用,使用 this 关键字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 例1
public class Apricot{
void pick();
void pit{ pick() };
// 以下写法没有必要
void pit{ this.pick() };
}
// 例2
public class Leaf{
int i = 0;
Leaf increment() {
i++;
return this; // 返回对当前对象的引用
}
}
void print() {
System.out.println("i = " + i);
}
public static void main(String[] args) {
Leaf x = new Leaf();
x.increment().increment().increment().print();
}
/* Output:
i = 3
*///:~
  • 构造器中调用构造器:仅可用 this 调用一个,且调用位于最起始处

4、成员初始化

  • 基本数据类型有默认初值,自定义的局部变量则必须给出初始化值

  • 注意初始化的顺序

5、构造器初始化

1
2
3
4
5
6
7
8
// i先置为0,后变为7
public class Counter {
int i;
Counter() {
i = 7;
}
...
}
  • 初始化将在构造器被调用前发生

  • 类内部,变量定义顺序决定了初始化顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Window {
Window(int marker) {
print("Windows(" + marker + ")"); // 初始化时打印
}
}
class House {
Window w1 = new Window(1); // 调用构造器前
House() {
print("House()");
w3 = new Window(33);
}
Window w2 = new Window(2); // 调用构造器后
void finished() {
print("finished()");
}
Window w3 = new Window(3); // 末尾
}
public class OrderOfInitialization {
public static void main(String[] args) {
House h = new House();
h.finished();
}
}
/* Output:
Window(1)
Window(2)
Window(3)
House()
Window(33)
finished()
*///~

上例说明,即使对象散布在 Window 的不同部分,仍会在调用构造器或其他方法前得到初始化。

  • 先初始化静态对象,后其他对象

  • 静态块:显式的静态初始化

1
2
3
4
5
static {
代码块1
代码块2
...
}

静态初始化动作只进行一次

6、数组的初始化

以下两种均可(前者更合理,后者符合 C、C++ 习惯):

1
2
3
4
5
6
7
8
int[] a;
int a[];
// 尽量在定义时初始化
int[] a = new int[rand.nextInt(20)];
// 产生一维数组的可打印版本
import java.util.*;
print(Arrays.toString(a));
// 注:toString默认打印 类名 和 对象的地址(@+16进制数字)
  • 不允许指定数组的大小,分配空间必须写初始化表达式

  • 使用花括号括起来的列表初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
// 形式1
Interger[] a = {
new Interger(1),
new Interger(2),
3,
};
// 形式2
public class DynamicArray {
public static void main(String[] args) {
Other.main(new String[]){ "fiddle", "de", "dum"};
// 在方法调用处创建数组,可在调用时提供可替换的参数
}
}
class Other {
public static void main(String[] args) {
for(String s : args)
System.out.print(s + " ");
}
}
/* Output:
fiddle de dum
*///~

7、可变参数列表

  • 将 0 个参数传递给可变参数列表是可行的

  • 不依赖于自动包装机制,使用基本类型

  • 使得重载变得复杂,编译器在各个情况均要使用自动包装机制来匹配重载

    • 在不适用参数调用时,则无法确定了。此时应添加一个非可变参数

二、清理

1、finalize ():清理不是 new 创建的内存

  • 使用原因:回收程序不再使用的内存

  • 终结条件的验证

2、辨析:并非所有对象都会被垃圾回收

3、回收

  • 引用计数:释放引用计数为 9 的空间

    • 简单,速度很慢
    • 缺陷:对循环引用不适用,应被回收的值,其引用计数不为 0
  • 停止 - 复制(自适应)技术:动作发生时,程序暂停

  • JIT 即时编译器技术:翻译程序为本地机器码以提升速度

    • 即时编译
      • 缺陷:累加时长长,且会增加可执行代码的长度,导致页面调度
    • 惰性评估:尽在必要时编译

三、枚举类型 enum

1、toString

2、ordinal:用于表示特定枚举常量的声明顺序

3、可把 enum 视作类,具有自己的方法

  • 可在 switch 语句中使用,配合在有限可能值集合中选择

第四章 控制执行流程

1、foreach(SE5+)

  • 对于任何返回一个数组的方法,不必创建 int 变量计即可自动计数

1
2
3
4
5
6
7
8
9
10
11
12
13
package HelloWorld;
import java.util.*;
public class ForEachFloat {
public static void main(String[] args){
Random rand = new Random(47);
float[] f = new float[10];
for (int i = 0; i < 10; i++){
f[i] = rand.nextFloat();
}
for (float x:f) // 定义一个float类型变量x,将每个f元素赋给x
System.out.println(x);
}
}
  • 还可用于任何 Iterable 对象

    • Iterable:Java 中的迭代器对象,是能够对 List 这样的集合进行迭代遍历的底层依赖

2、迭代前的标签:嵌套另一迭代或开关时使用

1
2
3
4
5
6
7
8
9
10
11
12
13
label1:
outer-iteration {
inner-iteration{
...
break;
...
continue;
...
continue label1; // 转至label1
...
break label1;
}
}

第三章 操作符

1、别名现象

赋值操作是对一个对象的引用,对象与对象相互赋值则丢失信息

2、生成数字:Random 类

  • nextInt / nextFloat …

3、可使用一元加减号

1
2
3
4
// 以下操作均合法
x = -a;
x = a * -b;
s = a * (-b);

4、关系操作符

  • 若为基本类型,直接比较

  • 不为基本类型,使用所有对象都适用的特殊方法 equals ()

    • 默认执行比较引用,不可用于自己的新类
1
2
3
4
5
6
7
8
9
10
11
n1.equals(n2)
// 以下返回行为不正确
class myclass{
int i;
}
public class wrongdoing{
myclass v1 = new v1;
myclass v2 = new v2;
System.out.println(v1.equals(v2));
}
// false
  • 三元操作符

1
2
// condition ? ex1 : ex2;
x < y ? x : y;

5、逻辑运算符

与或非仅可用于布尔值

1
2
3
4
// 错误实例
printf("i && j is" + (i && j));
printf("i && j is" + (i || j));
printf("i && j is" + !i);

6、直接常量

  • 后缀 L / F /D …

  • 前缀 0x / 0 / 0b

  • 可为数字字面量添加下划线,更可读(e.g. 1_000_000)

  • 指数

    • 注:结果不为一个数,返回 NaN(e.g. 0/0)
1
expfloat = 1.39E-43f

7、按位操作符

&= |= ^= 均合法

8、移位操作符 >> <<

  • 无符号右移:>>>,无论正负均在高位插入 0

    • 对 byte /short:会先转为 int,右移、截断、赋值,可能得到 - 1 结果
    • 推广:只要类型比 int 小均会被转换,可根据需求使用 cast 手动类型转换 / 提升
  • 与等号组合:>>= <<=,移动等号左边指定的位数

9、移植:无需考虑,不同机器均相同

  • 因而无 sizeof 操作符

注:溢出结果不会收到警告或出错

10、浮点数四舍五入

  • 得到最接近整数:使用 Max.round () 方法

1
2
double x = 9.997
int nx = (int) Math.round(x);

第二章 一切都是对象

1、引用 ref:操纵对象

2、存储位置

  • 常规位置:寄存器 堆栈 堆

  • 常量存储:程序代码内部

  • 非 RAM 存储:存活于程序外,不受程序任何控制

    • 实例:流对象 持久化对象

3、基本类型(P23)

  • byte 8 比特的比特值

  • 具有包装器类,可在堆中创建一个非基本对象表示对应基本类型

1
2
3
4
char c = "hhh";
Character ch = new Character(c);
// 还可以反向转换
char c = ch;
  • 高精度数字:BigInteger BigDecimal

  • 对象的生命周期独立于作用域之外

4、类 class

  • 构成:字段(数据成员)和 方法(成员函数)

  • DataOnly 类:如名,仅作保存数据使用

  • 基本成员默认值(P26)

5、方法(函数)

  • 组成:名称 参数 返回值 方法体

1
2
3
ReturnType methodName( /* 参数列表 */ ){
/* 方法体 */
}

6、构建

  • 名字可见性:反转域名,句点则表示子目录的划分,每个类标识符唯一

  • 使用构件

1
2
3
4
// 使用util中的ArrayList类
import java.util.ArrayList;
// 使用util中的几个类(一次说明)
import java.util.*;
  • static 关键字:

    • 为特定域分配单一存储空间
    • 不与包含它的类的任何对象实例关联
1
2
3
4
5
6
7
8
class StaticTest {
static int i = 47;
}
// 两者指向同一片存储空间
StaticTest st1 = new StaticTest();
StaticTest st2 = new StaticTest();
// 可通过类名直接引用
StaticTest.i++;
  • 定义静态方法

    • 可用它的类直接调用,或用对象调用
    • 可在不创建任何对象时调用
1
2
3
4
5
6
7
8
9
10
class Incrementable {
static void increment() {
StaticTest.i++;
}
}
// 通过对象调用
Incrementable sf = new Incrementable();
sf.increment();
// 通过类调用
Incrementable.increment();

7、使用

  • java.lang 默认导入

  • println ():控制台输出,完成后换行

    • sout + enter/tab
  • 注释风格:同 C++

  • javadoc

    • 提取注释:输出 HTML 文档
    • 语法:*//
    • 使用:嵌入 HTML 或 使用文档标签(以 @开头命令)
      • @see:引用其他类
      • @version version-information
      • @param parameter-name description:参数列表标识符
      • deprecated:旧特性,已由新特性取代
    • 构成:类、域和方法
    • 访问权限:仅可公共或受限,忽略私有注释

8、编码风格

  • 类名的首字母大写

  • 驼峰风格:

    • 多个单词类名合并(无下划线),每个首部大写
    • 标识符同上,但第一个字母小写