Java初始化与清理

使用构造器确保初始化

许多程序的错误都源于程序员忘记初始化变量。因此可以为每个类都顶一个initialize()方法。该方法会提示你在使用对象之前,应首先调用intitialize()。但构造器的命名存在这两个问题首先,无论构造方法起任何名称都有可能会与类中某个成员相冲突。其次,调用构造器是编译器的职责,编译器必须明确知道构造方法的名称。因此Java中的构造器命名采用与类相同的名称。

class Rock{

Rock(){

System.out.print(“Rock ”);

}

}

public class SimpleConstructor{

public static void main(String [] args){

for(int i=0;i<10;i++){

new Rock();

}

}

}

//输出

Rock Rock Rock Rock Rock Rock Rock Rock Rock Rock

new Rock();

将会为对象分配存储空间,并调用相应的构造器。这就确保了你再能操作对象之前,他已经被恰当的初始化了。

由于构造方法需要与类名同名,所以每个方法首字母小写的编码风格不适合构造方法使用。

构造器同样可以接收参数,无参的构造器叫做默认构造器。

class Rock2{

Rock2(int i){

System.out.print(“Rock “ + i +” ”);

}

}

public class SimpleConstructor2{

public static void main(String [] args){

for(int i =0;i<0;i++){

new Rock(i);

}

}

}

输出

Rock 0 Rock 1 Rock 2 Rock 3 Rock 4 Rock 5 Rock 6 Rock 7 Rock 8 Rock 9

有了构造器参数形式,我们就可以在初始化对象时对其提供实际参数。例如类Tree有一个构造器,他接受一个整型变量来表示树高。

Tree t=new Tree(12); //12米高的树

如果Tree(int),是Tree类的唯一构造器,那么编译器不会允许你以其他的方式对Tree对象进行初始化。

概念上来讲“初始化”和“创建”是彼此独立的,然而上面代码中你却找不到initialize()方法的明确调用。在Java中,”初始化”和”创建”捆绑在一起,两者不能分开。

构造方法是一种特殊的类型的方法,本身没有返回值,这与void不同,构造器绝对不允许返回任何东西(new明确返回了对新对象的引用,但构造器本身不会返回任何值),如果构造器可以返回任何值,那么编译器必须要知道该如何处理此返回值。

方法重载

日常生活中,人类的语言本身就存在着很强的冗余性,一个相同的词在不同的语境下被赋予不同的含义-----它们被“重载”了。你可以说“洗车”,“洗衣服”,“洗澡”。这三个“洗”字明显包含了不同的处理过程,然而你并不需要说“以洗车的方式洗车”,“以洗衣服的方式洗澡”,“以洗澡的方式洗澡”。这是因为听的人并不需要对明确的动作进行区分。

如果想用多种方式创建一个对象该怎么办呢,Java中为了让方法名相同而形式参数不同的构造器同时蹲在,必须用到方法重载。同时,尽管方法重载是构造器所必须的,但他也可以用于其它方法,且用法同样方便。

class Tree{

int height;

Tree(){

System.out.print(“种下一粒种子”);

height=0;

}

Tree(int initialHeight){

height=initialHeight;

System.out.println(“种下了一颗”+ height +”米高的树”);

}

void info(){

System.out.println(“这课树”+ height +”米高”);

}

void info(String s){

System.our.println(s+“:这棵树”+height+”米高”);

}

}

public class Overloading{

for(int i = 0;i < 5;i++){

Tree t=new Tree(i);

t.info();

t.info(“重载方法”);

}

new Tree();

}

输出

种下了一颗0米高的树

这课树0米高

重载方法:这棵树1米高

种下了一颗0米高的树

这课树1米高

重载方法:这棵树1米高

种下了一颗2米高的树

这课树2米高

重载方法:这棵树2米高

种下了一颗3米高的树

这课树3米高

重载方法:这棵树3米高

种下了一颗4米高的树

这课树4米高

重载方法:这棵树4米高

种下一粒种子

创建Tree的时候可以带参数也可以不带参数,前者表示种下一颗有高度的树,后者则表示种下种子。并且你还可以以多种方式调用info()以查看树的信息。

区分方法重载

那么Java是如何区分你所调用的是哪个重载方法呢?其实规则很简单:每个重载的方法都必须有一个独一无二的参数类型列表。

毕竟,一个名字相同的方法,除了参数类型差异以外,还能有什么办法将他们区分开呢?

甚至参数顺序不同也足以区分两个方法。不过,一般不要这样做,因为会是代码难以维护。

public class OverloadingOrder{

static void f(String s,int i){

System.out.print(“String:”+s+”,int:”+i);

}

static void f(int i,String s){

System.out.print(int :”+i+”,String:”+s);

}

public static void main(String [] args){

f(“String first”,11);

f(99,”Int first”);

}

}

输出

String: String first,int:11

int :99,String:int first

涉及基本类型的重载

基本类型能从一个较小的类型自动提升至一个较大的类型,此过程一但涉及重载,可能会有些混淆。

public class Test2 {

void f1(char x){

System.out.print("f1(char)");

}

void f1(byte x){

System.out.print("f1(byte");

}

void f1(short x){

System.out.print("f1(short)");

}

void f1(int x){

System.out.print("f1(int)");

}

void f1(long x){

System.out.print("f1(long)");

}

void f1(float x){

System.out.print("f1(float)");

}

void f1(double x){

System.out.print("f1(double)");

}

void f2(byte x){

System.out.print("f2(byte)");

}

void f2(short x){

System.out.print("f2(short)");

}

void f2(int x){

System.out.print("f2(int)");

}

void f2(long x){

System.out.print("f2(long)");

}

void f2(float x){

System.out.print("f2(float)");

}

void f2(double x){

System.out.print("f2(double)");

}

void f3(short x){

System.out.print("f3(short)");

}

void f3(int x){

System.out.print("f3(int)");

}

void f3(long x){

System.out.print("f3(long)");

}

void f3(float x){

System.out.print("f3(float)");

}

void f3(double x){

System.out.print("f3(double)");

}

void f4(int x){

System.out.print("f4(int)");

}

void f4(long x){

System.out.print("f4(long)");

}

void f4(float x){

System.out.print("f4(float)");

}

void f4(double x){

System.out.print("f4(double)");

}

void f5(long x){

System.out.print("f5(long)");

}

void f5(float x){

System.out.print("f5(float)");

}

void f5(double x){

System.out.print("f5(double)");

}

void f6(float x){

System.out.print("f6(float)");

}

void f6(double x){

System.out.print("f6(double)");

}

void f7(double x){

System.out.print("f7(double)");

}

void testConstVal(){

System.out.print("5: ");

f1(5);f2(5);f3(5);f4(5);f5(5);f6(5);f7(5);System.out.println();

}

void testChar(){

char x='x';

System.out.print("char: ");

f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);System.out.println();

}

void testByte(){

byte x=0;

System.out.print("byte: ");

f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);System.out.println();

}

void testInt(){

int x=0;

System.out.print("int: ");

f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);System.out.println();

}

void testLong(){

long x=0;

System.out.print("long: ");

f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);System.out.println();

}

void testFloat(){

float x=0;

System.out.print("float: ");

f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);System.out.println();

}

void testDouble(){

double x=0;

System.out.print("double: ");

f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);System.out.println();

}

public static void main(String[]args){

Test2 t2=new Test2();

t2.testConstVal();

t2.testChar();

t2.testByte();

t2.testInt();

t2.testLong();

t2.testFloat();

t2.testDouble();

}

}

输出

5: f1(int)f2(int)f3(int)f4(int)f5(long)f6(float)f7(double)

char: f1(char)f2(int)f3(int)f4(int)f5(long)f6(float)f7(double)

byte: f1(bytef2(byte)f3(short)f4(int)f5(long)f6(float)f7(double)

int: f1(int)f2(int)f3(int)f4(int)f5(long)f6(float)f7(double)

long: f1(long)f2(long)f3(long)f4(long)f5(long)f6(float)f7(double)

float: f1(float)f2(float)f3(float)f4(float)f5(float)f6(float)f7(double)

double: f1(double)f2(double)f3(double)f4(double)f5(double)f6(double)f7(double)

常数5被当做int值处理,若有某个重载方法接收int型参数,他就会被调用。至于其他情况如果传入参数小于方法中声明的形式参数类型,实际数据类型就会被提升。char略有不同,如果无法找到恰好接收char参数的方法,就会把char转化成int型。

如果传入参数大于方法声明的参数呢?

改写上面的例子

public class Test2 {

void f1(char x){

System.out.print("f1(char)");

}

void f1(byte x){

System.out.print("f1(byte");

}

void f1(short x){

System.out.print("f1(short)");

}

void f1(int x){

System.out.print("f1(int)");

}

void f1(long x){

System.out.print("f1(long)");

}

void f1(float x){

System.out.print("f1(float)");

}

void f1(double x){

System.out.print("f1(double)");

}

void f2(char x){

System.out.print("f2(char)");

}

void f2(byte x){

System.out.print("f2(byte)");

}

void f2(short x){

System.out.print("f2(short)");

}

void f2(int x){

System.out.print("f2(int)");

}

void f2(long x){

System.out.print("f2(long)");

}

void f2(float x){

System.out.print("f2(float)");

}

void f3(char x){

System.out.print("f3(char)");

}

void f3(byte x){

System.out.print("f3(byte)");

}

void f3(short x){

System.out.print("f3(short)");

}

void f3(int x){

System.out.print("f3(int)");

}

void f3(long x){

System.out.print("f3(long)");

}

void f4(char x){

System.out.print("f4(char)");

}

void f4(byte x){

System.out.print("f4(byte)");

}

void f4(short x){

System.out.print("f4(short)");

}

void f4(int x){

System.out.print("f4(int)");

}

void f5(char x){

System.out.print("f5(char)");

}

void f5(byte x){

System.out.print("f5(byte)");

}

void f5(short x){

System.out.print("f5(short)");

}

void f6(char x){

System.out.print("f6(char)");

}

void f6(byte x){

System.out.print("f6(byte)");

}

void f7(char x){

System.out.print("f7(char)");

}

void testDouble(){

double x=0;

System.out.print("double: ");

f1(x);f2((float)x);f3((long)x);f4((int)x);f5((short)x);f6((byte)x);f7((char)x);System.out.println();

}

public static void main(String[]args){

Test2 t2=new Test2();

t2.testDouble();

}

}

输出

double: f1(double)f2(float)f3(long)f4(int)f5(short)f6(byte)f7(char)

在这里方法接收较小的基本类型参数。如果参入的实际参数太大,就得通过类型转化来进行窄化转换。如果不这样做,编译器就会报错。

以返回值区分重载方法

那么在重载方法的时候时候能通过返回值的不同来区分呢?

void f(){}

int f(){return 1;}

这两个方法当我们这样调用时

int x=f();

编译器很明显知道我们想调用的是第二个方法,但是如果我们只想输出时并不关心返回值,而是想进行其他操作时:

f();

这样调用方法此时Java编译器无法判断该调用哪个一个f(),别人也无法理解。因材,根据返回值来区分方法重载是行不通的。

默认构造器

默认狗操起又称无参构造器是没有形式参数的---它的作用是创建一个默认对象。如果你写的类中没有构造器,则编译器会自动帮你创建一个默认构造器。

class Bird(){

public class DefaultConstructor{

public static void main(String[] args){

Bird b=new Bird();

}

}

}

这里new Bird(),创建了一个Brid对象,并调用了其默认构造器。可见没有他的话就没有方法可以调用,就没法创建对象。但是,如果已经定义了一个构造器(无论是否有参),编译器就不会帮你自动创建默认构造器:

class Brid2{

Brid2(int i){}

Brid2(double d){}

}

public class NoSynthesis{

public static void main(String[] args){

//! Brid2 b=new Bird2();//No default

Brid2 b2=new Bird2(1);

Brid2 b3=new Brid2(1.0);

}

}

若你这样初始化 new Brid2();编译器就会报错

posted on 2011-02-22 14:32  柠檬哥  阅读(556)  评论(0编辑  收藏  举报

导航