OCA/OCP Java Note (8): Methods and Encapsulation

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所示。

 图1

图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

  实例化类时,初始化顺序为:

  1. 如果有父类,则先初始化父类;
  2. 按顺序初始化静态变量和静态初始化器;
  3. 按顺序初始化实例变量和实例初始化器;
  4. 构造器。