复用代码是Java众多引人注目的功能之一。但要想成为极具革命性的语言,仅仅能够复制代码并对之加以改变是不够的,它还必须能够做更多的事情。
组合语法
组合技术就是将对象的引用置于新类当中即可。
关于初始化:类中域为基本类型时能够自动被初始化为零,但是对象的引用会被初始化为null,如果试图为它调用任何方法,都会得到一个异常。
继承语法
1.特殊的双main
为每一个类都创建一个main方法使得单元测试变得可行;即使一个程序含多个类,但只有命令行所调用的那个类的main()方法会被调用 如下边可以是java Detergent也可以是java Cleanser
关于继承时权限的问题:一般将包中的数据成员设为private,将其方法设置为public(特殊情况下调整);值得注意的是:如果包中某个public类中有一个无权限修饰词的方法被另一个包中的类继承了,那么他无法覆盖基类中的该方法,因为包改变了。他若有一个同名的,那么这就不是覆盖,是重写。
package Primary;
class Cleanser{
private String s = "Cleanser ";
public void append(String s) {
this.s = this.s + s;
}
public String toString(){ //子类覆盖父类方法时不能降低其可见性,但可以提升
return s;
}
public void scrub() {
append("Cleaser.scrub");
}
public static void main(String[] args) {
Cleanser x = new Cleanser();
x.scrub();
System.out.println(x);
}
}
public class Detergent extends Cleanser{
public void scrub() {
append("Detergent.scrub()");
super.scrub(); //super调用父类的方法
}
public Detergent() {
// TODO 自动生成的构造函数存根
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
Detergent x = new Detergent();
x.scrub();
System.out.println(x);
System.out.println("Test base class:");
Cleanser.main(args);
}
}
在second包中继承Detergent方法(之前先把scrub()方法的public消去)
package Second;
import Primary.Detergent;
public class success extends Detergent{
public void scrub() { //此时为重写
// super.scrub(); //该方法不可视,编译会出错
}
public success() {
}
}
2.初始化基类
当创建了一个导出类的对象时,该对象包含了一个基类的子对象。Java会自动在导出类的构造器中插入对基类构造器的调用。
class A{
A(){
System.out.println("Constructer A");
}
}
class B{
B(){
System.out.println("Constructer B");
}
}
public class C extends A{
B b = new B();
C(){
System.out.println("Constructer C");
}
public static void main(String[] args) {
new C();
}
}
代理
代理指的是继承与组合的中庸之道
指的是不直接继承,而是在类中创建一个基类,直接使用基类的方法
结合使用组合和继承
1.确保正确清理,即在Java中让垃圾回收器在必要时释放内存
2.名称屏蔽,指的就是基类中的方法,在导出类中加了新的重载方法,所有方法都是可用的。
@Override方法有很大作用
class Homer{
char doh(char c) {
System.out.println("doh(char)");
return 'd';
}
float doh(float f) {
System.out.println("doh(float)");
return 1.0f;
}
}
class Milhouse{
}
class Bart extends Homer{
//@Override注解可以防止在不想重载时意外进行了重载
@Override //Override注解,之后的一个方法,强制覆盖,不能重载
float doh(float m) {
System.out.println("doh(Milhouse)");
return 2.0f;
}
void doh(Milhouse m) {
System.out.println("doh(Milhouse)");
}
}
public class Hide {
}
在组合与继承中选择
组合和继承都允许在新的类中放置子对象,组合中是显式这样做,继承时隐式这样做。
组合技术通常用于想在新类中使用现有类的功能而并非它的接口这种类型。
即,在新类中嵌入某个对象,但新类的用户看到的只是为新类所定义的接口,而非所嵌入对象的接口;为取得此效果,需要在新类中嵌入一个现有类的private对象。
向上转型
向上转型可以用如下一句话概括:“新类是现有类的一种类型”
到底使用组合还是继承,可以通过:是否需要从新类向基类进行向上转型进行判断
final关键字
1.final数据
final数据用于两种情况,
如1.一个永远不改变的编译时常量
2.一个在运行时被初始化的值,不希望它改变;
一个既是static又是final的域只占据一段不能改变的存储空间。
对于基本类型的数据final使数值不变,对于对象的引用,final使引用恒定不变,但对象本身是可以修改的。
对于static final 和 final的区别就是:
static final在类装载时就被初始化,只初始化一次;
final在每次创建对象时都初始化;
对于final引用(对象、数组等),不能改变新的引用,但能改变该引用对象的值。
通常的常量的定义方法是:public static final int i = 0;
public表示可以被用于包之外,static强调只有一份,final说明它是一个常量。
以下是static final和final的区别
import java.util.*;
public class FinalTest {
private static Random rand = new Random(47);
final int a = rand.nextInt(20);
static final int b = rand.nextInt(20);
public static void main(String[] args) {
int valueOne = new FinalTest().a;
int valueTwo = new FinalTest().a;
int valueThree = new FinalTest().b;
int valueFour = new FinalTest().b;
System.out.println(valueOne+" "+valueTwo+" "+valueThree+" "+valueFour);
}
}
2.空白final
就是被声明为final但未给定初值的域,无论什么情况,Java都会确保空白final在使用前必须被初始化。
3.final参数
Java允许在参数列表中以声明的方式将参数声明为final,这意味着无法在方法中更改参数引用所指向的对象。
4.final方法
使用final的方法原因有两个:1.把方法锁定,以防止任何继承类修改它的含义2.效率(现在已经不主要了)
final和private关键字
类中所有private方法都隐式地指定为final的,由于无法取用private方法,也就无法覆盖它。
**“覆盖”**只有在某方法是基类的接口的一部分时才会出现。即,必须能将一个对象向上转为它的基类型并调用相同的方法,如果某方法是private,那么他就不是接口的一部分。此时若在导出类中与基类中的private方法名称一样,那么这仅仅是一个新的方法。
final方法子类中可用,但不可被覆盖;
private方法子类中不可用,不可被覆盖;
初始化及类的加载
Java中的所有事务都是对象,每个类的编译代码都存在于它自己的独立文件中;初次使用之处是static初始化发生之处,所有的static对象和static代码段都会在加载时依程序中的顺序进行初始化
继承与初始化:
在开始一个设计时,优先考虑组合,再考虑继承;
设计一个系统时,目标应该是找到或创建某些类。