1、构造器

每个类都必须至少有一个构造器,如果没有显式的定义,编译器会自动为该类创建一个隐式的无参构造器(无参构造器也称为默认构造器)。

构造器没有返回值,不会返回任何东西(返回值为空没有返回值是两码事),但是下面的语句会让人疑惑:

1 Object object = new Object();

实际上是new表达式返回了新建对象的引用,构造器没有返回任何东西。

2、方法的重载

方法名、方法参数表(参数数量、参数类型、参数顺序)区分了两个的方法。

改变参数顺序也可以实现方法重载,但是不推荐使用,因为不利于维护和使用。一般是利用参数数量、类型来实现方法重载。

由于基本类型能从一个“较”小的类型自动提升到一个“较大”的类型,所以当重载涉及到基本类型时,容易发生混淆。看下面的代码:

 1 import static java.lang.System.*;
 2 
 3 public class Overload {
 4 
 5     /**
 6      * @param args
 7      */
 8     public static void main(String[] args) {
 9         byte b = 1;
10         char c = 1;
11         short s = 1;
12         int i = 1;
13         long l = 1;
14         float f = 1;    //f=1 没有问题,因为1是整数,可以被提升为float而不丢失精度
15         //! float f = 1.0;    //f=1.0则会提示错误,因为小数默认是double。需要进行强制类型转换,或者通过 f=1.0F 明确告诉编译器我要定义一个float型数据
16         double d = 1;    // d=1,提升为double,正确; d=1.0,正确。
17 
18         
19         Overload ol = new Overload();
20         ol.f1(1); //整数字面常量被看做是int型,所以调用f1(int i)
21         ol.f1(1.0); //小数字面常量被看做是double型,所以调用f1(double i)
22         
23         //! ol.f2(b);    //错误,byte不会被自动提升到char
24         //! c=b            //错误,byte不会被自动提升到char
25         ol.f3(b);         //byte会自动提升到short,所以调用f3(short i)
26         
27         //首先寻找完全匹配的方法,有则调用,反之如果实际传入的数据类型小于方法声明的形参类型,实参会被就近提升,然后调用相应的方法。自动转型遵循下面规律:
28         //byte < short < int < long < float < double
29         //char < int < long < float < double
30 
31     }
32     
33     void f1(byte i) {
34         out.println("f1(byte i)");
35     }
36     void f1(char i) {
37         out.println("f1(char i)");
38     }
39     void f1(short i) {
40         out.println("f1(short i)");
41     }
42     void f1(int i) {
43         out.println("f1(int i)");
44     }
45     void f1(long i) {
46         out.println("f1(long i)");
47     }
48     void f1(float i) {
49         out.println("f1(float i)");
50     }
51     void f1(double i) {
52         out.println("f1(double i)");
53     }
54     
55     void f2(char i) {
56         out.println("f2(char i)");
57     }
58     void f3(short i) {
59         out.println("f3(short i)");
60     }
61 }

注意,不能用返回值类型来区分方法

3、this

表示调用方法的当前对象的引用,只能在方法内部使用。

this对于将当前对象传递给其他方法也很有用,例如:

 1 class Peeler {
 2     static Apple peel(Apple apple) {
 3         //...
 4         //...
 5         return apple;
 6     }
 7 }
 8 
 9 class Apple {
10     Apple getPeeled() {
11         return Peeler.peel(this);    //为了将自身传递给外部方法,Apple必须使用this关键字
12     }
13 }

this的另一种用法是在一个构造器中调用另一个,但是必须位于构造器方法体的第一行。

static方法中不存在this

4、类被加载的时机

当调用类中的静态成员变量、静态方法、创建该类的对象时,即使用该类时,类才被加载。

5、初始化顺序

类被加载时,静态成员、静态块中的变量依照定义顺序完成初始化;

创建对象时,先完成静态成员、静态块中的变量的初始化,然后初始化非静态成员,最后调用构造器。

静态成员、静态块中的变量尽在类被加载时被初始化一次,之后不再被初始化。

 1 public class Initialization {
 2     public static void main(String[] args) {
 3         Cups cups = new Cups();
 4         Cups cups2 = new Cups();
 5         Cup cup_ = Cups.cup1;
 6         Cup[] cup_arr = {new Cup(12),new Cup(11)};
 7         //! Cup cup8 = Cups.cup7;    //error, can not be seen 
 8     }
 9 }
10 
11 class Cup {
12     public Cup(int i) {
13         System.out.println("cup is "+i);
14     }
15     void f(int i) {
16         System.out.println("f() is "+i);
17     }
18 }
19 
20 class Cups {
21     static Cup cup1, cup2, cup3 = new Cup(3);
22     Cup cup4 = new Cup(4), cup5;
23     static {
24         cup1 = new Cup(1);
25         cup2 = new Cup(2);
26         cup3 = new Cup(33);
27         Cup cup7 = new Cup(7);        //local variable
28     }
29     public Cups() {
30         System.out.println("Cups()");
31     }
32     static Cup cup6 = new Cup(6);
33 }
34 //output:
35 /*
36 cup is 3
37 cup is 1
38 cup is 2
39 cup is 33
40 cup is 7
41 cup is 6
42 cup is 4
43 Cups()
44 cup is 4
45 Cups()
46 cup is 12
47 cup is 11
48 */

静态块中,

a、其所操作的field须是静态的

b、静态的field初始化顺序与其定义顺序一致,包括静态块中的初始化语句

c、静态块中定义的变量时局部变量,但同样是静态的。如上面的cup7。

6、数组初始化

数组属于对象,数组变量是其引用。

int [] array = new int[8];    //array是一个数组引用,它指向一个int型数组对象

三种定义数组的方式:

1 int [] int_arr_1 = {1,2,3};
2 Object [] obj_arr_2 = {new Object(), new Object()};
3 //这种方式下,数组的初始化必须位于数组的定义处
int [] int_arr_2 = new int[3];
for(int i = 0; i<3; i++) {
    int_arr_2[i] = i;
}
//这种定义方式在定义时为数组对象本省分配了空间,数组元素执行默认初始化,即如果是基本类型的数组,初始化为基本类型的默认初始值;如果是引用类型的数组,则初始化为空,此时在使用数组元素之前需要对数组元素进行初始化,使其指向一个实际的对象
1 int [] int_arr_1 = new int[]{1,2,3};
2 Object [] obj_arr_2; 
3 obj_arr_2 = new Object[]{new Object(), new Object()};
4 //这种初始化的位置很随意,多用与方法调用,如:
5 
6 //方法定义
7 void test(String[] s) {//...}
8 //方法调用
9 test(new String[]{"now", "you", "see"});

下面这种方式是正确的

1 Integer arr = {new Integer(1), new Integer(2), 3};
2 //SE 5出现的auto-boxing功能

7、可变参数

 1 public class Initialization {
 2     static void printArray(Object... args) {
 3         for (Object object : args) {
 4             System.out.println(object + "------" + object.getClass());
 5         }
 6     }
 7     
 8     public static void main(String[] args) {
 9         printArray(1, 2, 3);//自动包装
10         printArray(new Integer(11),new Integer(12));
11         printArray(new Integer(11),new Float(3.14));
12         printArray(47,3.14f,11.11);
13         printArray(new Integer[] {41,42,43,44});//提示:The argument of type Integer[] should explicitly be cast to Object[] 
14                                                 //for the invocation of the varargs method printArray(Object...) from 
15                                                 //type Initialization. It could alternatively be cast to Object for 
16                                                 //a varargs invocation
17         printArray((Object[])new Integer[] {413,423,433,443});
18         printArray();                            //可以为空        
19     }
20 }
21 //output
22 /*
23 1------class java.lang.Integer
24 2------class java.lang.Integer
25 3------class java.lang.Integer
26 11------class java.lang.Integer
27 12------class java.lang.Integer
28 11------class java.lang.Integer
29 3.14------class java.lang.Float
30 47------class java.lang.Integer
31 3.14------class java.lang.Float
32 11.11------class java.lang.Double
33 41------class java.lang.Integer
34 42------class java.lang.Integer
35 43------class java.lang.Integer
36 44------class java.lang.Integer
37 413------class java.lang.Integer
38 423------class java.lang.Integer
39 433------class java.lang.Integer
40 443------class java.lang.Integer
41 */

涉及重载时,考虑基本数据类型的提升问题

 1 static void F(Character... args) {
 2     System.out.println("Character... args");
 3 }
 4 
 5 static void F(float f, Character... args) {
 6     System.out.println("Character... args");
 7 }
 8 
 9 public static void main(String[] args) {
10     F(1,'2');
11     //!F('2','2');//'2'能够被提升为float,造成歧义,编译器不知道应该调用哪个函数
12 }
 1 static void F(Character c, Character... args) {
 2     System.out.println("Character... args");
 3 }
 4 
 5 static void F(float f, Character... args) {
 6     System.out.println("Character... args");
 7 }
 8 
 9 public static void main(String[] args) {
10     F(1,'2');
11     //F('2','2');//依旧造成歧义!!!!!!!!!!!!!!!!
12 }

如果改成这样就是可以的

 1 static void F(char c, Character... args) {
 2     System.out.println("Character... args");
 3 }
 4 
 5 static void F(float f, Character... args) {
 6     System.out.println("Character... args");
 7 }
 8 
 9 public static void main(String[] args) {
10     F(1,'2');
11     F('2','2');//完全匹配,调用第一个F
12 }