复用类的方法有两种:组合和继承。
组合:直接将对象置于新类中。
需要注意对这些对象的引用进行初始化,初始化可以在以下位置进行:
(1) 在对象定义的时候。这意味着它们在构造器调用之前肯定能得到初始化。
(2) 在那个类的构造器中。
(3) 紧靠在要求实际使用那个对象之前。这种方式称为“惰性初始化”,这样做可减少不必要的开销——假如对象并不需要创建的话。
(4) 使用实例初始化。
下面的代码展示了前三种方法。
//: Bath.java
// Constructor initialization withcomposition
class Soap {
private String s;
Soap() {
System.out.println("Soap()");
s= new String("Constructed");
}
public String toString() { return s; }
}
public class Bath {
private String
// Initializing at point of definition:
s1 = new String("Happy"),
s2 = "Happy",
s3, s4;
Soap castille;
inti;
float toy;
Bath() {
System.out.println("Inside Bath()");
s3 = new String("Joy");
i= 47;
toy = 3.14f;
castille = new Soap();
}
void print() {
// Delayed initialization:
if(s4 == null)
s4 = new String("Joy");
System.out.println("s1 = " + s1);
System.out.println("s2 = " + s2);
System.out.println("s3 = " + s3);
System.out.println("s4 = " + s4);
System.out.println("i = " + i);
System.out.println("toy = " + toy);
System.out.println("castille = " + castille);
}
public static void main(String[] args) {
Bath b = new Bath();
b.print();
}
} ///:~
继承:声明类时,在类名后面紧随extends关键字和基类类名,该子类会自动取得基类的域和方法。
<小技巧>每个类中都可以有一个main()方法,方便调试,每次只调用特定类的main()方法。
super关键字代表基类。
创建子类的时候实际相当于该子类对象也包含了一个基类的子对象,这个子对象位于子类对象的内部。
Java会自动在子类对象的构造器中调用基类构造器。
如果没有默认的基类构造器或是想用一个带参数的基类构造器,就必须用关键字super显式调用。
调用基类构造器的语句必须放在子类构造器的第一句。
覆写:子类中与基类名称和参数列表完全相同的方法。可以使用@Override注解来保证正确覆写了基类的方法。
protected关键字:对于继承于这个类的导出类和其他任何位于同一个包内的类来说,protected修饰的内容是可访问的,但对其他而言,却是private的。
“新类是现有类的一种类型”:在Java中,新类是现有类的一种类型。继承可以确保基类中所有的方法在导出类中也同样有效,所以能够向基类发送的所有信息同样也可以向导出类发送。这种把导出类当做基类使用的方式叫做“上转型”。
称为“上转型”的原因是传统的类继承图绘制方法是将基类置于子类的上方。
下面是“上转型”的一个例子:
//: Wind.java
// Inheritance & upcasting
import java.util.*;
class Instrument {
public void play() {}
static void tune(Instrument i) {
// ...
i.play();
}
}
// Wind objects are instruments
// because they have the same interface:
class Wind extends Instrument {
public static void main(String[] args) {
Wind flute = new Wind();
Instrument.tune(flute); // Upcasting
}
} ///:~
“组合”与“继承”的选择:一个最清晰的判断方法就是问一问自己是否需要从新类向基类进行向上转型,如果必须向上转型,则继承是必要的;但如果不需要,这组合可能是更好的选择。(注意了!!!)
final关键字:
需要用到final修饰数据的情形:
(1).一个永不改变的编译时常量。
(2).一个在运行时被初始化的值,而后不想要被改变。
一个既是static又是final的域只占用一段不能改变的存储空间。既static又final的数据常用大写加下划线表示。
对于基本类型,final使数据恒定不变;对于引用类型,final使引用恒定不变,对象本身是可以被修改的。
空白final:Java允许在声明final数据的时候不立刻给定初值,但空白final必须在使用前初始化,必须在域的定义处或者构造器中用表达式赋值。
空白final的例子:
//: BlankFinal.java
// "Blank" final data members
class Poppet { }
class BlankFinal {
final int i = 0; // Initialized final
final int j; // Blank final
final Poppet p; // Blank final handle
//Blank finals MUST be initialized
//in the constructor:
BlankFinal() {
j= 1; // Initialize blank final
p= new Poppet();
}
BlankFinal(intx) {
j= x; // Initialize blank final
p= new Poppet();
}
public static void main(String[] args) {
BlankFinal bf = new BlankFinal();
}
} ///:~
final参数:声明为final的参数将无法在方法中更改引用所指向的对象。
final方法:final修饰的方法不能被覆盖。
类中所有的private方法都是隐式指定为final的。
final类:final类禁止继承,所以其方法也是隐式指定为final的。
类的代码在初次使用时才会加载:加载发生在以下两种情况:
(1).创建类的第一个对象
(2).访问static域或static方法