瘋狂java講義第六章筆記

面向對象(下)

6.1 java8增強的包裝類

int Integer
char Character
其他的都是直接首字母變大寫
可以自動裝箱,自動拆箱。
如果int想變成Integer,直接賦值給一個Integer 變量就行。
如果Integer想變成int,直接賦值給一個int變量就行。

基本類型和字符串之間的轉換方法

  1. 字符串轉換成基本類型
    int i=Integer.parseInt(str);
    或者
    int i=new Integer(str);
  2. 基本類型轉換成字符串
    String flStr=String.valueOf(float變量);
    或者
    String flStr=float變量+“”;

包裝類比較大小

  1. 如果直接給integer數字,如果數字在-128-127之間,則兩個數字相等,包裝類相等。
  2. 如果用new integer(2)賦值,則必須兩個包裝類指向同一個對象才相等。
  3. 有一個Integer.compare(a,b)可以直接用來比較包裝類大小.
    a>b 返回1
    a=b 返回0
    a<b 返回-1

6.2 處理對象

6.2.1 打印對象和toString方法

toString方法
toString () 是Object類里面的一個實例方法,所有對象都具有這個方法。
系統自帶的tostring“類名+@+hashcode”
可以自己重寫這個方法。

6.2.2 ==和equals方法

“==”

  1. 對于基本類型的數值類型(包括char),只要兩個變量的值相等,返回true。
  2. 對于引用類型,必須指向同一個對象,才返回true。
    注意:“==“不能用于比較沒有父子關系的兩個對象。
    ”hello“直接量和new String (“hello”)區別
    直接使用hello這種可以在編譯時候計算出來的字符串值,jvm會用常量池來管理。jvm會保證相同的字符串直接量只有一個,不會產生多個副本。
    第二種,jvm會先用常量池來管理直接量,再調用string構造器來創建 i 個新的string對象。新創建的對象保存在堆中

equals()

equals()方法可以用來判斷字符串的內容是否相等。
但是當用于對象時,仍然必須是指向同一個對象才能夠返回true。
一般需要重寫equals()。

  1. 首先判斷是否是同一個對象
  2. 如果不是同一個對象,在判斷是否是同一個類型
  3. 如果是的話,把object轉化為目標類型,采用equals方法比較內容。

6.3 類成員

6.3.1 理解類成員

類成員就是用static修飾的成員變量,方法,初始化塊,內部類的統稱。能通過對象訪問這些類成員。即使對象是null 。類成員不能訪問實例成員,因為類成員的作用域更大,可能類成員還存在,但是成員變量已經不存在了,所以不能夠訪問實例成員。

6.3.2 單例類

一個類始終只能創建一個實例,稱為單例類。
如果不想讓別的類輕易的創建該類的對象,就需要把類的構造函數設置成private,但是這個時候就需要有一個方法來創建一個對象,由于使用這個方法的時候還沒有對象,因此需要給方法是static的。
同時。為了滿足只能創建一個對象,則必須把已經創建的對象保存起來,每次創建對象之前都檢查一下是否只有一個對象。由于存儲對象的成員變量需要通過上面的static方法調用,因此需要設置為static。

package demo6;

public class Singleton {
    //定義一個類變量用來保存創建出來的對象
    private static Singleton instance;
    private Singleton(){}
    //定義一個能夠返回對象的方法
    public static Singleton getSingleton()
    {
        if(instance==null)
        {
            instance=new Singleton();
        }
        return instance;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Singleton s1=Singleton.getSingleton();
        Singleton s2=Singleton.getSingleton();
        System.out.print(s1==s2);

    }

}

6.4 final修飾符

final修飾變量時候表示該變量一旦獲得了初始值,就無法再改變。

6.4.1 final成員變量

類變量:在靜態初始化塊或者聲明該變量時初始化
實例變量:在普通初始化塊,或者聲明該變量時候,或者構造器。如果已經在普通初始化塊賦值,則不可以再在構造器中賦值。
注意?:普通方法不能訪問final修飾的成員變量。
final修飾的成員變量必須程序員自己顯示初始化,系統不會默認賦值。

6.4.2 final局部變量

因為系統不會給局部變量初始化,因此在用final修飾的局部變量不一定非由程序員顯示初始化。
方法中的形參不能夠在方法里面初始化,因為形參的初始化是在被調用的時候由實參傳入的。

6.4.3 final修飾基本類型變量和引用類型變量的區別

final修飾基本類型變量,就不能更改值了。如果是引用類型,則只要不改變地址就行,里面的內容可以隨意

package demo6;

import java.util.Arrays;

class Person1
{
    private int age;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Person1() {}
    public Person1(int age)
    {
        this.age=age;
    }
}


public class FinalReferenceTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //可以無限的更改數組里面的內容,但是不能夠更改數組的地址
        final int[] iArr={3,4,5,6};
        iArr[2]=19;
        System.out.print(Arrays.toString(iArr));
        Arrays.sort(iArr);
        System.out.println(Arrays.toString(iArr));
        //iArr=null;
        Person1 p1=new Person1();
        p1.setAge(7);
        //這里竟然可以更改,,,,,不懂不懂
        p1=null;
        System.out.print(iArr);
        

    }

}

6.4.4 可執行“宏替換”的final變量

變量滿足三個條件,則變量相當于一個直接量

  1. final修飾
  2. 在定義的時候指定了初始值(只有在定義的時候賦值才有這種效果)
  3. 值可以在編譯的時候確定下來

6.4.5 final 方法

final方法不能夠被重寫。如果父類的方法不希望子類重寫,只要加上final 就好。
但是父類的private 是不會被子類繼承的,因此也不會有重寫這個說法。因此如果父類的private方法被final了,子類仍然可以寫一個一樣的方法。

6.4.6 final類

不能有子類的類

6.4.7 不可變類

不可變類是創建該類的實例后,實例變量不能夠更改。
創建自定義的不可變類方法:
1,類的成員變量用private和final修飾
2,提供帶參數的構造函數,用于根據傳入參數來初始化類的成員變量
3,該類僅有getter
4,重新定義equals()和hashcode()

package demo6;

public class Address {
    private final String detail;
    private final String postCode;
    public Address()
    {
        this.detail="";
        this.postCode="";
    }
    public Address(String detail,String postCode)
    {
        this.detail=detail;
        this.postCode=postCode;
    }
    public String getDetail()
    {
        return detail;
    }
    public String getPostCode()
    {
        return postCode;
    }
    public boolean equals(Object obj)
    {
        if(obj==this)
        {
            return true;
        }
        if(obj!=null&&obj.getClass().equals(Address.class))
        {
            Address AddObj=(Address)obj;
            if(AddObj.getDetail().equals(this.getDetail()))
            {
                return true;
            }
        }
        return false;
    }
    

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        

    }

}

當創建不可變類的時候,如果成員變量里面有引用類型,則很可能創建出一個可變類,因為成員變量的內容可以更改。必須采用一些其他的方法,才能創建真正的不可變類。

6.4.8 緩存實例的不可變類

緩存實例的不可變類,是因為有的時候一個對象的某個成員被多次引用,為了節省開銷,可以把它緩存起來。下邊是把它緩存在數組里面,如果緩存里面已經有了,就直接返回實例,如果沒有,就新建實例加進去。

package demo6;
//這個類主要是弄一個數組,然后緩存string數據
class CacheInnutale
{
    private static int MAX_SIZE;
    private static CacheInnutale[] cache=new CacheInnutale[MAX_SIZE];
    //pos為什么要是static
    private static int pos=0;
    private final String name;
    public String getName() {
        return name;
    }
    private CacheInnutale(String name)
    {
        this.name=name;
    }
    // 使用數組緩存已有的實例,并且記錄緩存的位置
    public static CacheInnutale valueOf(String name)
    {
        //遍歷已經緩存的對象,如果有相同的,直接返回緩存的實例
        for(int i=0;i<name.length();i++)
        {
            if(name!=null&&cache[i].getName().equals(name))
            {
                return cache[i];
            }
        }
        //如果緩存已經滿了,則從頭開始緩存
        if(MAX_SIZE==pos)
        {
            cache[0]=new CacheInnutale(name);
            pos=1;
        }
        //緩存沒滿的話,把新建的對象緩存起來
        else 
        {
            cache[pos++]=new CacheInnutale(name);
        }
        //因為是后?,所以pos-1
        return cache[pos-1];
    }
}

public class CacheInnutaleTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

    }

}

6.5 抽象類

抽象方法是只有方法的簽名,沒有方法的實現

6.5.1 抽象方法和抽象類

抽象方法和抽象類必須使用abstract修飾,有抽象方法的類一定是抽象類。
規則:

  1. 抽象方法不能有方法體
  2. 抽象類不能夠被實例化
  3. 抽象類的構造函數不能夠用來創造實例,主要用于被子類調用
  4. 含有抽象方法的類(包括直接定義了一個抽象方法;繼承了一個抽象父類,但是沒有完全實例化父類包含的抽象類;或是實現了一個接口,但是沒有完全實例化接口包含的抽象方法)
public class Triangle extends Shape{
    //定義三角形的三邊
    private double a;
    private double b;
    private double c;
    public Triangle(String color,double a,double b,double c)
    {
        super(color);
        this.sideSides(a,b,c);
    }
    public void sideSides(double a,double b,double c)
    {
        if(a+b<=c||a+c<=b||c+b<=a)
        {
            System.out.print("兩邊之和必須大于第三邊");
            return ;
        }
        this.a=a;
        this.b=b;
        this.c=c;
        
    }
    //重寫計算周長的方法
    public double calPerimeter()
    {
        return a+b+c;
    }
    public String getType()
    {
        return "三角形";
    }
    public static void main (String[] args)
    {
        //如果不用抽象類的話,s1是不能夠直接調用gettype方法的。
         
        Shape s1=new Triangle("yello", 3, 4,5);
        System.out.println(s1.getType());
        System.out.print(s1.calPerimeter());
    }
    

}

abstract與final不能同時出現:abstract類表示只能被繼承,但是final類不能被繼承。
abstract和static一般不能同時修飾方法:static修飾的方法表示屬于類的,可以通過類來訪問。但是如果同時也是abstract的話,則沒有方法體。這就沒辦法調用。(內部類除外)
abstract和private不能同時修飾方法:private修飾的方法是不會被繼承的。但是abstract需要繼承。

6.5.2 抽象類的作用

作為子類的模版。

6.6 java8改進的接口

將抽象類“抽象”到極致,只包含抽象方法。就是接口。

6.6.1 接口的概念

接口定義的是多個類共同的公共行為規范,接口里通常是定義一組公共方法。
接口不提供任何實現,體現的是實現和規范相分離的設計哲學。

6.6.2 java8中接口的定義

關鍵詞:interface
修飾符:public 或者省略,省略是默認default
一個接口可以繼承多個接口

由于接口定義的是一種規范,因此接口沒有構造器和初始化塊,接口可以包含成員變量(靜態常量),靜態方法和抽象方法以及默認方法。都必須是public

  1. 靜態常量:無論是否有修飾符,都是public static final的,需要在定義的時候指定默認值。可以跨包訪問,但是因為是final,不能修改值。
  2. 接口里面的普通方法只能是public的抽象abstract方法
  3. 在接口定義默認方法,需要使用default修飾(默認都是public修飾,不能static修飾)
  4. 在接口定義類方法,需要使用static(默認都是public ,不能用default修飾)
  5. java里面最多定義一個public的接口,如果有public的接口,則主文件名和接口名相同

6.6.3 接口的繼承

支持多繼承,以逗號分格

6.6.4 使用接口

implements實現多個接口。如果一個類繼承了一個接口,就必須把里面的抽象方法都實現,否則就必須定義成抽象類。
實現接口的方法時必須使用public
模擬多繼承:接口名 引用變量名=new 類(初始化參數),類就可以訪問接口的方法以及自己的方法。類的方法就變的很多。

package demo6;
//定義一個product接口
interface Product
{
    int getProductTime();
}
public class Printer implements Product , Output{
    private String[] printData=new String[MAX_CACHE_LINE];
    //記錄當前需打印的作業數
    private int dataNum=0;
    public void out()
    {
        //只要還有作業就繼續打印
        while(dataNum>0)
        {
            System.out.println(printData[0]);
            System.arraycopy(printData, 1, printData, 0, --dataNum);
        }
    }
    public void getData(String msg)
    {
        if(dataNum>=MAX_CACHE_LINE)
        {
            System.out.println("輸出隊列已經滿了。添加失敗");
        }else {
            printData[dataNum++]=msg;
        }
    }
    public int getProductTime()
    {
        return 45;
    }
    
    

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //創建一個printer對象,當成output使用
        Output o=new Printer();
        o.getData("瘋狂jav");
        o.getData("瘋狂jaba講義");
        o.out();
        o.getData("瘋狂安卓講義");
        o.getData("瘋狂安卓");
        o.out();
    }

}

6.6.5 接口和抽象類

接口:體現一種規范,對于接口的實現者,接口定義了必須實現那些服務;對于接口的調用者,規定了調用者可以調用哪些方法。
抽象類:體現一種模版的設計,他是沒有設計完的一個類,需要子類補充將它完成。

6.6.6 面向接口編程

  1. 簡單的工廠模式
    不太懂啊
package demo6;

public class Computer {
    private Output out;
    public Computer(Output out)
    {
        this.out=out;
    }
    //定義一個模擬獲得字符串的方法
    public void keyIn(String msg)
    {
        out.getData(msg);
    }
    public void print()
    {
        out.out();
    }

}


package demo6;

public class OutputFactory {
    public Output getOutput()
    {
        return new  Printer();
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        OutputFactory oF=new OutputFactory();
        Computer c=new Computer(oF.getOutput());
        c.keyIn("java");
        c.keyIn("ilovayou");
        c.print();

    }

}

2.命令模式

定義一個接口,接口里面定義一個抽象的方法,作用在一個數組上。然后實例化這個接口,可以實例化多個,每個都是作用在數組上的一種方法,
???????????

6.7 內部類

定義在其他類內部的類叫做內部類。
包含內部類的類叫做外部類。
內部類的作用:

  1. 提供了更好的封裝性,不允許同一個包中的其他類訪問。
  2. 內部類可以直接訪問外部類的私有數據。因為內部類可以當作外部類成員。外部類不可以訪問內部類的實現細節
  3. 匿名內部類適合用于創建只需要一次使用的類。
    內部類外部類區別:
  4. 內部類比外部類多3個修飾符,private protected static
  5. 非靜態內部類不能有靜態成員

6.7.1 非靜態內部類

在外部類里面使用非靜態內部類時,和使用普通的類沒有什么區別。非靜態內部類可以訪問外部類的pirvate成員,因為非靜態內部類的對象里面,保存了一個外部類對象的引用。
外部類成員變量,內部類成員變量,內部類里面方法的局部變量可以同名,用this區分。
外部類不能夠訪問非晶態內部類的成員,必須創建一個對象才行。new inner(),,,因為外部類存在的時候,內部類不一定存在,但是內部類存在,外部類一定存在。
不允許在外部類的靜態成員中直接使用非靜態內部類
不允許在非靜態內部類里面定義靜態成員。

6.7.2 靜態內部類

用static修飾的內部類叫做靜態內部類。這個內部類屬于外部類本身,不屬于外部類的任何一個對象。
外部類不能夠用statc修飾,因為外部類的上一級是包,所以沒有類的概念,但是內部類的上一層是外部類,所以可以用static修飾。
靜態內部類可以有靜態成員和非靜態成員,靜態內部類不能夠訪問外部類的實例成員,只能訪問類成員。(因為靜態內部類里面只有外部類的引用,沒有外部類對象的引用)
外部類依舊不能訪問內部類的成員,但是可以通過類名或者對象訪問內部類成員對象。
java允許定義接口內部類,默認是public static修飾。也就是說,接口的內部類一定是靜態內部類。

6.7.3 使用內部類

在外部類內部使用內部類
基本上與平常使用普通類沒有區別。唯一的區別是不要在外部類的靜態成員中使用非靜態內部類。

在外部類以外使用非靜態內部類
在外部類以外的地方定義內部類變量的語法:
outclassname.innerclassname name;
創建非靜態內部類對象(非靜態內部類的構造器必須用外部類對象調用)
outerInstance.new InnerConstructor()

class Out
{
    class In
    {
        public In(String msg)
        {
            System.out.println(msg);
        }
    }
}

public class CreateInnerInstance {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //使用outclass.innerclass的形式定義內部類變量
        Out.In in;
        //創建外部類對象
        Out out=new Out();
        //通過外部類對象創建內部類對象
        in=out.new In("測試出錯");
        

    }

}

1.創建非靜態內部類的子類

package demo6;

public class SubClass extends Out.In {
    public SubClass(Out out)
    {
        out.super("hello");
    }

}
  1. 在外部類以外使用靜態內部類
    new outclass.innerConstruction

可以看出無論是靜態內部類還是非靜態內部類,聲明變量的方法都是一樣的。區別在于創建內部類對象。優先考慮靜態內部類。

6.7.4 局部內部類

放在方法里面的內部類
一般不用

6.7.5 java8改進的匿名內部類

匿名內部類適合創建只需要一次使用的類。創建匿名內部類時會立即創建一個該類的實例,這個類定義立即消失,匿名內部類不能重復使用。
匿名內部類必須繼承一個父類,或者實現一個接口,但是最多只能是一個。
匿名內部類的兩條規則:

  1. 不能是抽象類,因為抽象類不能被實例化,但是匿名內部類創建的時候就要創建對象
  2. 不能定義構造器,因為匿名內部類沒有類名。
    最常用的創建匿名內部類是需要創建某個接口類型的對象。
    局部變量被匿名內部類訪問,局部變量相當于自動加了final修飾。因此不能夠再被修改。

6.8 java8新增的lambda表達式

6.8.1 lambda表達式入門

lambda表達式支持代碼作為方法參數,可以創建只有一個抽象方法的接口的實例。
lambda表達式由形參列表 ->和方法體組成

6.8.2 lambda表達式和函數式接口

lambda表達式的目標類型必須是函數式接口
函數式接口代表只包含一個抽象方法的接口。函數式接口可以包含多個默認方法,類方法,但只能有一個抽象方法。
java8為函數式接口加了@FunctionalInterface注解 用于告訴編譯器更嚴格的檢查

6.8.3 方法引用和構造器引用

如果代碼塊只有一行代碼,則可以在lambda表達式中使用方法引用和構造引用。
引用類方法 類名::類方法
引用特定對象的實力方法 特定對象::實例方法
引用某類對象的實例方法 類名::實例方法
引用構造器 類名::new

6.8.4 lambda表達式和匿名內部類的聯系和區別

lambda表達式是匿名內部類的一種簡化。
相同點:
都可以直接訪問“effectively final”的局部變量,以及外部類的成員變量
所創建的對象可以直接調用從接口中繼承的默認方法
區別
匿名內部類可以為任意接口創建實例,而lambda表達式必須是函數式接口
匿名內部類可以為抽象類甚至普通類創建實例。
匿名內部類的方法體可以調用接口中定義的默認方法,但是lambda不可以,它只有對象可以調用。

6.9 枚舉類

枚舉類是指實例有限而且固定的類

6.9.2 枚舉類入門

枚舉類是一種特殊的類,可以有自己的成員變量,方法,可以實現一個或者多個接口。

  1. 默認繼承java.lang.Enum類,不能顯式繼承其他父類。
  2. 使用Enum定義,非抽象的枚舉類默認是final修飾,不能派生子類
  3. 構造器為private
  4. 所有實例必須在第一行顯式列出,系統默認加上public static final
  5. 如果需要使用某個實例,用EnumClass.variable

6.9.3 枚舉類的成員變量,方法和構造器

枚舉類的成員變量最好都使用private final修飾
如果構造函數有參數,則在第一行列出實例的時候,要寫上參數。
枚舉類的實例只能是枚舉值,不能隨意通過new來創建。???

6.9.4 實現接口的枚舉類

與普通類完全一樣,也需要實現該接口所包含的方法
如果不同的枚舉值想在調用一個方法時呈現不同的行為方式,則可以讓每個枚舉值分別實現該方法,這個時候,不是在創建枚舉類的實例,而是創建匿名子類的實例。

6.9.5 包含抽象方法的枚舉類

每個枚舉值都必須為抽象方法提供實現,否則報錯。

6.10 對象和垃圾回收

6.10.1 對象在內存中的狀態

可達狀態
可恢復狀態
不可達狀態

6.10.2 強制垃圾回收

System.gc()
Runtime.getRuntime().gc()

6.10.3 finalize方法

6.11 修飾符的適用范圍

6.12 使用JAR文件

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

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,765評論 18 399
  • 一:java概述:1,JDK:Java Development Kit,java的開發和運行環境,java的開發工...
    ZaneInTheSun閱讀 2,687評論 0 11
  • 1、.java源文件: 一個以”.java“為后綴的源文件:只能有一個與文件名相同的類,可以包含其他類。 2、類方...
    Hughman閱讀 1,518評論 1 9
  • 本文出自 Eddy Wiki ,轉載請注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 1,227評論 0 5
  • 面向對象主要針對面向過程。 面向過程的基本單元是函數。 什么是對象:EVERYTHING IS OBJECT(萬物...
    sinpi閱讀 1,091評論 0 4