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(); }
「其他文章」
- 5分鐘的時間製作一個反彈球遊戲
- 35歲危機?內捲成程式設計師代名詞了…
- 線上文字實體抽取能力,助力應用解析海量文字資料
- 不買排名,不去SEO,如何做到登上谷歌搜尋首頁?
- HtmlParse:一款超輕量級的HTML檔案解析和爬取工具
- 五款當下超火熱的相親交友APP測評
- 盡一份孝心,為家人做一個老人防摔報警系統
- 作為軟體工程師,給年輕時的自己的建議(下)
- 技術分享| 淺談排程平臺設計
- 組態介面推陳出新:打造新一代再生水廠工藝二維組態系統
- 平頭哥 芯事訪談 | 全志科技CTO丁然:影片、AI市場爆發,RISC-V生態需要產業一起努力
- IDEA SSM Maven實現商品管理系統(超詳細SSM整合專案)
- 如何為迴歸測試選擇測試用例?
- 前端必學——函數語言程式設計(五)
- 40篇學完C語言——(第八篇)【指標陣列以及指向指標的指標】
- 焱融看|非結構化資料場景下,資料湖到底有多香?
- 低程式碼開發的未來~
- Docker容器:將帶UI的程式直接轉為Web應用,so easy
- PHP 基於 SW-X 框架,搭建WebSocket伺服器(二)
- 低程式碼開發的前後端聯調——APICloud Studio 3 API管理工具結合資料雲3.0使用教程