初始化与清理

用构造器确保初始化

在java中通过构造器,类的设计者可以确保每个对象都会得到初始化。
在创建对象时,如果类具有构造器,java就会在用户又能了操作对象之前自动调用构造器,从而保证了初始化的进行。
构造器命名与类具有相同的名称。
来看一个简单的构造器

class Rock {
    Rock() {
         System.out.print("Rock ");
    }
    public static void main(String[] args) {
        Rock rock = new Rock();
    }
}

在上面代码中new Rock();时,程序将会为对象分配存储空间,并且调用相应的构造器。这就确保了在你对这个对象操作对象之前,它就已经被恰当的初始化了。

不接受任何参数的构造器叫做默认构造器,或者叫做无参构造器。和其他的方法一样,构造器也能带有形式参数,以便指定如何创建对象。对上面修改一下:

class Rock {
    Rock(int i) {
         System.out.print("Rock " + i + " ");
    }
    public static void main(String[] args) {
        Rock rock = new Rock(3);
    }
}

从概念上来说,“初始化“和“创建“是独立的。但是在java中两者被捆绑在一起,不能分离。

方法的重载

当创建一个对象时,也就给此对象分配到的存储空间取了一个名字。所谓方法则是给某个动作取名字。通过使用名字,你可以引用所有的对象和方法。

方法重载
下面这个例子示范了重载的构造器和重载的方法

class Tree {
    int height;
    Tree() {
        height = 0;
        System.out.print("Plant a seed");    
    }
    Tree(int initHeight) {
        height = initHeight;
        System.out.print("Create Tree height is " + height + " feet tall" );
    }
    void info() {
        System.out.print("Tree height is " + height + " feet tall");
    }
    void info(String s) {
        System.out.print(s + " Tree height is " + height + " feet tall");
    }
}
public class Overloading {
    public static void main(String[] args) {
        for(int i = 0; i < 5; i++) {
            Tree t = new Tree(i);
            t.info();
            t.info("Over");
        }
        new Tree();
    }
}

区分重载的方法

要是有几个方法具有相同的名字,那么我们可以通过这些方法参数进行区分。

涉及基本类型的重载

基本类型能从一个“较小“的类型自动提升至一个“较大“的类型,此过程一旦牵涉到重载,可能会造成一下混淆。

以返回值区分重载方法

例如 int x = f()

void f()
int f() {return 1;}

默认构造器

默认构造器(无参构造器),它的作用是用来创建一个“默认对象“。如果你写的类中没有构造器,则编译器会自动帮组你创建一个默认构造器,例如:

class Bird {}
public class DefaultConstructor {
    public static void main(String[] s) {
        Bird b = new Bird();
    }
}

默认的构造器是Bird()

this关键字

this关键字只能在方法内部使用,表示对“调用方法的那个对象“的引用。
如果在方法内部调用同一个类的另一个方法,就不必使用this,直接调用即可。

public class Apricot {
    void pick() {}
    void pit() { pick(); }
}

只有当需要明确指出对当前对象的引用时,才需要使用this关键字。例如,当需要返回对当前对象的引用时,就使用return返回this。

public class HelloWorld {
    int i = 0;
    HelloWorld increment() {
        i++;
        return this;
    }
    void print() {
        System.out.println("i = " + i);
    }
    public static void main(String[] args) {
        HelloWorld x = new HelloWorld();
        x.increment().increment().print();
    }
}

由于increment()通过this关键字返回了对当前对象的引用,所以很容易在同一条语句里对同一个对象执行多次操作。
this关键字对于将当前对象传递给其他方法也很有用:


class Person {
    public void eat(Apple apple) {
        Apple peeled = apple.getPeeled();
        System.out.println("Yummy");
    }
}

class Peeler {
    static Apple peel(Apple apple) {
        return apple;
    }
}

class Apple {
    Apple getPeeled() {
        return Peeler.peel(this);
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        new Person().eat(new Apple());
    }
}

在构造器中调用构造器

当你在写一个类时,为这个类写了多个构造器,又是可能想在一个构造器中调用另一个构造器,以避免重复代码。可以使用this关键字做到这一点。
通常写this的时候,都是指“这个对象“或者“当前对象“,而且它本省表示对当前对象的引用。
在构造器中,如果为this添加了参数列表,将会产生对符合此参数列表的某个构造器的明确调用。

public class HelloWorld {
    int petalCount = 0;
    String s = "initial value";
    HelloWorld(int petals) {
        petalCount = petals;
        System.out.println("Constructor w/ int arg only, petalCount = " + petalCount);
    }
    HelloWorld(String ss) {
        s = ss;
        System.out.println("Constructor w/ string arg only, s = " + ss);
    }
    HelloWorld(String s, int petals) {
        this(s);
        //this(petals); Can not call two!
        this.petalCount = petals;
        System.out.println("String & int args");
    }
    HelloWorld() {
        this("hi", 47);
        System.out.println("Default Constructor no args");
    }
    void printPetalCount() {
        //!this(11); Not inside non-constructor
        System.out.println("petalCount = " + petalCount + " s = " + s);
    }
    public static void main(String[] args) {
        HelloWorld h = new HelloWorld();
    }
}

这里的例子表明,尽管可以使用this调用一个构造器,但是不能调用两个。
另外,必须将构造器调用于最起始处,否则编译器会报错。
本例中,由于参数s和类中的成员变量s的名字相同。所以使用了this.s来表示成员变量,避免歧义。在printPetalCount()方法中也体现了,除了构造器之外,编译器禁止在其他任何方法中调用构造器。

static含义

这里讨论一下static(静态)方法。static方法就是没有this的方法,怎么理解呢?首先我们知道this表示调用方法的那个对象的引用。
static方法,是在类没有创建任何对象,可以通过类来调用static方法。通过static修饰的成员或者是方法,在编译时就已经分配好了内存,直到程序退出这块内存才被释放。这样做的意义是?在Java的世界里,一切都是对象,而对象是类的实体,对于一个类而言,如果需要使用它的成员变量或者是方法时,必须先将这个类实例化成对象后,才能通过对象的引用使用这些变量或者是方法。但是通过static修饰后,可以直接通过类名.*来直接访问。

终结处理和垃圾回收

程序员都理解初始化的重要性,但是清理工作同样重要。

垃圾回收只与内存有关,也就是说使用垃圾回收器的唯一原因是为了回收不再使用的内存。

数组

java中数组的概念:数组只是相同类型的、用一个标识符名称封装到一起的一个对象序列或基本类型数据序列。

数组的定义:只要在类型名后面添加一对方括号即可:

int[] a1; or int a1[];
String[] s;

需要说明的是,编译器不允许指定数组的大小。比如在c语言中,定义一个数组:int a[10];

现在我们在java中定义一个数组:int[] a;
到此为止,我们只是拥有了这个类型数组的引用(并且你已经为该引用分配了足够的存储空间),但是并没有给这个数组对象本身分配任何空间。
所以我们需要对这个数组进行初始化。
对于数组,初始化动作可以出现在代码的任何地方;
但是,还有一种特殊的初始化表达式,这种初始化表达式必须在创建数组的地方出现。通过一对花括号括起来的值来组成。
例如:int[] a = {1, 2, 3, 4, 5};

数组赋值给另一个数组:

int[] a = {1, 2, 3, 4, 5};
int[] b;
b = a;

在编程过程中,如果不能确定数组中元素的个数,怎么办?
可以直接用new在数组里创建元素。
例如:

public class HelloWorld {
    public static void main(String[] args) {
        int[] array;
        array = new int[10];
        System.out.println(array.length);
        System.out.println(Arrays.toString(array));
    }
}

并且数组中的每个元素都被初始化成空值(对于数字和字符是0)
当然数组也可以在定义是同时进行初始化。
改写上面程序:

public class HelloWorld {
    public static void main(String[] args) {
        int[] array = new int[10];
        System.out.println(array.length);
        System.out.println(Arrays.toString(array));
    }
}

上面创建的数组都是基本类型的数据,如果需要创建一个非基本类型的数组,那么你需要创建一个引用数组。
例如以整型的包装容器类Integer为例,这是一个类,不是基本类型。

Integer[] a = new Integer[10];

但是我们创建的只是一个引用的数组,所以还要对每一个元素进行初始化(创建对象)。如果忘记创建对象,并且试图使用数组中的空引用,在运行时出现异常。
所以:

Integer[] a = new Integer[10];
for(int i = 0; i < 10; i++) {
    a[i] = i;
}

也可以用花括号来初始化对象数组。

Integer[] a = {
    new Integer(1),
    new Integer(9),
    3, //Autoboxing
}

Integer[] b = new Integer[]{
    new Integer(1),
    new Integer(9),
    3, //Autoboxing
}

但是第一种的形式,只能在数组定义的时候使用。

可变参数列表

由于所有的类都直接或者是间接的继承于Object类(暂时还没有深刻体会,是不是类似于c中的void *呢),所以可以创建以Object数组为参数的方法。

public class HelloWorld {
    static void printArray(Object[] args) {
        for(Object obj : args)
            System.out.print(obj + " ");
        System.out.println();
    }
    public static void main(String[] args) {
        printArray(new Object[] {"one", "two"});
        printArray(new Object[] {new Integer(1), new Integer(2)});
    }
}

在java se5中


public class HelloWorld {
    static void printArray(Object... args) {
        for(Object obj : args)
            System.out.print(obj + " ");
        System.out.println();
    }
    public static void main(String[] args) {
        printArray(47, 11.11, 3.14F);
        printArray("ONE", "TWO", "THREE");
    }
}

枚举类型

枚举类型使用关键字enum
看一个列子:public enum Spiciness {NOT, MILD, HOT, FLAMING}
这里创建了一个名为Spiciness的枚举类型,它具有5个具名值。枚举类型的实例是常量。
为了使用这个enum,我们需要创建一个该类型的引用,并初始化。

public enum Spiciness {
    NOT, MILD, HOT, FLAMING
};
public class HelloWorld {
    public static void main(String[] args) {
        Spiciness howHot = Spiciness.MILD;
        System.out.println(howHot);
    }
}

可以将enum作为类来看,事实上enum确实是类,并且有着自己的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值