Java 编程思想(第四版)学习笔记(5)初始化与清理

第五章 初始化与清理

一、用构造器确保初始化

1、什么是构造器(constructor)?

创建对象时被自动调用的特殊方法。

2、通过构造器,类的设计者可以确保每个对象都会得到初始化。

3、不接受任何参数的构造器叫做默认构造器,

如果某个class具备构造函数,Java便会在对象生成之际,使用者有能力加以操作之前,自动调用其构造函数,于是便能名确保初始化动作一定被执行。

二、方法重载(method overloading

什么是方法重载?

在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。

如何区分重载方法?

规则很简单:每个重载的方法都必须有一个独一无二的参数类型列表。

由于只能从函数名和函数的引数列来区分两个函数,而重载函数具有相同的函数名称,所以每个重载函数都必须具备独一无二的引数列。

注意:Java的方法重载要求同名的方法必须有不同的参数表,仅有返回类型不同是不足以区分两个重载的方法。

方法重载具体规范

1方法名一定要相同。  

2方法的参数表必须不同,包括参数的类型或个数,以此区分不同的方法体。  

 1)如果参数个数不同,就不管它的参数类型了!   

  2)如果参数个数相同,那么参数的类型或者参数的顺序必须不同。   

3方法的返回类型、修饰符可以相同,也可不同。

三、默认构造器

  1、 default构造函数是一种不带任何引数的构造函数。如果你所开发的class不具任何构造函数,编译器会自动为你生成一个default构造函数。

  2、如果你自行定义了任何一个构造函数(不论有无引数),编译器就不会为你生成default构造函数。

  3、如果定义了一个class,如

class Bush{

  Bush(int I){}

}

当想用new Bush();来产生class的实例时,会产生错误。因为在定义class时已定义了构造函数,所以编译器就不会为class生成default构造函数。当我们用new Bush()来产生实例时,会尝试调用default构造函数,但在class中没有default构造函数,所以会出错。如:

class Sundae

{

    Sundae(int i) {}

}

public class IceCream

{

    public static void main(String[] args)

{

            //Sundae x = new Sundae();会编译出错,无构造函数Sundae()

        Sundae y = new Sundae(1);

    }

}

注意:在定义一个class时,如果定义了自己的构造函数,最好同时定义一个default构造函数

四、This关键字

1、  this仅用于函数之内,能取得“唤起此一函数“的那个object reference。

2、 在构造函数中,通过this可以调用同一class中别的构造函数,如

public class Flower{

    Flower (int petals){}

    Flower(String ss){}

    Flower(int petals, String ss){

    //petals++;调用另一个构造函数的语句必须在最起始的位置

    this(petals);

    this(ss); //会产生错误,因为在一个构造函数中只能调用一个构造函数

    //Constructor call must be the first statement in a constructor

    //this(petals,ss);

    }

注意:  1)在构造调用另一个构造函数,调用动作必须置于最起始的位置

        2)不能在构造函数以外的任何函数内调用构造函数

        3)在一个构造函数内只能调用一个构造函数

  3Static含义

无法在static函数中调用non-static函数(反向可行)

非静态函数可以直接调用静态函数。为什么不能呢,我们看下面的例子。

例4.2.4.1

假设能在static函数中调用non-static函数,那么(a)处就将出错。因为在没有产生Movie class实例之前,在就不存在Movie class内的name实例,而在getName()中却要使用name实例,显然的错误的。

class Movie{

    String name = "12";

    Movie(){}

    public Movie(String name) {

    this.name = name; 

    }

    public static String getName() { 

    return name;//Cannot make a static reference to the non-static field name 

    }

}

public class Test{

    public static void main(String[] args){

        //下面两名先产生实例后再调用getName()没有问题

        Movie movie1 =new Movie("mo");

        String name1 = movie1.getName();

        //下面一名将出错

        String name2 = Movie.getName();

    }

}

五、清理:总结处理和垃圾回收

Java垃圾回收器只负责回收由new分配的内存,但不知道如何释放(并非使用new)获得的内存。

注意:1、对象可能不被垃圾回收

      只有当程序不够内存时,垃圾回收器才会启动去回收不再被使用的对象的内存空间。某个对象所占用的空间可能永远不会被释放掉,因为你的程序可能永远不会逼近内存用完的那一刻,而垃圾回收器完全没有被启动以释放你的对象所占据的内存,那些空间便会在程序终止时才一次归还给操作系统。

      2、垃圾回收并不等于“析构”(析构函数是c++中销毁对象必须用到的函数)

      3、垃圾回收只与内存有关

 只有在采用原生函数(native methods)时,才使用finalize()。

六、成员初始化

1、函数的变量不会被初始化

 void f(){

        int i;

        i++;

}

会报错,提示i not initialized

2、

class的数据成员会被自动初始化,具体情况如下:

基本型别:boolean:false、char:null(\u0000)、byte:0、short:0、int:0、

long:0 、float:0、double:0  对象(reference):null

3、指定初始化:

  1)可以为类的成员变量赋初值进行指定初始化

  2)可以对类创建new对象进行指定初始化。

  3)调用某个方法进行指定初始化

例如:

 public class MethodInit1 {

int i=f();

int f(){

return 11;

}

}

4)调用带参数的方法进行指定初始化

 public class MethodInit1 {    

int i=f();

int j=g(i);

int g(int n){

return n*10;

}

int f(){

return 11;

}

}

5)调用的方法可以带有参数,但是参数必须是已经初始化的。

 public class MethodInit1 {

    int j=g(i);

int i=f();

int g(int n){

return n*10;

}

int f(){

return 11;

}

}

}

换一下顺序会报错,因为int j=g(i);其中i未初始化。上述程序的正确性取决于初始化顺序,而与编译方式无关。

七、构造器初始化

1、初始化顺序:在类的内部,变量定义的先后顺序决定了初始化顺序,即使变量定义散布于方法定义之间,他们仍旧会在任何方法(包括构造器)被调用之前得到初始化。

例如:

class Window{

Window(int marker){

System.out.println("Window("+marker+")");

}

}

class House{

Window window1=new Window(1);

House(){

System.out.println("House()");

window3 =new Window(33);

}

Window window2 = new Window(2);

//void f(){

//System.out.println("f()");

//}

Window window3=new Window(3);

}

public static void main(String[] args) {

House house=new House();

//house.f();

}

/*output

Window(1)

Window(2)

Window(3)

House()

Window(33)

//f()

2、静态数据初始化

静态数据初始化顺序:

  1)先静态对象,而后是“非静态对象”

  2)要执行main(),必须加载静态初始化类(Table Cupboard 初始化),这导致对应Bowl 类的先被执行 ,后执行非静态Cupboard初始化

如下例子:

package com.myfirst.test;

class Bowl{

Bowl(int marker){

System.out.println("Bowl("+marker+")");

}

void f1(int marker){

System.out.println("f1("+marker+")");

}

}

class Table{

static Bowl bowl1 = 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+")");

}

staticBowl bowl5 = new Bowl(5);

}

public class StaticInitialzation {

public static void main(String[] args) {

// TODO Auto-generated method stub

System.out.println("创建对象newcupboard");

new Cupboard();

System.out.println("创建对象newcupboard");

new Cupboard();

table.f2(10);

cupboard.f3(11);

}

static Table table=new Table();

static Cupboard cupboardnew Cupboard();

}

3、显式的静态初始化

Java允许多个静态初始化动作组织成一个特殊的“静态句子”

如下例子:静态初始化动作只执行一次

package com.myfirst.test;

class Cup{

Cup(int marker){

System.out.println("Cup("+marker+")");

}

void f1(int marker){

System.out.println("f1("+marker+")");

}

}

class Cups{

static Cup cup1;

static Cup cup2;

static{

cup1=new Cup(1);

cup2=new Cup(2);

}

Cups(){

System.out.println("cups()");

}

}

public class ExplicitSatic {

public static void main(String[] args) {

System.out.println("inside main()");

Cups.cup1.f1(99);

}

static Cups cups = new Cups();

static Cups cups1 = new Cups();

}

/*outpu

Cup(1)

Cup(2)

cups()

cups()

inside main()

f1(99)

4、非静态实例初始化

八、数组初始化

1、数组初始化实例:

public static void main(String[] args) {

// TODO Auto-generated method stub

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

int[] a2;

a2=a1;//将一个数组赋值给另一个数组

for(int i=0 ;i<a1.length;i++)

System.out.println("a1["+i+"]="+a1[i]);

//java中计数是从第0个元素开始的,所以能使用的最大下标数十length-1

System.out.println("----------------------");

for (int i = 0; i < a2.length; i++) {

a2[i]=a2[i]+1;

System.out.println("a2["+i+"]="+a2[i]);

}

System.out.println("-----------------------");

for(int i=0 ;i<a1.length;i++)

System.out.println("a1["+i+"]="+a1[i]);

}

/*output

a1[0]=1

a1[1]=2

a1[2]=3

a1[3]=4

a1[4]=5

----------------------

a2[0]=2

a2[1]=3

a2[2]=4

a2[3]=5

a2[4]=6

-----------------------

a1[0]=2

a1[1]=3

a1[2]=4

a1[3]=5

a1[4]=6

2、数组初始化实例二三

public class ArrayNew {

public static void main(String[] args) {

// TODO Auto-generated method stub

Random random=new Random();

//random.nextInt(15)取得15以内的随机数

int[] a = new int[random.nextInt(15)];

System.out.println("a的长度"+a.length);

//Arrays.toString(a)方法,他将产生一维数组的可打印版本。

System.out.println(Arrays.toString(a));

//Integer是一个类不是基本类型(以下是一个引用数组)

Integer[] b =new Integer[random.nextInt(20)];

System.out.println("b的长度"+b.length);

//Arrays.toString(b)由于interger是非基本类型,所以产生null

System.out.println(Arrays.toString(b));

for (int i = 0; i < b.length; i++) {

b[i]=random.nextInt(30);

}

System.out.println(Arrays.toString(b));

//--------使用花括号列表来初始化对象数组---------------

int[] c = {new Integer(1),new Integer(2),3};

System.out.println(Arrays.toString(c));

Integer[] d={new Integer(1),new Integer(2),3};

System.out.println(Arrays.toString(d));

}

}

/*output

a的长度12

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

b的长度9

[null, null, null, null, null, null, null, null, null]

[25, 27, 11, 25, 20, 7, 19, 15, 8]

[1, 2, 3]

[1, 2, 3]

3、可变参数列表:

1)  object数组

使用foreach来迭代数组

package com.myfirst.test;

class A{}

public class VarArgs {

 static void printArray(Object[] args){

for (Object object : args) {

System.out.print(object+"  ");

}

System.out.println();

}

public static void main(String[] args) {

// TODO Auto-generated method stub

printArray(new Object[]{new Integer(1),new Float(3.12),new Double(11.11)});

printArray(new Object[]{"s1","b2"});

//打印类的名称和对象的地址

printArray(new Object[]{new A(),new A()});

printArray((Object[]) new Integer[]{1,2,3});

//printArray();//会报错The method printArray(Object[]) in the type VarArgs is not applicable for the arguments ()

printArray(args);//it is ok

}

}/*output

1  3.12  11.11  

s1  b2  

com.myfirst.test.A@1a1c887  com.myfirst.test.A@743399  

1  2  3  

2) Object之外类型的可变参数列表实例

public class AarargType {

//character即是:char 固定长度 (char) 或可变长度 (varchar) 字符数据类型。

static void f(Character...args){

//args.getClass()将产生对象的类

System.out.print(args.getClass());

System.out.println(args.length);

}

static void g(int...args){

System.out.print(args.getClass());

System.out.println(args.length);

}

public static void main(String[] args) {

// TODO Auto-generated method stub

f('a');

f();

g(1);

g();

System.out.println(new int[0].getClass());

}

}

九、枚举类型

1、枚举类型的实例是常量

2、用大写字母表示(如果一个名字中含有多个单词,用下划线表示)

3、创建enum时,编译器会自动添加一些有用的特征:如下

   1)它会创建toString()方法,以便显示某个enum实例的名字

   2)会创建ordinal()方法,用来表示特定enum常量的声明顺序

   3static values()方法,根据声明顺序,产生常量的数组

4enum其中一个实用的特性,可以在swith语句使用

实例如下:

public enum Spiciness {

NOT,TONG,LOVE,YOU

}

public class EnumOrder {

public static void main(String[] args) {

Spiciness spiciness = Spiciness.LOVE;

System.out.println(spiciness);

for (Spiciness spiciness2 : Spiciness.values()) {

System.out.println(spiciness2+"ordinal"+spiciness2.ordinal());

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值