初始化与清理
初始化和清理是涉及程序安全的两个问题。Java构造器用于新建对象时的初始化,而垃圾回收器则进行清理。
构造器
其名称必须与类名一样,虽然构造器是一种特殊的方法,但是每个方法首字母小写的编码风格并不适合用于构造器。
构造器是没有返回值的,但是new表达式却返回了对新建对象的引用。
方法重载
方法重载是构造器所必须的。每个重载方法都必须独一无二的参数列表。甚至参数顺序的不同,也足以区分两个方法。不过一般不建议这么做,因为这会使代码难以维护。当传入的数据类型小于方法中声明的形式参数类型,实际数据类型就会被提升。但是boolean不能转换,char也比较特殊,提升至int。如果反过来,传入大于声明,则必须进行强转,否则报错。(注意,根据返回值的不同来区分方法是不成立的。)
各参数类型大小顺序排列
boolean:1/8;byte:1;char:2(一个字符可以存储一个中文汉字);short:2;int:4;float:4;long:8;double:8。(单位:字节)
this关键字
只能在方法内部使用,表示对"调用方法的那个对象"的引用。只有在需要明确指出对当前对象的引用时,才有必要使用this。如果在方法内部使用同一个类中的另一个方法,就不用使用this。return this表示返回当前引用。
通常写this的时候,都是指"这个对象"或者"那个对象",而且它本身表示对当前对象的引用。在构造器中,如果this添加了参数列表,那么就有了不同的含义。这将产生对符合此参数列表的某个构造器的明确调用。通过下面的代码示例将会理解的更加深刻。
public class Flower { int petalCount = 0; String s = "initial value"; Flower(int petals){ petalCount = petals; System.out.println("Constructor w/ int arg only,petalCount=" + petalCount); } Flower(String ss){ System.out.println("Constructor w/ String arg only,s=" + ss); s = ss; } Flower(String s,int petals){ this(petals);
//this(s)//错误,不能在一个构造器里面调用两次构造器 this.s = s;//因为成员名字和参数S的名称一致,所有采用这种写法加以区分。 System.out.println("String & int args"); } Flower(){ this("hi",47); System.out.println("default constructor(no args)"); } void printPetalCount(){
//this(11);//错误,不能在非构造器方法里通过this调用构造器。 System.out.println("petalCount =" + petalCount + " s=" + s); } public static void main(String[] args){ Flower x = new Flower(); x.printPetalCount(); } }
output:
Constructor w/ int arg only,petalCount=47
String & int args
default constructor(no args)
petalCount =47 s=hi
关于static的补充
static方法不能包含this,即不能调用非静态方法。反过来倒是可以。而且在没有创建对象的时候,单依靠对象本身就可以对static方法进行调用。这实际上是static的主要作用。这很像全局方法,Java中禁止使用全局方法,但你在类中置入static方法,就可以访问其他的static方法和static域。
有些人认为static方法不是"面向对象"的,因为他们的确具有全局函数的含义,使用static方法时,由于并不是通过this来向对象发送信息。的确,要是代码中存在大量的static,就应该重新考虑自己的设计。然而static的概念有其实用之处,许多时候都要用到它,至于是不是面向对象,不是我们说了算的。
******************************关于终结处理和垃圾回收,将在后面的博文中详细介绍。******************************
初始化
Java尽力保证:所有变量在使用前必须得到恰当的初始化。
对于类中基本成员(即字段)是基本类型的,会自动为这些成员初始化。但是方法中的局部变量则不会,必须强制程序员赋予初始值,否则编译报错。
成员初始化的三种情况
(1)类中基本成员变量:直接在定义的地方为其赋值。(C++中不可以)
(2)非基本类型的对象:
class Depth{}
public class Measurement {
Depth d = new Depth();
}
(3)通过调用某个方法来提供初值,这个方法也可以带有参数,但是这些参数必须是已被初始化了的:
public calss MethodInit2{
int i = f();
int j = g(i);
int f(){
return 11;
}
int g(int n){
return n * 10;
}
}
构造器初始化
(1)初始化顺序(牢记):在类的内部,变量定义的顺序决定了初始化的顺序,即使变量定义或者创建对象引用散布于各方法之间,它们仍旧会在任何方法(包括构造器)被调用之前得到初始化。
(2)静态数据的初始化:static关键字不能作用于局部变量,只能作用于域,即成员变量或者对象引用。如果一个域是静态的基本类型域,且没有对它进行初始化,那么它将获得基本类型的标准值,如果它是一个对象引用,那么初始值为null。初始化的查询是先静态对象,再非静态对象。
class Bowl {
Bowl(int marker) {
System.out.println("Bowl(" + marker + " )");
}
void f1(int marker) {
System.out.println("f1(" + marker + ")");
}
}
class Table {
static Bowl bow1 = new Bowl(1);
Table() {
System.out.println("table()");
bowl2.f1(1);
}
void f2(int marker) {
System.out.println("f2(" + marker + ")");
}
static Bowl bowl2 = new Bowl(2);
}
class Cupboard {
Bowl bowl3 = new Bowl(3);//此处的初始化会在静态对象之后。
static Bowl bowl4 = new Bowl(4);
Cupboard() {
System.out.println("cupboard()");
bowl4.f1(2);
}
void f3(int marker) {
System.out.println("f3(" + marker + ")");
}
static Bowl bowl5 = new Bowl(5);
}
public class StaticTest {
public static void main(String[] args) {
System.out.println("creating new cupboard in main");
new Cupboard();
System.out.println("creating new cupboard() in main");
new Cupboard();//此处虽然创建了Cupboard对象,但是静态bowl4和bowl5不会再次被初始化。
table.f2(1);//这里如果对象引用不是static型,直接使用table.f2是会报错的。下行类似。
cupboard.f3(1);
}
static Table table = new Table();//只有创建Table对象,而且引用静态域时,静态的bowl1和bowl2才会创建。下行类似。
static Cupboard cupboard = new Cupboard();//第一次对bowl4和bowl5进行初始化。
}
output:
Bowl(1 )
Bowl(2 )
table()
f1(1)
Bowl(4 )
Bowl(5 )
Bowl(3 )
cupboard()
f1(2)
creating new cupboard in main
Bowl(3 )
cupboard()
f1(2)
creating new cupboard() in main
Bowl(3 )
cupboard()
f1(2)
f2(1)
f3(1)
显式的静态初始化
Java允许将对个静态子句组织成一个特殊的静态块。
class Spoon{
static int i;
static int j;
static Spoon spoon1;
static{
i = 7;
j = 5;
spoon1 = new Spoon();
}
}
非静态实例初始化:
和上面类似,可以集中进行初始化。只不过少了static关键字。
数组初始化:
int[] a1 = {1,2,3,4};
int[] a2;
a2 = a1;
改变a2中的值,将会影响a1,因为是将a1的引用赋值给了数组a2,a1和a2是不同名的同一数组。