Java基礎 - 6 - 面向對象(二)

Java基礎 - 6 - 面向對象(一)-CSDN博客


二. 面向對象高級

2.1 static

????????static叫做靜態,可以修飾成員變量、成員方法

2.1.1 static修飾成員變量

????????成員變量按照有無static修飾,分為兩種:類變量、實例變量(對象的變量)

????????類變量(靜態成員變量):有static修飾,屬于類,與類一起加載一次,在計算機內存里只有一份,會被類的全部對象共享? ? ? ? 類名.類變量

????????實例變量(對象的變量):無static修飾,屬于每個對象的,每個對象都有一份? ? ? ??對象.實例變量

//demo
public class demo {public static void main(String[] args) {//類變量 通過類名.類變量的方式訪問(推薦)Student.name = "張三";//對象.類變量(不推薦)Student s1 = new Student();s1.name= "李四";Student s2 = new Student();s2.name= "王五";//因為類變量在計算機中只有一份,被共享System.out.println(Student.name);  //王五System.out.println(s1.name);  //王五System.out.println(s2.name);  //王五//實例變量s1.age = 20;s2.age = 22;System.out.println(s1.age);  //20System.out.println(s2.age);  //22}
}//Student
public class Student {//類變量static String name;//實例變量int age;
}

類變量的應用場景

????????在開發中,如果某個數據只需要一份,且希望能夠被共享(訪問、修改),則該數據可以定義為類變量來記住

//demo
public class demo {public static void main(String[] args) {User u1 = new User();User u2 = new User();User u3 = new User();User u4 = new User();System.out.println(User.number);  //4}
}//User
public class User {//類變量(通常用public修飾)public static int number;public User(){//注意:在同一個類中,訪問自己的類變量,才可以直接不寫類名User.number++;  //在這里可以直接寫成 number++;}
}

2.1.2?static修飾成員方法

????????成員方法的分類按照有無static修飾,可以分為類方法和實例方法

????????????????類方法:有static修飾的成員方法,屬于類

????????????????實例方法:無static修飾的成員方法,屬于對象

//demo
public class demo {public static void main(String[] args) {//類方法的使用//類名.類方法(推薦)Student.printHelloWorld();//對象.類方法(不推薦)Student s1 = new Student();s1.printHelloWorld();//實例方法的使用s1.score=70;s1.printPass();//不能直接用類名.實例方法(會報錯)}
}//Student
public class Student {double score;//類方法(有static,通常用public修飾)public static void printHelloWorld(){System.out.println("Hello World");System.out.println("Hello World");}//實例方法(對象的方法)public void printPass(){System.out.println("成績"+((score>=60)?"及格":"不及格"));}
}

?補充:main方法——是一個類方法

類方法的應用場景

????????類方法最常見的應用場景是做工具類

????????工具類是什么?

? ? ? ????????? 工具類中的方法都是一些類方法,每個方法都是用來完成一個功能的,工具類是給開發人員共同使用的

????????使用類方法來設計工具類有啥好處?

????????????????提高代碼的復用;調用方便,提高開發效率

????????為什么工具類中的方法要用類方法,而不用實例方法?

?? ? ? ? ·?實例方法需要創建對象來調用,此時對象只是為了調用方法,對象占內存,這樣會浪費內存

? ? ? ? ?· 類方法,直接用類名調用即可,調用方便,也節省內存

????????注意:

????????????????工具類沒有創建對象的需求,建議將工具類的構造器進行私有

//muUtil  是一個工具類
public class muUtil {//將工具類的構造器進行私有private muUtil(){}public static String createCode(int n){String str = "";Random r = new Random();for (int i = 0; i < n; i++) {//怎么隨機生成一個隨機字符、可能是數字、大寫字母、小寫字母?//思路:隨機一個0-1-2,0表示數字、1表示大寫字母、2表示小寫字母int type = r.nextInt(3);//可以產生0-1-2的隨機數if(type == 0){//0表示隨機一個數字str += r.nextInt(10);//0-9}else if(type == 1){//1表示隨機大寫字母 A 65 Z 65+25=90str += (char)(r.nextInt(26)+65);}else{//2表示隨機小寫字母 a 97 z 97+25=122str += (char)(r.nextInt(26)+97);}}return str;}
}//登錄界面  4位驗證碼  LoginDemo
public class LoginDemo {public static void main(String[] args) {int n = 4;System.out.println("登錄驗證碼:" + muUtil.createCode(n));}
}//注冊界面  6位驗證碼  RegisterDemo
public class RegisterDemo {public static void main(String[] args) {int n = 6;System.out.println("注冊驗證碼:" + muUtil.createCode(n));}
}

使用類方法和實例方法的注意事項

????????· 類方法中可以直接訪問類成員,不可以直接訪問實例成員

????????· 實例方法中既可以直接訪問類成員,也可以直接訪問實例成員

????????· 實例方法中可以出現this關鍵字,類方法中不可以出現this關鍵字

//Student
public class Student {//類變量static String school;//實例變量double score;//類方法public static void printHello() {}//實例方法public void printIsPass() {}1.類方法可以直接訪問類的成員,不可以直接訪問實例成員//類方法Test1public static void Test1() {//類方法可以直接訪問類的成員//同一個類中,訪問類成員,可以省略類名Student.school = "清華";  //school = "清華"Student.printHello();  //printHello2();//類方法不可以直接訪問實例成員(因為實例成員屬于對象)//System.out.println(score);  報錯//printIsPass();   報錯//類方法中不可以出現this關鍵字//System.out.println(this);   報錯}2.實例方法中既可以直接訪問類成員,也可以直接訪問實例成員3.實例方法中可以出現this關鍵字,類方法中不可以出現this關鍵字//實例方法Test2public void Test2(){//實例方法中既可以直接訪問類成員school = "北大";printHello();//實例方法也可以直接訪問實例成員System.out.println(score);printIsPass();//實例方法中可以出現this關鍵字System.out.println(this);}
}

2.1.3 代碼塊*

????????代碼塊是類的五大成分之一(成員變量、構造器、方法、代碼塊、內部類)

????????代碼塊按照有無static劃分為兩類:靜態代碼塊、實例代碼塊

靜態代碼塊

????????格式:static {}

????????特點類加載時自動執行,由于類只會加載一次,所以靜態代碼塊也只會執行一次

????????作用:完成類的初始化,例如:對類變量的初始化賦值

實例代碼塊

????????格式:{}

????????特點每次創建對象時,執行實例代碼塊,并在構造器前執行

????????作用:和構造器一樣,都是用來完成對象的初始化,例如:對實例變量的初始化賦

//Student
public class Student {static int number = 80;static String school;int age;//靜態代碼塊static {System.out.println("靜態代碼塊執行~~~");school = "清華";}//實例代碼塊{System.out.println("實例代碼塊執行~~~");//age = 18; //實例變量初始化賦值意義不大(不可能所有人年齡一致)}public Student(){System.out.println("無參數構造器執行~~~");}public Student(String name){System.out.println("有參數構造器執行~~~");}
}//demo
public class demo {public static void main(String[] args) {System.out.println(Student.number);System.out.println(Student.number);System.out.println(Student.number);System.out.println(Student.school); //清華System.out.println("--------------------");//輸出結果//實例代碼塊執行~~~//無參數構造器執行~~~Student s1 = new Student();System.out.println("--------------------");//輸出結果//實例代碼塊執行~~~//有參數構造器執行~~~Student s2 = new Student("張三");System.out.println(s1.age);  //18System.out.println(s2.age);  //18}
}

2.1.4 單例設計模式

設計模式:一個問題有很多解法,其中一種是最優的,這個最優解法被人總結后稱之為設計模式

設計模式有20多種,對應20多種軟件開發中會遇到的問題

設計模式學習思路:這個設計模式解決什么問題?這個設計模式怎么寫?

單例設計模式

? ? ? ? 確保一個類只有一個對象

單例設計模式的應用場景

????????任務管理器、runtime(獲取運行時對象)……

單例設計模式的好處

????????可以避免浪費內存

餓漢式單例設計模式(拿對象時,對象早就創建好了)的寫法

? ? ? ?· 把類的構造器私有

? ? ? ?·?定義一個類變量記住類的一個對象

? ? ? ?· 定義一個類方法,放回對象

懶漢式單例設計模式(拿對象時,才開始創建對象)的寫法

? ? ? ?· 把類的構造器私有

? ? ? ?·?定義一個類變量用于存儲對象

? ? ? ?· 提供一個類方法,保證返回的是用一個對象

//A
//餓漢式單例  頻繁使用建議選擇餓漢式
public class A {//2.定義一個類變量記住類的對象private static A a = new A();//1.私有類的構造器private A(){}//3.定義一個類方法返回類的對象apublic static A getObject(){return a;}
}//B
//懶漢式單例
public class B {//2.定義一個類變量,用于存儲這個類的一個對象private static B b;//1.私有類的構造器private B(){}//3.定義一個類方法,這個方法要保證第一次調用時才創建一個對象,后面調用時都會用著同一個對象返回public static B getInstance(){if(b == null){b = new B();}return b;}
}//demo
public class demo {public static void main(String[] args) {A a1 = A.getObject();A a2 = A.getObject();System.out.println(a1);  //輸出兩個地址相同System.out.println(a2);  //輸出兩個地址相同B b1 = B.getInstance();  //第一次創建對象B b2 = B.getInstance();System.out.println(b1);  //輸出兩個地址相同System.out.println(b2);  //輸出兩個地址相同}
}

2.2 繼承?

????????Java中提供一個關鍵字extends,用這個關鍵字可以讓一個類和另一個類建立起父子關系

// A稱為父類(基類或超類)? ?B稱為子類(派生類)

public class B extends A{

}

?繼承的特點

????????· 子類能夠繼承父類的非私有成員(成員變量、成員方法)

????????· 繼承后對象的創建:子類的對象是由子類、父類共同完成的

//A 父類
public class A {//公開成員public int i;public void print1(){System.out.println("print1111111");}//私有成員private int j;private void print2(){System.out.println("print2222222");}
}//B 子類
public class B extends A{private int x;public int y;//子類是可以繼承父類的非私有成員public void print3(){System.out.println(i);print1();//System.out.println(j);    報錯//print2();    報錯}
}//demo
public class demo {public static void main(String[] args) {B b = new B();System.out.println(b.i);System.out.println(b.y);//System.out.println(b.x);  報錯//System.out.println(b.j);  報錯b.print1();b.print3();//b.print2();  報錯}
}

?繼承的好處

? ? ? ? 減少重復代碼的編寫

//People
public class People {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}//Teacher
public class Teacher extends People{private String skill;public String getSkill() {return skill;}public void setSkill(String skill) {this.skill = skill;}public void printInfo(){System.out.println(getName());System.out.println(getSkill());}
}//demo
public class demo {public static void main(String[] args) {Teacher t = new Teacher();t.setName("張三");t.setSkill("Java python");System.out.println(t.getName());System.out.println(t.getSkill());System.out.println("====================");t.printInfo();}
}

?2.2.1 權限修飾符

????????權限修飾符是用來限制類中的成員(成員變量、成員方法、構造器、代碼塊……)能夠被訪問的范圍

修飾符在本類中同一個包下的其他類里任意包下的子類里任意包下的任意類里
private
缺省
protected√(要求繼承,要子類才可以訪問,子類對象不可以)
public

2.2.2 單繼承

????????Java是單繼承的,Java中的類不支持多繼承,但是支持多層繼承

?2.2.3 Object類

????????object類是java所有類的祖宗類,我們寫的任何一個類,其實都是object的子類或子孫類

2.2.4 方法重寫

????????當子類覺得父類的某個方法不好用,或者無法滿足自己的需求時,子類可以重寫一個方法名稱、參數列表一樣的方法,去覆蓋父類的這個方法,這就是方法重寫

注意:

1.重寫后,方法的訪問,Java會遵循就近原則

2.重寫小技巧:使用Override注解,它可以指定Java編譯器,檢查我們方法重寫的格式是否正確,代碼可讀性會更好

3.子類重寫父類方法時,訪問權限必須大于或等于父類該方法的權限(public>protected>缺省)

4.重寫的方法返回值類型,必須與重寫方法的返回值類型一樣或范圍更小

5.私有方法(private)、靜態方法(static)不能被重寫,如果重寫會報錯的

//A
public abstract class A {protected void print1(){System.out.println("111");}public void print2(int a, int b){System.out.println("1111111");}
}//B
public class B extends A{//方法重寫@Override //可讀性好 檢查格式是否正確public void print1(){   //子類重寫父類方法時,訪問權限必須大于或等于父類該方法的權限System.out.println("666");}@Override//方法重寫public void print2(int a,int b){System.out.println("6666666");}
}//demo
public class demo {public static void main(String[] args) {B b = new B();b.print1();b.print2(1,2);}
}

方法重寫在開發中的常見應用場景

????????子類重寫Object類的toString()方法,以便返回對象的內容

//Student
public class Student {private String name;private int age;//    @Override
//    public String toString(){
//        String str = getName()+"今年"+getAge()+"歲";
//        return str;
//    }//快捷方式:右鍵 -> 生成 -> toString()@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}//demo
public class demo {public static void main(String[] args) {Student s1 = new Student("張三",18);System.out.println(s1.toString()); //輸出地址System.out.println(s1); //不加.toString()默認.toString()  輸出地址}
}

2.2.5?子類訪問成員的特點

????????在子類方法中訪問其他成員(成員變量、成員方法),是依照就近原則的(先找子類的局部范圍,再找子類的成員范圍,最后找父類的成員范圍,沒找到則報錯)

? ? ? ? 如果子父類中出現了重名的成員,優先子類的,此時一定要使用父類的使用super關鍵字,指定訪問父類的成員:super.父類成員變量/父類成員方法

2.2.6 子類構造器的特點

????????子類的全部構造器,都會先調用父類的構造器,再執行自己

子類構造器是如何實現調用父類構造器的?

????????· 默認情況下,子類全部構造器的第一行代碼都是super()(寫不寫都有),它會調用父類的無參數構造器

????????· 如果父類沒有無參數構造器?,則必須在子類構造器的第一行手寫super(…),指定去調用父類的有參數構造器

//父類中存在無參數構造器,都不寫也是默認存在
class F{public F(){System.out.println("==父類的無參數構造器執行了==");}
}class Z extends F{public Z(){//super(); //寫不寫都默認存在System.out.println("==子類的無參數構造器執行了==");}public Z(int a){//super(); //寫不寫都默認存在System.out.println("==子類的有參數構造器執行了==");}
}public class demo {public static void main(String[] args) {Z z = new Z();  //先輸出==父類的無參數構造器執行了==  再輸出==子類的無參數構造器執行了==Z z2 = new Z(1);  //先輸出==父類的無參數構造器執行了==  再輸出==子類的有參數構造器執行了==}
}//父類中存在有參數構造器,不存在無參數構造器,子類一定要寫super()才能不報錯
class F{public F(int m){System.out.println("==父類的有參數構造器執行了==");}
}class Z extends F{public Z(){super(1);System.out.println("==子類的無參數構造器執行了==");}public Z(int a){super(1);System.out.println("==子類的有參數構造器執行了==");}
}public class demo {public static void main(String[] args) {Z z = new Z();  //先輸出==父類的有參數構造器執行了==  再輸出==子類的無參數構造器執行了==Z z2 = new Z(1);  //先輸出==父類的有參數構造器執行了==  再輸出==子類的有參數構造器執行了==}
}

子類構造器的應用場景

super(…)調用父類有參數構造器的常見應用場景是為對象中包含父類這部分的成員變量進行賦值

class Teacher extends People{private String skills;public Teacher(String name, int age, String skills) {super(name, age);  //!!!!!!子類構造器調用父類構造器this.skills = skills;}public String getSkills() {return skills;}public void setSkills(String skills) {this.skills = skills;}
}class People{private String name;private int age;public People() {}public People(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}public class demo {public static void main(String[] args) {Teacher t = new Teacher("張三",33,"Java");System.out.println(t.getName());System.out.println(t.getAge());System.out.println(t.getSkills());}
}

2.2.7 this(…)調用兄弟構造器

? ? ? ? ?任意類的構造器中,是可以通過this(…)去調用該類的其他構造器的

????????不能在一個構造器中同時寫this()和super()

class Student{private String name;private int age;private String School;public Student() {}public Student(String name, int age){//this.name = name;//this.age = age;//this.School = "無";//this(…)調用兄弟構造器,可以簡化代碼this(name,age,"無");  //不能在一個構造器中同時寫this()和super()}public Student(String name, int age, String school) {this.name = name;this.age = age;this.School = school;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSchool() {return School;}public void setSchool(String school) {this.School = school;}
}public class demo {public static void main(String[] args) {Student s1 = new Student("張三",18,"清華");//如果學生沒寫學校,默認無Student s2 = new Student("李四",18);System.out.println(s2.getName());System.out.println(s2.getAge());System.out.println(s2.getSchool());}
}

2.3 多態

????????多態是在繼承/實現情況下的一種現象,表現為:對象多態、行為多態

//People 父類
public class People {public String name = "父類名稱";public void run(){System.out.println("人在跑步");}
}//Student
public class Student extends People{public String name = "學生名稱";@Overridepublic void run() {System.out.println("學生在跑步");}
}//Teacher
public class Teacher extends People{public String name = "老師名稱";@Overridepublic void run() {System.out.println("老師在跑步");}
}//demo
public class demo {public static void main(String[] args) {//對象多態People p1 = new Student();People p2 = new Teacher();//行為多態p1.run();  //識別技巧:編譯看左邊父類(看父類有沒有該方法,沒有則報錯),運行看右邊子類p2.run();System.out.println(p1.name);    //父類名稱   原因是變量沒有多態性System.out.println(p2.name);    //父類名稱}
}

多態的前提

????????有繼承/實現關系;存在父類引用子類對象;存在方法重寫?

多態的注意事項

????????多態是對象、行為的多態,Java中的屬性(成員變量)不談多態

使用多態的好處

? ? ? ? · 在多態形式下,右邊對象是解耦合的,更便于拓展和維護

? ? ? ? · 定義方法時,使用父類類型的形參,可以接收一切子類對象,擴展性更強、更便利

使用多態的弊端

? ? ? ? 多態下不能直接調用子類的獨有功能

多態下的類型轉換問

????????自動類型轉換:父類 變量名 = new? 子類();

????????強制類型轉換:子類 變量名 = (子類)父類變量

強制類型轉換的注意事項:

????????· 存在繼承/實現關系就可以在編譯階段進行強制類型轉換,編譯階段不會報錯

????????· 運行時,如果發現對象的真實類型與強制后的類型不同,就會報類型轉換異常(ClassCastException)

???????· ?強制轉換前,Java建議:使用instanceof關鍵字,判斷當前對象的真實類型,在進行強轉

//People 父類
public class People {public void run(){System.out.println("人在跑步");}
}//Student
public class Student extends People{@Overridepublic void run() {System.out.println("學生在跑步");}public void learn(){System.out.println("學生要學習");}
}//Teacher
public class Teacher extends People{@Overridepublic void run() {System.out.println("老師在跑步");}public void teach(){System.out.println("老師要教書");}
}//demo
public class demo {public static void main(String[] args) {//好處1:可以實現解耦,右邊對象可以隨意切換Student()People p1 = new Student();p1.run();//強制類型轉換Student s = (Student)p1;s.learn();//強制類型轉換可能存在的問題,編譯階段有繼承或實現關系就可以強制轉換,但在運行時可能出現類型轉換異常//Teacher t = (Teacher)p1;//t.teach();  //ClassCastException(類型轉換異常),因為Teacher類型不能指向Student()if(p1 instanceof Student){Student s2 = (Student)p1;s2.learn();}else{Teacher t2 = (Teacher)p1;t2.teach();}}
}

2.4 final

????????final關鍵字是最終的意思,可以修飾(類、方法、變量)

? ? ? ? ????????修飾類:該類被稱為最終類,特點是不能被繼承

? ? ? ? ????????修飾方法:該方法被稱為最終方法,特點是不能被重寫

? ? ? ? ????????修飾變量:該變量只能被賦值一次

final修飾變量的注意事項

??????? · final修飾基本類型的變量,變量存儲的數據不能被改變

????????· final修飾引用類型的變量,變量存儲的地址不能被改變,但地址所指向對象的內容是可以被改變的

public class demo {
//常量:用static final修飾的類變量是常量。常量建議名稱全部大寫,多個單詞下劃線連接//用final修飾成員變量-類變量,要直接賦值,否則報錯;二次賦值也報錯public static final String SCHOOL_NAME = "清華";//public static final String SCHOOL_NAME;  報錯(沒有直接賦值)//用final修飾成員變量-實例變量,要直接賦值,否則報錯;二次賦值也報錯//private final String name = "張三";  //用final修飾實例變量無意義,導致實例變量的值無法修改//private final String name;  報錯(沒有直接賦值)public static void main(String[] args) {//final修飾變量,有且只能賦值一次//變量(變量包括局部變量和成員變量(成員變量包括類變量和實例變量))//final修飾局部變量用途1final int a;a = 1;//a = 2;  //final修飾的變量不能二次賦值final double pai = 3.14;final int[] arr = {1,2,3,4};//arr = null; //報錯,變量arr不能二次賦值(變量arr存放的是數組{1,2,3,4}的地址)arr[0] = 5;  //final修飾引用類型的變量,變量存儲的地址不能被改變,但地址所指向對象的內容是可以被改變的//用final修飾成員變量-類變量,二次賦值報錯//SCHOOL_NAME = "北大";  //二次賦值 報錯//用final修飾成員變量-實例變量,二次賦值報錯//demo d = new demo();//d.name = "李四";   //二次賦值 報錯}//final修飾局部變量用途2public static void buy(final double z){//z = 1; //形參加了final,z不能被二次賦值(第一次賦值是傳參的時候)}
}final class A{}  //被final修飾后,類不能被繼承
//class B extends A{}class C{public final void test(){  //被final修飾后,方法不能被重寫System.out.println("C test");}
}class D extends C{
//    @Override
//    public void test(){
//        System.out.println("D test");
//    }
}

2.4.1 常量

????????使用了static final修飾的成員變量就被稱為常量

????????作用:通常用于記錄系統的配置信息

? ? ? ? 命名規范:建議使用大寫英文單詞,多個單詞使用下劃線鏈接起來

使用常量記錄系統配置信息的優勢、執行原理:

? ? ? ? · 代碼可讀性更好,可維護性也更好

????????· 程序編譯后,常量會被“宏替換”;出現常量的地方全部會被替換成其記住的字面量,這樣可以保證使用常量和直接用字面量的性能是一樣的

public class demo {//常量:static final修飾的類變量是常量。常量建議名稱全部大寫,多個單詞下劃線連接public static final String SCHOOL_NAME = "清華";public static void main(String[] args) {System.out.println(SCHOOL_NAME);System.out.println(SCHOOL_NAME);}
}

2.5 抽象類

什么是抽象類?

????????在Java中有一個關鍵字叫abstract,它就是抽象的意思,可以用它修飾類、成員方法

????????abstract修飾類,這個類就是抽象類;修飾方法,這個方法就是抽象方法

修飾符 abstract class 類名{

? ? ? ? 修飾符 abstract 返回值類型 方法名稱(形參列表);

}

public abstract class A{

? ? ? ? public abstract void test();

}

?抽象類的注意事項、特點

· 抽象類中不一定有抽象方法,有抽象方法的類一定是抽象類

· 類該有的成員(成員變量、方法、構造器)抽象類都可以有

· 抽象類最主要的特點:抽象類不能創建對象,僅作為一種特殊的父類,讓子類繼承并實現

· 一個類繼承抽象類,必須重寫完抽象類的全部抽象方法,否則這個類也必須定義成抽象類

//A 抽象類
public abstract class A {private String name;public static String schoolName;//抽象方法public abstract void run(); //抽象方法不能有方法體({})public A() {}public A(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public static String getSchoolName() {return schoolName;}public static void setSchoolName(String schoolName) {A.schoolName = schoolName;}
}//B 子類
//一個類繼承抽象類,必須重寫完抽象類的全部抽象方法,否則這個類也必須定義成抽象類
public class B extends A{@Overridepublic void run() {}
}//demo
public class demo {public static void main(String[] args) {//抽象類不能創建對象//A a = new A();  報錯}
}

使用抽象類的好處

? ? ? ? ?父類知道每個子類都要做某個行為,但每個子類要做的情況不一樣,父類就把該行為定義成抽象方法,交給子類去重寫實現(這樣設計是為了更好的支持多態

//Animal
public abstract class Animal {private String name;//抽象方法public abstract void action();public Animal() {}public Animal(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}//Dog
public class Dog extends Animal {public Dog() {}public Dog(String name) {super(name);}@Overridepublic void action() {System.out.println(getName()+"汪汪汪的叫……");}
}//Cat
public class Cat extends Animal{@Overridepublic void action() {System.out.println(getName()+"喵喵喵的叫……");}
}//demo
public class demo {public static void main(String[] args) {Animal animal1 = new Dog("汪汪1號");animal1.action();Animal animal2 = new Cat();animal2.setName("喵喵1號");animal2.action();}
}

抽象類的常見應用場景:模板方法設計模式

????????模板方法設計模式解決了方法中存在重復代碼的問題

模板方法設計模式的寫法

????????1.定義一個抽象類

????????2.在里面定義2個方法

? ? ? ? ? ? ? ? 一個是模板方法:把相同代碼放里面去

????????????????一個是抽象方法:具體實現子類完成?

建議使用final關鍵字修飾模板方法

????????模板方法是給對象直接使用的,不能被子類重寫

? ? ? ? 一旦子類重寫了模板方法,模板方法就失效了

//Paper
public abstract class Paper {//模板方法//建議使用final關鍵字修飾模板方法(模板方法是給對象直接使用的,不能被子類重寫)public final void write(){System.out.println("《我的爸爸》");System.out.println("我的爸爸今年40歲了!");zhengwen();System.out.println("對我而言他就是我的hero");}//抽象方法public abstract void zhengwen();
}//Student
public class Student extends Paper{@Overridepublic void zhengwen() {System.out.println("他個字很高……");}
}//Teacher
public class Teacher extends Paper {@Overridepublic void zhengwen() {System.out.println("他教會我騎車……");}
}//demo
public class demo {public static void main(String[] args) {//模板方法設計模式//場景:學生、老師都要寫一篇作文(我的爸爸),開頭結尾都給定,正文自由發揮Paper paper1 = new Student();paper1.write();System.out.println("===================");Paper paper2 = new Teacher();paper2.write();}
}

2.6 接口

????????Java提供了一個關鍵字interface,用這個關鍵字我們可以定義出一個特殊的結構:接口

public interface 接口名{

? ? ? ? //成員變量(常量)

????????// 成員方法(抽象方法)

}

注意:接口不能創建對象;接口是用來被類實現(implements)的,是實現接口的類稱為實現類

修飾符 class 實現類 implements ?接口1,接口2,接口3,…{

}

?一個類可以實現多個接口(繼承是親爹,接口是干爹),實現類實現多個接口,必須重寫完全部接口的全部抽象方法,否則實現類需要定義成抽象類

//A
public interface A {//成員變量(常量)//前面加不加public static final 都是常量String SCHOOL_NAME = "清華";//成員方法(抽象方法)//前面加不加public abstract 都是抽象方法void testa();//接口中只能定義成員變量和成員方法,不能有構造器、不能有代碼塊
}//B
public interface B {void testb1();void testb2();
}//C
public interface C {void testc1();void testc2();
}//D  實現類實現多個接口,必須重寫完全部接口的全部抽象方法
public class D implements B,C {@Overridepublic void testb1() {}@Overridepublic void testb2() {}@Overridepublic void testc1() {}@Overridepublic void testc2() {}
}//demo
public class demo {public static void main(String[] args) {System.out.println(A.SCHOOL_NAME);// A a = new A(); 接口不能創建對象D d = new D();  //D是實現類}
}

接口的好處?

????????彌補了類單繼承的不足,一個類同時可以實現多個接口

????????讓程序可以面向接口編程,這樣程序員就可以靈活方便的切換各種業務實現

//demo
public class demo {public static void main(String[] args) {Student s = new A();Driver d1 = new A();d1.drive();  //面向接口編程Singer si = new A();si.sing();Driver d2 = new B(); //面向接口編程d2.drive();  //面向接口編程}
}class B implements Driver{@Overridepublic void drive() {}
}//A是Student的子類,也是Driver, Singer的實現類
class A extends Student implements Driver, Singer{@Overridepublic void drive() {}@Overridepublic void sing() {}
}class Student{}interface Driver{void drive();}interface Singer{void sing();
}

接口的綜合案例

//Student
public class Student {private String name;  //姓名private String sex;  //性別private double score;  //成績public Student() {}public Student(String name, String sex, double score) {this.name = name;this.sex = sex;this.score = score;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public double getScore() {return score;}public void setScore(double score) {this.score = score;}
}//StudentOperator
//學生操作接口
public interface StudentOperator {public void printInfo(ArrayList<Student> arr);public void printAvgScore(ArrayList<Student> arr);
}//StudentOperatorImpl1
//學生操作實現類  業務方案1
public class StudentOperatorImpl1 implements StudentOperator {@Overridepublic void printInfo(ArrayList<Student> arr) {System.out.println("全班學生信息");System.out.println("姓名 性別 成績");for (int i = 0; i < arr.size(); i++) {System.out.println(arr.get(i).getName()+" "+arr.get(i).getSex()+" "+arr.get(i).getScore());}}@Overridepublic void printAvgScore(ArrayList<Student> arr) {double sum = 0;for (int i = 0; i < arr.size(); i++) {sum += arr.get(i).getScore();}double avg = sum / arr.size();System.out.println("全班學生的平均成績是:"+avg);}
}//StudentOperatorImpl2
//學生操作實現類  業務方案2
public class StudentOperatorImpl2 implements StudentOperator {@Overridepublic void printInfo(ArrayList<Student> arr) {int boy = 0;   //男生人數int girl = 0;  //女生人數System.out.println("全班學生信息");System.out.println("姓名 性別 成績");for (int i = 0; i < arr.size(); i++) {if(arr.get(i).getSex() == "男"){boy++;}else if(arr.get(i).getSex() == "女"){girl++;}System.out.println(arr.get(i).getName()+" "+arr.get(i).getSex()+" "+arr.get(i).getScore());}System.out.println("=====================");System.out.println("該班級男生"+boy+"人,女生"+girl+"人");}@Overridepublic void printAvgScore(ArrayList<Student> arr) {double sum = 0;double max =arr.get(0).getScore();    //最高分double min =arr.get(0).getScore();    //最低分for (int i = 0; i < arr.size(); i++) {if(i != 0){if(arr.get(i).getScore()>max){max = arr.get(i).getScore();}if(arr.get(i).getScore()<min){min = arr.get(i).getScore();}}sum += arr.get(i).getScore();}double avg = (sum-min-max) / (arr.size()-2);System.out.println("全班學生的平均成績是:"+avg);}
}//ClassManage 班級管理類
public class ClassManage {//如果用數組,數組大小不可以變,這里更應該選用集合ArrayList(集合大小可變)
//  private Student[] s_arr = new Student[4];private ArrayList<Student> arr = new ArrayList<>();//如果要切換方案1  直接把StudentOperatorImpl2()改成StudentOperatorImpl1()private StudentOperator so2 = new StudentOperatorImpl2(); //面向接口編程public ClassManage() {
//        s_arr[0] = new Student("張三","男",99);
//        s_arr[1] = new Student("李四","男",89);
//        s_arr[2] = new Student("王五","男",59);
//        s_arr[3] = new Student("張三","男",99);arr.add(new Student("張三","男",70));arr.add(new Student("李四","男",89));arr.add(new Student("王五","男",59));arr.add(new Student("小美","女",99));}//打印全班學生信息public void printInfo(){
//        System.out.println("全班學生信息");
//        System.out.println("姓名 性別 成績");
//        for (int i = 0; i < arr.size(); i++) {
//            System.out.println(arr.get(i).getName()+" "+arr.get(i).getSex()+" "+arr.get(i).getScore());
//        }so2.printInfo(arr);}//打印全班學生的平均成績public void printAvgScore(){
//        double sum = 0;
//        for (int i = 0; i < arr.size(); i++) {
//            sum += arr.get(i).getScore();
//        }
//        double avg = sum / arr.size();
//        System.out.println("全班學生的平均成績是:"+avg);so2.printAvgScore(arr);}//數組版本測試
//    public void method(){
//        for (int i = 0; i < s_arr.length; i++) {
//            System.out.println(s_arr[i].getName()+" "+s_arr[i].getSex()+" "+s_arr[i].getScore());
//        }
//    }
}//demo
public class demo {public static void main(String[] args) {ClassManage cm = new ClassManage();cm.printInfo();System.out.println("=================");cm.printAvgScore();}
}

?接口的細節知識:JDK8開始,接口中新增的三種方法

????????JDK8之前,接口中只能有成員變量(成員變量是常量)和成員方法(成員方法是抽象方法),JDK8開始,接口中新增三種方法

//A
public interface A {//新增 1.默認方法:必須使用default修飾,默認會被public修飾//默認方法是實例方法,對象的方法,因為接口不能創建對象,所以必須使用實現類的對象來訪問//public可省略  default void test1(){}public default void test1(){//可以帶方法體System.out.println("JDK8開始接口新增");System.out.println("默認方法:必須使用default修飾,默認會被public修飾");System.out.println("默認方法可以帶方法體");test2(); //私有方法}//新增 2.私有方法:必須使用private修飾(JDK 9開始才支持)//私有方法也是實例方法,對象的方法,因為接是私有方法,所以實現類的對象也不能訪問,接口內部方法可以訪問private void test2(){System.out.println("JDK9開始接口新增");System.out.println("私有方法:必須使用private修飾");}//新增 3.類方法(靜態方法):必須使用static修飾//默認會被public修飾,public可省略//類方法用類名直接調用,在接口里用接口名直接調用public static void test3(){System.out.println("JDK8開始接口新增");System.out.println("類方法(靜態方法):必須使用static修飾");}
}//B
public class B implements A{
}//demo
public class demo {public static void main(String[] args) {//默認方法必須使用實現類的對象來訪問B b = new B();b.test1();//b.test2(); //私有方法 實現類的對象不能訪問,接口內部方法可以訪問A.test3();}
}

接口的細節知識:接口的多繼承、使用接口的注意事項

接口的多繼承

? ? ? ? 一個接口可以同時繼承多個接口(作用是便于實現類去實現)

public interface C extends B,A{

}

public class demo {public static void main(String[] args) {}
}interface A{void test1();
}interface B{void test2();
}//接口的多繼承
interface C extends A , B{}//class D implements A , B{} 兩者等同(實現C相當于實現了A和B)
//其實就是把AB省略直接寫成C
class D implements C{@Overridepublic void test1() {}@Overridepublic void test2() {}
}

?接口的其他注意事項

1.一個接口繼承多個接口,如果多個接口中存在方法簽名沖突,則此時不支持多繼承

2.一個類實現多個接口,如果多個接口中存在抽象方法簽名沖突(不管返回值類型是否一致,方法名一致就沖突),則此時不支持多實現

3.一個類繼承了父類,又同時實現了接口,父類中和接口中有同名的默認方法,實現類會優先用父類的

4.一個類實現了多個接口,多個接口中存在同名的默認方法(返回值類型要一致,方法名也要一致),可以不沖突,這類重寫該方法即可

//demo
public class demo {public static void main(String[] args) {Zi zi = new Zi();zi.run();  //一個類繼承了父類,又同時實現了接口,父類中和接口中有同名的默認方法,實現類會優先用父類的}
}interface A{void test1();  //抽象方法
}
interface B{String test1();  //抽象方法
}
//1.一個接口繼承多個接口,如果多個接口中存在方法簽名沖突,則此時不支持多繼承
//interface C extends A,B{
//   沖突
//}//2.一個類實現多個接口,如果多個接口中存在抽象方法簽名沖突(不管返回值一不一樣,方法名一樣就沖突),則此時不支持多實現
//class C implements A,B{
//    沖突
//}//3.一個類繼承了父類,又同時實現了接口,父類中和接口中有同名的默認方法,實現類會優先用父類的
class Fu{public void run(){System.out.println("父類的run方法");}
}interface J{//public可省略public default void run(){System.out.println("接口的run方法");}
}class Zi extends Fu implements J{}//4.一個類實現了多個接口,多個接口中存在同名的默認方法(返回值類型要一致,方法名也要一致),可以不沖突,這類重寫該方法即可
interface A1{default void test1(){}  //默認方法
}
interface B1{default void test1(){}  //默認方法
}class D implements A1,B1{//重寫方法@Overridepublic void test1() {}
}

2.7 內部類

????????內部類是類中的五大成分之一(成員變量、方法、構造器、內部類、代碼塊),如果一個類定義在另一個類的內部,這個類就是內部類

????????場景:當一個類的內部,包含一個完整的事物,且這個事物沒有必要單獨設計時,就可以把這個事物設計成內部類

public class Car{

????????//內部類

????????public class Engine{

????????}

}

????????內部類有四種形式:成員內部類、靜態內部類、局部內部類、匿名內部類?

2.7.1 成員內部類

????????就是類中的一個普通成員,類似前面學過的普通的成員變量、成員方法

public class Outer{

????????//成員內部類

????????public class Inner{

????????}

}

注意:JDK16之前,成員內部類中不能定義靜態成員,JDK16開始也可以定義靜態成員

創建對象的格式:

????????外部類名.內部類名 對象名 = new 外部類(…).new 內部類(…);

????????Outer.Inner in = new Outer().new Inner();

//Outer
public class Outer {private int age = 99;public static String a;//成員內部類public class Inner{private String name;//private static String schoolName; //JDK16開始才支持定義靜態成員public int age = 88;public void test(){System.out.println(age);System.out.println(a);int age = 66;System.out.println(age);  //66 就近原則System.out.println(this.age);  //88 成員內部類Inner的成員變量age的值System.out.println(Outer.this.age);  //99 指定訪問外部類Outer的成員變量age的值}public Inner() {}public Inner(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
}//demo
public class demo {public static void main(String[] args) {//創建成員內部類對象,需要先創建外部對象Outer.Inner inner = new Outer().new Inner();inner.setName("zhang");inner.test();}
}

2.7.2?靜態內部類

????????有static修飾的內部類,屬于外部類自己持有

public class Outer{

????????//靜態內部類

????????public static class Inner{

????????}

}

創建對象的格式:

????????外部類名.內部類名 對象名 = new 外部類.內部類(…);

????????Outer.Inner in = new Outer.Inner();

靜態內部類中訪問外部類成員的特點

????????可以直接訪問外部類的靜態成員,不可以直接訪問外部類的實例成員

//Outer
public class Outer {private int age;public static String a;//靜態內部類public static class Inner{private String name; //普通成員變量private static String schoolName;   //類變量(靜態成員變量)public void test(){//類方法(靜態方法)中可以直接訪問類成員,不可以直接訪問實例成員(實例成員屬于對象)System.out.println(a);  //靜態內部類可以訪問外部類的類變量//System.out.println(age);  //報錯  靜態內部類不能訪問外部類的實例變量}public Inner() {}public Inner(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
}//demo
public class demo {public static void main(String[] args) {//創建靜態內部類對象Outer.Inner inner = new Outer.Inner();inner.setName("zhang");}
}

2.7.3 局部內部類

????????局部內部類是定義在方法中、代碼塊中、構造器等執行體中

?

2.7.4 匿名內部類

????????匿名內部類就是一種特殊的局部內部類;所謂匿名:指的是程序員不需要為這個類聲明名字

new 類或接口(參數值…){

????????類體(一般是方法重寫);

};

特點:匿名內部類本質就是一個子類,并會立即創建出一個子類對象

作用:用于更方便的創建一個子類對象

//demo
public class demo {public static void main(String[] args) {
//        Animal a = new Cat();
//        a.cry();//匿名內部類//1.把這個匿名內部類編譯成子類,然后會立即創建出一個子類對象來Animal a = new Animal(){@Overridepublic void cry() {System.out.println("喵喵喵");}};a.cry();}
}//抽象類
abstract class Animal{public abstract void cry();
}//class Cat extends Animal{
//    @Override
//    public void cry() {
//        System.out.println("喵喵喵");
//    }
//}

匿名內部類在開發中的使用場景

? ? ? ? 通常作為一個參數傳輸給方法

//demo
public class demo {public static void main(String[] args) {
//        Swimming s1 = new Swimming(){
//            @Override
//            public void swim() {
//                System.out.println("小狗游泳");
//            }
//        };
//        go(s1);go(new Swimming(){@Overridepublic void swim() {System.out.println("小狗游泳");}});Swimming s2 = new Swimming(){@Overridepublic void swim() {System.out.println("小貓游泳");}};go(s2);}//設計一個方法,可以接收swimming接口的一切實現類對象進來參加游泳比賽public static void go(Swimming s){System.out.println("開始——————————————————");s.swim();}}//貓和狗都要參加游泳比賽
interface Swimming{void swim();
}

匿名內部類不是自己主動去用,是別人需要讓我們用的時候用(別人需要的對象是接口類型用匿名內部類 或寫實現類)

//demo
public class demo {public static void main(String[] args) {//搞清楚匿名內部類在開發中的真是使用場景//GUI編程(桌面程序)//1.創建窗口JFrame win = new JFrame("登錄界面");JPanel panel = new JPanel();win.add(panel);JButton btn = new JButton("登錄");panel.add(btn);   //窗口加按鈕//給按鈕綁定單機事件監聽器//匿名內部類不是自己主動去用,是別人需要讓我們用的時候用(別人需要的對象是接口類型用匿名內部類 或寫實現類)
//        btn.addActionListener(new ActionListener() {
//            @Override
//            public void actionPerformed(ActionEvent e) {
//                JOptionPane.showMessageDialog(win,"登錄一下");
//            }
//        });//匿名內部類的核心目的是簡化代碼btn.addActionListener(e -> JOptionPane.showMessageDialog(win,"登錄一下"));win.setSize(400,400);  //窗口大小win.setLocationRelativeTo(null);  //窗口居中win.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);  //關閉窗口退出程序win.setVisible(true);  //可見}
}

2.8 枚舉

????????枚舉是一種特殊類

枚舉類的格式:

? ? ? ? 修飾符 enum 枚舉類名{

????????????????名稱1,名稱2,…;

????????????????其他成員…

}

注意:

? ? ? ? · 枚舉類中的第一行,只能寫一些合法的標識符(名稱),多個名稱用逗號隔開

? ? ? ? · 這些名稱,本質是常量,每個常量都會記住枚舉類的一個對象

//A
public enum A {//注意:枚舉類的第一行必須羅列的是枚舉對象的名字X, Y, Z;private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}//B
//抽象枚舉
public enum B {//枚舉類中的第一行,只能寫一些合法的標識符(名稱),這些名稱本質是常量,每個常量都會記住枚舉類的一個對象//因為枚舉類中有抽象方法,所以這個枚舉類是抽象枚舉類,因此一個類繼承抽象類,必須重寫完抽象類的全部抽象方法X(){  //相當于創建了一個B枚舉對象@Overridepublic void go(){}},Y("張三"){  //相當于創建了一個B枚舉對象@Overridepublic void go(){System.out.println(getName());}};private String name;//private可省略,默認私有private B() {}//private可省略,默認私有private B(String name) {this.name = name;}public abstract void go();public String getName() {return name;}public void setName(String name) {this.name = name;}
}//demo
public class demo {public static void main(String[] args) {A a1 = A.X;System.out.println(a1);//枚舉類的構造器是私有的,不能對外創建對象//A a = new A();//枚舉類的第一行都是常量,記住的是枚舉類的對象A a2 = A.Y;//枚舉類提供一些額外的APIA[] all = A.values();  //拿到全部對象A a3 = A.valueOf("Z");System.out.println(a3.name());  //拿到a3的名字System.out.println(a3.ordinal());   //拿到a3的索引B b1 = B.Y;b1.go();}
}

用枚舉類寫單例設計模式

public enum C {X;  //單例
}

枚舉的常見應用場景

? ? ? ? 用來表示一組信息,然后作為參數進行傳輸

選擇定義一個一個的常量來表示一組信息,并作為參數傳輸

????????· 參數值不受約束

選擇定義枚舉表示一組信息,并作為參數傳輸

????????· 代碼可讀性好,參數值得到了約束,對使用者更友好(建議!)

// Constant2
public enum Constant2 {BOY,GRIL;
}//demo
public class demo {public static void main(String[] args) {//拿枚舉類做信息標志和分類check(Constant2.BOY);}public static void check(Constant2 sex){switch (sex){case BOY:System.out.println("男生關注的信息");break;case GRIL:System.out.println("女生關注的信息");break;}}
}

2.9 泛型

????????定義類、接口、方法時,同時聲明了一個或者多個類型變量(如:<E>),稱為泛型類、泛型接口、泛型方法,它們統稱為泛型

public class ArrayList<E>{

? ? ? ? ……

}

作用:泛型提供了在編譯階段約束所能操作的數據類型,并自動進行檢查的能力!這樣可以避免強制類型轉換,及其可能出現的異常

泛型的本質:把具體的數據類型作為參數傳給類型變量

//demo
public class demo {public static void main(String[] args) {//沒有定義泛型,默認時object類型ArrayList list = new ArrayList();list.add("java1");list.add("java2");list.add("java3");//list.add(new Cat());for (int i = 0; i < list.size(); i++) {String s = (String) list.get(i);System.out.println(s);}System.out.println("=====================");//ArrayList<String> list1 = new ArrayList<String>();ArrayList<String> list1 = new ArrayList<>(); //JDK1.7開始后面<>中可以不寫類型list1.add("java1");list1.add("java2");list1.add("java3");//list1.add(new Cat());  報錯(泛型可以在編譯階段約束能夠操作的數據類型)for (int i = 0; i < list.size(); i++) {String s =list1.get(i);System.out.println(s);}}
}

2.9.1 泛型類

????????自定義泛型類

修飾符 class 類名<類型變量,類型變量,……>{

}

//demo
public class demo {public static void main(String[] args) {MyArrayList<String> list = new MyArrayList<>();list.add("java1");list.add("java2");//list.add("java3");System.out.println(list.get(6));//泛型可以聲明多個類型變量MyClass<String,String> c = new MyClass<>();//是它本身或者它的子類MyClass2<Dog> m1 = new MyClass2<>();MyClass2<Animal> m2 = new MyClass2<>();}
}//MyArrayList
public class MyArrayList<E> {private Object[] o_arr = new Object[2];private int size=0;public boolean add(E e){if(size<o_arr.length){o_arr[size] = e;size++;return true;}else{System.out.println("超出數組長度");return false;}}public E get(int index){if(index<o_arr.length){return (E)o_arr[index];}else{return (E)"您訪問的索引越界";}}
}//MyClass(泛型可以聲明多個類型變量)
public class MyClass<E,T> {public void put(E e,T t){}
}//MyClass2  //是它本身或者它的子類
public class MyClass2<E extends Animal> {
}//Animal
public class Animal {
}//public class Dog extends Animal {
}

2.9.2 泛型接口

修飾符 interface 接口名<類型變量,類型變量,……>{

}

//demo
public class demo {public static void main(String[] args) {//系統需要處理學生和老師的數據//兩個功能:保存對象數據,根據名稱查詢數據Teacher t = new Teacher("張三","男","Java");TeacherData t1 = new TeacherData();t1.add(t);t1.find("張三");t1.find("李四");}
}//People
public class People {private String name;   //姓名private String sex;    //性別public People() {}public People(String name, String sex) {this.name = name;this.sex = sex;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}
}//Teacher
public class Teacher extends People{private String teach;  //學科public Teacher(){}public Teacher(String teach) {this.teach = teach;}public Teacher(String name, String sex, String teach) {super(name, sex);this.teach = teach;}public String getTeach() {return teach;}public void setTeach(String teach) {this.teach = teach;}
}//Student
public class Student extends People{private int classroom;   //班級public Student(){}public Student(int classroom) {this.classroom = classroom;}public Student(String name, String sex, int classroom) {super(name, sex);this.classroom = classroom;}public int getClassroom() {return classroom;}public void setClassroom(int classroom) {this.classroom = classroom;}
}//Data
//泛型接口
public interface Data<E> {void add(E e);  //即需要保存學生數據也需要保存老師數據,使用泛型比較好ArrayList<E> find(String name);
}//TeacherData
public class TeacherData implements Data<Teacher> {private ArrayList<Teacher> arr_s = new ArrayList<>();  //保存老師數據的集合@Overridepublic void add(Teacher teacher) {arr_s.add(teacher);}@Overridepublic ArrayList<Teacher> find(String name) {for (int i = 0; i < arr_s.size(); i++) {if(arr_s.get(i).getName() == name){ //找到名字一樣的System.out.println("查詢成功");System.out.println(arr_s.get(i).getName()+" "+arr_s.get(i).getSex()+" "+arr_s.get(i).getTeach());}else{System.out.println("查詢失敗,老師列表中沒有此人");}}return null;  //返回ArrayList<Teacher>感覺不太對,查詢信息返回整個集合?? 應該返回學生對象即可}
}//StudentData
public class StudentData implements Data<Student> {private ArrayList<Student> arr_s = new ArrayList<>();  //保存學生數據的集合@Overridepublic void add(Student student) {arr_s.add(student);}@Overridepublic ArrayList<Student> find(String name) {return null;}
}

2.9.3 泛型方法

修飾符<類型變量,類型變量,……>返回值類型 方法名(形參列表){

}

?通配符

????????就是 ? 可以在使用泛型的時候代表一切類型;E T K V等字符是在定義泛型的時候使用

泛型的上下限

? ? ? ? 泛型上限:?extends Car:?能接收的必須是Car或者它的子類

????????泛型下限:?super Car:?能接收的必須是Car或者它的父類

//demo
public class demo {public static void main(String[] args) {String s = method("Java");System.out.println(s);Dog d = method(new Dog());System.out.println(d);//需求:所有汽車參加比賽ArrayList<Car> cars = new ArrayList<>();cars.add(new BENZ());cars.add(new BNW());go(cars);ArrayList<BNW> bnws = new ArrayList<>();bnws.add(new BNW());bnws.add(new BNW());//go(bnws);//報錯 因為go的形參需要ArrayList<Car>,所以ArrayList<BNW>不行//雖然Car是BNW的父類,但是ArrayList<BNW>和ArrayList<Car>無關//public static void go(ArrayList<Car> cars)//如果想要把ArrayList<BNW>可以使用,需要把go方法加上泛型go(bnws);}//    public static void go(ArrayList<Car> cars){
//
//    }//    public static <T extends Car> void go(ArrayList<T> cars) {
//        //不加extends Car,任何ArrayList<XX>都能加進來
//    }//? 通配符  在使用泛型的時候可以代表一切類型  ? extends Car(上限 Car和Car的子類能進來)   ? super Car(下限 Car和Car的父類能進來)public static void go(ArrayList<? extends Car> cars) {//不加extends Car,任何ArrayList<XX>都能加進來}//泛型方法public static <T> T method(T t){return t;}
}//Car
public class Car {
}//BENZ
public class BENZ extends Car{
}//BNW
public class BNW extends Car{
}//Dog
public class Dog {
}

泛型的擦除問題和注意事項

????????· 泛型是工作在編譯階段的,一旦程序編譯成class文件,class文件中就不存在泛型了,這就是泛型擦除

????????· 泛型不支持基本數據類型(int、double等),只能支持對象類型(引用數據類型)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/717887.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/717887.shtml
英文地址,請注明出處:http://en.pswp.cn/news/717887.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JavaScript 語句語法的教程

JavaScript 是一種廣泛應用于網頁開發的腳本語言&#xff0c;熟練掌握 JavaScript 的語法是成為一名優秀的前端開發工程師的必備技能之一。本教程將詳細介紹 JavaScript 中的語句語法&#xff0c;幫助初學者快速入門并加深對 JavaScript 語法的理解。 一、注釋 在 JavaScript…

常見的爬蟲逆向面試題

文章轉載于&#xff1a;https://mp.weixin.qq.com/s/dXRo0D_Xx7E_h85XbnwPVQ 有興趣去源站瀏覽學習 主要自己看著方便些 1.HTTS三次握手 目前使用的 HTTP/HTTPS 協議是基于 TCP 協議之上的&#xff0c;因此也需要三次握手。在 TCP 三次握手建立鏈接之后&#xff0c;才會進行 …

故障診斷 | 一文解決,XGBoost極限梯度提升樹的故障診斷(Matlab)

效果一覽 文章概述 故障診斷 | 一文解決,XGBoost極限梯度提升樹的故障診斷(Matlab) 模型描述 XGBoost通過集成多個決策樹來建立一個強大的預測模型。它采用了一種特殊的梯度提升技術,稱為極限梯度提升(Extreme Gradient Boosting),以提高模型的性能和魯棒性。 極限梯度…

【大數據Hive】hive 多字段分隔符使用詳解

目錄 一、前言 二、hive默認分隔符規則以及限制 2.1 正常示例&#xff1a;單字節分隔符數據加載示例 2.2 特殊格式的文本數據&#xff0c;分隔符為特殊字符 2.2.1 文本數據的字段中包含了分隔符 三、突破默認限制規則約束 3.1 數據加載不匹配情況 1 3.2 數據加載不匹配…

python paramiko 網絡系統運維

概述 背景&#xff1a;網絡系統運維與建設&#xff1a;工作中發現客戶使用python腳本批量操作網絡設備導出多臺網絡設備的配置定期執行相關的巡檢工作 修改配置 # -*- coding:utf8 -*- """ # editor: hjjdreamer # create-time: 2024/3/3-23:31 # Python-Scri…

Java項目推薦|幾個B站上的從零搭建項目

分享幾個B站上搜集到的技術比較全&#xff0c;講解也詳細的Java后端開發項目 目錄 谷粒商城 2020-03-31 iHRM 人力資源管理系統 2021-04-16 瑞吉外賣 2022-04-12 學成在線 2023-01-13 尚上優選 2023-06-06 黑馬頭條 2023-06-13 蒼穹外賣 2023-07-05 谷粒商城 2020-03-3…

命名實體識別NER

一、什么是命名實體識別&#xff1a; 命名實體&#xff1a;通常我們將人名、地名、機構名等專有名詞統稱命名實體&#xff0c;如&#xff1a;周杰倫&#xff0c;黑山縣&#xff0c;孔子學院&#xff0c;24方鋼直機 顧名思議&#xff0c;命名實體識別&#xff08;簡稱NER&#x…

【常用的 Git 命令及簡要示例說明】

常用的 Git 命令及簡要示例說明&#xff0c;以供參考&#xff1a; 初始化一個新的代碼倉庫&#xff1a; git init克隆一個遠程倉庫到本地&#xff1a; git clone https://github.com/user/repo.git添加當前所有變更到暫存區&#xff1a; git add .提交暫存區的變更到本地倉庫&a…

STM32FreeRTOS任務通知(STM32cube高效開發)

文章目錄 一、任務通知(一&#xff09;任務通知概述1、任務通知可模擬隊列和信號量2、任務通知優勢和局限性 (二) 任務通知函數1、xTaskNotify&#xff08;&#xff09;發送通知值不返回先前通知值的函數2、xTaskNotifyFromISR&#xff08;&#xff09;發送通知函數ISR版本3、x…

Java面試題總結200道(二)

26、簡述Spring中Bean的生命周期&#xff1f; 在原生的java環境中&#xff0c;一個新的對象的產生是我們用new()的方式產生出來的。在Spring的IOC容器中&#xff0c;將這一部分的工作幫我們完成了(Bean對象的管理)。既然是對象&#xff0c;就存在生命周期&#xff0c;也就是作用…

LeetCode 刷題 [C++] 第73題.矩陣置零

題目描述 給定一個 m x n 的矩陣&#xff0c;如果一個元素為 0 &#xff0c;則將其所在行和列的所有元素都設為 0 。請使用 原地 算法。 題目分析 題目中要求使用原地算法&#xff1a;即直接在輸入矩陣上進行修改。因此如果在輸入矩陣上把行/列的值修改成0后&#xff0c;在…

【Linux】基本指令(下)

&#x1f984;個人主頁:修修修也 &#x1f38f;所屬專欄:Linux ??操作環境:Xshell (操作系統:CentOS 7.9 64位) 日志 日志的概念: 網絡設備、系統及服務程序等&#xff0c;在運作時都會產生一個叫log的事件記錄&#xff1b;每一行日志都記載著日期、時間、使用者及動作等相關…

計算機視覺(Computer Vision)和機器視覺(Machine Vision)

舉例說明計算機視覺&#xff08;CV&#xff09;技術的優勢和挑戰 計算機視覺&#xff08;CV&#xff09;技術是一種使用計算機科學和機器學習方法來解釋、分析和理解圖像和視頻的技術。它的優勢和挑戰如下&#xff1a; 優勢&#xff1a; 高效性&#xff1a;CV技術可以快速處…

課時53:數組實踐_基礎操作_數組基礎

1.1.2 數組定義 學習目標 這一節&#xff0c;我們從 基礎知識、簡單實踐、小結 三個方面來學習。 基礎知識 數組創建 在Shell中&#xff0c;用括號來表示數組&#xff0c;數組元素用“空格”符號分割開。定義數組的語法格式&#xff1a;array_name(value1 ... valuen) 注意…

MSCKF4講:后端理論推導(下)

MSCKF4講&#xff1a;后端理論推導&#xff08;下&#xff09; 文章目錄 MSCKF4講&#xff1a;后端理論推導&#xff08;下&#xff09;6 可觀測性分析與約束6.1 為什么要做能觀性分析6.2 關于零空間解釋6.3 可觀測性分析6.4 可觀測性約束① 狀態轉移矩陣Φ② 對觀測矩陣H--觀測…

【洛谷 P8682】[藍橋杯 2019 省 B] 等差數列 題解(數學+排序+輾轉相除法)

[藍橋杯 2019 省 B] 等差數列 題目描述 數學老師給小明出了一道等差數列求和的題目。但是粗心的小明忘記了一部分的數列&#xff0c;只記得其中 N N N 個整數。 現在給出這 N N N 個整數&#xff0c;小明想知道包含這 N N N 個整數的最短的等差數列有幾項&#xff1f; 輸…

deep learning with pytorch(一)

1.create a basic nerual network model with pytorch 數據集 Iris UCI Machine Learning Repository fully connected 目標:創建從輸入層的代碼開始&#xff0c;向前移動到隱藏層&#xff0c;最后到輸出層 # %% import torch import torch.nn as nn import torch.nn.funct…

【大數據】詳細講解

大數據 0. 前言1. 大數據的5V特征2. 大數據技術3. 大數據分析4. 大數據應用5. 失效風險與挑戰 0. 前言 大數據是一個涉及非常龐大和復雜數據集的領域&#xff0c;這些數據集因其規模和復雜性而難以使用傳統數據處理軟件進行有效處理。在講解大數據之前&#xff0c;我們首先需要…

LeetCode26 刪除有序數組中的重復項

題目 給你一個 非嚴格遞增排列 的數組 nums &#xff0c;請你原地刪除重復出現的元素&#xff0c; 使每個元素 只出現一次 &#xff0c;返回刪除后數組的新長度。 元素的 相對順序 應該保持 一致 然后返回 nums 中唯一元素的個數。 示例 示例 1&#xff1a;輸入&#xff1a;num…

30天JS挑戰(第十四天)------數據的復制

第十四天挑戰(數據的復制) 地址&#xff1a;https://javascript30.com/ 所有內容均上傳至gitee&#xff0c;答案不唯一&#xff0c;僅代表本人思路 中文詳解&#xff1a;https://github.com/soyaine/JavaScript30 該詳解是Soyaine及其團隊整理編撰的&#xff0c;是對源代碼…