日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

java面向?qū)ο蟾呒?jí)

 路人甲Java 2021-04-30

1、類變量(靜態(tài)類變量)
1、為什么要有靜態(tài)類變量?

引出: 
過(guò)年,公司發(fā)過(guò)年禮品,假設(shè)我們有一個(gè)禮品類Gift,有一個(gè)發(fā)放禮品的類方法receive(),我想知道當(dāng)前有多少個(gè)員工領(lǐng)取禮品,怎么辦?

解決:
1、在類中定義一個(gè)屬性count,然后在receive()里每調(diào)用該方法進(jìn)行conut++?
2、在main方法定義一個(gè)count局部變量,每調(diào)用一次receive()進(jìn)行count++?
3、在類中定義一個(gè)靜態(tài)的類變量,在方法receive()中進(jìn)行count++?

答案:選擇3!第一種不管領(lǐng)取了多少禮品,每個(gè)對(duì)象中的count屬性值都是1;第二種可以是可以,但不符合oop的思想,如果需要在別的地方用到該count值,沒(méi)辦法調(diào)用??;第三種,靜態(tài)類變量多個(gè)對(duì)象共享該變量,不管是用那個(gè)對(duì)象獲取的count值,都是最新的且一致的!

#測(cè)試代碼:
public class StaticDemo {
    public static void main(String[] args) {
        Gift gift = new Gift("張三");
        Gift gift1 = new Gift("李四");

        gift.receive();
        System.out.println("當(dāng)前有"+Gift.count+"個(gè)員工領(lǐng)取了禮品"+"  名字分別為:"+ Gift.str);

        gift1.receive();
        System.out.println("當(dāng)前有"+gift1.count+"個(gè)員工領(lǐng)取了禮品"+"  名字分別為:"+ Gift.str);
    }
}
//禮品類
class Gift{
    private String name;
    protected static int count;
    public static String str="";

    public Gift(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    //發(fā)放禮品
    public void receive(){
        giftEliminate();
        count++;
        str = str.concat(getName());
    }

    //當(dāng)領(lǐng)取人數(shù)大于5個(gè)我就調(diào)用該方法將count清零;
    public void giftEliminate(){
        if (count>5){
            Gift.count = 0;
        }
    }
}

輸出:
當(dāng)前有1個(gè)員工領(lǐng)取了禮品  名字分別為:張三
當(dāng)前有2個(gè)員工領(lǐng)取了禮品  名字分別為:張三李四

小結(jié)(什么時(shí)候使用類變量?):
1、靜態(tài)類變量的作用就是存儲(chǔ)一些獨(dú)立于對(duì)象的數(shù)據(jù),但各對(duì)象又能共享該變量值



2、如何定義和使用靜態(tài)類變量?
定義:
1、static public int count  
2、public static int count (推薦使用)
#從上面代碼可以看出,在普通屬性上聲明一個(gè)static關(guān)鍵字,靜態(tài)類方法也是如此

使用:
1、使用類名.變量名(推薦使用) Gift.count
2、對(duì)象名.變量名 gift1.count

3、類變量于實(shí)例變量(普通類屬性)的區(qū)別?
1、類變量屬于類,但被所有對(duì)象共享
2、實(shí)例變量只屬于這一個(gè)對(duì)象,獨(dú)立不被共享



4 小結(jié):
類變量:
1、使用關(guān)鍵字static聲明定義,推薦定義格式: 修飾符 static 數(shù)據(jù)類型 變量名
        2、使用類名.變量名調(diào)用該類變量
        3、被所有對(duì)象共享變量值
        
實(shí)例變量:
1、定義:修飾符 數(shù)據(jù)類型 變量名
2、使用對(duì)象名.變量名調(diào)用該變量
3、只屬于該對(duì)象本身,不被共享
2、靜態(tài)方法
1、為什么要有靜態(tài)方法?
 應(yīng)用:
 當(dāng)我們要寫(xiě)一個(gè)方法操作一些跟對(duì)象無(wú)關(guān)的數(shù)據(jù)時(shí),可以使用靜態(tài)方法。
  

2、靜態(tài)方法的定義和使用
定義:
1、public static void print(){}
2、static void print(){}
修飾符 static 返回?cái)?shù)據(jù)類型 方法名(){}

#注意:因?yàn)樾揎椃椒ǖ男揎椃挥衟ublic 或 默認(rèn)(不寫(xiě))

使用:
 1、類名.方法名() (推薦使用)
 
 2、對(duì)象名.方法名()
 
 
 
 
代碼:

public class StaticDemo {
    public static void main(String[] args) {
        Student student = new Student("張三");
        Student student1 = new Student("李四");

        Student.count_study_money(3000);
        Student.count_study_money(5000);

        System.out.println("當(dāng)前學(xué)費(fèi)共交了"+Student.get_study_money()+"元");
        student.print();
    }
}

class Student{
    public String name;
    private static double study_money;
    static String str="";

    public Student(String name){
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    //計(jì)算學(xué)費(fèi)
    public static void count_study_money(double study_money){
        //Student.study_money = Student.study_money + study_money;
        Student.study_money += study_money;
    }

    //返回學(xué)費(fèi)
    public static double get_study_money(){

        return Student.study_money;
    }
    
    public void print(){
        System.out.println(get_study_money());//非靜態(tài)方法中調(diào)用靜態(tài)方法
        System.out.println(name);//非靜態(tài)方法中調(diào)用非靜態(tài)變量
        System.out.println(str);//非靜態(tài)方法中調(diào)用靜態(tài)變量
    }
}

輸出:
當(dāng)前學(xué)費(fèi)共交了8000.0元
8000.0
張三



3、使用類方法時(shí),有哪些要注意的細(xì)節(jié)?

1、類方法中不能使用this和super與對(duì)象相關(guān)的關(guān)鍵字。 因?yàn)閠his代表調(diào)用者當(dāng)前對(duì)象本身,而靜態(tài)方法執(zhí)行是無(wú)需實(shí)例化對(duì)象,那這個(gè)this就是空,所以靜態(tài)方法中不能用this

2、類方法和類變量調(diào)用跟對(duì)象是否創(chuàng)建無(wú)關(guān),調(diào)用時(shí)都是通過(guò)類名.類變量/類方法()調(diào)用

3、而對(duì)象變量和對(duì)象方法與實(shí)例對(duì)象有關(guān),調(diào)用對(duì)象方法和對(duì)象變量時(shí)只能用對(duì)象名.變量 或 對(duì)象名.方法名(),不能使用類名.方法和變量!

4、靜態(tài)(類)方法中只能調(diào)用靜態(tài)(類)變量和靜態(tài)方法,無(wú)法使用非靜態(tài)變量和非靜態(tài)方法

5、非靜態(tài)方法可以調(diào)用非靜態(tài)變量、非靜態(tài)方法、靜態(tài)方法、靜態(tài)變量

i

3、Main()方法
public static void main(String[] args){}

1、為什么main()方法要這樣寫(xiě)?
# 因?yàn)橛辛藀ublic權(quán)限,所以jvm才能調(diào)用main;
  因?yàn)橛辛藄tatic,所以調(diào)用mian()方法時(shí)不需要有對(duì)象創(chuàng)建; 
  因?yàn)橛辛薙tring[] args字符串?dāng)?shù)組,所以運(yùn)行main里面的程序時(shí),可以用字符串?dāng)?shù)組去存儲(chǔ)中轉(zhuǎn)所需的參數(shù)!
4、代碼塊
1、代碼塊的定義
1、普通代碼塊
格式:{代碼體}

2、靜態(tài)代碼塊
static{代碼體}


2、普通代碼與靜態(tài)代碼塊的使用區(qū)別

普通代碼塊:
1、是對(duì)對(duì)象進(jìn)行初始化。每創(chuàng)建一次對(duì)象就執(zhí)行一次

靜態(tài)代碼塊:
1、是對(duì)類進(jìn)行初始化。隨著類被加載的時(shí)候就執(zhí)行了,且只會(huì)執(zhí)行一次(不管new幾個(gè)對(duì)象)


#代碼驗(yàn)證:

//午餐類
class Lunch{
    public static double price=20;

    //普通代碼塊
    {
        System.out.println("普通代碼塊:先煮飯,洗菜,炒菜");
    }
    //靜態(tài)代碼塊
    static {
        System.out.println("靜態(tài)代碼塊:先煮飯,洗菜,炒菜");
    }

    //無(wú)參構(gòu)造器
    public Lunch() {
        System.out.println("這是無(wú)參構(gòu)造器");
    }

    //靜態(tài)方法
    public static void makeLunch(){
        System.out.println("這是一個(gè)靜態(tài)方法");
    }
}

public class codeBlock {
    public static void main(String[] args) {
        Lunch lunch = new Lunch();
        Lunch lunch1 = new Lunch();
        Lunch lunch2 = new Lunch();
        Lunch.makeLunch();
        System.out.println(Lunch.price);
    }
}


輸出:
靜態(tài)代碼塊:先煮飯,洗菜,炒菜
普通代碼塊:先煮飯,洗菜,炒菜
這是無(wú)參構(gòu)造器
普通代碼塊:先煮飯,洗菜,炒菜
這是無(wú)參構(gòu)造器
普通代碼塊:先煮飯,洗菜,炒菜
這是無(wú)參構(gòu)造器
這是一個(gè)靜態(tài)方法
20.0

說(shuō)明:
1、執(zhí)行順序: 靜態(tài)代碼塊——》普通代碼塊——》構(gòu)造器
2、執(zhí)行次數(shù):靜態(tài)代碼塊只執(zhí)行一次,普通代碼塊執(zhí)行次數(shù)跟對(duì)象創(chuàng)建次數(shù)一樣
3、靜態(tài)方法調(diào)用一次就執(zhí)行一次



3、觸發(fā)類加載的幾種情況(靜態(tài)代碼塊)
1、創(chuàng)建對(duì)象實(shí)例時(shí)
2、當(dāng)創(chuàng)建子類對(duì)象實(shí)例時(shí),先加載父類,再加載子類
3、使用類的靜態(tài)成員(靜態(tài)屬性、靜態(tài)方法)
4、還有一種是反射( 我還沒(méi)學(xué)>_<...)

#代碼驗(yàn)證:

public class codeBlock02 {
    public static void main(String[] args) {
        new CC();
        //1、創(chuàng)建對(duì)象實(shí)例時(shí)會(huì)觸發(fā)類加載,執(zhí)行靜態(tài)代碼塊。
        //2、當(dāng)創(chuàng)建子類對(duì)象實(shí)例時(shí),當(dāng)前類CC向上的所有父類AA、BB類都會(huì)觸發(fā)類加載,從而執(zhí)行對(duì)應(yīng)類的靜態(tài)代碼塊
     

        //System.out.println(CC.str);
        //1、當(dāng)調(diào)用靜態(tài)成員(靜態(tài)方法和變量)時(shí),會(huì)觸發(fā)類加載,執(zhí)行靜態(tài)代碼塊內(nèi)容
    }
}

class AA{
    //普通代碼塊
    {
        System.out.println("普通代碼塊AA");
    }
    //靜態(tài)代碼塊
    static {
        System.out.println("靜態(tài)代碼塊AA");
    }
}

class BB extends AA{
    //普通代碼塊
    {
        System.out.println("普通代碼塊BB");
    }
    //靜態(tài)代碼塊
    static {
        System.out.println("靜態(tài)代碼塊BB");
    }
}

class CC extends BB{
    public static String str="這是靜態(tài)變量";
    //普通代碼塊
    {
        System.out.println("普通代碼塊CC");
    }
    //靜態(tài)代碼塊
    static {
        System.out.println("靜態(tài)代碼塊CC");
    }

    public CC() {
        System.out.println("這是CC的無(wú)參構(gòu)造器");
    }
}

執(zhí)行new CC()輸出:
靜態(tài)代碼塊AA
靜態(tài)代碼塊BB
靜態(tài)代碼塊CC
普通代碼塊AA
普通代碼塊BB
普通代碼塊CC
這是CC的無(wú)參構(gòu)造器

執(zhí)行System.out.println(CC.str)輸出:
靜態(tài)代碼塊AA
靜態(tài)代碼塊BB
靜態(tài)代碼塊CC
這是靜態(tài)變量

說(shuō)明:上面結(jié)論是正確的!



4、創(chuàng)建一個(gè)類對(duì)象時(shí),類中靜態(tài)代碼塊、靜態(tài)變量、普通代碼塊、普通變量、構(gòu)造器的執(zhí)行順序是什么?

上代碼測(cè)試:

public class codeBlock02 {
    public static void main(String[] args) {
        AA aa = new AA();
    }
}

class AA{

    //普通變量
    public int numb = getNumb();

    //靜態(tài)類變量
    public static String str=getStr();

    //普通方法
    public int getNumb(){
        System.out.println("getNumb被執(zhí)行了");
        return 10;
    }

    //靜態(tài)方法
    public static String getStr(){
        System.out.println("getStr()方法被執(zhí)行");
        return "類變量";
    }

    //構(gòu)造器
    public AA(){
    super();//當(dāng)有父類時(shí)會(huì)執(zhí)行,沒(méi)有不執(zhí)行    <1>
       <2>
        System.out.println("這是AA的無(wú)參構(gòu)造器"); <3>
    }
    // 在<2>這里我感覺(jué)隱藏了調(diào)用普通代碼塊的引用代碼,因?yàn)槊縩ew一個(gè)對(duì)象時(shí),執(zhí)行順序都是: <1> ---> <2> ---> <3>; 
    

    //普通代碼塊
    { System.out.println("普通代碼塊AA");}
             
    //靜態(tài)代碼塊
    static {System.out.println("靜態(tài)代碼塊AA");}
}

//輸出:
//    getStr()方法被執(zhí)行   ---》靜態(tài)類變量
//    靜態(tài)代碼塊AA     ---》靜態(tài)代碼塊
//    getNumb被執(zhí)行了    ---》普通類變量
//    普通代碼塊AA---》普通代碼塊
//    這是AA的無(wú)參構(gòu)造器  ---》構(gòu)造器


說(shuō)明什么?
1、先執(zhí)行靜態(tài)static的靜態(tài)代碼塊或靜態(tài)類變量,這兩優(yōu)先級(jí)一樣,執(zhí)行順序就看定義的位置誰(shuí)先誰(shuí)后
2、然后執(zhí)行普通代碼塊或普通類變量,這兩優(yōu)先級(jí)也一樣,執(zhí)行順序就看定義的位置誰(shuí)先誰(shuí)后
3、最后執(zhí)行構(gòu)造器

4、在構(gòu)造器中super()下面還隱藏了一段看不見(jiàn)的調(diào)用普通代碼塊的引用代碼



5、小練習(xí)(代碼塊)
 #請(qǐng)問(wèn)以下代碼輸出什么?

public class codeBlock01 {
    public static void main(String[] args) {
        new B();
    }
}

class A{
    //靜態(tài)屬性
    public static int number_A = getA1();

    //靜態(tài)代碼塊
    static { System.out.println("A類靜態(tài)代碼塊");}

    //普通代碼塊
    {  System.out.println("A類普通代碼塊"); }

    //普通屬性
    public int age_A = getA2();

    //父類構(gòu)造方法
    public A(){
        System.out.println("打印A類構(gòu)造器");
    }

    public static int getA1(){
        System.out.println("調(diào)用了getA1方法");
        return 20;
    }

    public int getA2(){
        System.out.println("調(diào)用了getA2方法");
        return 31;
    }
}
class B extends A{

    //靜態(tài)代碼塊
    static { System.out.println("B類的靜態(tài)代碼塊"); }

    //靜態(tài)屬性
    public static String getStringB1 = getB1();

    //普通代碼塊
    { System.out.println("B類的普通代碼塊"); }

    //普通屬性
    public String getStringB2 = getB2();

    //子類構(gòu)造方法
    public B(){
        super();
        System.out.println("打印A類構(gòu)造器");
    }

    public static String getB1(){
        System.out.println("調(diào)用了getB1方法");
        return "B1";
    }

    public String getB2(){
        System.out.println("調(diào)用了getB2方法");
        return "B2";
    }
}

輸出:
調(diào)用了getA1方法
A類靜態(tài)代碼塊
B類的靜態(tài)代碼塊
調(diào)用了getB1方法
A類普通代碼塊
調(diào)用了getA2方法
打印A類構(gòu)造器
B類的普通代碼塊
調(diào)用了getB2方法
打印A類構(gòu)造器


6、小練習(xí)
以下程序會(huì)輸出?
public class Test {
    static String s = "琳";
    static {
        String s = "麗";
        System.out.println(s);   // <1> 靜態(tài)代碼塊最先執(zhí)行,輸出麗
    }
    public static void main(String[] args) {
        new Son(s);  //把"琳"傳進(jìn)去

    }
}

class Father{
    static int m=100;
    public Father(){ m=999;} //父類的m=999,不改變靜態(tài)變量m的值
    static {
        m=10000;
        System.out.println("父類"+m);}  // <2> 輸出:父類10000
}

class Son extends Father{
    int m;
    { super.m=5;} //這里修改了父類屬性m=5

    static {
        System.out.println("static block");  //<3> 輸出:static block
    }

    public Son(String name){
        System.out.println(name); //<4> 輸出: "琳"
        System.out.println(m);<5> 輸出: 子類屬性沒(méi)有賦值,所以m=0;
        System.out.println(super.m); <6>輸出: 5
    }
}

最終輸出:麗,父類10000,static block,"琳",0,5
5、單例模式
# 使用靜態(tài)方法和靜態(tài)屬性實(shí)現(xiàn)單例模式
# 單例模式特點(diǎn):一點(diǎn)創(chuàng)建了一個(gè)對(duì)象,之后就無(wú)法創(chuàng)建新對(duì)象,一個(gè)類只能有一個(gè)對(duì)象實(shí)例

#思路
1、限制創(chuàng)建對(duì)象
2、判斷是否已經(jīng)存在一個(gè)對(duì)象實(shí)例


代碼實(shí)現(xiàn):
public class SingletonMode {
    public static void main(String[] args) {
        //固定式
        Singleton1 singleton1 = Singleton1.getSingleton();
        Singleton1 singleton2 = Singleton1.getSingleton();
        System.out.println(singleton1==singleton2);//返回true,說(shuō)明成功了

        //靈活式
        Singleton2 singleton3 = Singleton2.getSingleton("小花");
        Singleton2 singleton4 = Singleton2.getSingleton("小梅");
        System.out.println(singleton3==singleton4);//返回true,說(shuō)明成功了

        /*
        實(shí)現(xiàn)單例模式
        思路:
            1、限制創(chuàng)建新對(duì)象
            2、判斷該類中是否已經(jīng)存在一個(gè)對(duì)象實(shí)例
        */
    }
}

//實(shí)現(xiàn)一:固定式
class Singleton1{  //缺點(diǎn)就是:這個(gè)name參數(shù)值在編寫(xiě)時(shí)必須寫(xiě)死,那有沒(méi)有自己傳參值來(lái)new一個(gè)呢,看下一個(gè)

    private String name;
    private static Singleton1 singleton = new Singleton1("小琳");
    //私有化構(gòu)造器
    private Singleton1(String name){
        super();
        this.name =name;
    }
    //提供一個(gè)static方法獲取對(duì)象
    public static Singleton1 getSingleton(){
        return singleton;
    }
}

//實(shí)現(xiàn)二:靈活式  可以自定義單例對(duì)象的數(shù)值
class Singleton2{
    private String name;
    private static Singleton2 Singleton;

    //私有化構(gòu)造器
    private Singleton2(String name){
        super();
        this.name = name;
    }
    //提供一個(gè)判斷對(duì)象是否存在且可以返回對(duì)象的方法
    public static Singleton2 getSingleton(String name){
        //判斷當(dāng)前是否存在對(duì)象
        if (Singleton == null){
            return Singleton = new Singleton2(name);
        }
        return Singleton;
    }
}


小結(jié)(固定式和靈活式的區(qū)別):

對(duì)象創(chuàng)建時(shí)間上:
    固定式是在類加載時(shí)就創(chuàng)建了該對(duì)象,而靈活式要調(diào)用才會(huì)創(chuàng)建對(duì)象
    
    資源浪費(fèi)上:
    固定式有可能創(chuàng)建后就沒(méi)有用過(guò)所以存在浪費(fèi)資源的可能,而靈活式就不會(huì)有這情況
    
    靈活度上:
    固定式是在編寫(xiě)代碼時(shí)對(duì)象就確定了,后續(xù)不能改變,而靈活式可以在第一次創(chuàng)建對(duì)象時(shí)選擇創(chuàng)建的對(duì)象值
    
    線程安全上:
    固定式是線程安全的,靈活式是線程不安全的!
6、抽象類
6.1、抽象類的介紹
1、抽象類定義
訪問(wèn)修飾符 abstract 類名{ }//沒(méi)有類實(shí)現(xiàn) 

2、抽象方法定義
訪問(wèn)修飾符 abstract 方法名(參數(shù)列表)//沒(méi)有方法體

3、抽象類的價(jià)值更多的體現(xiàn)在設(shè)計(jì)層面,設(shè)計(jì)者設(shè)計(jì)好抽象類讓子類繼承并實(shí)現(xiàn)抽象類的功能,更多的是充當(dāng)一個(gè)模板的作用,應(yīng)用場(chǎng)景更多體現(xiàn)在設(shè)計(jì)模式和框架上!
6.2、抽象類的特點(diǎn)
1、抽象類不能被實(shí)例化創(chuàng)建

2、抽象類中,可以有抽象方法,也可以沒(méi)有抽象方法

3、一個(gè)方法一旦聲明了成抽象方法,該方法的類也必須聲明為抽象類!總結(jié):抽象類不一定有抽象方法,但有抽象方法的類一定是抽象類

4、abstract只能修飾類和方法,不能修飾類屬性(只有抽象類和方法之說(shuō),沒(méi)有抽象屬性之說(shuō))

5、普通類里可以有的抽象類都可以有(如靜態(tài)方法、靜態(tài)屬性、靜態(tài)代碼塊、普通代碼塊),普通類里沒(méi)有的抽象方法抽象類有!

6、抽象方法沒(méi)有方法體

7、如果一個(gè)類繼承了抽象類,那就必須實(shí)現(xiàn)該抽象類的所有抽象方法,除非把自己也聲明為抽象類!

8、抽象方法不能使用private、final、static修飾。
#因?yàn)槌橄蠓椒ǘx后必須實(shí)現(xiàn),而重寫(xiě)也是一種實(shí)現(xiàn)的方式,private私有化不能被重寫(xiě),final不能被繼承也就無(wú)法重寫(xiě),static靜態(tài)化方法只跟類相關(guān),沒(méi)有對(duì)象去實(shí)現(xiàn)這個(gè)抽象方法,重寫(xiě)是跟對(duì)象相關(guān)的!

6.3、多態(tài)在抽象類的體現(xiàn)
1、多態(tài)參數(shù): 
[抽象父類的引用也可以指向繼承它的所有子類對(duì)象,所以可以使用抽象父類的引用作為形參去接收傳遞過(guò)來(lái)的所有子類對(duì)象參數(shù)] 什么意思?看下面代碼


代碼:
----------------------------------------------------------------------------------------
/*  驗(yàn)證:
    多態(tài)參數(shù):接收子類對(duì)象
    多態(tài)數(shù)組:存儲(chǔ)各個(gè)子類對(duì)象
 */

//抽象父類-寵物類
abstract class  Pets{
    private String name;

    public Pets(String name) {
        super();
        this.name = name;
        System.out.println(name);
    }
}
//寵物狗類
class petsDog extends Pets{
    public petsDog(String name){
        super(name);
    }
}
//寵物貓類
class petsCat extends Pets{
    public petsCat(String name){
        super(name);
    }
}
//測(cè)試類

public class Abstract01 {
    public static void main(String[] args) {
        Pets cat = new petsCat("加菲貓");
        Pets dog = new petsDog("旺財(cái)");
        //抽象父類引用Pets可以作為形參接收petsCat("加菲貓")和petsDog("旺財(cái)")
        // 這兩個(gè)子類對(duì)象實(shí)例,就證明了抽象類也具有多態(tài)參數(shù)的特性
    }
}

輸出:
加菲貓
旺財(cái)


2、多態(tài)數(shù)組:
[抽象父類也可以存放所有繼承的子類對(duì)象]什么意思?看下面代碼

代碼:

/*  驗(yàn)證:
    多態(tài)參數(shù):接收子類對(duì)象
    多態(tài)數(shù)組:存儲(chǔ)各個(gè)子類對(duì)象
 */
//抽象父類-寵物類
abstract class  Pets{
    private String name;

    public Pets(String name) {
        super();
        this.name = name;
        System.out.println(name);
    }

    public String getName(){
        return name;
    }

    //定義一個(gè)公有的抽象方法play(),玩
    public abstract void play();
}
//寵物狗類
class petsDog extends Pets{
    public petsDog(String name){
        super(name);
    }

    //重寫(xiě)實(shí)現(xiàn)play()方法
    @Override
    public void play() {
        System.out.println(getName()+"可以拿來(lái)擼");
    }

    //狗特有行為:看大門(mén)
    public void guardHome(){
        System.out.println(getName()+"會(huì)幫主人看家");
    }
}
//寵物貓類
class petsCat extends Pets{
    public petsCat(String name){
        super(name);
    }
    @Override
    public void play(){
        System.out.println(getName()+"可以拿來(lái)擼");
    }
    //貓?zhí)赜行袨?抓老鼠
    public void captureMouse(){
        System.out.println(getName()+"會(huì)抓老鼠");
    }
}

//測(cè)試類
public class Abstract01 {
    public static void main(String[] args) {
        //在這里定義一個(gè)抽象父類Pets數(shù)組,去接收不同的子類對(duì)象
        Pets[] pets = new Pets[]{new petsCat("加菲貓"),new petsDog("旺財(cái)"),};
        //抽象父類引用pets去接收并存儲(chǔ) new petsCat("加菲貓") 和 new petsDog("旺財(cái)")子類對(duì)象,運(yùn)行時(shí)會(huì)進(jìn)行動(dòng)態(tài)綁定!
        new Abstract01().getObject(pets);
    }

    //定義一個(gè)判斷子類對(duì)象類型的方法,并打印出對(duì)象對(duì)應(yīng)的特有方法
    public void getObject(Pets[] abs){
        //使用instanceof進(jìn)行子類對(duì)象類型判斷
        for (Pets p:abs){
            if (p instanceof petsCat){
                ((petsCat)p).captureMouse();
            }else { //因?yàn)槌橄蟾割悷o(wú)法被實(shí)例化,所以不可能會(huì)有父類的對(duì)象出現(xiàn),對(duì)象只可能兩種類型
                ((petsDog) p).guardHome();
            }
        }
    }
}
6.4、抽象類體現(xiàn)了模板設(shè)計(jì)模式
1、抽象充當(dāng)了多個(gè)子類的通用模板,子類可以在繼承抽象類的基礎(chǔ)上進(jìn)行擴(kuò)展,但子類中還是保留一定的抽象父類的行為方法

2、什么是模板設(shè)計(jì)模式?
#當(dāng)有一部分功能是確定的,一部分功能是不確定的,可以用模板設(shè)計(jì)模式設(shè)計(jì)一個(gè)抽象父類,里面定義一個(gè)抽象方法,這個(gè)抽象方法做不確定功能,確定的功能在抽象父類寫(xiě)一個(gè)方法實(shí)現(xiàn)好;然后讓子類繼承并實(shí)現(xiàn)這個(gè)功能不確定的抽象方法


上代碼演示:
3、需求:我想要一個(gè)抽象類,用于計(jì)算一個(gè)方法執(zhí)行的時(shí)間(什么方法不確定,但是用于計(jì)算時(shí)間的方法確定)

//抽象計(jì)算類
//抽象計(jì)算類
abstract class Calculation{
    //抽象方法
    abstract public void Method();

    //計(jì)算耗時(shí)的方法
    public void consumeTime(){
        long start_time = System.currentTimeMillis();
        Method();
        long end_time = System.currentTimeMillis();
        System.out.println("該方法耗時(shí)為:"+(end_time-start_time));
    }
}

class Son1 extends Calculation{
    @Override
    public void Method(){
        String str = "";
        for (int i = 0; i < 100000; i++) {
            str += "SB";
        }
    }
}

class Son2 extends Calculation{
    @Override
    public void Method(){
        StringBuffer str = new StringBuffer("");
        for (int i = 0; i < 100000; i++) {
            str.append("SB");
        }
    }
}

class Son3 extends Calculation{
    @Override
    public void Method(){
        StringBuilder str = new StringBuilder("");
        for (int i = 0; i < 100000; i++) {
            str.append("SB");
        }
    }
}


//測(cè)試類
public class Template {
    public static void main(String[] args) {
        //實(shí)現(xiàn)一:
            //new Son1().consumeTime();
            //son1先找自己consumeTime方法,沒(méi)有就找父類consumeTime方法,
            // 父類consumeTime根據(jù)動(dòng)態(tài)綁定調(diào)用自己的Method方法
            //new Son2().consumeTime();
            //new Son3().consumeTime();

        //實(shí)現(xiàn)二:
        Template.test(new Son1()); //調(diào)用靜態(tài)方法:類名.方法名
        new Template().test(new Son2());//調(diào)用靜態(tài)方法:對(duì)象.方法名
        test(new Son3()); //因?yàn)樵摲椒ㄔ谕愔?,直接方法?    }

    public static void test(Calculation c){
        c.consumeTime();
    }
}

輸出:
該方法耗時(shí)為:12139
該方法耗時(shí)為:3
該方法耗時(shí)為:2
//說(shuō)明字符串拼接操作效率:StringBuilder > StringBuffer > String;

7、接口
1、接口介紹:
就是把一些沒(méi)有實(shí)現(xiàn)的方法通過(guò)接口封裝到一起,當(dāng)哪個(gè)類需要使用到接口的方法的時(shí)候,該類根據(jù)需求再具體去實(shí)現(xiàn)接口里的方法

接口定義格式:
interface 接口名{
屬性
抽象方法(接口里的方法默認(rèn)是abstract抽象的)
在jdk1.8后,接口里可以有 靜態(tài)方法 和 默認(rèn)方法的實(shí)現(xiàn)
}

實(shí)現(xiàn)接口格式:
class 類名 implements 接口名{
//可以有自己的屬性和方法,但是必須實(shí)現(xiàn)(重寫(xiě))接口的所有方法,可以跟接口隔離原則去優(yōu)化
自己屬性
自己方法
必須實(shí)現(xiàn)接口的抽象方法
}


#栗子:

//接口
interface interfaceDemo{
    //接口里的屬性必須定義時(shí)給定初始值
    public String str="111"; 
    //等同public static final String str = "111"

    //靜態(tài)方法
    public static void print01(){
        System.out.println("靜態(tài)方法");
    }

    //默認(rèn)方法
    public default void pint02(){
        System.out.println("默認(rèn)方法");
    }
    
    //抽象方法
    void absMethod1();
    void absMethod2();
}

//測(cè)試類
public class Interface02 {
    public static void main(String[] args) {
        //接口里的靜態(tài)方法直接用接口名調(diào)用,跟類的靜態(tài)方法調(diào)用一樣
        interfaceDemo.print01();
        //默認(rèn)方法接口自己無(wú)法使用接口名調(diào)用
        //interfaceDemo.print02();

    }
}

//普通類
class Ordinary implements interfaceDemo{
    
    //實(shí)現(xiàn)一個(gè)抽象方法1還是報(bào)錯(cuò),接著實(shí)現(xiàn)方法2報(bào)錯(cuò),實(shí)現(xiàn)默認(rèn)方法后不報(bào)錯(cuò),說(shuō)明要全部實(shí)現(xiàn)(包含默認(rèn)方法)
    @Override
    void pint02() { //一旦我把print2方法的改為默認(rèn),就報(bào)錯(cuò),而根據(jù)實(shí)現(xiàn)接口的子類方法訪問(wèn)權(quán)限必須 >= 接口抽象方法的訪問(wèn)權(quán)限,
                    //那就證明接口的抽象方法的訪問(wèn)權(quán)限默認(rèn)是public 
    }

    @Override
    public void absMethod1() {

    }

    @Override
    public void absMethod2() {

    }
}

//抽象類
abstract class absClass implements interfaceDemo{
    //不報(bào)錯(cuò),說(shuō)明抽象類可以不用實(shí)現(xiàn)接口的抽象方法
}

//測(cè)試類
public class Interface02 {
    public static void main(String[] args) {
        //接口里的靜態(tài)方法直接用接口名調(diào)用,跟類的靜態(tài)方法調(diào)用一樣
        interfaceDemo.print01();
        //默認(rèn)方法接口自己無(wú)法使用接口名調(diào)用,只能給實(shí)現(xiàn)了接口的子類調(diào)用
        //interfaceDemo.print02();

    }
}

小細(xì)節(jié):
1、在jdk1.8后,接口里可以有 靜態(tài)方法 和 默認(rèn)方法的實(shí)現(xiàn) 及定義接口自己屬性
2、接口里的屬性必須定義時(shí)給定初始值,等同于常量屬性
3、接口里的靜態(tài)方法直接用接口名調(diào)用,跟類的靜態(tài)方法調(diào)用一樣
4、默認(rèn)方法接口自己無(wú)法使用接口名調(diào)用,只能給實(shí)現(xiàn)了接口的子類調(diào)用
5、實(shí)現(xiàn)接口的子類方法權(quán)限 >= 接口的抽象方法訪問(wèn)權(quán)限
6、抽象類可以實(shí)現(xiàn)接口,但可以實(shí)現(xiàn)接口的抽象方法
7、接口可以繼承別的接口,但是不能繼承普通類,當(dāng)然也包含抽象類

//注意:
1、當(dāng)多個(gè)接口里如果有重名的抽象方法,不會(huì)影響使用,如果是重名的常量屬性時(shí),調(diào)用時(shí)使用接口名.屬性名區(qū)分

7.2、繼承與接口在應(yīng)用上有什么區(qū)別?
1、接口其實(shí)是對(duì)java單繼承缺點(diǎn)的一種彌補(bǔ)和擴(kuò)展,讓子類有更豐富的方法和屬性,而這些屬性來(lái)源于子類實(shí)現(xiàn)接口里的抽象方法!

#栗子

package P3;

//猴子父類
class Monkey{
    private String name;

    public Monkey(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }
    //爬樹(shù)
    public void climbTree(){
        System.out.println(getName()+"會(huì)爬樹(shù)");
    }
}
//想要給悟空加技能,會(huì)上天飛,會(huì)下海潛,使用實(shí)現(xiàn)接口的抽象方法
interface FlightClass{
    public void flight();//會(huì)飛行
}
interface DivingClass{
    public void diving();//會(huì)潛水
}

//孫悟空類
class sunMonkey extends Monkey implements DivingClass,FlightClass{

    public sunMonkey(String name) {
        super(name);
    }

    @Override
    public void climbTree() {
        super.climbTree();
    }

    //實(shí)現(xiàn)飛行和潛水方法
    @Override
    public void diving(){
        System.out.println(getName()+"會(huì)潛水");
    }
    @Override
    public void flight(){
        System.out.println(getName()+"會(huì)飛行");
    }
}

//測(cè)試類
public class Relation {
    public static void main(String[] args) {
        new sunMonkey("孫悟空").diving();
        new sunMonkey("孫悟空").flight();
        new sunMonkey("孫悟空").climbTree();

        //接口多態(tài),跟普通類多態(tài)一樣具有多態(tài)參數(shù)和多態(tài)數(shù)組特性
        test1(new sunMonkey("孫大圣"));
        test2(new sunMonkey("孫大圣"));
        test3(new sunMonkey("孫大圣"));
    }

//在別的類的方法中去接收父類對(duì)象和實(shí)現(xiàn)接口方法的對(duì)象,這就是多態(tài)
    public static void test1(Monkey monkey){
        monkey.climbTree();
    }
    public static void test2(DivingClass divingClass){
        divingClass.diving();
    }
    public static void test3(FlightClass flightClass){
        flightClass.flight();
    }
}

輸出:
孫悟空會(huì)潛水
孫悟空會(huì)飛行
孫悟空會(huì)爬樹(shù)
孫大圣會(huì)爬樹(shù)
孫大圣會(huì)潛水
孫大圣會(huì)飛行

7.3、接口的多態(tài)性
# 接口的多態(tài)跟類的多態(tài)差不多,也有多態(tài)參數(shù)和多態(tài)數(shù)組的特性

1、多態(tài)參數(shù) 與 多態(tài)數(shù)組
代碼舉栗:

package P3;

import org.omg.CORBA.PUBLIC_MEMBER;

//游戲接口
interface IGame{
    public void loading();
    public void start();
    public void end();
}

//游戲類
class Game{
    private String gameName;

    public Game(){};
    public Game(String gameName){ this.gameName = gameName;}

    public String getGameName(){ return gameName;}

    //游戲運(yùn)行
    public void runGame(IGame iGame){
        //這里使用接口引用去接收實(shí)現(xiàn)該接口的類的對(duì)象,體現(xiàn)了接口的多態(tài)參數(shù)
        iGame.loading();
        iGame.start();
        iGame.end();
    }
}

//LOL
class LOL extends Game implements IGame {

    public LOL(){}

    public LOL(String gameName){ super(gameName);}

    @Override
    public void loading() {
        System.out.println(getGameName()+"正在加載....");
    }

    @Override
    public void start() {
        System.out.println(getGameName()+"加載完成,可以開(kāi)始游戲啦....");
    }

    @Override
    public void end() {
        System.out.println(getGameName()+"正在關(guān)閉游戲....");
    }

    //獨(dú)特方法
    public void lolObject(){
        System.out.println(getGameName()+"是5v5推塔游戲");
    }
}

//CF
class CF extends Game implements IGame{

    public CF(){}

    public CF(String gameName) {
        super(gameName);
    }

    @Override
    public void loading() {
        System.out.println(getGameName()+"正在加載....");
    }

    @Override
    public void start() {
        System.out.println(getGameName()+"加載完成,可以開(kāi)始游戲啦....");
    }

    @Override
    public void end() {
        System.out.println(getGameName()+"正在關(guān)閉游戲....");
    }

    //獨(dú)特方法
    public void cfObject(){
        System.out.println(getGameName()+"是多人槍?xiě)?zhàn)游戲");
    }
}

//測(cè)試類
public class Relation {
    public static void main(String[] args) {
        //接口多態(tài)參數(shù)的體現(xiàn)
        Game game = new Game("LOL");
        game.runGame(new LOL("LOL"));
        game.runGame(new CF("CF"));
        System.out.println("----------------------");

        //接口多態(tài)數(shù)組的體現(xiàn)
        IGame[] iGames = new IGame[]{new LOL("英雄聯(lián)盟"),new CF("穿越火線")};
        for (IGame i: iGames) {
            if (i instanceof LOL){
                //如果想調(diào)用子類對(duì)象的獨(dú)特方法,可以使用instanceof進(jìn)行對(duì)象類型判斷,
                ((LOL) i).lolObject();
            }else { ((CF)i).cfObject();}
        }
    }
}

輸出:
LOL正在加載....
LOL加載完成,可以開(kāi)始游戲啦....
LOL正在關(guān)閉游戲....
CF正在加載....
CF加載完成,可以開(kāi)始游戲啦....
CF正在關(guān)閉游戲....
----------------------
英雄聯(lián)盟是5v5推塔游戲
穿越火線是多人槍?xiě)?zhàn)游戲




2、接口存在多態(tài)傳遞特性

代碼舉栗:

package p4;

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

//測(cè)試類
public class Interface{
    public static void main(String[] args) {
        Son son = new Son();
        //這是實(shí)現(xiàn)了子接口Ison的子類Son對(duì)象

        ISon iSon = son;
        //這里可以把son對(duì)象賦值給子接口ISon的引用,說(shuō)明子接口引用是可以指向并接收Son類對(duì)象的

        IFather iFather = son;
        //這里可以把son對(duì)象賦值給父接口IFather的引用,說(shuō)明父接口引用是可以指向并接收Son類對(duì)象的

        Father father = son;
        //這里可以把son對(duì)象賦值給父類Father的引用,說(shuō)明父類引用是可以指向并接收Son類對(duì)象的
    }
}

//父接口
interface IFather{
    public void father();
}

//子接口
interface ISon extends IFather{
    public void son();
}

//父類
class Father {
    public void print(){
        System.out.println("這是父類的print()方法");
    }
}
//子類
class Son extends Father implements ISon{
    @Override
    public void son(){
        System.out.println("這是子接口的son()方法");
    }

    @Override
    public void father(){
        System.out.println("這是父接口的father()方法");
    }
}


小結(jié):
1、當(dāng)一個(gè)接口B繼承接口A,而子類b繼承父類a,而b實(shí)現(xiàn)接口B方法時(shí),b類對(duì)象可以傳遞給接口B的所有父接口的接口引用,這就是接口的多層傳遞



3、多態(tài)參數(shù)與多態(tài)數(shù)組在使用上的區(qū)別?

1、多態(tài)數(shù)組在程序運(yùn)行時(shí),所有繼承的子類對(duì)象或?qū)崿F(xiàn)接口抽象方法的類對(duì)象,可以以數(shù)組的方式同時(shí)傳遞多個(gè)對(duì)象給父類引用

2、而參數(shù)多態(tài)只能同時(shí)傳遞一種類對(duì)象

3、所以當(dāng)需要使用多個(gè)不同類對(duì)象時(shí),使用多態(tài)數(shù)組;反之,使用多態(tài)參數(shù)就可以了




4、小練習(xí)
//課后小練習(xí):以下程序輸出什么?如有錯(cuò)誤,請(qǐng)修改
interface A{ int a = 0;}

class B{ int a = 1;}

class C extends B implements A{
    public void method1(){
        System.out.println(a); 
        
    }

    public static void main(String[] args) {
        new C().method1();
    }
}

解:
錯(cuò)誤:調(diào)用a會(huì)有歧義。如果想調(diào)用接口的a,使用接口名A.a ; 如果想用B類的a,使用super.a

8、內(nèi)部類
8.1 、內(nèi)部類介紹
1、內(nèi)部類介紹:
#一個(gè)類中有嵌入一個(gè)完整的類結(jié)構(gòu),這個(gè)嵌套的類稱為內(nèi)部類

內(nèi)部類特點(diǎn):
1、內(nèi)部類可以直接訪問(wèn)外層類的私有屬性
2、內(nèi)部類的作用域在它的外部類中
3、本質(zhì)上其實(shí)也是外部類的一個(gè)成員,其他都一樣

內(nèi)部類定義格式:

class Outer{ //外部類

class Inner{//內(nèi)部類

public void Method1(){
class Inner01{} //方法里的內(nèi)部類
}
}
} 

調(diào)用內(nèi)部類格式:
new 外部類().new 內(nèi)部類().內(nèi)部類方法名或?qū)傩?
代碼舉栗:
//外部類
class A{
    private int a = 1;
    private void A(){
        System.out.println("這是外層類的A方法");
    }

    //內(nèi)部類
    class Inner{
        public void print(){
            System.out.println(a);
        }
    }


    public static void main(String[] args) {
        new A().new Inner().print();
    }
}
輸出:
    1
    
    
    
2、內(nèi)部類的分類:

*在外部類的方法中
1、局部?jī)?nèi)部類(有類名)
2、匿名內(nèi)部類(沒(méi)有類名,這是重點(diǎn),常用)

*類似外部類的成員類
1、成員內(nèi)部類(沒(méi)用static修飾)
2、靜態(tài)內(nèi)部類(用static修飾)

8.2、局部?jī)?nèi)部類
1、局部?jī)?nèi)部類的介紹:

訪問(wèn)權(quán)限: 可以訪問(wèn)外部類所有成員和自己的成員

位置: 定義在外部類的方法或代碼塊中

修飾符: 只能使用final常量修飾符,因?yàn)樗淖饔糜騼H限于局部方法中,局部變量不能用修飾符,但final可以

作用域: 僅在外部類的方法或代碼塊中



#使用局部?jī)?nèi)部類舉栗:

//外部類
class A{
    private int a = 1;

    public void f1(){
        
        //外部類訪問(wèn)局部?jī)?nèi)部類
    };

    //外部類
    class C1{ public void m1(){}};

    private void print(){
        class LocalInnerClass{
            public void LocalInnerMethod(){
                System.out.println("這是局部?jī)?nèi)部類的方法");

                //局部?jī)?nèi)部類-->訪問(wèn)-->外部類成員-->直接訪問(wèn)
                f1();
                System.out.println(a);
            }
        }
        //如果想在外部類調(diào)用局部?jī)?nèi)部類里的方法,這里得先這樣
        new LocalInnerClass().LocalInnerMethod();
    }
    public static void main(String[] args) {
        new A().print();
    }
}

8.3、匿名內(nèi)部類
1、匿名內(nèi)部類的介紹


方式一(使用接口名new)、

//接口
interface Interface1{
    public void print();
}


class Anonymous {
    
    public void Method() {
        /*這是匿名內(nèi)部類方式一、
        * 解讀:
        *1、編譯類型是接口Interface1,
        *2、運(yùn)行類型是:
        * new Interface1() {
            @Override
            public void print() {
                System.out.println("這是匿名內(nèi)部類");
            }
        };
        * 3、匿名內(nèi)部類是一個(gè)對(duì)象,也相當(dāng)于實(shí)現(xiàn)接口Interface1的無(wú)名子類
        * */
        Interface1 i = new Interface1() {
            @Override
            public void print() {
                System.out.println("這是匿名內(nèi)部類");
            }
        };
        i.print();
    }
    
    //測(cè)試
    public static void main(String[] args) {
        new Anonymous().Method();
    }
}



方式二(使用類名new)、

package p4;

//接口
interface Interface1{
    public void print();
}


class  FatherClass{
    public void test(){}
}


class Anonymous {

    public void Method() {
        /*這是匿名內(nèi)部類方式一、
        * 解讀:
        *1、可以理解為:相當(dāng)于接口Interface1的子類的實(shí)例對(duì)象
        *2、編譯類型是接口Interface1,
        *3、運(yùn)行類型是: class p4.Anonymous$1 表示Anonymous編號(hào)為1的內(nèi)部類
        Interface1() {
            @Override
            public void print() {
                System.out.println("這是匿名內(nèi)部類");
            }
        };
        * 3、匿名內(nèi)部類是一個(gè)對(duì)象,也相當(dāng)于實(shí)現(xiàn)接口Interface1的無(wú)名子類
        * */
        Interface1 i = new Interface1() {
            @Override
            public void print() {
                System.out.println("這是匿名內(nèi)部類方式一");
            }
        }; //4、匿名內(nèi)部類尾部記得加;
        i.print();
        System.out.println(i.getClass());
    }

    public void Method1(){
        /*匿名內(nèi)部類方式二
        * 1、可以理解為:相當(dāng)于類FatherClass的子類的實(shí)例對(duì)象
        * 2、編譯類型是FatherClass類
        * 3、運(yùn)行類型是: class p4.Anonymous$2 表示Anonymous編號(hào)為2的內(nèi)部類
        FatherClass() {
            @Override
            public void test() {
                System.out.println("這是匿名內(nèi)部類方式二");
            }
        };
        * */
        FatherClass father = new FatherClass() {
            @Override
            public void test() {
                System.out.println("這是匿名內(nèi)部類方式二");
            }
        };father.test();
        System.out.println(father.getClass());
    }

    //測(cè)試
    public static void main(String[] args) {
        new Anonymous().Method();//匿名內(nèi)部類方式一
        new Anonymous().Method1();//匿名內(nèi)部類方式二
    }
}

輸出:
這是匿名內(nèi)部類方式一
class p4.Anonymous$1
這是匿名內(nèi)部類方式二
class p4.Anonymous$2



2、匿名內(nèi)部類的調(diào)用特點(diǎn):
1、通過(guò)對(duì)象本身調(diào)用內(nèi)部類的方法
 new FatherClass() {
            @Override
            public void test() {
                System.out.println("這是匿名內(nèi)部類方式二");
            }
        }.test();
        
        
2、通過(guò)對(duì)象引用調(diào)用本身內(nèi)部的方法
 FatherClass father = new FatherClass() {
            @Override
            public void test() {
                System.out.println("這是匿名內(nèi)部類方式二");
            }
        };father.test();



3、匿名內(nèi)部類的應(yīng)用場(chǎng)景
1、當(dāng)作實(shí)參直接傳遞

代碼舉栗:

public class Anonymous01 {
    public static void main(String[] args) {
        Kitchen kitchen = new Kitchen();
        /**
         * 1、匿名內(nèi)部類只執(zhí)行一次,適合作參數(shù)進(jìn)行傳遞
         * */
        kitchen.rinseFood(new Soup(){
            public void cooking(){
                System.out.println("午餐吃陽(yáng)澄湖大閘蟹");
            }
            public void stewSoup(){
                System.out.println("加三鮮湯");
            }
        });


        kitchen.rinseFood(new Soup() {
            @Override
            public void cooking() {
                System.out.println("午餐吃糖醋排骨");
            }

            @Override
            public void stewSoup() {
                System.out.println("加排骨蘿卜湯");
            }
        });
    }
}

//烹飪接口
interface ICook{ void cooking();}

//煮湯接口
interface Soup extends ICook{ void stewSoup();}

//廚房類
class Kitchen {
    //洗菜方法
    public void rinseFood(Soup soup){
        soup.cooking();
        soup.stewSoup();
    }
}

輸出:
午餐吃陽(yáng)澄湖大閘蟹
加三鮮湯
午餐吃糖醋排骨
加排骨蘿卜湯



4、如何使用多態(tài)機(jī)制把局部?jī)?nèi)部類接到外部類使用

##### 1、使用接口接收

?```
package p5;

public class Test {

    public static void main(String[] args) {
        /**
         * 1、frock類型class p5.Frock; inner類型是class p5.Frock$1InnerH3
         * 2、frock.h2()返回對(duì)象類型是其實(shí)是實(shí)現(xiàn)接口InnerH3類的對(duì)象類型,
         * 屬于外部類Frock的成員,所以不需要向下轉(zhuǎn)型
         * */
        Frock frock = new Frock();
        Inner inner = frock.h2();
        inner.show();
        System.out.println(frock.getClass());
        System.out.println(inner.getClass());
    }
}

//1、使用接口把內(nèi)部類InnerH3接出來(lái)
interface Inner{ public void show();}

//使用子類把InnerH3接出來(lái)


//外部類Frock
class Frock {
    int a1 = 20;
    //局部?jī)?nèi)部類
    public Inner h2(){
        class InnerH3 implements Inner{
            int a1 = 10;
            public void show(){
                System.out.println("------------------");
                //內(nèi)部類成員與外部類成員重名時(shí),在內(nèi)部類調(diào)用屬性遵循就近原則
                System.out.println("局部?jī)?nèi)部類-a1:"+a1);
                //調(diào)用外部類成員名使用必須 外部類名.this.重名屬性名,this.重名屬性名都不行
                System.out.println("外部類屬性-a1:"+Frock.this.a1);
            }
        }
        InnerH3 innerH3 = new InnerH3();
        innerH3.show();
        return innerH3;
    }

}

輸出:
------------------
局部?jī)?nèi)部類-a1:10
外部類屬性-a1:20
------------------
局部?jī)?nèi)部類-a1:10
外部類屬性-a1:20
class p5.Frock
class p5.Frock$1InnerH3
?```



##### 2、使用抽象類接收

package p5;

public class Test1 {
    public static void main(String[] args) {
        /**分析:
         * 1、frock1對(duì)象類型是class p5.Frock1,
         * 而inner1類型是 class p5.Frock1$1InnerH3,所以需要向下轉(zhuǎn)型
         * 2、 frock1.h2()返回對(duì)象是抽象類的子類,轉(zhuǎn)成抽象類類型Inner1時(shí),所以需要向下轉(zhuǎn)型
         * */
        Frock1 frock1 = new Frock1();
        Inner1 inner1= (Inner1) frock1.h2();
        inner1.show();
        System.out.println(frock1.getClass());
        System.out.println(inner1.getClass());
    }
}

//1、使用接口把內(nèi)部類InnerH3接出來(lái)
//interface Inner{ public void show();}

//2、使用抽象類把InnerH3接出來(lái)
abstract class  Inner1{  //
    /**第一步,建一個(gè)抽象類和抽象方法,
     * 給h2()方法提供一個(gè)接受內(nèi)部類對(duì)象
     * */
    public void show(){}
}

//外部類Frock
class Frock1 {
    int a1 = 20;
    //局部?jī)?nèi)部類
    public Inner1 h2(){
        /**
         * 第二步,讓內(nèi)部類繼承抽象類,
         * 然后返回內(nèi)部類對(duì)象,讓抽象類接收
         * */
        class InnerH3 extends Inner1{
            int a1 = 10;
            public void show(){
                System.out.println("------------------");
                //內(nèi)部類成員與外部類成員重名時(shí),在內(nèi)部類調(diào)用屬性遵循就近原則
                System.out.println("局部?jī)?nèi)部類-a1:"+a1);
                //調(diào)用外部類成員名使用必須 外部類名.this.重名屬性名,this.重名屬性名都不行
                System.out.println("外部類屬性-a1:"+Frock1.this.a1);
            }
        }
        InnerH3 innerH3 = new InnerH3();
        innerH3.show();
        return innerH3;
    }
}

8.4、 成員內(nèi)部類
1、成員內(nèi)部類介紹:
1、顧名思義,就是定義在外部類的成員位置(除方法中外),沒(méi)有static修飾,可以直接訪問(wèn)外部類的所有成員,包括私有屬性!

2、它可以使用任何訪問(wèn)修飾符,因?yàn)樗牡匚粚儆诔蓡T而不是局部

3、如果成員內(nèi)部類的成員與外部類的成員有重名的,那么在內(nèi)部類調(diào)用內(nèi)部類成員,直接調(diào)用;在內(nèi)部類調(diào)用外部類重名成員時(shí),使用 外部類名.this.重名成員名


格式長(zhǎng)這樣:
class OtherClass{
private String str="老黃牛"
class InnerClass{
public void show(){
System.out.println("向"+str+"學(xué)習(xí)")
}
}
}



代碼舉栗(成員內(nèi)部類):

package p5;

public class Test01 {
    public static void main(String[] args) {
        //調(diào)用成員內(nèi)部類方式一、
        OtherClass otherClass = new OtherClass();
        otherClass.new InnerClass().show();

        //方式二、
        otherClass.Method().show();
    }
}
class OtherClass{
    private String str="老黃牛";

    private void PMethod(){
        System.out.println("我是私有方法");
    }

    //成員內(nèi)部類
    class InnerClass{
        public InnerClass show(){
            //1、成員內(nèi)部類訪問(wèn)外部類,直接訪問(wèn)
            System.out.println("向"+str+"學(xué)習(xí)");
            PMethod();
            return null;
        }
    }

    public InnerClass Method(){
        //2、外部類訪問(wèn)成員內(nèi)部類的成員,先創(chuàng)建內(nèi)部類對(duì)象.成員
        return new InnerClass();
    }
}




2、如果內(nèi)部成員類被私有化了,外部其他類還是想訪問(wèn)該私有成員類中的方法呢,怎么辦呢?還是用接口接出來(lái)

代碼舉栗:

方式一、接口

package p5;

import javax.jws.Oneway;

public class Test01 {
    public static void main(String[] args) {
        //方式一、接口
        OtherClass otherClass = new OtherClass();
        I i = otherClass.PMethod();
        i.show();
    }
}

//方式一、接口
interface I{ public void show();}

//方式二、抽象類
//abstract class ABS{ public void show(){}}

class OtherClass{
    private String str="老黃牛";


    public InnerClass PMethod(){
        return new InnerClass();
    }

    //成員內(nèi)部類
    private class InnerClass implements I{
        public void show(){
            //1、成員內(nèi)部類訪問(wèn)外部類,直接訪問(wèn)
            System.out.println("向"+str+"學(xué)習(xí)");
            PMethod();
        }
    }
}
輸出:
向老黃牛學(xué)習(xí)

-------------------------------------------------------------------------------

方式二、抽象類

package p5;

public class Test02 {
    public static void main(String[] args) {
        //方式二、抽象類
        OtherClass01 otherClass01 = new OtherClass01();
        ABS abs = (ABS)otherClass01.PMethod();
        abs.show();
    }
}

//方式二、抽象類
abstract class ABS{ public void show(){}}


//外部類
class OtherClass01{
    private String str="老黃牛";

    public InnerClass PMethod(){
        return new InnerClass();
    }

    //成員內(nèi)部類
    private class InnerClass extends ABS{
        public void show(){
            //1、成員內(nèi)部類訪問(wèn)外部類,直接訪問(wèn)
            System.out.println("向"+str+"學(xué)習(xí)");
            PMethod();
        }
    }
}
輸出:
向老黃牛學(xué)習(xí)




3、如果成員內(nèi)部類的成員與外部類的成員有重名的,那么調(diào)用在內(nèi)部類調(diào)用外部類成員,直接調(diào)用; 在外部類調(diào)用內(nèi)部類成員時(shí),使用 外部類名.this.內(nèi)部類成員名

8.5、 靜態(tài)內(nèi)部類
1、靜態(tài)內(nèi)部類的介紹

1、靜態(tài)內(nèi)部類 = 使用static修飾內(nèi)部類

2、跟成員內(nèi)部類其他的相同,唯一區(qū)別就是:靜態(tài)內(nèi)部類只能訪問(wèn)外部類的靜態(tài)成員



2、靜態(tài)內(nèi)部類的使用方式:

package p5;

public class Test03 {
    public static void main(String[] args) {
        //方式二、
        new OtherClass02().Method01();
        
        //方式一
        OtherClass02.Method01();
    }
}

//外部類
class OtherClass02{
    private static int a1 = 1;
    private int a2 = 2;
    static class InnerClass02{
        public void Method(){
            System.out.println("外部類屬性a1:"+a1);
        }
    }
    //在外部其他類,使用靜態(tài)內(nèi)部類的Method()方法
    //方式一、使用靜態(tài)方法直接調(diào)用靜態(tài)方法
    public static void Method01(){
        new InnerClass02().Method();
    }

    //方式二、使用該方法返回一個(gè)靜態(tài)內(nèi)部類對(duì)象
    public InnerClass02 Method02(){
        return new InnerClass02();
    }
}



3、當(dāng)靜態(tài)內(nèi)部類成員與外部類成員出現(xiàn)重名時(shí),在內(nèi)部類調(diào)用內(nèi)部類重名的成員時(shí),直接調(diào)用; 在靜態(tài)內(nèi)部調(diào)用外部類靜態(tài)重名成員,使用外部類名.重名成員名

#這里就不寫(xiě)代碼舉栗了

9、枚舉
9.1、枚舉的介紹
1、枚舉的介紹:
1、枚舉是一種特殊的類,用于表示一組常量,比如性別只有男和女,一天只有24小時(shí)等常識(shí)常量

2、使用關(guān)鍵字euum來(lái)定義,常量名使用大寫(xiě),各常量之間使用,分割。 如eunum Sex{ MAN,WOWAN; }





2、枚舉的實(shí)現(xiàn)方式:


1) 方式一、自定義枚舉

public class Custom {
    public static void main(String[] args) {
        //類似調(diào)用靜態(tài)屬性調(diào)用,類名.屬性名
        System.out.println(Season.spring);
        System.out.println(Season.summer);
        System.out.println(Season.autumn);
        System.out.println(Season.winter);
    }
}

//自定義枚舉: 季節(jié)類
class Season{
    private String name;
    private String description;

    //把構(gòu)造器私有化,不給外部new新的對(duì)象
    private Season(String name, String description) {
        this.name = name;
        this.description = description;
    }

    //外部只能讀取不能修改
    public String getName() {
        return name;
    }
    public String getDescription() {
        return description;
    }

    //使用static + final是為了優(yōu)化底層(不會(huì)觸發(fā)類加載,但是這里new對(duì)象還是會(huì)類加載)
    public static final Season spring = new Season("春季","溫暖");
    public static final Season summer = new Season("夏季","炎熱");
    public static final Season autumn = new Season("秋季","肅殺");
    public static final Season winter = new Season("冬季","寒冷");

    @Override
    public String toString() {
        return "季節(jié):" + name + "  特點(diǎn):"+ description;
    }
}


自定義枚舉注意點(diǎn):
1、構(gòu)造器私有化
2、本類內(nèi)部使用 static+final 創(chuàng)建一組對(duì)象,對(duì)外暴露對(duì)象
3、只提供get方法,不提供set方法





2)方式二、使用enum關(guān)鍵字

package p5;

public class Custom {
    public static void main(String[] args) {
        //類似調(diào)用靜態(tài)屬性調(diào)用,類名.屬性名
        System.out.println(Season1.SPRING);
        System.out.println(Season1.SUMMER);
        System.out.println(Season1.AUTUMN);
        System.out.println(Season1.WINTER);
    }
}

//使用enum關(guān)鍵字實(shí)現(xiàn)枚舉
enum Season1 {
//這個(gè)必須寫(xiě)到這個(gè)enum類的首行
//使用enum關(guān)鍵字,默認(rèn)會(huì)讓Season1繼承Enumeration這個(gè)類

    SPRING("春季", "溫暖"),
    SUMMER("夏季", "炎熱"),
    AUTUMN("秋季", "肅殺"),
    WINTER("冬季", "寒冷");

    private String name;
    private String description;

    private Season1(String name, String description) {
        this.name = name;
        this.description = description;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    @Override
    public String toString() {
        return "季節(jié):" + name + "  特點(diǎn):"+ description;
    }
}


小結(jié)(用enum關(guān)鍵字實(shí)現(xiàn)枚舉注意細(xì)節(jié))
1、枚舉常量必須放在枚舉類首行
2、當(dāng)有多個(gè)枚舉對(duì)象時(shí),使用,隔開(kāi),用;結(jié)束
3、public static final Season1  枚舉對(duì)象 = new Seson1("春天","溫暖"); 等同于 SPRING("春天","溫暖"),


9.2、枚舉的常用方法
1、toString: Enum類已重寫(xiě)過(guò),返回的是當(dāng)前對(duì)象名(大寫(xiě)),子類可重寫(xiě)該方法,用于返回自定義的對(duì)象屬性信息
2、name: 返回當(dāng)前對(duì)象名(常量名),子欸不能重寫(xiě) 
3、ordinal: 返回當(dāng)前對(duì)象的位置編號(hào),默認(rèn)從0開(kāi)始
4、values: 返回當(dāng)前枚舉類的所有常量
5、valueOf; 將字符串轉(zhuǎn)成枚舉對(duì)象,要求字符串必須為已存在的常量名,否則報(bào)異常
6、compareTo: 比較兩個(gè)枚舉常量的位置編號(hào),



代碼舉栗:

package p5;

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;

public class Custom {
    public static void main(String[] args) {
        Season1 autumn = Season1.AUTUMN;
        System.out.println(autumn);//這里已重寫(xiě)過(guò)
        System.out.println(autumn.name());//返回大寫(xiě)的autumn對(duì)象名:AUTUMN
        System.out.println(autumn.ordinal());//返回該對(duì)象的編號(hào)(理解下標(biāo)也行),用于
        System.out.println(Season1.values());//返回該枚舉中所有對(duì)象,是一個(gè)數(shù)組類型,可迭代
        Season1[] season1s = (Season1.values());
        for (Season1 s:season1s){
            System.out.println(s);
        }
        System.out.println(Season1.valueOf("SPRING"));//判斷該枚舉中是否有SPRING對(duì)象,有返回該對(duì)象信息,沒(méi)有報(bào)異常
    }
}

//使用enum關(guān)鍵字實(shí)現(xiàn)枚舉
enum Season1 {
    //這個(gè)必須寫(xiě)到這個(gè)enum類的首行
    //使用enum關(guān)鍵字,默認(rèn)會(huì)讓Season1繼承Enumeration這個(gè)類
    SPRING("春季", "溫暖"),
    SUMMER("夏季", "炎熱"),
    AUTUMN("秋季", "肅殺"),
    WINTER("冬季", "寒冷");

    private String name;
    private String description;

    private Season1(String name, String description) {
        this.name = name;
        this.description = description;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    @Override
    public String toString() {
        return "季節(jié):" + name + "  特點(diǎn):"+ description;
    }
}

輸出:
季節(jié):秋季  特點(diǎn):肅殺
AUTUMN
2
[Lp5.Season1;@14ae5a5
季節(jié):春季  特點(diǎn):溫暖
季節(jié):夏季  特點(diǎn):炎熱
季節(jié):秋季  特點(diǎn):肅殺
季節(jié):冬季  特點(diǎn):寒冷
季節(jié):春季  特點(diǎn):溫暖

10、注解
1、注解的介紹:

1、注解也稱為元數(shù)據(jù),用于修飾解釋包、類、方法、屬性、構(gòu)造器、局部變量等信息

2、和注釋一相似之處在于它不影響代碼邏輯,不同之處注解可以被編譯貨或運(yùn)行,相當(dāng)于嵌入代碼中的補(bǔ)充信息
3、使用注解主要是為了標(biāo)記過(guò)時(shí)功能、忽略警告信息等

10.1、Override

1、用于限定某個(gè)方法,常用于重寫(xiě)父類方法,該注解只能用于方法中

10.2、Deprecated

1、用于表示某個(gè)程序中的類、方法已過(guò)時(shí)

10.3、supresswarning

1、用于屏蔽編譯器的警告信息

11、包裝類與基本數(shù)據(jù)類型
11.1、包裝類的介紹
1、在java中,有常見(jiàn)的8種基本數(shù)據(jù)類型,分別為byte、boolean、char、short、int、long、float、double,在工作中需要頻繁使用它們進(jìn)行各種操作。java設(shè)計(jì)者就為每個(gè)基本類型封裝了一個(gè)類并提供常見(jiàn)的方法,大大提高了工作效率,而這些類就是包裝類

2、基本類型 ---> 包裝類

基本數(shù)據(jù)類型 包裝類
boolean Boolean
char Character
byte Byte
short Short
int Integer
long Long
float Float
double Double
2、裝箱與拆箱
裝箱: 基本類型  ————> 包裝類型
拆箱:包裝類型  ————> 基本類型




3、裝箱拆箱舉栗:

package p5;

public class Packaging {
    public static void main(String[] args) {
        int i = 10;
        //手動(dòng)裝箱(jdk1.5前)
        Integer integer = new Integer(i);
        Integer integer1 = Integer.valueOf(i);//手動(dòng)裝箱調(diào)用的其實(shí)是valueOf()方法
        System.out.println(integer1.getClass());
        System.out.println(integer.getClass()==integer1.getClass());

        //手動(dòng)拆箱
        int i1 = integer.intValue();//拆箱調(diào)用的是intValue()方法
        System.out.println(i1);

        //自動(dòng)裝箱
        short s = 10;
        Short s1 = s;//底層調(diào)用的還是Short.ValueOf(s)
        System.out.println(s1.getClass());

        //自動(dòng)拆箱
        short s2 = s1; //底層調(diào)用的還是shortValue()進(jìn)行拆箱
        System.out.println(s2);
    }
}
輸出:
class java.lang.Integer
true
10
class java.lang.Short
10

11.2、小練習(xí)( 包裝類)
1、以下輸出結(jié)果是?
public static void main(String[] args) {
        Integer i = new Integer(1);
        Integer i1 = new Integer(1);
        System.out.println(i==i1);
        //false,new開(kāi)辟了新的空間,所以不是同一個(gè)對(duì)象,故false
        System.out.println(i.equals(i1));
        //true,底成先判斷兩對(duì)象是否為同一類型對(duì)象,在判斷兩對(duì)象的值是否相等,相等返回true,否則false

        Integer m = 1;
        Integer n = 1;
        System.out.println(n==m);
        //true,底層會(huì)先判斷該基本類型的值是否在-128~127之間,是就指向同一對(duì)象,否則new一個(gè)新對(duì)象
System.out.println(n.equals(m));
//true,底成先判斷兩對(duì)象是否為同一類型對(duì)象,在判斷兩對(duì)象的值是否相等,相等返回true,否則false

        Integer x = 128;
        Integer y = 128;
        System.out.println(x==y);
        //false,超過(guò)常量池范圍-128~127之間,new新對(duì)象,不是同一對(duì)象,故false
System.out.println(x.equals(y));
//true,底成先判斷兩對(duì)象是否為同一類型對(duì)象,在判斷兩對(duì)象的值是否相等,相等返回true,否則false
   
   }
    
    
    
2、下面輸出的值是?
public static void main(String[] args){
Integer i = 127;
int i2 = 127;
System.out.println(i==i2);//true,只要比較時(shí)出現(xiàn)一個(gè)基本數(shù)據(jù)類型,比較的就是值大小

Integer i3 = 128;
int i4 = 128;
System.out.println(i3==i4);//true,只要比較時(shí)出現(xiàn)一個(gè)基本數(shù)據(jù)類型,比較的就是值大小
}


小結(jié)(包裝類)
1、當(dāng)基本數(shù)據(jù)類型與包裝類==比較時(shí),比較的是兩對(duì)象的值
2、只要是new的對(duì)象,就不可以是同一對(duì)象
3、當(dāng)兩個(gè)包裝類對(duì)象進(jìn)行==比較時(shí),如果對(duì)象值在-128~127之間,那就指向同一常量池對(duì)象

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多