第五章 初始化和清理

本文详细介绍了Java中初始化和清理的相关概念,包括构造器的使用确保初始化、方法重载、默认构造器、this关键字、静态数据的初始化顺序以及对象的清理。讲解了构造器如何通过参数确保对象初始化,方法重载的实现,以及在构造器中调用构造器的技巧。同时,文章涵盖了静态和非静态成员的初始化,以及数组和枚举类型的初始化方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第五章 初始化和清理

第五章 初始化和清理

初始化变量和清理数据

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();
	}
	//static
	void 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值