不少类都包含一个无参数的构造函数,对象由无参数构造函数建立时,其状态会设置为适当的默认值。例如,以下是Employee的无参数构造函数:java
pubilc Employee() { name = ""; salary = 0; hireDay = new Date(); }
因为类的构造器方法能够重载,因此能够采用多种形式设置类的实例域的初始状态。确保无论怎么调用构造器,每一个实例域均可以被设置为一个有意义的数初值。这是一种很好的设计习惯。
能够在类的定义中,直接将一个值付给任何域。例如:数组
class A{} Class Employee { private String name = ""; private A a = new A(); }
在执行构造器以前先执行赋值操做。当一个类的全部构造器都但愿把相同的值赋给某个特定的实例域时,这种方式特别有用。
初始值不必定是常量。在下面这个例子中,能够调用方法对域进行初始化。Employee类中每一个雇员都有一个id域。可使用下列方式进行初始化:app
class Employee{ private static int nextId; private int id = assignId(); private static int assignId() { int r = nextId(); nextId++; return r; } }
这个方法也可带有参数,但这些参数必须是已经初始化的了。所以,能够这样写:ide
public class MethodInit { int i = f(); int j = g(i); int f() {return 11;} int g(int n ) {return n* 10;}
但像下面这样就不对了:函数
public class MethodInit{ int j = g(i); //Illegal forward reference int i = f(); int f() {return 11;} int g(int n) {return n * 1
前面已经讲过两种初始化数据域的方法:this
class Employee{ private static int nextId; private int id; private String name; private double salary; //object initialization block { id = nextId; nextId++; } public Employee(String n, dobule s) { name = n; salary = s; } public Employee(){ name = ""; salary = 0; } }
在这个示例中,不管使用哪一个构造器构造对象,id域都在对象初始化块中被初始化。首先运行初始化块,而后才运行构造器的主体部分。设计
假设你但愿在方法的内部得到对当前对象的引用,就可使用this关键字。this关键字只能在方法的内部使用,表示对“调用这个方法的那个对象”的引用。this的用法和其余对应引用并没有不一样。只要注意,若是在方法内部调用同一个类的另外一个方法,就没必要使用this,直接调用便可。code
只有当须要明确指出对当前对象的引用时,才须要使用this关键字。例如,当须要返回对当前对象的引用时,就经常须要在return语句里这样写:对象
public class Leaf{ int i = 0; Leaf increment() { i++: return this; } } public static void main(String[] args) { Leaf x = new Leaf(); x.increment().increment().increment(); }
因为increment()经过this关键字返回了对当前对象的引用,因此很容易在一条语句中对同一个对象进行屡次操做。
this关键字对于将对于将当前对象传递给其余对象也颇有用:ci
Class Person{ public void eat(Apple apple) { Apple peeled = apple.getPeeled(); System.out.println("Yummy"); } } class Peeler { static Apple peel(Apple apple) { //... remove peel return apple; //Peeled } } class Apple{ Apple getPeeled() {return Peeler.peel(this);} } public class PassingThis { public static void main(Strings[] args) { new Person.eat(new Apple)); } }
构造器的的参数名和引用以下所示:
Class Employee{ private String name; private double salary; public Employee(String name , double salary) { this.name = name; this.salary = salary; } }
它基于这样一个事实:参数变量用一样的名字将实例域屏蔽起来。例如,若是将参数命名为salary,salary将引用这个参数,而不是实例域。可是,能够采用this的形式访问实例域。
若是构造器的第一个句子形如(this...),这个构造器将调用同一个类的另外一个构造器。下面是一个典型的例子:
public Employee() { //calls Employee(String, double) this("Employee #" + nextId, s); nextId++; }
尽管能够用this调用另外一个构造器,但却不能同时调用两个。此外,必须将构造器调用置于方法最起始处,不然编译器会报警。
***
Class A{ private static B b = new B(); }
3.也能够用使用指定初始化,不过要在初始化块的外面加 static关键字
class Cup{ Cup(int marker) { } } class Cups{ static Cup cup1; static Cup cup2; static { cup1 = new Cup(1); cup2 = new Cup(2); } Cup() { print("Cups()"); } } public class ExplicitStatic { public static void main(Strings[] args) { print("Inside main()"); Cups.cup1.f(99); } static Cups cups1 = new Cups(); static Cups cups2 = new Cups(); }
不管是经过标为(1)的那行代码访问静态的cup1对象,仍是把标为(1)的行注释掉,让它去运行标为(2)的那行代码(即解除标为(2)的行的注释),Cups的静态初始化动做都会获得执行。若是把标为(1)和(2)的行同时注释掉,Cups的静态初始化动做就不会进行。此外,激活一行仍是两行标为(2)的代码(即解除注释)都可有可无,静态初始化动做只进行一次。
数组初始化主要有两种形式。第一种以下:
//Aggregate initialization BerylliumSphere[] d = { new BerylliumSphere(), new BerylliumSphere(), new BerylliumSphere()};
数组d代表使用"汇集初始化"语法建立数组对象,而且以BerylliumSphere对象将其初始化的过程,可是这个操做必须在定义d的位置使用。
第二种以下:
//Dynamic aggregate initialization a = new BerylliumSphere[] { new BerylliumSphere(), new BerylliumSphere() };
这种方法被看做是"动态的汇集初始化",这种方法能够在任意位置建立和初始化数组对象。例如,假设方法hide()须要一个BerylliumSpere对象的数组做为输入参数。能够以下调用:
hide(d);
但也能够动态地建立将要做为参数传递的数组:
hide(new BerylliumSpere[]{new BerylliumSpere()}
双括号初始化利用了内部类的语法。假设想构造一个数组列表,并将它传递到一个方法。
ArrayList<String> friends = new ArrayList<>(); friends.add("Harrys"); friends.add("Tony"); invite(friends);
若是不须要这个数组列表,最好让它做为一个匿名列表。不过做为一个匿名列表,添加元素方法以下:
invite(new ArrayList<String>(){{add("Harrys");add(""Tony"")}})
注意这里的双括号。外括号创建了Arraylist的一个匿名子类。内括号则是一个对象构造块。