第五章 初始化和清理

  • 第五章 初始化和清理
    • 5.1 用构造器确保初始化
      • 练习1 :创建一个类,它包含一个未初始化的String引用,验证该引用被Java初始化成null
      • 创建一个类,它包含一个在定义时候就被初始化了String域,以及另一个通过构造器初始化的String域
    • 5.2 方法重载
      • 5.2.1 区分重载方法
      • 设计基本类型的重载
      • 5.2.3 已返回值区分重载方法
    • 5.3 默认构造器
      • 练习三:创建一个带默认构造器的类,在构造器中打印一条消息。为这个类创建一个对象
      • 练习四:为前一个练习中的类添加一个重载构造器,令其接受一个字符串参数,并在构造器中吧你的消息和接受的参数一起打印出来
      • 练习五:创建一个名为Dog的类,它具有重载的bark方法,此方法根据不同的基本数据类型进行重载,并根据被调用的版本,打印出不同类型的狗吠(barking)、咆哮(howling)。并调用
      • 练习六:修改前一个程序,让两个重载方法各自接受两个类型的不同的参数,但是顺序相反。
      • 练习七:创建一个没有构造器的类,并在main方法中创建对象,验证编译器是否添加了默认的构造器
    • 5.3 this关键字
      • 练习八:编写具有两个方法的类,在第一个方法内调用第二个方法两次;第一次调用时不使用this关键字,第二次调用使用this关键字-只是为了验证他是否起作用,在实践中不应该使用。
      • 5.4.1 在构造器中调用构造器
      • 练习九:编写具有两个重载构造器的类,并在第一个构造器中通过this调用第二个构造器
      • 5.4.2 static的含义
    • 5.5 清理:终结处理和垃圾回收
    • 5.6 成员初始化
      • 5.6.1 指定初始化
    • 5.7 构造器初始化
      • 5.7.1 初始化顺序
      • 5.7.2 静态数据的初始化
      • 5.7.3显示的静态初始化
      • 练习13:验证创建对象的时候初始化
      • 练习14:编写一个类,拥有两个静态字符串域,其中一个在定义处,另一个在静态块中初始化。现在,加入一个静态方法用以打印两个字段值,证明它们在被使用前都会被初始化
      • 5.7.4 非静态实例初始化
      • 练习15:编写一个含有字符串域的类,并采用实例化初始化
    • 5.8 数组初始化
      • 练习16:创建一个String数组,赋值,打印。
      • 练习17:创建一个类,它有一个接受String的构造器。构造的时候,打印参数。创建一个该类的对象引用数组,不为对象数组赋值。注意构造器中的初始化消息是否打印出来。
      • 练习18:赋值给对象
      • 5.8.1可变参数列表
      • 练习19:写一个类,他接受一个可变参数的String数组。接受String列表或者String【】
      • 练习20:创建一个使用可变参数列表而不是普通的main()语法的main。打印所产生args数组的所有元素。
    • 5.9 枚举类型
      • 练习21:创建一个enum,它包含纸币中的最小面值的六个类型。通过values()打印ordinal()
      • 练习22:在switch语句中打印面值

第五章 初始化和清理

初始化变量和清理数据

5.1 用构造器确保初始化

假设为每个类都定义一个initialize方法,该方法提醒你在使用对象的时候,先调用initialize方法。这要求用户必须自己调用该方法。
在Java中,通过构造器,类的设计者可以确保每个对象都会得到初始化。创建对象的时候,类有构造器,Java就会在用户操作对象之前就调用相应的构造器,保证了初始化的进行。
构造器的名称和类相同。


public class Demo{public static void main(String args[]){for(int i = 0; i < 10; i++){Rock rock = new Rock();}}
}class Rock{Rock(){System.out.println("Rock");}
}

创建对象 new Rock(),将会为对象分配存储空间,并调用相应的构造器。这确保了在你能操作对象的时候,他已经初始化了。
构造器的名称和类名相同,方法首字母小写的规则并不适用于构造器。
默认构造器:不接受任何参数的构造器,无参构造器

public class Demo{public static void main(String args[]){for(int i = 0; i < 8; i++){new Rock(i);}}
}
class Rock{Rock(int i){System.out.println("Rock" + i);}
}

构造器有了参数之后,就可以在初始化对象的时候提供实际参数。Tree有一个构造器,它接受一个整型变量来表示树的高度
Tree t = new Tree(12);
如果Tree(int)是Tree类中的唯一构造器,那么编译器将不会允许你以任何方式创建Tree对象
构造器有助于减少错误,并且代码更容易阅读。
在Java中初始化和创建捆绑在一起,两者不能分离。

构造器是一种特殊的方法,没有返回值

练习1 :创建一个类,它包含一个未初始化的String引用,验证该引用被Java初始化成null

public class Demo{static String s;public static void main(String args[]){System.out.println(Demo.s);Demo demo = new Demo();System.out.println(demo.s);}
}

创建一个类,它包含一个在定义时候就被初始化了String域,以及另一个通过构造器初始化的String域

public class Demo{static String s;public static void main(String args[]){System.out.println(s);Demo demo = new Demo("sdfasf");}public Demo(String s){System.out.println(s);}
}
//构造器里面的数据必须手动进行初始化

5.2 方法重载

当创建一个对象的时候,也就给对象分配到的存储空间娶了一个名字。方法实际上是给某个动作取得名字。
通过名字可以引用所有的名字和方法
方法重载:相同的名字可以表示不同的含义。
在Java中,构造器是强制重载方法名的另一个原因。构造器的名字由类决定,就只能有一个构造器名。但是想用多种方法来构造对象。这就需要多个构造器。但是它们的名字相同,必须用到方法重载。方法重载除了可以用在构造器上,用在其他方法也是可以的。

public class Demo{public static void main(String args[]){for(int i = 0; i < 5; i++){Tree t = new Tree(i);t.info();t.info("嘻sdf");}new Tree();}
}
class Tree{int height;Tree(){System.out.println("种一个种子");height = 0;}Tree(int i){height = i;System.out.println("种了一个树"+height);}void info(){System.out.println("树高"+height);}void info(String s ){System.out.println(s+"树高"+height);}
}

5.2.1 区分重载方法

有几个名字相同的方法,Java如何知道你指的是哪一个?每个重载的方法都必须有一个独一无二的参数类型列表。甚至参数顺序的不同也能区分两个方法,但是一般别这么做。

public class Demo{public static void main(String args[]){f(1,"sdfsf");f("sdfsfdfd",3);}static void f(int i, String s){System.out.println(i +""+ s);}static void f(String s, int i){System.out.println(s +""+ i);}}

设计基本类型的重载

基本类型从一个较小的类型自动提升为一个较大的类型,

public class Demo{public static void main(String args[]){}void f1(char x) {System.out.println("f1(char)");}void f1(byte x) {System.out.println("f1(byte)");}void f1(short x) {System.out.println("f1(short)");}void f1(int x) {System.out.println("f1(int)");}void f1(long x) {System.out.println("f1(long)");}void f1(float x) {System.out.println("f1(float)")}void f1(double x) {System.out.println("f1(double)");}void f2(byte x){System.out.println("f2(byte)");}void f2(short x){System.out.println("f2(short)");}void f2(int x){System.out.println("f2(int)");}void f2(long x){System.out.println("f2(long)");}void f2(float x){System.out.println("f2(float)");}void f2(double x){System.out.println("f2(double)");}void f3(short x){System.out.println("f3(short)");}void f3(int x){System.out.println("f3(int)");}void f3(long x){System.out.println("f3(long)");}void f3(float x){System.out.println("f3(float)");}void f3(double x){System.out.println("f3(double)");}void f4(int x){System.out.println("f4(int)")}void f4(long x){System.out.println("f4(long)")}void f4(float x){System.out.println("f4(float)");}void f4(double x){System.out.println("f4(double");}void f5(long x){System.out.println("f5(long)");}void f5(float x){System.out.println("f5(float)");}void f5(double x){System.out.println("f5(double)")}void f6(float x){System.out.println("f6(float)");}void f6(double x){System.out.println("f6(double)");}void f7(double x){System.out.println("f7(double)");}void test1(){System.out.println("5");f1(5);f2(5);f3(5);f4(5);f5(5);f6(5);f7(5); // int,int,int,int,long,float,double}void test2(){char x = 'x';System.out.println("char");f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);// char,byte,short,int,long,float,double// char,int,int ,int ,long ,float,double//如果没有char类型,会直接提升为int类型}void test3(){byte x = 0;System.out.println("byte");f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);//byte,byte,short,int,long,float,double}void test4(){short x = 0;System.out.println("short");f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);//short,short,short,int,long,float,double}void test5(){int x = 0;System.out.println("int");f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);//int,int,int,int,long,float,double}void test6(){long x = 0;System.out.println("long");f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);//long,long,long,long,long,float,double}
}

如果传入的实际参数大于重载方法声明的形式参数,会出现什么情况呢。

public class Demo{public static void main(String args[]){Demo demo = new Demo();demo.test();}void f1(char x){System.out.println("f1(char)");}void f1(byte x){System.out.println("f1(byte)");}void f1(short x){System.out.println("f1(short)");}void f1(int x){System.out.println("f1(int)");}void f1(long x){System.out.println("f1(long)");}void f1(float x){System.out.println("f1(float)");}void f1(double x){System.out.println("f1(double)");}void f2(char x){System.out.println("f2(char)");}void f2(byte x){System.out.println("f2(byte)");}void f2(short x){System.out.println("f2(short)");}void f2(int x){System.out.println("f2(int)");}void f2(long x){System.out.println("f2(long)");}void f2(float x){System.out.println("f2(float)");}void f3(char x){System.out.println("f3(char)");};void f3(byte x){System.out.println("f3(byte)");};void f3(short x){System.out.println("f3(short)");};void f3(int x){System.out.println("f3(int)");};void f3(long x){System.out.println("f3(long)");};void f4(char x){System.out.println("f4(char)");}void f4(byte x){System.out.println("f4(byte)");}void f4(short x){System.out.println("f4(short)");}void f4(int x){System.out.println("f4(int)");}void f5(char x){System.out.println("f5(char)");}void f5(byte x){System.out.println("f5(byte)");}void f5(short x){System.out.println("f5(short)");}void f6(char x){System.out.println("f6(char)");}void f6(byte x){System.out.println("f6(byte)");}void f7(char x){System.out.println("f7(char)");}void test(){double x = 0;System.out.println("double");f1(x);f2((float)x);f3((long)x);f4((int)x);f5((short)x);f6((byte)x);f7((char)x);}}

方法接受较小的基本类型作为参数。如果传入的实际参数较大,通过强制转换。

5.2.3 已返回值区分重载方法

区分方法重载的时候,为什么只能以类名和方法的形参列表。能否考虑方法的返回值区分。

void f(){}
int f(){}
int x = f();
//编译器可以明确的知道调用的是哪一个方法
//如果只是单纯的调用方法,不接收返回值
f();
//此时编译器不知道要调用的是哪一个方法

5.3 默认构造器

默认构造器,创建一个默认对象。如果你写的类中没有构造器,则编译器会自动帮助你创建一个默认构造器

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

new Bird()创建了一个对象,并调用其默认构造器。没有默认构造器,就没有方法可以调用,就无法创建对象。如果已经定一个构造器(无论有没有参数)编译器不会自动帮助你创建

public class Demo{public static void main(String args[]){//Bird b = new Bird(); 没有默认的构造方法,编译器不会创建,会报错Bird b1 = new Bird(1);Bird b2 = new Bird(1.0);}
}class Bird{Bird(int i){};Bird(double d){};
}

练习三:创建一个带默认构造器的类,在构造器中打印一条消息。为这个类创建一个对象

public class Demo{public Demo(){System.out.println("这是一个默认构造器");}public static void main(String args[]){Demo demo = new Demo();}
}

练习四:为前一个练习中的类添加一个重载构造器,令其接受一个字符串参数,并在构造器中吧你的消息和接受的参数一起打印出来

public class Demo{public Demo(){System.out.println("这是一个默认的构造方法");}public Demo(String s){System.out.println("这是一个带参数的构造方法,参数是:"+s);}public static void main(String args[]){Demo demo = new Demo();Demo demo1 = new Demo("123");}
}

练习五:创建一个名为Dog的类,它具有重载的bark方法,此方法根据不同的基本数据类型进行重载,并根据被调用的版本,打印出不同类型的狗吠(barking)、咆哮(howling)。并调用

public class Demo{static void bark(int i){System.out.println("barking");}static void bark(String s){System.out.println("howling");}public static void main(String args[]){bark(1);bark("sdf");}
}

练习六:修改前一个程序,让两个重载方法各自接受两个类型的不同的参数,但是顺序相反。

public class Demo{static void bark(int i, String s){System.out.println("barking");}static void bark(String s, int i){System.out.println("howling");}public static void main(String args[]){bark(123,"sdf");bark("sdf",123);}
}

练习七:创建一个没有构造器的类,并在main方法中创建对象,验证编译器是否添加了默认的构造器

public class Demo{public static void main(String args[]){Demo demo = new Demo();}
}

5.3 this关键字

如果有同一类型的两个对象,分别是a和b。如何才能让两个对象都能调用peel()方法。

public class Demo{public static void main(String args[]){Banana b = new Banana(),c = new Banana();b.peel(1);c.peel(2);}
}
class Banana{void peel(int i){}
}

只有一个peel方法,如何知道是被a还是b调用的。
编译器做了一些幕后工作,它暗自把所操作对象的引用作为第一个参数传递给peel。
Banana.peel(a, 1);
Banana.peel(b, 2);

如果你希望在方法的内部获得对当前对象的引用。因为这个引用是由编译器偷偷传入的,所以没有标识符可用。为此有一个专门的关键词:this。this关键字只能在方法的内部使用,表示调用方法的那个对象的引用。this和其他对象引用并无不同。如果在方法内部调用同一个类的另一个方法,不必使用this。

public class Demo{vodi pick(){};vodi pit(){pick();};
}

当需要返回当前对象的引用时,

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

increment方法通过this关键字返回了当前对象的引。
this关键字对于将当前对象传递给其他方法也很有用。

public class Demo{public static void main(String args[]){new Person().eat(new Apple());}
}
class Person{public void eat(Apple apple){Apple apple1 = apple.getPeeled();System.out.println("Yummy");}
}
class Peeler{static Apple peel(Apple apple){return apple;}
}class Apple{Apple getPeeled(){return Peeler.peel(this);};
}

练习八:编写具有两个方法的类,在第一个方法内调用第二个方法两次;第一次调用时不使用this关键字,第二次调用使用this关键字-只是为了验证他是否起作用,在实践中不应该使用。

public class Demo{public static void main(String args[]){//Demo.method1(); //无法从静态中使用this。因为this代表一个对象,static不需要对象Demo demo = new Demo();demo.method1();}//staticvoid method1(){System.out.println("这是第一个方法");method2();this.method2();}void method2(){System.out.println("这是第二个方法");}
}

5.4.1 在构造器中调用构造器

一个类可能有多个构造器,一个构造器中调用另一个构造器,避免代码重复。使用this可以做到这一点。
this,是指这个对象或者当前对象。
但是在构造器中,如果为this添加了参数列表,就有了不同的涵义。将产生对符合此参数列表的某个构造器的明确调用

public class Demo{int petalCount = 0;String s = "initial value";Demo(int petal){petalCount = petal;System.out.println(petalCount);}Demo(String ss){System.out.println(ss);s = ss;}Demo(String ss, int petal){this(petal);//this(s); 一个构造器中只能引用一个this方法this.s = ss;System.out.println("String&&int");}Demo(){this("jo", 47);System.out.println("默认构造器");}void printPetalCount(){//this(11); 方法内部不能使用构造器System.out.println(petalCount+""+s);}public static void main(String args[]){Demo demo = new Demo();demo.printPetalCount();}
}

Demo(String s,int petal):尽管可以使用this调用要给构造器,但是不能调用两个,必须将构造i去调用置于最起始处。
this.s = s;
由于参数s和数据成员s的名字相同,所以会产生歧义。使用this就指定了这个是数据成员
printPetalCount方法显示,出构造器外,编译器禁止在其他任何方法中调用构造器。

练习九:编写具有两个重载构造器的类,并在第一个构造器中通过this调用第二个构造器

public class Demo{Demo(int i){System.out.println(i);}Demo(String s){this(1);System.out.println(s);}public static void main(String args[]){Demo demo = new Demo("sdf");}
}

5.4.2 static的含义

static方法就是没有this的方法。在static方法的内部不能调用非静态方法,反过来倒是可以。在没有对象的情况下,可以通过类型调用静态方法,很想全局方法

5.5 清理:终结处理和垃圾回收

5.6 成员初始化

Java尽可能做到,所有变量在使用前都能得到恰当的初始化。对于方法的局部变量,Java以编译错误的形式来保证。

void f(){int i;i++;//错误i可能未被初始化
}

类的数据成员都会保证有一个初始值

public class Demo{boolean t;char c;byte b;short s;int i;long l;float f;double d;Demo demo;void print(){System.out.println(t);System.out.println(c);System.out.println(b);System.out.println(s);System.out.println(i);System.out.println(l);System.out.println(f);System.out.println(d);System.out.println(demo);}public static void main(String args[]){Demo d = new Demo();d.print();}
}

5.6.1 指定初始化

想为某个变量赋初值,该怎么做。

  1. 直接在定义成员变量的时候为其赋值
public class Demo{boolean bool = true;char ch = 'x';byte b = 47;short s = 0xff;int i = 999;long lng = 1;float f = 3.14f;double d = 3.314;Depth depth = new Depth();//如果没有为depth初始化,使用它的话,就会报错。//调用方法赋值int ii = f();int f(){return 11;}
}class Depth{}

这样会有一个限制,就是每一个类的对象都具有相同的值

5.7 构造器初始化

可以使用构造器来进行初始化。但是要注意,无法阻止自动初始化的进行,他将在构造器被调用之前就发生了。

public class Counter{int i ;Counter(){i = 7;}
}
//i会先被初始化为0,然后创建对象的时候被赋值7

5.7.1 初始化顺序

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

public class Demo{public static void main(String args[]){House h = new House();h.f();}
}
class Window{Window(int marker){System.out.println(marker);}
}class House{Window w1 = new Window(1);House(){System.out.println("House");w3 = new Window(33);}Window w2 = new Window(2);void f(){System.out.println("f()");}Window w3 = new Window(3);
}
//在构造方法中代码还是按照顺序执行的,但是初始化,还是先初始化,后再运行构造器和方法,按照代码的顺序。

5.7.2 静态数据的初始化

无论创建多少个对象,静态数据都只会占据一份。static不能作用域局部变量。同时也会被赋值基本类型的默认值。
静态数据是什么时候初始化的

public class Demo{public static void main(String args[]){new CupBoard();new CupBoard();}static Table table = new Table();static CupBoard cupboard = new CupBoard();
}
class Bowl{Bowl(int marker){System.out.println(marker);}void f1(int marker){System.out.println("f"+marker);}
}class Table{static Bowl bowl1 = new Bowl(1);Table(){System.out.println("Table()");bowl2.f1(1);}void f2(int i){System.out.println("f2()"+i);}static Bowl bowl2 = new Bowl(2);
}
class CupBoard{Bowl bowl3 = new Bowl(3);static Bowl bowl4 = new Bowl(4);CunBoard(){System.out.println("CunBoard");bowl4.f1(2);}void f3(int i){System.out.println("f3()"+i);}static Bowl bowl5 = new Bowl(5);
}
//静态只会在第一次初始化,然后就不会初始化了

如果不创建Table对象或者调用Table.b1,那么静态的Bowl b1和b2永远都不会创建。只有在创建Table对象或者访问静态数据的时候。之后不会再被创建。
初始化的顺序:静态对象,非静态对象。
要执行main方法,先加载Demo类,此时会先初始化静态域table和cupboard,同时对应的类也被加载。有都包含Bowl对象,随后Bowl加载
对象的创建过程:

  1. 创建Dog的对象,或者Dog的静态方法或者静态域首次被访问的时候,Java解释器先查找类路径,定位Dog.class
  2. 在如Dog.class,这时候所有的静态初始化都会执行。静态初始化只会在Class对象首次加载的时候进行。
  3. 当创建对象的时候,在堆上分配存储空间
  4. 存储空间会被清零,Dog对象中所有的基本类型数据都设置成了默认值
  5. 执行所有字段定义的初始化
  6. 执行构造器

5.7.3显示的静态初始化

Java允许将多个静态初始化动作组织成一个静态子句(静态块)。

public class Spoon{static int i;static {i = 47;}
}
//与静态初始化一样,这段代码只执行一次;当首次生成这个类的对象,或者访问8静态数据
public class Demo{public static  void main(String args[]){System.out.println("main");Cups.cup1.f(99);//访问静态数据,此时会初始化静态数据,同时又会加载Cup类。}
}class Cup{Cup(int i){System.out.println("Cup"+ i);}void f(int i){System.out.println("f()"+ i);}
}class Cups{static Cup cup1;static Cup cup2;static{cup1 = new Cup(1);cup2 = new Cup(2);}Cups(){System.out.println("Cups()");}
}

练习13:验证创建对象的时候初始化

public class Demo{public static  void main(String args[]){System.out.println("main");//Cups.cup1.f(99);//访问静态数据,此时会初始化静态数据,同时又会加载Cup类。//还有一种就是创建对象的时候会初始化数据Cups cup1 = new Cups();}
}class Cup{Cup(int i){System.out.println("Cup"+ i);}void f(int i){System.out.println("f()"+ i);}
}class Cups{static Cup cup1;static Cup cup2;static{cup1 = new Cup(1);cup2 = new Cup(2);}Cups(){System.out.println("Cups()");}
}

练习14:编写一个类,拥有两个静态字符串域,其中一个在定义处,另一个在静态块中初始化。现在,加入一个静态方法用以打印两个字段值,证明它们在被使用前都会被初始化

public class Demo{public static void main(String args[]){Test.print();}}class Test{static String s = "123";static String ss;static{ss = "asdf";}static void print(){System.out.println(s);System.out.println(ss);}
}

5.7.4 非静态实例初始化

实例初始化,用来初始化每一个对象的非静态变量。

public class Mugs{Mug mug1;Mug mug2;{mug1 = new Mug(1);mug2 = new Mug(2);System.out.println("mug1&mug2初始化");}Mugs(){System.out.println("Mugs()");}Mugs(int i){System.out.println("Mugs(int)");}public static void main(String args[]){System.out.println("Inside main()");new Mugs();System.out.println("new Mugs() ompleted");new Mugs(1);System.out.println("new Mugs(1)");}
}
class Mug{Mug(int i){System.out.println();}void f(int i){System.out.println("f()"+i);}
}

实例初始化子句实在两个构造器之前完成的。无论你调用了那个构造器,某些操作都会发生。

练习15:编写一个含有字符串域的类,并采用实例化初始化

public class Demo{public static void main(String args[]){Test test = new Test();}
}
class Test{String s;{s = "asef";System.out.println("123");//由此可见,实例初始化一定是在构造器之前完成的}Test(){System.out.println("构造器");}}

5.8 数组初始化

数组是相同类型,用一个标识符封装到一起的序列。
数组的定义:int[] a1; 或者int a[]
现在拥有的只是对数组的一个引用(已经为引用分配了足够的空间),但是并没有为数组对象本身分配空间。给数组分配空间,必须初始化表达式
int[] a1 = {1, 2, 3, 4, 5}
那么还要再没有数组的时候定义另一个数组引用呢。
int[] a2;
将一个数组赋值给另一个数组
a2 = a1;

public class Demo{public static void main(String args[]){int[] a1 = {1, 2, 3, 4, 5 };int[] a2;a2 = a1;for(int i = 0; i < a2.length; i++){a2[i] = a2[i] + 1;}for(int i = 0;i < a1.length; i++){System.out.println(a1[i]);}}
}

数组可以通过length获得他的长度。java中是从0开始存储数据。
如果数组的大小不确定,那么该如何做呢。
可以通过new创建一个数组

import java.util.*;
public class Demo{public static void main(String args[]){int[] a;Random random = new Random(47);a = new int[random.nextInt(20)];System.out.println(a.length);System.out.println(Arrays.toString(a));}
}

数组中的基本类型会被初始化默认值
创建一个非基本类型的数组

import java.util.*;
public class Demo{public static void main(String[] args){Random rand = new Random();Integer[] a = new Integer[rand.nextInt(20)];System.out.println(a.length);for(int i = 0; i < a.length; i++){a[i] = rand.nextInt(500);//这里才进行了初始化}System.out.println(Arrays.toString(a));}
}
import java.util.*;
public class Demo{public static void main(String[] args){Integer[] a = {new Integer(1), new Integer(2), new Integer(3)};Integer[] b = new Integer[]{new Integer(1), new Integer(2), 3};System.out.println(Arrays.toString(a));System.out.println(Arrays.toString(b));}
}

创建一个String数组,传递给另一个main方法()

public class Demo{public static void main(String[] args){Test.main(new String[]{"df", "dsfxcv"});}
}class Test{public static void main(String[] args){for(String arg : args){System.out.println(arg);}}
}

练习16:创建一个String数组,赋值,打印。

import java.util.*;
public class Demo{public static void main(String[] args){String [] s0 = new String[3];String[] s = new String[]{"23", "xc"};String[] s1 = {"1", "2", "3"};System.out.println(s0);System.out.println(Arrays.toString(s));System.out.println(Arrays.toString(s1));}
}

练习17:创建一个类,它有一个接受String的构造器。构造的时候,打印参数。创建一个该类的对象引用数组,不为对象数组赋值。注意构造器中的初始化消息是否打印出来。

public class Demo{public static void main(String[] args){Test[] test = new Test[20];}
}class Test{Test(String s){System.out.println(s);}
}
//创建数组并不会调用构造器

练习18:赋值给对象

public class Demo{public static void main(String[] args){Test[] test = new Test[]{new Test("sdf"), new Test("xcvD")};}
}class Test{Test(String s){System.out.println(s);}
}

5.8.1可变参数列表

数组初始化的第二种形式,创建对象并调用方法。这可以用在参数个数或者类型未知的场合。

 public class  Demo{static void print(Object[] object){//所有的类都是直接或者间接的继承Object类for(Object obj : object){System.out.println(obj);}}public static void main(String[] args){print(new Object[]{new Integer(48), new Integer(123), new Integer(23)});print(new Object[]{"one", "two", "three"});print(new Object[]{new A(), new A(), new A()});}
}class A{}

可变参数

public class Demo{static void print(Object... args){for(Object obj : args){System.out.println(obj);}}public static void main(String[] args){print(new Integer(1), new Float(1.2f), new Double(3.2));print(47, 3.14f, 11.11);print("one", "two", "three");print(new A(), new A(), new A());print(new Integer[]{1, 2, 3 , 4});//???? print();}
}
class A{}

当你指定参数时,编译器帮你填充数组

public class Demo{static void f(int i, String... args){System.out.println(i);for(String arg : args){System.out.println(arg);}}public static void main(String args[]){f(1);f(1,"sdf","xcv");f(0);}
}

可变参数不依赖于自动包装机制

public class Demo{public static void main(String[] args){f('a');f();g(1);g();System.out.println(new int[0].getClass());}static void f(Character... args){System.out.println(args.getClass());System.out.println(args.length);}static void g(int... args){System.out.println(args.getClass());System.out.println(args.length);}
}
public class Demo{static void f(Integer... args){for(Integer arg : args){System.out.println(arg);}}public static void main(String args[]){f(new Integer(1), new Integer(2));f(4, 5, 6, 7, 8);f(9, 10, new Integer(11));}
}
//可变参数中基本类型提升为包装器
//可变参数的重载
public class Demo{public static void main(String args[]){f('a', 'b', 'c');f(1);f(2, 1);f(0);f(0L);}static  void f(Character... args){System.out.println("first");for(Character arg : args){System.out.println(arg);}}static void f(Integer... args){System.out.println("second");for(Integer arg : args){System.out.println(arg);}}static void f(Long... args){System.out.println("third");}//一个参数默认运行的是这个方法static void f(Integer i){System.out.println("four");}
}

但是当不使用参数调用f(),编译器就不知道是哪个方法了。
可以通过某个方法中添加一个非可变的参数

public class Demo{public static void main(String[] args){f(1, 'a');f('a', 'b');}static void f(float i, Character... args){System.out.println("first");}static void f(Character... args){System.out.println("second");}
}
//此时两个方法都会匹配
//自动转换float--》char--》Character
//两个方法都添加一个非可变参数,就可以解决问题了。

练习19:写一个类,他接受一个可变参数的String数组。接受String列表或者String【】

public class Demo{public static void main(String args[]){f("123", "456", "789", "0");f(new String[]{"asdf", "zcxv"});}static void f(String... args){for(String arg : args){System.out.println(arg);}}
}

练习20:创建一个使用可变参数列表而不是普通的main()语法的main。打印所产生args数组的所有元素。

public class Demo{public static void main(String[] args){Test.main("123", "123", "123", "123");Test.main("123", "123");}}
class Test{static void main(String... args){for(String arg : args){System.out.println(arg);}}
}

5.9 枚举类型

创建一个集合,并将自身的取值限制在这个集合内。

public class Demo{public static void main(String args[]){S s = S.NOT;System.out.println(s);}
}
public enum S{NOT, MILD, MEDIUM, HOT, FLAMING
}
public class Demo{public static void main(String args[]){for(S s : S.values()){System.out.println(s+""+s.ordinal());}}
}
public enum S{NOT, MILD, MEDIUM, HOT, FLAMING
}
//values()产生数组
//ordinal产生顺序

枚举和switch

public class Demo{S degree;public Demo(S degree){this.degree = degree;}public void describe(){System.out.println("This Demo is");switch(degree){case NOT:System.out.println("NOT");break;case MILD:System.out.println("MILD");break;case MEDIUM:System.out.println("MEDIUM");break;case HOT:System.out.println("HOT");break;case FLAMING:System.out.println("FLAMING");break;default:System.out.println("default");}}public static void main(String[] args){Demo d = new Demo(S.NOT),d1 = new Demo(S.MILD),d2 = new Demo(S.FLAMING);d1.describe();d2.describe();d.describe();}
}
public enum S{NOT, MILD, MEDIUM, HOT, FLAMING
}

练习21:创建一个enum,它包含纸币中的最小面值的六个类型。通过values()打印ordinal()

public class Demo{public static void main(String[] args){for(Money m : Money.values()){System.out.println(m+":"+m.ordinal());}}
}
public enum Money{VALUE1, VALUE2, VALUE5, VALUE10, VALUE20, VALUE50, VALUE100;
}

练习22:在switch语句中打印面值

public class Demo{public static void main(String[] args){for(Money m : Money.values()){switch(m){case VALUE1:System.out.println("1块钱");break;case VALUE2:System.out.println("2块钱");break;case VALUE5:System.out.println("5块钱");break;case VALUE10:System.out.println("10块钱");break;case VALUE20:System.out.println("20块钱");break;case VALUE50:System.out.println("50块钱");break;case VALUE100:System.out.println("100块钱");break;default:System.out.println("没有该面值");}}}
}
public enum Money{VALUE1, VALUE2, VALUE5, VALUE10, VALUE20, VALUE50, VALUE100;
}

第五章 初始化和清理相关推荐

  1. 20190816 On Java8 第六章 初始化和清理

    第六章 初始化和清理 利用构造器保证初始化 在 Java 中,类的设计者通过构造器保证每个对象的初始化. 构造器名称与类名相同. 在 Java 中,对象的创建与初始化是统一的概念,二者不可分割. 方法 ...

  2. java编程思想初始化引用,JAVA编程思想--第5章 初始化与清理

    随着计算机革命的发展,"不安全"的编程方式已逐渐成为编程代价高昂的主因之一. 初始化和清理(cleanup)是涉及安全的两个问题.初始化时,忘记初始化时许多错误的来源,还有就是不知 ...

  3. Java编程思想 4th 第5章 初始化与清理

    cnblogs原创 转载于:https://www.cnblogs.com/pluse/p/7358062.html

  4. 第五章:初始化与清理

    第五章 初始化与清理 初始化和清理正是涉及安全的两个问题,Java中也引入了构造器,并额外提供了垃圾回收器 5.1 用构造器确保初始化 构造方法会在new对象的时候,也就是我们调用对象之前去执行一些初 ...

  5. Java编程思想总结篇(1-11章学习笔记)——第五章

    第五章 初始化与清理 1.用构造器确保初始化 构造器:和类名相同,分无参构造器和有参构造器. 和C++一样,你不写他也会帮你写. 构造器有利于减少错误,并使代码更易阅读.从概念上讲,"初始化 ...

  6. java编程思想 初始化_《java编程思想》_第五章_初始化与清理

    初始化和清理是涉及安全的两个问题,java中采用了构造器,并额外提供了"垃圾回收器",对于不再使用的内存资源,垃圾回收器能自动将其释放. 一.用构造器确保初始化 java中,通过提 ...

  7. java 析构函数_《JAVA编程思想》5分钟速成:第5章(初始化和清理)

    第五章.初始化和清理 前言 1.初始化顺序(静态成员.非静态成员,构造器.父类构造器)的排序: 2.构造器(constructor)是否可被重写(override)? 3.final, finally ...

  8. 「地表最强」C++核心编程(五)类和对象--对象初始化和清理

    环境: 编译器:CLion2021.3:操作系统:macOS Ventura 13.0.1 文章目录 一.构造函数和析构函数 1.1 构造函数 1.2 析构函数 1.3 示例 二.构造函数的分类及调用 ...

  9. Visual C++ 2008入门经典 第十五章 在窗口中绘图

    /*第十五章 在窗口中绘图 主要内容: 1 Windows为窗口绘图提供的坐标系统 2 设置环境及其必要性 3 程序如何以及在窗口中绘图 4 如何定义鼠标消息的处理程序 5 如何定义自己的形状类 6 ...

  10. 聚焦3D地形编程第五章GeomipMapping for the CLOD

    第二部分高级地形编程 聚焦3D地形编程第五章GeomipMapping for the CLOD 译者: 神杀中龙 邵小宁 microsoftxiao@163.com 翻译的烂请见谅 原著 <F ...

最新文章

  1. ie下面出现Notice: Undefined index: HTTP_REFERER 的解决办法
  2. Linux基础第一周
  3. Java反射机制和动态代理实例
  4. TCP/IP详解学习笔记(7)-广播和多播,IGMP协议
  5. ASP.NET MVC (四、ASP.NET Web API应用程序与跨域操作)
  6. 如何用JavaScript判断前端应用运行环境(移动平台还是桌面环境)
  7. python画五角星代码_Python使用Turtle模块绘制五星红旗代码示例
  8. 娜塔莉波特曼2015哈佛毕业演讲
  9. Flutter视频播放、Flutter VideoPlayer 视频播放组件精要
  10. Locked Treasure
  11. Tensorflow-(4)使用Tensorflow加载csv,pandas dataframes,图像,文本文件
  12. Oracle 数据库生成2022年节假日表SQL
  13. 2016,我有些明白了
  14. 移动机器人 | 同时定位与建图
  15. (45.5)【API接口漏洞】API接口之Web Service测试工具Soap UI PRO、SOAPSonar、Burp Suite、WSSAT、WS-Attacker
  16. linux vi回到末行模式,Linux vi/vim 的命令模式,,编辑模式,末行模式
  17. 2015年3月TIOBE编程语言排行榜单
  18. WZOI-359字符串哈希
  19. 竖版视频怎么批量转换成横版视频
  20. 如何做出好看的三维平面地图?

热门文章

  1. 构建虚拟Web主机——基于IP地址的虚拟主机
  2. 清除“我的电脑”地址栏中的记录
  3. 【5GC】三种SSC(Session and Service Continuity)模式介绍
  4. AltiumDesigner2020导入3D Body-SOLIDWORKS三维模型
  5. 随着员工转为远程办公,Diligent在所有董事会管理平台中提供无缝视频会议接入,确保安全的虚拟董事会议
  6. WKWebView 如何支持window.open方法
  7. java编程第七周作业
  8. win10删除工作组计算机,win10工作组怎么退出-退出win10工作组的教程 - 河东软件园...
  9. 优质软文怎么写----皆义 网途
  10. VOT 数据集下载toolkit