复用代码的两种方式:
1.组合
2.继承
每一个非基本类型的对象都有一个toString()方法。
组合
1.引用的初始化:
类中域的基本数据类型能够自动被初始化为”零”,但是对象引用会被初始化为null,如果这时你试图为他们调用任何方法,都会得到一个空指针异常。然而,在不抛出异常的情况下,仍旧可以打印一个null引用。
初始化引用的位置:
1.在定义对象的地方,意味着它们总是能够在构造器被调用之前初始化。
2.在类的构造器中。
3.使用实例初始化。
4.“惰性初始化”、就在正要使用这些对象之前。(在生成对象不值得及
不必每次都生成对象的情况下,这种方式可以减少额外的负担)上代码,演示四种方式:
package me.funnyzhao.recycleclass;
class Soap{
private String s;
Soap(){
//构造器中初始化
System.out.println("Soap()");
s="Constructed";
}
@Override
public String toString(){
return s;
}
}
public class Bath {
//在定义对象的地方初始化
private String s1="Happy",
s2="Happy",
s3,s4;
private Soap catille;
private int i;
private float toy;
public Bath(){
System.out.println("Inside Bath()");
s3="joy";
toy=3.14f;
catille=new Soap();
}
{
//在所有初始化前调用
i=47;
System.out.println(i);
}
@Override
public String toString() {
//惰性初始化
if(s4==null){
s4="joy";
}
return
"s1="+s1+"\n"+
"s2="+s2+"\n"+
"s3="+s3+"\n"+
"s4="+s4+"\n"+
"i="+i+"\n"+
"toy="+toy+"\n"+
"castille= "+catille;
};
public static void main(String[] args) {
Bath b=new Bath();
System.out.println(b);
}
}
OutPuts:
47
Inside Bath()
Soap()
s1=Happy
s2=Happy
s3=joy
s4=joy
i=47
toy=3.14
castille= Constructed
继承
1.初始化基类
java会自动在子类的构造器中插入对基类构造器的调用,下面的代码展示了上述机制在三层继承关系上是如何工作的:
class Art{
Art(){Sytem.out.println("Art Cr")}
}
class Drawing extends Art{
Drawing(){
System.out.println("Deawing Cr");
}
}
public class Cartoon extends Drawing{
public Cartoon(){System.out.println("Cartoon Cr");}
public static void main(String[] args){
Cartoon x=new Cartoon();
}
}
/*
output:
Art Cr
Drawing Cr
Cartoon Cr
*/
可以看到,对于构造器的调用是从基类“向外”扩散的,所以基类在子类构造器可以访问它之前,就已经完成了初始化。即使你不为Cartoon()创建构造器,编译器也会为你合成一个默认的构造器,该构造器将调用基类的构造器。
1.1下面的我们来证明基类构造器总是会被调用,并且在子类构造器之前被调用:
class Soap{
Soap(){
System.out.println("Soap()");
}
}
public class Bath extends Soap{
static{
System.out.println("static域");
}
{
System.out.println("空白");
}
Bath(){
System.out.println("Bath");
}
Bath(int i){
System.out.println("Bath"+i);
}
public static void main(String[] args) {
new Bath(1);
new Bath(2);
}
}
/*output:
static域
Soap()
空白
Bath1
Soap()
空白
Bath2
*/
从打印的结果可以看出,结论是成立的。
2.带参数的构造器
如果一个类的基类没有默认的构造器,或者想调用一个带参数的基类构造器,就必须用关键字super显示地编写调用基类构造器的语句,并且配以适当的参数列表:
class Game{
Game(int i){
System.out.println("Game()");
}
}
class BoardGame extends Game{
BoardGame(int i) {
super(i);
System.out.println("BoardGame()");
}
}
public class Bath extends BoardGame {
Bath(){
super(11);
System.out.println("Bath()");
}
public static void main(String[] args) {
Bath c=new Bath();
}
}
/*output:
Game()
BoardGame()
Bath()
*/
如果不在BoardGame()中显示的调用基类构造器,编译器会出错误提示;而且,调用基类构造器是你在子类中应该做的第一件事情。