《Thinking In Java》復用類

Java復用類

組合與繼承

  • 組合:在新的類中產生現有類的對象。
  • 繼承:按照現有類的類型來創建新類,無需改變現有類的形式,采用現有類的形式并在其中添加新的代碼。

組合:

public class TestDemo1 {
public static void main(String[] args) {
  A a = new A();
  a.f1();
}
}
class  A{
public void f1(){
B b = new B("哈登");//組合
b.f2();
System.out.println(b);// 如果不覆寫B類中的toString(),那么就會輸出b對象的地址
}
}
class B{
private int age;
private String name ;
public B(String name){
this.name = name;
this.age=28;
}
public void f2(){
System.out.println("姓名為:"+name+" ,年齡為:"+age);
}

@Override
public String toString() {
return name;
}
}

打印結果

這里在B類的構造方法中初始化了age的值,如果將this.age=28注釋掉,那么年齡為0.

關于初始化

1.類中域為基本類型時,默認自動初始化為0

2.類中域為引用類型時,默認自動初始化為null

初始化位置

1.在定義對象的地方。意味著在調用構造器之前進行初始化

2.在類的構造器中

3.實例初始化

4.延遲初始化(惰性初始化)在使用對象之前

看一下具體代碼

public class ChuShiHua {
public static void main(String[] args) {
Student student = new Student("Messi");
System.out.println(student);
}
}

class Student {
//1.在定義對象的地方。意味著在調用構造器之前進行初始化
  private String name1="Ronaldo";
  private String name2,name3,name4;
  //2.在類的構造器中
  public Student(String name2){
  this.name2 = name2;
  }
  // 3.實例初始化
{
name3="Alice";
}

 // 4.延遲初始化(惰性初始化)在使用對象之前
@Override
public String toString() {
  if(name4==null){
  name4="Peter";
  }
return name1+" "+name2+" "+name3+ " "+ name4;
}
}

繼承

class Fu{
public Fu(){
System.out.println("這是父類構造");
}
}
class Son extends  Fu{
public Son(){
System.out.println("這是子類構造");
}
}

public class JiCheng {
public static void main(String[] args) {
 new Son();
}
}

這里Son類繼承了Fu類。關鍵字是extends.無論如何,父類構造總是先被初始化,然后再初始化子類構造。

子類默認調的是父類的無參構造,如果想要調用父類的有參構造,那么在子類構造的第一句話寫上super(..)

class Fu{
int age;
public Fu(){
System.out.println("aaa");
}
public Fu(int age){
this.age = age;
System.out.println("這是父類構造"+this.age);
}
}
class Son extends  Fu{
int i;
public Son(int i){
**super(20);**
this.i  = i ;
System.out.println("這是子類構造"+ i);
}
}

public class JiCheng {

public static void main(String[] args) {
 new Son(10);
}
}
protected關鍵字
  • 對于類的用戶而言,是私有的
  • 對于其子類或者同一包的類而言,是可以訪問的

在F類中定義了一個protected修飾的方法,在Z類中可以訪問的。

向上轉型

繼承的最大用處并不是復用類,而是多態。多態又是基于繼承的。

class Instrument{
static void play(Instrument e){
System.out.println("通過向上轉型"+e);
}
}
public class Wind  extends  Instrument{
public static void main(String[] args) {
Wind wind = new Wind();
Instrument.play(wind);
}
}

在play()方法中,將Wind對象傳入到父類Instrument的play()方法中,照樣能夠打印出Wind對象。用父類的引用去接收子類的對象,其指向的是子類對象。

final關鍵字

final所描述的對象是無法改變的。主要用在類,方法,數據中。

數據

告知編譯器這塊數據是無法改變的。

1.一個永不改變的編譯時常量---減輕了運行時的負擔

2.一個運行時被初始化的值,而你并不需要它被改變

3.一個即是static 又是 final 的數據描述的是只占據一塊不能改變的存儲空間

4.當final作用在基本類型的時候,指的是數值無法改變。當fianl作用于對象的引用時,指的是對象的引用不變,但對象本身還是可以改變的。

class FinalData{
int num = 1;
   public final  int age1 =20;

   /*
   * 1.用static final 修飾的變量應該字母全部大寫
   * 2.用public可以無限制被訪問
   * 3.static:強調只有一份
   * 4.final: 說明它是一個常量
   *
   * */
   public static final int AGE = 10;
}
public class FinalTest {
public static void main(String[] args) {
FinalData fd = new FinalData();
System.out.println(fd.age1);//輸出20
//  fd.age1=30; 由于age是final所修飾的基本類型,數值不能被改變。

 final FinalData fdFinal  = new FinalData();
 fdFinal.num=30;
System.out.println(fdFinal.num);//打印30

   //無法編譯,因為fdFinal的引用是不能被改變的 
   // fdFinal = new FinalData();
}
}
final參數
  class FinalData{
public void fun(final  int i){
  //  i++;無法編譯,因為i是final類型,值無法改變
}
public void fun2(final FinalData f){
f.fun(1);
  //  f = new FinalData(); 無法編譯,因為f的引用不可變
}
}
public class FinalTest {
public static void main(String[] args) {
  
}
}
final方法

作用:

  • 把方法鎖定,防止任何繼承類修改它的含義
  • 效率

類中所以的private方法都是final類型的,由于無法取用private方法,所以也就無法覆蓋它。

   class GrandFather{
private   final void fun(){
System.out.println("11");
}
}
class  Father extends GrandFather{
private   final void fun(){
System.out.println("22");
}
}
class  Son extends  Father{
public  final void fun(){
System.out.println("33");
}
}

public class FinalMethodTest {

public static void main(String[] args) {
  Son s = new Son();
  s.fun();//打印33

GrandFather f = s;
   
//f.fun();  無法編譯   

}
}

類內所有 private 方法都自動成為 final。由于我們不能訪問一個 private 方法,所以它絕對不會被其他方
法覆蓋(若強行這樣做,編譯器會給出錯誤提示)。可為一個 private 方法添加 final 指示符,但卻不能為
那個方法提供任何額外的含義。

final類

final類描述的是該類沒有子類,無法被繼承。

可以看到上面代碼報錯,無法編譯,原因是父類被聲明為final類型。

在一個類中如果被聲明為final類型,那么該類的方法隱式的都被聲明為final類型。

初始化及類的加載

class Fu {
private int age =70;
private String name;
public static String address = "崇明島";
static {
System.out.println("這是父類的static靜態塊");
}
public Fu(){
System.out.println("這是父類構造");
}
public void fu(){
System.out.println(age+name+address);
}
}
class  Zi extends  Fu{
private int age=30 ;
private String name;
public static String address = "海南島";
static {
System.out.println("這是子類的static靜態塊");
}
public Zi(){
System.out.println("這是子類構造");
}
public void zi(){
System.out.println(age+name+address);
}
}


public class CSHTest extends  Zi{
private int age=10 ;
private String name;
public static String address = "臺灣島";
static {
System.out.println("這是孫類的static靜態塊");
}
public CSHTest(){
System.out.println("這是孫類構造");
}
public void test(){
System.out.println(age+name+address);
}

public static void main(String[] args) {
 CSHTest t = new CSHTest();
 t.test();
}
}

首先執行CSHTEST類的main方法,類加載器查找CSHTEST編譯后的代碼.class,發現其有一個父類Zi,于是加載Zi,發現它又有一個父類,于是再加載Fu,此時,根基類中的static初始化(static修飾符描述的方法只執行一次),然后是下一個導出類,以此類推。此種方式很重要。因為導出類初始化有可能依賴于父類的初始化。

此時類已經加載完畢了。現在可以創建對象了。首先,對象中的基本類型都被初始化為0,對象的引用都被初始化為null,然后,基類的構造器就被調用,在本例中,是默認調用的,默認調用super(),如果想指定調用有參構造,那么自己寫super(Type Args).

總結就是:加載父類的靜態塊--->加載子類靜態塊---->加載父類的構造--->加載子類構造

聲明

所寫內容是《Thinking In Java》讀書筆記

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容