- 合成 - 在新类里简单地创建原有类的对象 - 新类由现有类的对象合并而成
- 继承 - 创建一个新类,将其作为现有类的一个“类型”
//对于非基本类型的对象来说,只需将句柄置于新类即可;而对于基本数据类型来说,则需在自己的类中定义它们。 // composition for code reuse class WaterSource{ private String s; WaterSource(){ System.out.println("WaterSource()"); s = new String("Cnstructed"); } public String toString(){ return s; } } public class SprinklerSystem { private String valve1, valve2, valve3, valve4; WaterSource source; int i; float f; void print(){ System.out.println("valve1 = " + valve1); System.out.println("valve2 = " + valve2); System.out.println("valve3 = " + valve3); System.out.println("valve4 = " + valve4); System.out.println("i = " + i); System.out.println("f = " + f); System.out.println("source = " + source); } public static void main(String[] args) { SprinklerSystem x = new SprinklerSystem(); x.print(); } } /* valve1 = null valve2 = null valve3 = null valve4 = null i = 0 f = 0.0 source = null */
如希望句柄得到初始化,可在下面这些地方进行:
- 在对象定义的时候。这意味着它们在构建器调用之前肯定能得到初始化。
- 在那个类的构建器中。
- 紧靠在要求实际使用那个对象之前。这样做可减少不必要的开销——假如对象并不需要创建的话。
// Inheritance syntax & properties
class Cleaner{
private String s = new String("Cleaner");
public void append(String a){s += a;}
public void dilute(){append("dilute()");}
public void apply(){append("apply()");}
public void scrub(){append("scrub()");}
public void print(){System.out.println(s);}
public static void main(String[] args) {
Cleaner x = new Cleaner();
x.dilute();x.apply();x.scrub();
x.print();
}
}
public class Detergent extends Cleaner {
// change a method
public void scrub(){
append("Detergent.scrub()");
super.scrub(); // call base-class version
}
// add methods to the interface
public void foam(){append("foam()");}
// test the new class
public static void main(String[] args) {
Detergent x = new Detergent();
x.dilute();
x.apply();
x.scrub();
x.foam();
x.print();
System.out.println("Testing base class:");
Cleaner.main(args);
}
}
/*
Cleanerdilute()apply()Detergent.scrub()scrub()foam()
Testing base class:
Cleanerdilute()apply()scrub()
*/
// Constructor calls during inheritance
/**
* 可以看出,构建是在基础类的“外部”进行的,所以基础类会在衍生类访问它之前得到正确的初始化。 即使没有为
* Cartoon()创建一个构建器,编译器也会为我们自动合成一个默认构建器,并发出对基础类构建 器的调用。
*
*/
class Art {
Art() {
System.out.println("Art constructor");
}
}
class Drawing extends Art {
Drawing() {
System.out.println("Drawing constructor");
}
}
public class Cartoon extends Drawing {
Cartoon() {
System.out.println("Cartoon constructor");
}
public static void main(String[] args) {
Cartoon x = new Cartoon();
}
}
/*
* Art constructor
* Drawing constructor
* Cartoon constructor
*/
在衍生类构建器中,对基础类构建器的调用是必须做的第一件事情
final 数据:
许多程序设计语言都有自己的办法告诉编译器某个数据是“常数”。
- 编译期常数,它永远不会改变 - 编译器可将常数值“封装”到需要的计算过程里。也就是说:计算可在编译期间提前执行,从而节省运行时的一些开销。在Java中,这些形式的常数必须属于基本数据类型。
- 在运行期间初始化的一个值,不希望它发生变化
// can be compile-time constants final int i1 = 9; static final int I2 = 99; //typical public constants public static final int I3 = 39; // cannot be compile-time constants final int i4 = (int)(Math.random()*20); static final int i5 = (int)(Math.random()*20);
final 参数变量
意味:在一个方法内部,我们不能改变参数变量句柄指向的东西。
//Using "final" with method arguments
class Gizmo {
public void spin() {
}
}
public class FinalArguments {
void with(final Gizmo g) {
// ! g = new Gizmo(); // Illegal -- g is final
g.spin();
}
void without(Gizmo g) {
g = new Gizmo(); // OK -- g not final
g.spin();
}
// void f(final int i) { i++; } // Can't change
// You can only read from a final primitive:
int g(final int i) {
return i + 1;
}
public static void main(String[] args) {
FinalArguments bf = new FinalArguments();
bf.without(null);
bf.with(null);
}
}
final方法:
- 第一个是为方法“上锁”,防止任何继承类改变它的本来含义。
- 程序执行的效率。
Think in Java 写道将一个方法设成 final 后,编译器就可以把对那个方法的所有调用都置入“嵌入”调用里。
只要编译器发现一个final 方法调用,就会(根据它自己的判断)忽略为执行方法调用机制而采取的常规代码插入方法(将自变量压入堆栈;跳至方法代码并执行它;跳回来;清除堆栈自变量;最后对返回值进行处理)。
相反,它会用方法主体内实际代码的一个副本来替换方法调用。这样做可避免方法调用时的系统开销。
final方法体执行效率一般会高一些:
- replace the method call:push arguments on the stack, hop over to the method code and execute it, hop back and clean off the stack arguments, and deal with the return value
- with a copy of the actual code in the method body
final 类:
表明自己不希望从这个类继承,或者不允许其他任何人采取这种操作。
换言之,出于这样或那样的原因,我们的类肯定不需要进行任何改变;或者出于安全方面的理由,我们不希望进行子类化(子类处理)。
所以与我们将一个方法明确声明为final 一样,编译器此时有相同的效率选择。
装载 - 首先parent、然后child
初始化 - 首先parent的static、然后child的static