JavaSE-07 Opp面向對象(完整版)
JavaSE-07 Opp 面向對象(完整版)
1.方法的調用補充:package com.fenfen.oop.Demo1
1.1非靜態方法下方法調用(不同的類)
①在Student的類中建立study的方法 package com.fenfen.oop.Demo1; //學生類的方法 public class Student { //方法 public void study(){ System.out.println("學生在學習"); } } ②在Demo2類中調用Student類中的student方法 //在別的類中調用 package com.fenfen.oop.Demo1; public class Demo2 { public static void main(String[] args) { //在方法非靜態下:實例化這個類 //對象類型 對象名 = 對象值 Student student = new Student(); student.say(); } }
1.2非靜態方法下的方法調用(同個類)
public class Demo2 { //static和類(class:Demo2)一起加載 public static void a(){ b();//會報錯原因:可以理解為:存在的去調用不存在的了 } //沒有static:這個得等到類實例化(new 後)才存在 public void b(){ a(); } }
1.3 值傳遞:
//值傳遞 public class Demo4 { public static void main(String[] args) { int a = 1; change(a); System.out.println(a);//輸出仍然是a = 1 } //無返回值 public static void change(int a){ //原因:a只是一個形式參數,a=10後沒有返回值給到a,於是回到了主方法,主方法中有int a = 1,因此輸出就是1了 a = 10; } /* 更加高端的解釋: ①change方法調用完畢就出棧了,main方法還在棧中 ②對於基本數據類型來説,給形參傳遞的是實參值的副本 而對於引用數據類型來説,傳遞則是地址的副本,但由於地址的副本和原來的相似,因此傳遞過去後的形參也指向同一個內存空間 */
1.4 引用傳遞:
public class Demo5 { public static void main(String[] args) { Person person = new Person(); System.out.println(person.name);//null change(person); System.out.println(person.name);//fenfen } //寫個方法 public static void change(Person person){ person.name = "fenfen";//原因:引用傳遞:指針修改,因為引用指向原對象在內存中的區域,所以可以修改原對象的值 } } //定義了一個Person類,有一個屬性:name class Person{ String name; }
2. 對象的創建與分析:com.fenfen.oop.Demo2
2.1 類和方法的創建:Student,Application
//學生類 public class Student { //①屬性:字段 String name;//未賦任何值,默認初始化為null int age;//為賦任何值,初始化為0 //②方法 public void study(){ System.out.println(this.name+"學生在學習");//this表示當前這個類 } }
public class Application { public static void main(String[] args) { //實例化:student對象就是一個Student類的具體實例 Student student = new Student(); Student xiaoming = new Student(); Student xiaohong = new Student(); //給對象賦值: xiaoming.name = "小明"; xiaoming.age = 3; //打印賦值後的對象屬性:未賦值出來是null和0 Person person = new Person(); System.out.println(person.name); } }
2.2 構造器詳解
2.2.1 無參構造器
public class Person { String name; //1、一個類即使什麼都不寫,也會存在構造方法(和類名相同,且無返回值),即構造器:無參構造器 //構造器的作用:實例化初始值:使用new對象,本質是在調用構造器 public Person(){ this.name = "fenfen"; }
public class Application { public static void main(String[] args) { Person person = new Person(); System.out.println(person.name);//fenfen }
2.2.2 有參構造器
public class Person { String name; //2、有參構造器:一旦定義了有參構造,無參就必須顯示定義(就是有了有參,無參不能刪,空着就好) public Person(){ } public Person(String name){ this.name = name; }
public class Application { public static void main(String[] args) { //實例化了一個對象:走的無參構造器 Person person = new Person(); System.out.println(person.name); //走有參構造器 Person person1 = new Person("fenfen"); System.out.println(person1.name); } } //注:快捷鍵alt+insert然後點擊constructor,可以選擇無參或有參快速生成構造器
2.3 創建對象內存分析:com.fenfen.oop.Demo3
棧的概念是彈壓,就像子彈殼裝彈,一粒一粒壓進去,但是打出來的時候是從上面打出來的,最先壓進去的最後彈出來,如果進去順序是123,打出來順序是321,這就是後進先出
隊列的概念就是我們平時排隊,按次序來,你排在第1個,那你就第一個輪到,就是先進先出,先到先來
2.3.1 對應代碼
public class Pet { public String name; public int age; public void shout(){ System.out.println("叫了一聲"); }
public class Application { public static void main(String[] args) { Pet dog = new Pet(); dog.name = "饅頭"; dog.age =1; dog.shout(); System.out.println(dog.name); System.out.println(dog.age); } }
2.3.2 對應內存順序圖:
3. 三大特性
3.1 封裝:com.fenfen.oop.Demo4
3.1.1 相關概念:
原因: |
---|
a.程序設計應”高內聚,低耦合“,即類的內部數據操作細節不允許外界干涉,以及僅暴露少量方法給外部使用 |
b.封裝:應禁止直接訪問一個對象中數據的實際顯示,通過操作接口去訪問,以便信息隱藏 |
3.1.2 封裝
//封裝:屬性私有 get/set public class Student2 { //名字、姓名、學號:一般封裝對於屬性來説比較多,對於方法少一些 //學習、睡覺 private String name; private int id; private char sex; private int age; //提供一些可以操作的這個屬性的方法:因為上面private了 //提供一些public的get、set的方法 //①get獲得這個數據 public String getName() { return this.name; } //②set 給這個數據設置值 public void setName(String name){ this.name = name; } //注:快捷鍵alt+insert然後點擊setter and getter,可以快速生成 //③甚至可以在set裏面寫if判斷來進行安全性檢查 public void setAge(int age) { if (age>120 || age<0) { this.age = 3; }else{ this.age = age; } } }
public class Application { public static void main(String[] args) { Student2 s1 = new Student2(); //s1.name = "fenfen";私有的不可調用 String name = s1.getName();//get s1.setName("fenfen"); System.out.println(s1.getName());//s1.getName().sout s1.setAge(999); System.out.println(s1.getAge()); } }
3.1.3 封裝的意義:
封裝的意義: 1、提高程序的安全性,保護數據 2、隱藏代碼的實現細節 3、統一接口 4、提高系統的可維護性 5、封裝和重載一般一起用的比較多
3.2 繼承:com.fenfen.oop.Demo5
3.2.1 子類繼承父類的方法與屬性
public class Person { public int money = 10_0000_0000; public void say(){ System.out.println("説了一句話"); } }
public class Student extends Person{ public static void main(String[] args) { Student student = new Student(); student.say(); System.out.println(student.money); }//子類繼承父類,就會擁有父類的方法
3.2.2 子類繼承父類私有的屬性
public class Person { private int money2 = 99999999; //get和set方法針對private搞個封裝 public int getMoney2() { return money2; } public void setMoney2(int money2) { this.money2 = money2; } }
public class Student extends Person{ public static void main(String[] args) { Student student = new Student(); //針對private的封裝方法的調用 student.setMoney2(99); System.out.println(student.getMoney2()); } } //注: //ctrl+h可以彈出繼承樹
3.2.3 super詳解
- super在屬性上的運用
- 父類
public class Person { //protected protected String name = "fenfen父類"; }
- 子類
public class Student extends Person{ private String name = "fenfen子類"; public void test(String name){ System.out.println(name);//main傳遞過來的參數 System.out.println(this.name); System.out.println(super.name);//super去調用父類的 } }
- Application類
public class Application { public static void main(String[] args) { com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student(); student1.test("fenfenmain類"); } }
- super在方法上的運用
- 父類
public class Person { public void print(){//如果是私有的方法,子類就不能直接訪問了 System.out.println("Person"); } }
- 子類
public class Student extends Person{ public void print(){ System.out.println("Student"); } public void test1(){ print();//當前方法 this.print();//當前方法 super.print();//父類的方法 } }
- Application類
public class Application { public static void main(String[] args) { com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student(); student1.test1(); } }
- super在無參構造器上的運用
- 父類
public class Person { public Person(){ System.out.println("Person無參執行了"); } protected String name = "fenfen父類"; }
- 子類
public class Student extends Person{ public Student() { //隱藏代碼:調用了父類的無參構造 //即有一行:super();且調用父類的構造器必須在子類的第一行 System.out.println("子類的無參執行了"); } private String name = "fenfen子類"; }
- Application類:
public class Application { public static void main(String[] args) { com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student(); } } /* Person無參執行了 子類的無參執行了 */
- super在有參構造器上的運用
- 父類
public class Person { //整一個有參構造器 public Person(String name){ System.out.println("Person無參執行了"); } }
- 子類
public class Student extends Person{ public Student() { super(name:"name");//記得寫參數,才會去調用有參的 System.out.println("子類的無參執行了"); } private String name = "fenfen子類"; }
- Application類:
public class Application { public static void main(String[] args) { com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student(); } }
3.2.4 方法的重寫:com.fenfen.oop.Demo5
- 提前介紹多態:有static
- 父類
public class B { public static void test(){ System.out.println("B=>test"); } }
- 子類
public class A extends B { public static void test(){ System.out.println("A=>test"); } }
- Application類
public class C { public static void main(String[] args) { //方法的調用只和左邊的類型有關,定義的數據類型有關 A a = new A(); a.test();//走的是A類的方法 //A繼承B,父類的引用指向子類 B b = new A(); b.test();//走的B類的方法 } }
- 方法重寫:非靜態
- 父類
public class B { public void test(){ System.out.println("B=>test"); } }
- 子類
public class A extends B{ //重寫1 @Override//把static去掉,這個就是註解:有功能的註釋 public void test() { System.out.println("A=>test"); } }
- Application
public class C { public static void main(String[] args) { A a = new A(); a.test();//A=>test B b = new A(); b.test();//A=>test } }
總結看看:
/*第二次用重寫的沒有static的結果截然不同: 有static靜態時:b調用的是B類的方法,因為b是用B類去定義的 沒有static靜態時:b調用的是對象的方法,b是用A類new的 重寫:需要有繼承關係,而且是子類重寫父類 1、方法名必須相同 2、參數列表必須相同 3、修飾符:範圍可以擴大: private--->default---->protected---->public 4、重寫可能會拋出異常:範圍可以被縮小,但不能被擴大 ClassNotFoundException 注意:子類的方法和父類必要一致:方法體不同 為啥要重寫:override 1、父類的功能子類不一定需要,或者不一定滿足
3.3 多態:com.fenfen.oop.Demo6
3.3.1 多態的創建
public class Main { public static void main(String[] args) { //一個對象的實際類型是確定的 //new Student(); //new Person(); //可以指向的引用類型就不確定了 Student s1 = new Student();//Student能調用的方法都是自己或者是繼承來的:Student類繼承了Person類 //①父類的引用指向子類的類型 Person s2 = new Student();//父類的可以指向子類,但是不能調用子類特定的方法 //②指向Object Object s3 = new Student(); } }
3.3.2 多態方法的調用
- 父類
public class Person { public void run(){ System.out.println("run"); } }
- 子類
public class Student extends Person{ //重寫下父類的方法 @Override public void run() { System.out.println("son"); } public void eat(){ System.out.println("eat"); } public void go(){ System.out.println("go"); } }
- Application
public class Main { public static void main(String[] args) { Student s1 = new Student(); Person s2 = new Student(); s2.run();//子類重寫了父類的方法,因此父類的方法調用的時候變成子類了 s1.run(); s1.eat(); ((Student)s2).eat();//強制轉換(高類型轉成) ,Person裏面沒有eat方法,所以強制轉換成Student去調用 } }
總結一下 :
/* 多態注意事項: 1、多態是方法的多態,屬性沒有多態 2、父類和子類,有聯繫 如不符合:會出現異常ClassCastException! 3、存在條件:①繼承關係②方法需要重寫③父類引用指向子類對象 Father f1 = new Student(); 有些方法不能重寫: ①static靜態,修飾的方法,屬於類,不屬於實例 ②final常量,修飾的 ③private方法: */
3.3.3 instance of和類型轉換
- instance of
public static void main(String[] args) { //Object > String //Object > Person > Student //Object > Person > Teacher Object student2 = new Student(); //instanceof判斷左邊對象是否是右邊類的一個實例 System.out.println(student2 instanceof Student);//看看是不是Student類型呢true System.out.println(student2 instanceof Person);//看看是不是Student類型呢true System.out.println(student2 instanceof Object);//看看是不是Student類型呢true System.out.println(student2 instanceof Teacher);//看看是不是Student類型呢false //因為沒有new:object和Teacher System.out.println(student2 instanceof String);//看看是不是Student類型呢false } } /*總結一波: System.out.println(X instanceof Y);能不能編譯通過取決於X、Y有沒有父子關係 */
- 類型轉換
- 父類
public class Person { public void run(){ System.out.println("run"); } }
- 子類
public class Student extends Person{ public void go(){ System.out.println("go"); } }
- Application類
public class Main3 { public static void main(String[] args) { //父類 子類 //高 低 Person student = new Student(); //student.go();報錯原因:student屬於Person,Person中沒有go //student將這個對象轉換未Student類型,我們就可以使用Student類型的方法了:高往低走 Student student1 = (Student) student;//(Student)student; student1.go(); ((Student)student).go();//前面寫成一句話完成類型轉換 //低 高 //子類轉換為父類,可能回丟失原來自己的方法 Student student2 = new Student(); student2.go(); //把student變成person類型 Person person = student2; //person.go();就用不了了 } }
3.3.4 static關鍵字詳解:com.fenfen.oop.Demo7
- static在屬性上的使用
public class Student { //靜態屬性 private static int age;//靜態的變量 private double score;//非靜態變量
public static void main(String[] args) { student student = new Student(); //用對象輸出 System.out.println(student.score);//student.score.sout //用類輸出 System.out.println(Student.age); //System.out.println(Student.score);沒有static這個就不行 //或者直接輸出 System.out.println(age+"kkkkk"); } }
- static在方法上的使用
public class Student { //靜態方法 public void run(){ } public static void go(){ }
public static void main(String[] args) { Student student = new Student(); //方法調用 //用對象調 student.run(); student.go(); //用類調 Student.go(); //Student.run();沒有static這個就不行:具體原因,現在是靜態方法,只能去調靜態方法的 //直接調 go(); } }
- static在代碼塊、構造器上的運用
public class Person { //代碼塊 { System.out.println("匿名代碼塊兒,一般會根據對象每次都跑,所以會被用來賦予初始值"); } //靜態代碼塊 static { System.out.println("靜態代碼塊兒,這個反而執行的時候是最先的,而且我就跑一次,後面不玩了"); } //構造器 public Person() { System.out.println("構造方法"); } public static void main(String[] args) { Person person1 = new Person(); System.out.println("==============="); Person person2 = new Person(); } }
- static在靜態導入包的使用
package com.fenfen.oop.Demo7; //靜態導入包的方法和常量 import static java.lang.Math.random; import static java.lang.Math.PI; public class Test { public static void main(String[] args) { //System.out.println(Math.random()); 不想怎麼寫可以在前面直接導包,但是記得寫static System.out.println(random()); }
4. 抽象類和接口:com.fenfen.oop.Demo8
4.1 抽象類
4.1.1 抽象對象和方法的建立
public abstract class Action { //約束 //abstrct ,抽象方法,只有方法名字,沒有具體的方法內容實現,並且抽象方法跟抽象類 public abstract void doSomething(); /* 1、不能在這個抽象類new(在main中都不給new,只能靠子類去實現它(重寫? 2、抽象類中可以寫普通的方法 3、抽象方法必須在抽象類中 抽象的抽象:約束 抽象存在的意義: 例如遊戲中,抽象出一定的內容,每創建一個角色就去繼承這個抽象類,直接重寫部分方法,改掉一些不必要的東西即可 */
4.1.2 無法在其他類中new一個抽象類的對象
public class Main { public static void main(String[] args) { // new Action(); 不給new } }
4.1.3重寫抽象的方法
public class A extends Action{ //繼承用了abstract的類會報錯,必須得重寫一下才可以 //抽象類得所有方法,繼承了他的子類,都必須要實現他的方法 @Override public void doSomething() { } }
4.2 接口:com.fenfen.oop.Demo9
4.2.1 創建接口以及基本方法
//接口:用interface // 寫簡單方法,然後有一個對應實現類UserServiceimp public interface UserService { //public void run(){ 此處需要加上abstract不然不給寫方法 //} //接口中的所有定義其實都是抽象的 public abstract的方法 public abstract void run(); void add(String name); void delete(String name); void update(String name); void query(String name); //接口中定義屬性:就是一個常量,很少在接口中定義常量:默認public static final public static final int AGE = 99; } public interface TimeService { void timer(); }
4.2.2 接口對應的實現類
//一個類實現接口 implemnts 接口:可以繼承多個接口 //實現了接口中的類,就需要重寫接口中的方法 public class UserServiceimp implements UserService,TimeService{//可以實現多個接口,實現多繼承 //右擊generate:implement methods或者ctrl+i快捷鍵 @Override public void run() { } @Override public void add(String name) { } @Override public void delete(String name) { } @Override public void update(String name) { } @Override public void query(String name) { } @Override public void timer() { }
5 內部類:com.fenfen.oop.Demo10
5.1 類中類
5.1.1創建內中類
public class Outer { private int id = 10; public void out(){System.out.println("這是外部類的方法");} //類內部類;類中類 public class Inner{ public void in(){System.out.println("這是內部類的方法");} //獲得外部類的私有屬性:外部出現的id = 10 public void getID(){ System.out.println(id); } //可以在內部類Inner前加上static: // 但是會出現:靜態的內部類無法訪問非靜態的內部屬性 } }
5.1.2 實例化並調用類中類
public class Main { public static void main(String[] args) { //new Outer outer = new Outer(); //通過這個外部類來實例化內部類 Outer.Inner inner = outer.new Inner();//outer.new Inner(); inner.in(); inner.getID(); } }
5.2 局部內部類(方法中的類)
public class Outer3 { //方法中的類:叫做局部內部類 public void method(){ class Inner{ public void in(){ } } } }
5.3 匿名內部類
public class Outer4 { public static void main(String[] args) { //一般是Apple apple = new Apple(); //也可以是:沒有名字初始類,不用將實例保存到變量中 new Apple().eat(); //接口重寫下方法 new UserService() //實際寫全是:UserService userService = new UserService() { @Override public void hello() { } }; } } class Apple{ public void eat(){ System.out.println("1"); } } //整一個接口 interface UserService{ void hello(); }
「其他文章」
- RP原型資源分享-購物類App
- 實現各種效果和功能的按鈕,讀這篇文章就夠了
- 5分鐘的時間製作一個反彈球遊戲
- 35歲危機?內捲成程序員代名詞了…
- 在線文本實體抽取能力,助力應用解析海量文本數據
- 不買排名,不去SEO,如何做到登上谷歌搜索首頁?
- HtmlParse:一款超輕量級的HTML文件解析和爬取工具
- 五款當下超火熱的相親交友APP測評
- 盡一份孝心,為家人做一個老人防摔報警系統
- 作為軟件工程師,給年輕時的自己的建議(下)
- 技術分享| 淺談調度平台設計
- 組態界面推陳出新:打造新一代再生水廠工藝二維組態系統
- 平頭哥 芯事訪談 | 全志科技CTO丁然:視頻、AI市場爆發,RISC-V生態需要產業一起努力
- IDEA SSM Maven實現商品管理系統(超詳細SSM整合項目)
- 如何為迴歸測試選擇測試用例?
- 前端必學——函數式編程(五)
- 40篇學完C語言——(第八篇)【指針數組以及指向指針的指針】
- 焱融看|非結構化數據場景下,數據湖到底有多香?
- 低代碼開發的未來~
- Docker容器:將帶UI的程序直接轉為Web應用,so easy