abstract类中不可以有private的成员_别再说你不懂java面向对象了,阿里P7大佬一次性给你讲的明明白白
前言
面向對象在百度百科中是這樣解釋的:“面向對象是一種對現實世界理解和抽象的方法,是計算機編程技術發展到一定階段后的產物”。說的好像很流弊的樣子,看看就行。
包的認識
1.1:包的概念包是組織、整合類的一種方式其目的在于保證使用類的唯一性(同一個包中,里面所包含的類名是唯一的)比如在包A中定義了一個Test類,在包B中也定義了一個Test類,那么當使用A中的Test類時便導入包A調用A中的Test類(A.Test),以此保證類的唯一性。
1.2:導入包中的類Java中有很多現成的包供我們使用,使用這些包的方式有兩種
public class TestDemo { public static void main(String[] args) { java.util.Date time = new java.util.Date(); //使用 util 包中的Date類創建一個對象 System.out.println(time.getTime()); //調用該對象的 getTime 方法,獲得一個毫秒級別的時間戳 }}上述代碼中,util 就是一個包,Date就是該包中的一個類,使用時用 java.包名.類名 使用
import java.util.Date;public class TestDemo { public static void main(String[] args) { Date time = new Date(); System.out.println(time.getTime()); }第一個代碼每次使用類時都要加包的前綴,太過麻煩,因此還可使用第二種方式,在代碼最開頭使用 import 關鍵字導入需要的包,這樣就可以像使用自己定義的類一樣,直接用類名創建對象當同時需要同一個包中的多個類是,可以用 import.java.包名.* 的方式導入包,這樣就可以使用該包下的所有類(但建議不要這么使用,否則當導入多個包時還是會出現類名重復的現象)。
1.3:靜態導入包中除了類的普通方法外,還有一些靜態方法,使用這些方法時,可以使用 import static 的方式導入包中的靜態字段和方法,無需創建對象直接使用
import static java.lang.Math.*;public class TestDemo { public static void main(String[] args) { double x = 10.5; double y = 3.0; double result = sqrt(pow(x,y)+pow(x,y)); System.out.println(result); }1.4:自定義類放入包中基本規則
- 在文件的最上方加一個 package 語句指定該代碼在哪個包中
- 包名盡量指定成唯一名字,防止多文件間沖突
- 包名和代碼路徑相匹配
- 如果一個類沒有 package 語句,則該類會被放到默認包中
1.5:包的訪問權限控制如果某個成員不包含 public 和 private 關鍵字,此時這個成員可以被包中的其他類使用,但不能在包外部類中使用
1.6:常見的系統包1、java.lang:系統常用基礎類(String,Object),jdk1.1以后自動導入2、java.lang.reflect: java 反射編程包3、java.net:進行網絡編程開發包4、java.sql:進行數據庫開發的支持包。5、java.util:是java提供的工具程序包。(集合類等)6、java.io:I/O編程開發包。
繼承
2.1 概念:當創建多個類時發現這些類之間存在一定的關聯關系,則可以創建一個父類擁有這些類的相同屬性和方法,讓這些類繼承與父類,來提高效率,達到代碼重用的效果。此時被繼承的類我們成為 父類、基類或者超類,而繼承的類我們稱為子類或者派生類,子類會繼承父類除構造方法外的其他所有東西。2.2 語法規則:class 子類 extend 父類{
}
- 子類使用 extend 關鍵字繼承父類
- Java中一個子類只能繼承一個父類
- 子類會繼承父類的所有 public 的字段和方法
- 對于父類的 private 的字段和方法,子類無法訪問
- 子類實例中也包含父類實例,可使用 super 關鍵字得到父類的引用
2.3、protected關鍵字上述代碼中,如果將父類的 name 設為 private子類將無法訪問,但設為 public 又違背了封裝的規則,此時就需要用到 protect 關鍵字
- 對于其他類的調用者來說,被 protect 修飾的字段和方法是不能被訪問的
- 但對于 該類的子類 和 同一個包下的其他類 來說,被 protect 修飾的字段和方法是可以被訪問的
小結:Java中對字段和方法共有四種訪問權限
- private:只能在類內部訪問,內外部一律不行
- 默認:在類內部能訪問,同一個包中的類也可以訪問
- protect:在類內部能訪問,且在其子類和同一個包中的類也可以訪問
- public:類內部和類的調用者都能訪問
2.4、final關鍵字final 可以修飾一個變量或者字段,用來表示常量final 也惡意修飾一個類,用來表現該類不能被繼承組合:即一個類中對另一個類的嵌套,在一個類中實例另一個類,達到代碼重用的效果
多態
3.1、向上轉型:如上代碼,創建一個 Bird 的對象可以寫成
Bird bird = new Bird();也可以寫成
Bird bird = new Bird();Animal bird2 = bird;Animal bird3 = new Bird();此時bird2、bird3是一個父類(Animal)的引用,指向子類(bird)的實例,這稱為向上轉型。向上轉型發生的時機:
- 直接賦值(即上述代碼演示)
- 方法傳參
- 方法返回
方法傳參:
public static void main(String[] args) { Bird bird = new Bird("啾啾"); feed(bird);}public static void feed(Animal animal){ animal.eat("谷子");}此時形參的類型是 Animal(父類) ,實際上是對應到 Bird(子類)的實例
方法返回:
public static void main(String[] args) { findAnimal().eat("谷子");}public static Animal findAnimal(){ Bird bird = new Bird("啾啾"); return bird;}方法 findAnimal 返回值是 Animal 的一個引用,但實際指向 Bird 的一個實例
3.2:動態綁定子類和父類出現同名方法時發生
class Animal{ public String name; public Animal(String name) { this.name = name; } public void eat(String food){ System.out.println("我是一只小動物"); System.out.println(this.name+"正在吃"+food); }}class Bird extends Animal{ public Bird(String name){ super(name); } public void eat(String food){ System.out.println("我是一只小鳥"); System.out.println(this.name+"正在吃"+food); } public void fly(){ System.out.println(this.name+"正在飛"); }}public class TestDemo { public static void main(String[] args) { Animal animal1 = new Animal("動物"); Animal animal2 = new Bird("小鳥"); animal1.eat("谷子"); animal2.eat("谷子"); }執行以上代碼我們發現:
- animal1 和 animal2 雖然都是 Animal 類型的引用,但animal1指向 Animal 實例的對象,animal2指向 Bird 實例的對象
- 對 animal1 和 animal2 分別調用eat方法,發現 animal1 調用的是父類的方法,animal2 調用的是子類的方法
在Java中,調用某個方法,究竟執行哪段代碼(是父類方法還是子類),取決于看這個引用指向的對象是父類對象還是子類對象,這個過程是在運行時才決定的,因此成為動態綁定父類引用,引用子類對象時,只能訪問自己特有的,不能訪問子類獨有的
3.3、重寫對于上述代碼,父類和子類的eat方法來說,就構成了重寫重寫的注意事項:
- 普通方法可以重寫,static 修飾的方法不能重寫
- 重寫中子類的訪問權限不能低于父類的訪問權限
- 重寫和重載不同
重寫和重載的區別
1.要求不同重載:a.方法名相同 b.參數列表不同 c.返回值不做要求重寫:a.方法名相同 b.參數列表相同(參數類型和個數) c.返回值也要相同2.范圍不同重載:同一個類中重寫:繼承關系,不同類中3.限制重載:無限制重寫:子類中重寫的方法訪問權限不能低于父類的訪問權限
3.4、理解多態
class Shape { public void draw(){ }}class Circle extends Shape{ public void draw(){ System.out.println("畫一個圓圈○"); }}class Rectangle extends Shape{ public void draw(){ System.out.println("畫一個矩形□"); }}class Triangle extends Shape{ public void draw(){ System.out.println("畫一個三角△"); }}//================================================//================================================public class TestDemo { public static void main(String[] args) { Shape shape1 = new Circle(); Shape shape2 = new Rectangle(); Shape shape3 = new Triangle(); drawMap(shape1); drawMap(shape2); drawMap(shape3); } public static void drawMap(Shape shape){ shape.draw(); }以上代碼,分割線以上是由類的實現者編寫的,分割線以下是由類的調用者編寫的當調用者編寫drawMap方法的時候(參數類型為父類Shape),并不關心當前shape引用指向哪個類型的實例,此時shape調用的draw方法只取決于shape指向的哪個類型的實例,以實現不同的表現形式,這種思想叫做多態。
3.5、向下轉型父類引用,引用子類對象稱為向上轉型;子類引用,引用父類對象稱為向下轉型。
class Animal{ public String name; public Animal(String name) { this.name = name; } public void eat(String food){ System.out.println("我是一只小動物"); System.out.println(this.name+"正在吃"+food); }}ass Bird extends Animal{ public Bird(String name){ super(name); } public void eat(String food){ System.out.println("我是一只小鳥"); System.out.println(this.name+"正在吃"+food); } public void fly(){ System.out.println(this.name+"正在飛"); }} public class TestDemo { public static void main(String[] args) { Animal animal = new Bird("啾啾"); animal.eat("谷子"); animal.fly();//執行該行代碼時,會報錯誤 }編譯過程中 animal 的類型時 Animal ,編譯器編譯時根據類型只知道 animal 中只有一個eat方法,找不到fly方法
- 編譯器檢查存在哪些方法時候,看的是 Animal 類型
- 執行時究竟執行父類方法還是子類方法,看的是 Bird 類型
但很多時候為了讓向下轉型更安全,需要判斷一下 animal 是否指向 Bird 的引用,使用instanceof 關鍵字判斷
3.6、super關鍵字當在子類內部要調用父類方法時,就要用到 super 關鍵字super 表示獲取到父類實例的引用,其有兩種常用方法
一、使用 super 來調用父類的構造方法,super(參數)
public Bird(String name){ super(name);}二、使用 super 來調用父類的普通方法,super.方法名(參數)
class Bird extends Animal{ public Bird(String name){ super(name); } public void eat(String food){ super.eat(food); System.out.println("我是一只小鳥"); System.out.println(this.name+"正在吃"+food); }}上述代碼中個,如果直接調用eat方法,則被編譯器認為是調用子類的方法(同遞歸),想要調用父類方法則需要使用 super 關鍵字
this和super的區別:
1、概念this:訪問本類的屬性和方法super:訪問父類的屬性和方法2、查找范圍this:先查找本類,子類沒有再調用父類super:不查找本類,直接調用父類3、特殊this:表示當前對象的引用super:表現父類對象的引用
多態存在的意義就在于,讓調用者不必關注對象的具體類型,降低用戶的使用成本
4、抽象類
4.1語法規則類似于之前代碼的父類 Shape 中的draw方法,其中并沒有實際工作,而由其子類重新該方法實現,那么像這種沒有實際工作的方法我們就可以用 abstract 關鍵字修飾把它設計成一個抽象方法,而包含抽象方法的類我們就稱為抽象類
abstract class Shape { abstract public void draw();}- 在draw方法前加一個 abstract 修飾表示該方法是抽象方法,抽象方法沒有方法體
- 對于包含抽象方法的類,class 前必須加一個 abstract 關鍵字表示是抽象類
注意事項:
- 抽象類不能直接實例
- 抽象方法的訪問權限不能是private
- 抽象類中可以包含其他非抽象方法,也可以包含字段,和普通方法一樣,可以被重新可以被調用
4.2抽象類的作用抽象類的意義在于為了被繼承抽象類本身不能實例化,想要使用,必須創建該抽象類的子類,在子類中重寫抽象方法使用抽象類相當于多了一重編譯器的檢驗(對于抽象了來說,如果繼承的子類不重寫父類的抽象方法,則會報錯)
5、接口
接口是比抽象類還抽象,接口只包含抽象方法,其字段也只能包含靜態常量
interface IShape{ abstract public void draw();}class Circle implements Shape{ @Override public void draw() { System.out.println(); }}- 用 interface 定義一個接口
- 接口中的方法只能是抽象方法,所以可以省略 abstract
- 并且接口中的方法只能是 public ,所以可以省略
- Circle 用 implement 來實現接口
- 在調用的時候同樣可以創建一個接口的引用,對應到一個子類的實例
- 接口不能被單獨實例化
在Java中一個類只能繼承一個父類,但同時可以實現多個接口
class Animal{ public String name; public Animal(String name){ this.name = name; }}interface IFlying{ void fly();}interface IRunning{ void run();}interface ISwimming{ void swim();}class Dog extends Animal implements IRunning{ public Dog(String name){ super(name); } @Override public void run() { System.out.println(this.name+"正在跑步"); }}class Frog extends Animal implements IRunning,ISwimming{ public Frog(String name){ super(name); } @Override public void run() { System.out.println(this.name+"正在跑步"); } @Override public void swim() { System.out.println(this.name+"正在游泳"); }}class Duck extends Animal implements IRunning,ISwimming,IFlying{ public Duck(String name){ super(name); } @Override public void fly() { System.out.println(this.name+"正在飛"); } @Override public void run() { System.out.println(this.name+"正在游泳"); } @Override public void swim() { System.out.println(this.name+"正在游泳"); }}public class TestDemo { public static void main(String[] args) { Dog dog = new Dog("汪汪"); Frog frog = new Frog("呱呱"); Duck duck = new Duck("嘎嘎"); dog.run(); frog.run(); frog.swim(); duck.fly(); duck.run(); }}接口使用實例——給對象數組排序創建一個學生類
class Students implements Comparable{ private String name; private int score; public Students(String name, int score) { this.name = name; this.score = score; } @Override public String toString() { return "Students{" + "name='" + name + ''' + ", score=" + score + '}'; } @Override public int compareTo(Object o) { Students s = (Students)o; if(s.score > ((Students) o).score){ return 1; }else if(s.score == ((Students) o).score){ return 0; }else{ return -1; } }}在 sort 方法中會自動調用 compareTo 方法.compareTo 的參數是 Object,其實傳入的就是Students類型的對象,然后比較當前對象和參數對象的大小關系
接口間的承接一個接口可以承接另一個接口,達到復用效果,使用 extends 關鍵字接口間承接相當于把多個接口憑借在一起
Clonable 接口和深拷貝Object 類中存在一個 clone 方法,調用這個方法可以創建一個對象的“拷貝”,但是想要合法的調用clone方法,必須先要實現 Clonable 接口,否則就會拋出 CloneNotSupportedException 異常
class Person implements Cloneable{ public String name; public Person(String name) { this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Person{" + "name='" + name + ''' + '}'; }}public class TestDemo { public static void main(String[] args) throws CloneNotSupportedException { Person person1 = new Person("小明"); Person person2 = (Person) person1.clone(); person2.name = "小紅"; System.out.println(person1); System.out.println(person2); }}如下代碼即深拷貝:
class Money implements Cloneable{ public int m=10; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }}class Person implements Cloneable{ public String name; public Money money ; public Person(String name) { this.name = name; this.money = new Money(); } @Override protected Object clone() throws CloneNotSupportedException { Person person = (Person) super.clone(); person.money = (Money) this.money.clone(); return person; } @Override public String toString() { return "Person{" + "name='" + name + ''' + ", money=" + money.m + '}'; }}public class TestDemo { public static void main(String[] args) throws CloneNotSupportedException { Person person1 = new Person("小明"); Person person2 = (Person) person1.clone(); person2.name = "小紅"; person2.money.m = 15; System.out.println(person1); System.out.println(person2); }}總結
- 抽象類和接口都是Java中多態的常見使用方法,但兩者又有區別
最核心區別:抽象類可以包含普通方法和普通字段,可以被子類直接使用,而接口中只有抽象方法,實現該接口的類必須重寫所有抽象方法
最后
感謝你看到這里,看完有什么的不懂的可以在評論區問我,覺得文章對你有幫助的話記得給我點個贊,每天都會分享java相關技術文章或行業資訊,歡迎大家關注和轉發文章!
總結
以上是生活随笔為你收集整理的abstract类中不可以有private的成员_别再说你不懂java面向对象了,阿里P7大佬一次性给你讲的明明白白的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab和python哪个好学_py
- 下一篇: dnf剑魂buff等级上限_剑魂完美换装