OCA/OCP Java Note (2): Java Building Blocks (2)
Contents
4. Creating Objects
4.1. Constructors
构造器的两个重要特征是名称与类名相同,且没有返回类型,下面的Chick() 不是构造器,因为它有返回类型void:
public void Chick() { } // NOT A CONSTRUCTOR
4.2. Reading and Writing Object Fields
略
4.3. Instance Initializer Blocks
在大括号中的内容成为代码块(code block),在方法外面出现的代码段称为实例初始化器(instance initializers)。相关内容在Class Design一节中阐述。
4.4. Order of Initialization
字段和实例初始化器按其在文件中出现的顺序进行初始化,构造器在所有字段和实例初始化器初始化完毕后才运行。下面看一个例子:
public class Chick { private String name = "Fluffy"; {System.out.println("setting field");} public Chick() { name = "Tiny"; System.out.println("setting constructor"); } public static void main(String[] args) { Chick chick = new Chick(); System.out.println(chick.name); } }
输出是:
setting field setting constructor Tiny
再看一个例子:
public class Egg { public Egg() { number = 5; } public static void main(String[] args) { Egg egg = new Egg(); System.out.println(egg.number); } private int number = 3; {number = 4;} }
输出是:5 。
注意辨别在初始化前进行访问的错误:
{ System.out.println(name); } // DOES NOT COMPILE private String name = "Fluffy";
5. Distinguishing Between Object References and Primitives
5.1. Primitive Types
Java有8种内置的数据类型,如表1所示。
Keyword | Type | Example |
boolean | true or false | true |
byte | 8-bit integral value | 123 |
short | 16-bit integral value | 123 |
int | 32-bit integral value | 123 |
long | 64-bit integral value | 123 |
float | 32-bit floating-point value | 123.45f |
double | 64-bit floating-point value | 123.456 |
char | 16-bit Unicode value | ‘a’ |
需要注意,float类型字面值需要在数字末尾加上f ,如123.45f ;形如123.456 的字面值为double类型。Java默认整数字面值为int类型,最大的int型数值为2^31-1 = 2,147,483,647,如要使用long,需要在数字末尾加上L 或l :
long max = 3123456789; // DOES NOT COMPILE long max = 3123456789L; // now Java knows it is a long
第1行无法编译,Java默认3123456789 为int类型,但这个数字超过了int所能容纳的范围,导致编译错误。第二行在数字末尾加上L ,告诉Java这是一个long型,可以编译。虽然可以使用大写L 或小写l ,一般使用的是大写,因为小写l 容易与数字“1”混淆。
十进制之外的表示方法:
- 2进制:数字前加“0b”或“0B”,如0b10。
- 8进制:数字前加“0”,如017。
- 16进制:数字前加“0x”或“0X”,如0xFF。
Java 7中新加入了一个功能,可以在字面值中加入下划线“_”来提高可读性:
int million1 = 1000000; int million2 = 1_000_000;
除了在字面值开头、末尾、小数点前、小数点后这几个位置,可以在字面值的任意位置加下划线“_”。
double notAtStart = _1000.00; // DOES NOT COMPILE double notAtEnd = 1000.00_; // DOES NOT COMPILE double notByDecimal = 1000_.00; // DOES NOT COMPILE double annoyingButLegal = 1_00_0.0_0; // this one compiles
5.2. Reference Types
引用类型指向对象(Object),即指向类的实例。一个引用可以指向同类型的其他对象,也可以通过new关键词指向一个新对象。
5.3. Key Differences
基本类型和引用类型主要有一下三点区别:
- 引用类型可以被赋值为null ,表示该引用当前不指向任何对象;基本类型赋值为null 会导致编译错误:
int value = null; // DOES NOT COMPILE String s = null;
- 引用类型不为null 时,可以通过引用来调用方法;基本类型本身不具备任何方法可供调用:
String reference = "hello"; int len = reference.length(); int bad = len.length(); // DOES NOT COMPILE
- 所有基本类型的名称都是小写,Java自带的所有类首字母都是大写,在编写自己的代码时,也应当遵守这个惯例。
6. Declaring and Initializing Variables
6.1. Declaring Multiple Variables
略
6.2. Identifiers
合法的标识符须遵守一下规则:
- 必须由字母、$ 或_ 开头。
- 后续字符可以是数字。
- 不能使用与Java保留字相同的名称。
7. Understanding Default Initialization of Variables
7.1. Local Variables
本地变量是在方法中定义的变量,使用前必须进行初始化。本地变量没有默认值,在初始化前,里面保存的是垃圾数据。编译器会阻止你读取尚未初始化的值,如:
public int notValid() { int y = 10; int x; int reply = x + y; // DOES NOT COMPILE return reply; }
执行int reply = x + y; 时x尚未初始化,出现编译错误:
Test.java:5: variable x might not have been initialized int reply = x + y; ^
编译器还可以识别更复杂的情况,如存在分支时,可能存在访问未初始化本地的变量的机会:
public void findAnswer(boolean check) { int answer; int onlyOneBranch; if (check) { onlyOneBranch = 1; answer = 1; } else { answer = 2; } System.out.println(answer); System.out.println(onlyOneBranch); // DOES NOT COMPILE }
上面的例子中,onlyOneBranch 只在一个分支进行了初始化,如果check 为false,运行至System.out.println(onlyOneBranch); 时onlyOneBranch 并没有初始化。编译器会识别出这里的问题,给出编译错误。
7.2. Instance and Class Variables
实例和类变量不要求初始化,它们会在定义的时候获得一个初始值。不同数据类型的默认初始值如表2所示。
Variable type | Default initialization value |
boolean | false |
byte, short, int, long | 0 (in the type’s bit-length) |
float, double | 0.0 (in the type’s bit-length) |
char | ‘\u0000’ (NUL) |
All object references (everything else) | null |