第7章 复用类

第7章 复用类

组合:在新的类中产生现有类的对象,该方法是复用了现有程序代码的功能,而非它的形式。

继承:按照现有类的类型来创建新类,并在其中添加新代码。

7.1 组合语法

public class Table {
    public  void print(){
        System.out.println("hello");
    }
}

public class Space {    
    public Table table;
}

  public static void main(String[] args) {
        Space space = new Space();
        space.table = new Table();
        space.table.print();
    }

初始化引用的四种方式:

  • 一:在定义对象的地方,意味着在构造器被调用前初始化;
  • 二:在类的构造器中;
  • 三:在正要用这些对象前,这被称为惰性初始化;
  • 四:使用实例初始化
public class Space {
    // 一
    public Table table = new Table();

    {
        // 四
        table = new Table();
    }
    public Space(){
        // 二
        table = new Table();
    }
}
  public static void main(String[] args) {
        Space space = new Space();
        // 三
        space.table = new Table();
        space.table.print();
    }

什么时候使用实例初始化

  • 初始化代码需要处理异常
  • 初始化有复杂的运算
  • 虽然可以写在构造函数中,但是当有多个构造函数时就会代码重复

7.2 继承语法

public class Table {

    public void test1(){
        System.out.println("基类test1");
    }

    public void test2(){
        System.out.println("基类test2");
    }
}

public class SmallTable extends Table {
    @Override
    public void test2() {
        super.test2();
        System.out.println("导出类test2");
    }

    public void test3(){
        System.out.println("导出类test3");
    }
}

 public static void main(String[] args) {
        SmallTable st = new SmallTable();
        st.test1();
        st.test2();
        st.test3();
}
/*
基类test1
基类test2
导出类test2
导出类test3
*/
  • 每个类中都可以有main()方法,这样方便测试(现在不需要这样做)
  • 一般情况下,将基类的数据成员指定为private,方法指定为public

基类的初始化

// 默认初始化
public class Table {
    public Table(){
        System.out.println("基类初始化");
    }
}
public static void main(String[] args) {
   SmallTable st = new SmallTable(); // 基类初始化
}

// 显示初始化
public class SmallTable extends Table {  
    public SmallTable(){
        // 必须放在开头
        super();
    }
}

// 有参初始化
public class Table {
    // 没有无参构造器是不合理的,这里只是为了展示使用
    public Table(int i){
        System.out.println("基类初始化");
    }
}
public class SmallTable extends Table {
	// 必须指定对应的基类构造器
    public SmallTable(){
        super(1);
    }
}

7.3 代理

Java并没有提供直接的支持,它是继承和组合之间的中庸之道,方式是将成员对象置于新类中,同时暴露该成员对象的所有方法。

public class A {
       void print(){
        System.out.println("hello");
    }
    void test(){
        System.out.println("test");
    }
}

public class B {
    private A a = new A();
    
    public void print(){
        a.print();
    }
    public void test(){
        a.test();
    }
}

 public static void main(String[] args) {
        B b = new B();
        b.print();
        b.test();
}

本质上是加了一层包装,但是相对于组合和继承的优势是在不改变方法内部的实现逻辑下,可以对方法进行增强处理。

7.4 结合使用组合和继承

public class Shirt {
}

public class Animal {

    public Animal(int i) {
        System.out.println("初始化Animal");
    }

    public void print(int i) {
        System.out.println("打印数字:" + i);
    }

    public void dispose() {
        System.out.println("清理Animal");
    }
}

public class Person extends Animal {
    private Shirt shirt;
    public Person(int i) {
        // 编译器强制要求初始化父类
        super(i);
        // 必须手动初始化成员对象,否则该成员对象无法使用
        shirt = new Shirt();
    }

    public void print(String s){
        System.out.println("打印字符串"+s);
    }
    @Override
    public void dispose() {
        System.out.println("清理Person");
        // 调用清理方法时,应当先清理子类中的元素,再清理父类中元素,因为子类可能依赖父类中的元素
        super.dispose();
    }
}

  public static void main(String[] args) {
        Person person = new Person(1);
        try {
            // 子类重载父类中的方法,父类的方法不会被覆盖,除非重写
            person.print(1);
            person.print("s");
        }finally {
            // 肯定执行执行清理工作
            person.dispose();
        }

    }

7.5 在组合与继承之间选择

当希望在新类中使用现有类功能时,用组合,它们是has-a的关系;当希望用现有类的接口时,用继承,它们是is-a的关系。

7.6 protected关键字

对于子类或包内的其他类,该成员是可访问的;对于基类而言,应当对域使用private,同时提供protected方法,让子类可以修改。

7.7 向上转型

将子类引用转换为基类引用的动作,称为向上转型。

**称为向上转型的原因:**类继承图的绘制是将根置于顶端,子类置于下方,所以子类向父类的转换称为向上转型。

**再论组合与继承:**继承应当慎用,如果新类需要向上转型,则继承是需要的,否则应当使用组合。

7.8 final关键字

用到final的三种情况:数据、方法、类。

7.8.1 final数据
  • 一个永不改变的编译时常量
  • 在运行时被初始化,随后不再改变。
public class FinalData {
    private static Random random = new Random(47);
    // 基本类型
    public final int i1 = 1; // 一个对象存在一份
    public final static int I2 = 2; // 仅存在一份
    public final int i3 = random.nextInt(); 
    public final static int I4 =random.nextInt();
    // 引用类型
    public final String s1 = "a";
    public final static String S2 = "b";
    // 数组
    public final int[] a1 = {1,2,3};
    public final static int[] a2 = {1,2,3};
    // 空白final
    public final int i5;
    public final String s3;

    public FinalData(){
        // 空白的final必须在构造器中赋值,这样保证了在使用前,肯定被初始化
        i5 = 1;
        s3 = "c";
    }
    
    // 对参数使用final,在方法内无法更改参数的引用
    public void test(final String str){
        
    }
}
7.8.2 final方法

把方法锁定,防止继成类修改它。

final和private关键字private方法都是隐式的指定为final,因为无法取得,所有无法覆盖。

public class Animal {

    private void print(int i) {
        System.out.println("打印数字:" + i);
    }

}

public class Person extends Animal {

    public void print(int s){
        System.out.println(s);
    }

}

  public static void main(String[] args) {
        Person person = new Person();
        person.print(1);
        Animal animal = person;
        // 下面写法报错,说明无法向上转型,证明子类只是含有一个和基类同名的方法
        // animal.print(4);
    }
7.8.3 final类

final类不能被继承,同时隐含了方法为final,因为类不能被继承,所有也不存在被重写的情况。

7.9 初始化及类的加载

public class Animal {

    private static int i1 = setValue("基类静态域初始化");
    public int i2;

    public Animal() {
        System.out.println("基类构造方法初始化" + i2);
        i2 = 1;
    }

    public static int setValue(String s) {
        System.out.println(s);
        return 1;
    }

}

public class Person extends Animal {
    private static int i3 = setValue("子类静态域初始化");
    private int i4 = setValue("子类成员变量初始化");
    public Person(){
        System.out.println("子类构造方法初始化"+i2);
    }
}

 public static void main(String[] args) {
       Person person = new Person();
    }
// 注意i2值的前后变化
/*
基类静态域初始化
子类静态域初始化
基类构造方法初始化0
子类成员变量初始化
子类构造方法初始化1
*/

加载Person类->加载基类[->上层基类……]->基类static初始化->子类static初始化->基类实例初始化->基类构造方法初始化->子类实例初始化->子类构造方法初始化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值