第6-8章 访问权限控制、复用种和多态

第6-8章 访问权限控制、复用类和多态
访问权限控制

1、java类可以不显示编写"package xxx.xxx",这样的话该类存在于"(default package)"下。

2、一个java文件(编译单元)只能有一个public的类,该类名与文件名完全相同,文件内其他非public的类具有“包访问权限”(只能被同一包中的其他类所访问)。一个java文件可以没有public的类(这并不常见)。

3、编写java类时,package位于除了注释和空行之外的第一行。

4、类的访问控制修饰符只有如下几种:1、public 2、无 3、final 4、abstract。类修饰符不存在protected和private。

5、Cannot use super in a static context
在子类中的任何静态方法中无法使用this或者super关键字调用父类的的成员
-------------------------------

复用类
1、组合语法

package reusing;//: reusing/Bath.java
// Constructor initialization with composition.
import static net.mindview.util.Print.*;

class Soap {
  private String s;
  Soap() {
    print("Soap()");
    s = "Constructed";
  }
  public String toString() { return s; }
}

public class Bath {
  private String // Initializing at point of definition:
    s1 = "Happy",
    s2 = "Happy",
    s3, s4;
  private Soap castille;
  private int i;
  private float toy;
  public Bath() {
    print("Inside Bath()");
    s3 = "Joy";
    toy = 3.14f;
    castille = new Soap();
    //Soap中的构造器在之后执行,如果Soap是Bath的父类,则会先行加载,而在此两者没有这种关系
  }
  // Instance initialization:在构造器之前执行
  { i = 47; System.out.println("Before Constructor");}
  public String toString() {
    if(s4 == null) // Delayed initialization:
      s4 = "Joy";
    return
      "s1 = " + s1 + "\n" +
      "s2 = " + s2 + "\n" +
      "s3 = " + s3 + "\n" +
      "s4 = " + s4 + "\n" +
      "i = " + i + "\n" +
      "toy = " + toy + "\n" +
      "castille = " + castille;
  }
  public static void main(String[] args) {
    Bath b = new Bath();
    print(b);
  }
} /* Output:
Inside Bath()
Soap()
s1 = Happy
s2 = Happy
s3 = Joy
s4 = Joy
i = 47
toy = 3.14
castille = Constructed
*///:~

2a、继承的概念和实质
当创建出一个导出类的对象时,该对象包含了一个基类的子对象。这个子对象与你用基类直接创建出的对象是一样的,二者区别在于,后者来自于外部,而基类的子对象被包装在导出类对象内部




2b、如下代码分析
package reusing;//: reusing/Detergent.java
// Inheritance syntax & properties.
import static net.mindview.util.Print.*;

class Cleanser {
  private String s = "Cleanser";
  public void append(String a) { s += a; }
  public void dilute() { append(" dilute()"); }
  public void apply() { append(" apply()"); }
  public void scrub() { append(" scrub()"); }
  public String toString() { return s; }
  public static void main(String[] args) {
    Cleanser x = new Cleanser();
    x.dilute(); x.apply(); x.scrub();
    print(x);
  }
}

public class Detergent extends Cleanser {
  // 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();
    print(x);
    print("Testing base class:");
    Cleanser.main(args);
  }
} /* Output:
Cleanser dilute() apply() Detergent.scrub() scrub() foam()
Testing base class:
Cleanser dilute() apply() scrub()
*///:~

注意要点:
父类中的s是private的,子类并不会存在这个成员,所以子类中的dilute()、apply()等方法中操作的字符串为父类的成员域s

3、分析以下代码:
public class A {
public A() {System.out.println(" A Constructor ");}
public static void main(String[] args) {
new C();
}
}

class B {
public B() {
System.out.println(" B Constructor ");
}
}

class C extends A {
public B b = new B();
}
问题:先输出" A Constructor "还是" B Constructor "?答案:尽管与成员初始化优先于构造器,但在继承关系中,还是先加载父类。

4、如果基类没有默认的构造器并且存在带参数的构造器,那么在子类中的构造器中需要显式的调用super(参数),否则无法初始化基类,如代码所示:
package reusing;//: reusing/Chess.java
// Inheritance, constructors and arguments.
import static net.mindview.util.Print.*;

class Game {
  Game(int i) {
    print("Game constructor");
  }
}

class BoardGame extends Game {
  BoardGame(int i) {
    super(i);
    print("BoardGame constructor");
  }
}

public class Chess extends BoardGame {
  Chess() {
    super(11);
    print("Chess constructor");
  }
  public static void main(String[] args) {
    Chess x = new Chess();
  }
} /* Output:
Game constructor
BoardGame constructor
Chess constructor
*///:~

4、关于类的加载次序问题
一、一般情况下,类的成员对象new初始化优先于类的构造器;
二、A extends B,new A(),如果A中存在static C c = new C()的静态成员,则优先于B的构造器,落后于B的static区块;如果是普通成员C c = new C(),则父类B构造器优先;
三、A extends B,没有new A(),类加载到A.class,会执行B中static区块的内容,但不包括B的构造器;既然A中存在static C c = new C()的静态成员,没有new A(),C中的任何静态非静态区块和构造器都不会执行


5、@Override进行编译检查

6、组合和继承的选择:is-a的关系就用继承;has-a的关系就用组合;真的需要向上转型就使用继承,否则慎用。

-------------------------------------
多态
1、父类中的private方法与子类中的同名方法不具有继承关系,是2个独立的方法。
public class PrivateOverride {
  private void f() { print("private f()"); }
  public static void main(String[] args) {
    PrivateOverride po = new Derived();
    po.f();
    Derived d = new Derived();
    d.f();
  }
}

class Derived extends PrivateOverride {
  protected void f() { print("public f()"); }
} /* Output:
private f()
*///:~

2a、类中定义有OtherClass[] o = new OtherClass[5];执行到该类时不会加载OtherClass。


2、父类中的域和静态方法与子类中的同名域和方法不具有继承关系。

class Super {
  public int field = 0;
  public int getField() { return field; }
}

class Sub extends Super {
  public int field = 1;
  public int getField() { return field; }
  public int getSuperField() { return super.field; }
}

public class FieldAccess {
  public static void main(String[] args) {
    Super sup = new Sub(); // Upcast
    System.out.println("sup.field = " + sup.field +
      ", sup.getField() = " + sup.getField());
    Sub sub = new Sub();
    System.out.println("sub.field = " +
      sub.field + ", sub.getField() = " +
      sub.getField() +
      ", sub.getSuperField() = " +
      sub.getSuperField());
  }
} /* Output:
sup.field = 0, sup.getField() = 1
sub.field = 1, sub.getField() = 1, sub.getSuperField() = 0
*///:~
当Sub转型为Super时,任何域访问操作都是由编译器解析,所以不是多态的。Sub包含2个field,自己的和父类的。