第五章 初始化和清理
第五章 初始化和清理
初始化变量和清理数据
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 指定初始化
想为某个变量赋初值,该怎么做。
- 直接在定义成员变量的时候为其赋值
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加载
对象的创建过程:
- 创建Dog的对象,或者Dog的静态方法或者静态域首次被访问的时候,Java解释器先查找类路径,定位Dog.class
- 在如Dog.class,这时候所有的静态初始化都会执行。静态初始化只会在Class对象首次加载的时候进行。
- 当创建对象的时候,在堆上分配存储空间
- 存储空间会被清零,Dog对象中所有的基本类型数据都设置成了默认值
- 执行所有字段定义的初始化
- 执行构造器
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;
}