OCA/OCP Java Note (8): Methods and Encapsulation
Contents
1. Designing Methods
1.1. Access Modifiers
- private
- default
- protected
- public
1.2. Optional Specifiers
- static
- abstract
- final
- synchronized
- native
- strictfp: strict float point,精确浮点,参考Wiki。
可选说明符要放在返回值类型之前。
eg.
public void final walk6() {} // DOES NOT COMPILE
1.3. Return Type
具有非void返回类型的方法,必须始终能返回对应类型。
eg.
String walk6(int a) { if (a == 4) return ""; } // DOES NOT COMPILE
无法编译,因为不能保证return总被执行。
eg.
int long() {] return 9L; // DOES NOT COMPILE }
无法编译,返回值的类型与声明不符。
2. Working with Varargs
可变参数必须是参数列表中的最后一个元素,每个方法最多只能有一个可变参数。
eg.
public void walk1(int... nums) { } public void walk2(int start, int... nums) { } public void walk3(int... nums, int start) { } // DOES NOT COMPILE public void walk4(int... start, int... nums) { } // DOES NOT COMPILE
eg.
15: public static void walk(int start, int... nums) { 16: System.out.println(nums.length); 17: } 18: public static void main(String[] args) { 19: walk(1); // 0 20: walk(1, 2); // 1 21: walk(1, 2, 3); // 2 22: walk(1, new int[] {4, 5}); // 2 23: walk(1, null); // throws a NullPointerException 24: }
3. Applying Access Modifiers
3.1. Calling a Static Variable or Method
可以用类名或对象的实例来访问静态变量或方法。当使用对象的实例来访问静态成员时,编译器会检查引用的类型,并使用该类型来替代实例本身。
eg.
5: Koala k = new Koala(); 6: System.out.println(k.count); // 0 7: k = null; 8: System.out.println(k.count); // 0
3.2. Static Initialization
静态初始化在类首次被使用时执行。
eg.
private static final int NUM_SECONDS_PER_HOUR; static { int numSecondsPerMinute = 60; int numMinutesPerHour = 60; NUM_SECONDS_PER_HOUR = numSecondsPerMinute * numMinutesPerHour; // 可以对final进行(首次)初始化 }
eg.
14: private static int one; 15: private static final int two; 16: private static final int three = 3; 17: private static final int four; // DOES NOT COMPILE,没有对four进行初始化 18: static { 19: one = 1; 20: two = 2; 21: three = 3; // DOES NOT COMPILE, 不能对final进行重复赋值 22: two = 4; // DOES NOT COMPILE, 不能对final进行重复赋值 23: }
3.3. Static Imports
普通的导入用于导入类, 静态导入用于导入类的静态成员,可以静态导入某个特定成员,也可以在静态导入中使用通配符。
eg.
import java.util.List; import static java.util.Arrays.asList; // static import public class StaticImports { public static void main(String[] args) { List<String> list = asList("one", "two"); // no Arrays. } }
静态导入了Arrays.asList 后,调用asList() 不需要前缀Arrays. 。
eg.
1: import static java.util.Arrays; // DOES NOT COMPILE 2: import static java.util.Arrays.asList; 3: static import java.util.Arrays.*; // DOES NOT COMPILE 4: public class BadStaticImports { 5: public static void main(String[] args) { 6: asList("one"); 7: Arrays.asList("one"); // DOES NOT COMPILE 8: } }
第1行无法编译,不能使用静态导入来导入类;第3行无法编译,应使用import static;第7行无法编译,之前静态导入了asList,但没有导入Arrays。
与普通导入类似,不能静态导入具有想用名称的静态成员。此时可以使用类名来访问静态成员,取代静态导入。
eg.
import static statics.A.TYPE; import static statics.B.TYPE; // DOES NOT COMPILE
4. Overloading Methods
4.1. Overloading and Varargs
可变参数等用于数组参数,不能相互重载。
eg.
public void fly(int[] lengths) { } public void fly(int... lengths) { } // DOES NOT COMPILE
两个fly() 是等效的,重复定义无法编译。
传入数组参数,可以调用具有可变参数或数组参数的方法;分别传入参数,只能调用具有可变参数的方法。
eg.
fly(new int[] { 1, 2, 3 }); // Call fly(int[] lengths) or fly(int... lengths) fly(1, 2, 3); // Call fly(int... lengths) only
4.2. Autoboxing
Java会匹配最准确的参数列表。 如果只有:
public void fly(Integer numMiles) { }
使用fly(3) 时Java会自动把3封装为Integer,从而调用fly(Integer numMiles) 。如果同时有:
public void fly(int numMiles) { } public void fly(Integer numMiles) { }
fly(3) 会直接调用fly(int numMiles) 而不会发生自动封装。
Java选择重载方法的顺序如图1所示。
eg.
public class TooManyConversions { public static void play(Long l) { } public static void play(Long... l) { } public static void main(String[] args) { play(4); // DOES NOT COMPILE play(4L); // calls the Long version } }
Java可以自动把int 4转换为long 4或Integer 4,但不能把把int 4自动转换为Long 4。
5. Creating Constructors
5.1. Default Constructor
如果类中没有构造器,则Java自动添加一个没有参数的默认构造器。
5.2. Overloading Constructors
构造器必须通过在类名前加new来调用。
eg.
public Hamster(int weight) { Hamster(weight, "brown"); // DOES NOT COMPILE }
可以使用this来调用本实例的其他构造器,必须在方法的第一行使用。
eg.
public Hamster() { this(weight, "brown"); } public Hamster(int weight) { System.out.println("in constructor"); // ready to call this this(weight, "brown"); // DOES NOT COMPILE }
5.3. Final Fields
可以在构造器中对final成员变量进行初始化。
5.4. Order of Initialization
实例化类时,初始化顺序为:
- 如果有父类,则先初始化父类;
- 按顺序初始化静态变量和静态初始化器;
- 按顺序初始化实例变量和实例初始化器;
- 构造器。