JAVA學(xué)習(xí)筆記_面向?qū)ο?/h1>
1. 面向?qū)ο?/h2>
1.1 面向?qū)ο蟮乃枷?/h3>
-
概述
Java語言是一種面向?qū)ο蟮某绦蛟O(shè)計(jì)語言,而面向?qū)ο笏枷胧且环N程序設(shè)計(jì)思想,我們?cè)诿嫦驅(qū)ο笏枷氲闹敢?,使用Java語言去設(shè)計(jì)、開發(fā)計(jì)算機(jī)程序。 這里的對(duì)象泛指現(xiàn)實(shí)中一切事物,每種事物都具備自己的屬性和行為。面向?qū)ο笏枷刖褪窃谟?jì)算機(jī)程序設(shè)計(jì)過程中,參照現(xiàn)實(shí)中事物,將事物的屬性特征、行為特征抽象出來,描述成計(jì)算機(jī)事件的設(shè)計(jì)思想。 它區(qū)別于面向過程思想,強(qiáng)調(diào)的是通過調(diào)用對(duì)象的行為來實(shí)現(xiàn)功能,而不是自己一步一步的去操作實(shí)現(xiàn)。
面向過程:強(qiáng)調(diào)步驟。
面向?qū)ο螅簭?qiáng)調(diào)對(duì)象,這里的對(duì)象就是洗衣機(jī)
-
三大特征:
- 繼承
- 封裝
- 多態(tài)
1.1 面向?qū)ο蟮乃枷?/h3>
-
概述
Java語言是一種面向?qū)ο蟮某绦蛟O(shè)計(jì)語言,而面向?qū)ο笏枷胧且环N程序設(shè)計(jì)思想,我們?cè)诿嫦驅(qū)ο笏枷氲闹敢?,使用Java語言去設(shè)計(jì)、開發(fā)計(jì)算機(jī)程序。 這里的對(duì)象泛指現(xiàn)實(shí)中一切事物,每種事物都具備自己的屬性和行為。面向?qū)ο笏枷刖褪窃谟?jì)算機(jī)程序設(shè)計(jì)過程中,參照現(xiàn)實(shí)中事物,將事物的屬性特征、行為特征抽象出來,描述成計(jì)算機(jī)事件的設(shè)計(jì)思想。 它區(qū)別于面向過程思想,強(qiáng)調(diào)的是通過調(diào)用對(duì)象的行為來實(shí)現(xiàn)功能,而不是自己一步一步的去操作實(shí)現(xiàn)。
面向過程:強(qiáng)調(diào)步驟。
面向?qū)ο螅簭?qiáng)調(diào)對(duì)象,這里的對(duì)象就是洗衣機(jī)
-
三大特征:
- 繼承
- 封裝
- 多態(tài)
概述
Java語言是一種面向?qū)ο蟮某绦蛟O(shè)計(jì)語言,而面向?qū)ο笏枷胧且环N程序設(shè)計(jì)思想,我們?cè)诿嫦驅(qū)ο笏枷氲闹敢?,使用Java語言去設(shè)計(jì)、開發(fā)計(jì)算機(jī)程序。 這里的對(duì)象泛指現(xiàn)實(shí)中一切事物,每種事物都具備自己的屬性和行為。面向?qū)ο笏枷刖褪窃谟?jì)算機(jī)程序設(shè)計(jì)過程中,參照現(xiàn)實(shí)中事物,將事物的屬性特征、行為特征抽象出來,描述成計(jì)算機(jī)事件的設(shè)計(jì)思想。 它區(qū)別于面向過程思想,強(qiáng)調(diào)的是通過調(diào)用對(duì)象的行為來實(shí)現(xiàn)功能,而不是自己一步一步的去操作實(shí)現(xiàn)。
面向過程:強(qiáng)調(diào)步驟。
面向?qū)ο螅簭?qiáng)調(diào)對(duì)象,這里的對(duì)象就是洗衣機(jī)
三大特征:
- 繼承
- 封裝
- 多態(tài)
實(shí)例:輸出數(shù)組
package cn.itcast.day06.demo01;
import java.util.Arrays; // 導(dǎo)入Arrays類
public class Demo01PrintArray {
public static void main(String[] args) {
int[] array = { 10, 20, 30, 40, 50, 60 };
// 要求打印格式為:[10, 20, 30, 40, 50]
// 使用面向過程,每一個(gè)步驟細(xì)節(jié)都要親力親為。
System.out.print("[");
for (int i = 0; i < array.length; i++) {
if (i == array.length - 1) { // 如果是最后一個(gè)元素
System.out.println(array[i] + "]");
} else { // 如果不是最后一個(gè)元素
System.out.print(array[i] + ", ");
}
}
System.out. println("==============");
// 使用面向?qū)ο? // 找一個(gè)JDK給我們提供好的Arrays類,
// 其中有一個(gè)toString方法,直接就能把數(shù)組變成想要的格式的字符串
System.out.println(Arrays.toString(array));
}
}
- 特點(diǎn): 特點(diǎn)面向?qū)ο笏枷胧且环N更符合我們思考習(xí)慣的思想,它可以將復(fù)雜的事情簡(jiǎn)單化,并將我們從執(zhí)行者變成了指揮者。面向?qū)ο蟮恼Z言中,包含了三大基本特征,即封裝、繼承和多態(tài) 。
1.2 類和對(duì)象
-
什么是類:
- 類:是一組相關(guān)屬性和行為的集合??梢钥闯墒且活愂挛锏哪0?,使用事物的屬性特征和行為特征來描述該類事物。
- 現(xiàn)實(shí)中,描述一類事物:
- 屬性:就是該事物的狀態(tài)信息。
- 行為:就是該事物能夠做什么。
-
什么是對(duì)象:
? 一類事物的具體體現(xiàn)。對(duì)象是類的一個(gè)實(shí)例,必然具備該類事物的屬性和行為。
-
類與對(duì)象的關(guān)系 :
- 類是對(duì)一類事物的描述,是抽象的。
- 對(duì)象是一類事物的實(shí)例,是具體的。
- 類是對(duì)象的模板,對(duì)象是類的實(shí)體。
1.3 類的定義
- 屬性:事物的狀態(tài)信息。
- 行為:事物能夠做什么。
public class ClassName {
//成員變量
//成員方法
}
- 定義類:就是定義類的成員,包括成員變量和成員方法。
- 成員變量:和以前定義變量幾乎是一樣的。只不過位置發(fā)生了改變。在類中,方法外。
- 成員方法:把
static去掉
定義一個(gè)Student類:
public class Student {
// 成員變量
String name; // 姓名
int age; // 姓名
// 成員方法
public void eat() {
System.out.println("吃飯飯!");
}
public void sleep() {
System.out.println("睡覺覺!");
}
public void study() {
System.out.println("學(xué)習(xí)!");
}
}
成員變量(屬性):
String name; // 姓名
int age; // 年齡
成員方法(行為):
public void eat() {} // 吃飯
public void sleep() {} // 睡覺
public void study() {} // 學(xué)習(xí)注意事項(xiàng):
- 成員變量是直接定義在類當(dāng)中的,在方法外邊。
- 成員方法不要寫
static關(guān)鍵字。
1.4 類的對(duì)象的創(chuàng)建和使用
- 創(chuàng)建的一個(gè)Student的對(duì)象
public class Student {
public static void main(String[] args) {
// 1. 導(dǎo)包。
import XXX.XXX.Student;
// 2. 創(chuàng)建,格式:
// 類名稱 對(duì)象名 = new 類名稱();
Student stu = new Student(); // 根據(jù)Student類,創(chuàng)建了一個(gè)名為stu的對(duì)象
// 3. 使用其中的成員變量,格式:
// 對(duì)象名.成員變量名
System.out.println(stu.name); // null
System.out.println(stu.age); // 0
System.out.println("=============");
// 改變對(duì)象當(dāng)中的成員變量數(shù)值內(nèi)容
// 將右側(cè)的字符串,賦值交給stu對(duì)象當(dāng)中的name成員變量
stu.name = "小明";
stu.age = 18;
System.out.println(stu.name); // 小明
System.out.println(stu.age); // 18
System.out.println("=============");
// 4. 使用對(duì)象的成員方法,格式:
// 對(duì)象名.成員方法名()
stu.eat();
stu.sleep();
stu.study();
}
}
- 導(dǎo)包:也就是指出需要使用的類,在什么位置。
import 包名稱.類名稱;
對(duì)于和當(dāng)前類屬于同一個(gè)包的情況,可以省略導(dǎo)包語句不寫。- 創(chuàng)建,格式:
類名稱 對(duì)象名 = new 類名稱();
Student stu = new Student();- 使用,分為兩種情況:
使用成員變量:對(duì)象名.成員變量名
使用成員方法:對(duì)象名.成員方法名(參數(shù))注意事項(xiàng):
如果成員變量沒有進(jìn)行賦值,那么將會(huì)有一個(gè)默認(rèn)值,規(guī)則和數(shù)組一樣。
1.5成員變量和局部變量的區(qū)別
在類中的位置不一樣
成員變量:類中,方法外
局部變量:方法中或者方法聲明上(形式參數(shù))
-
作用的范圍不一樣
- 成員變量:類中
- 局部變量:方法中
-
**初始化值的不同 **
- 成員變量:有默認(rèn)值
- 局部變量:沒有默認(rèn)值。必須先定義,賦值,最后使用
-
**在內(nèi)存中的位置不同 **
- 成員變量:堆內(nèi)存
- 局部變量:棧內(nèi)存
-
**生命周期不同 **
- 成員變量:隨著對(duì)象的創(chuàng)建而存在,隨著對(duì)象的消失而消失
- 局部變量:隨著方法的調(diào)用而存在,隨著方法的調(diào)用完畢而消失
1.6 內(nèi)部類
內(nèi)部類就是一個(gè)類里面還包含另一個(gè)類
分類:
- 成員內(nèi)部類
- 局部?jī)?nèi)部類(包含匿名內(nèi)部類)
1.6.1 內(nèi)部類的格式
-
成員內(nèi)部類
格式:
修飾符 class 外部類名稱 { 修飾符 class 內(nèi)部類名稱 { // ... } // ... }注意:內(nèi)用外,隨意訪問;外用內(nèi),需要內(nèi)部類對(duì)象。
-
局部?jī)?nèi)部類
如果一個(gè)類是定義在一個(gè)方法內(nèi)部的,那么這就是一個(gè)局部?jī)?nèi)部類。只有當(dāng)前所屬的方法才能使用它,出了這個(gè)方法外面就不能用了。
格式:
修飾符 class 外部類名稱 { 修飾符 返回值類型 外部類方法名稱(參數(shù)列表) { class 局部?jī)?nèi)部類名稱 { // ... } } } -
類的權(quán)限修飾符(能否使用)
修飾符 外部類 成員內(nèi)部類 局部?jī)?nèi)部類 public Y Y N protected Y Y N default N Y N private N Y N
1.6.2 內(nèi)部類使用
成員內(nèi)部類的使用
-
兩種方法
-
間接方式:
在外部類的方法當(dāng)中,使用內(nèi)部類;然后main只是調(diào)用外部類的方法。
-
直接方法:
外部類名稱.內(nèi)部類名稱 對(duì)象名 = new 外部類名稱().new 內(nèi)部類名稱(); //或 如果內(nèi)部類使用Static修飾則可使用這種方式去創(chuàng)建內(nèi)部類的對(duì)象 外部類名稱.內(nèi)部類名稱 對(duì)象名 = new 外部類名稱.內(nèi)部類名稱();
例如:
public class Car { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public void methodCar() { System.out.println("外部Car的方法"); // 調(diào)用內(nèi)部類的方法 Engine engine = new Engine(); engine.methodEngine(); } // 定義一個(gè)內(nèi)部類 public static class Engine { // 內(nèi)部類的方法 public void methodEngine() { System.out.println("發(fā)動(dòng)機(jī)點(diǎn)火"); } } } -
局部?jī)?nèi)部類的使用
局部?jī)?nèi)部類,只有當(dāng)前所屬的方法才能使用它。
注意:
局部?jī)?nèi)部類,如果希望訪問所在方法的局部變量,那么這個(gè)局部變量必須是【有效
final的】。備注:從Java 8+開始,只要局部變量事實(shí)不變,那么final關(guān)鍵字可以省略。
原因:
- new出來的對(duì)象在堆內(nèi)存當(dāng)中。
- 局部變量是跟著方法走的,在棧內(nèi)存當(dāng)中。
- 方法運(yùn)行結(jié)束之后,立刻出棧,局部變量就會(huì)立刻消失。
- 但是new出來的對(duì)象會(huì)在堆當(dāng)中持續(xù)存在,直到垃圾回收消失。
1.6.3 * 匿名內(nèi)部類
匿名內(nèi)部類是為了省略接口的實(shí)現(xiàn)類,直接使用new來重寫接口的抽象方法。
格式:
接口名稱 對(duì)象名 = new 接口名稱() {
// 覆蓋重寫所有抽象方法
};
public class Demo03AnonymityClass {
public static void main(String[] args) {
MyInterface myInterface = new MyInterface() {
@Override
public void method() {
System.out.println("匿名類重寫抽象方法");
}
};
myInterface.method();
}
}
注意事項(xiàng):
- 匿名內(nèi)部類,在【創(chuàng)建對(duì)象】的時(shí)候,只能使用唯一一次。
- 匿名對(duì)象,在【調(diào)用方法】的時(shí)候,只能調(diào)用唯一一次。
- 匿名內(nèi)部類是省略了【實(shí)現(xiàn)類/子類名稱】,但是匿名對(duì)象是省略了【對(duì)象名稱】
2. 面向?qū)ο筇卣鳌庋b
2.1封裝的概念
面向?qū)ο缶幊陶Z言是對(duì)客觀世界的模擬,客觀世界里成員變量都是隱藏在對(duì)象內(nèi)部的,外界無法直接操作和修改。封裝可以被認(rèn)為是一個(gè)保護(hù)屏障,防止該類的代碼和數(shù)據(jù)被其他類隨意訪問。要訪問該類的數(shù)據(jù),必須通過指定的方式。適當(dāng)?shù)姆庋b可以讓代碼更容易理解與維護(hù),也加強(qiáng)了代碼的安全性。
2.2 封裝的關(guān)鍵字——private
private的含義:
private是一個(gè)權(quán)限修飾符,代表最小權(quán)限。
可以修飾成 員變量和成員方法。
被private修飾后的成員變量和成員方法,只在本類中才能訪問。
-
private的使用格式private 數(shù)據(jù)類型 變量名 ; -
**使用
private修飾成員變量,代碼如下 **public class Student { private String name; private int age; }注: 使用了
private本類可以直接訪問,但是在類外無法直接進(jìn)行訪問 -
使用
setXxx方法、getXxx訪問間接訪問private的成員變量public class Student { private String name; private int age; public void setName(String n) { name = n; } public String getName() { return name; } public void setAge(int a) { age = a; } public int getAge() { return age; } }注:必須叫setXxx或者是getXxx命名規(guī)則。
對(duì)于Getter來說,不能有參數(shù),返回值類型和成員變量對(duì)應(yīng);
對(duì)于Setter來說,不能有返回值,參數(shù)類型和成員變量對(duì)應(yīng)。 -
對(duì)于
boolean類型的private成員變量的Getter方法public class Person { private boolean male; //性別 public void setMale(boolean male) { this.male = male; } public boolean isMale() { return male; } }
2.3封裝優(yōu)化——this關(guān)鍵字
this的使用:
public class Person {
String name; // 我自己的名字
// 參數(shù)name是對(duì)方的名字
// 成員變量name是自己的名字
public void sayHello(String name) {
System.out.println(name + ",你好。我是" + this.name);
System.out.println(this);
}
}
當(dāng)方法的局部變量和類的成員變量重名的時(shí)候,根據(jù)“就近原則”,優(yōu)先使用局部變量。
如果需要訪問本類當(dāng)中的成員變量,需要使用格式:
this.成員變量名
通過誰調(diào)用的方法,誰就是this。
2.4 封裝優(yōu)化——構(gòu)造方法
構(gòu)造方法是專門用來創(chuàng)建對(duì)象的方法,當(dāng)我們通過關(guān)鍵字new來創(chuàng)建對(duì)象時(shí),其實(shí)就是在調(diào)用構(gòu)造方法。
-
格式:
public 類名稱(參數(shù)類型 參數(shù)名稱) { 方法體 }package cn.fate.java_learn.basic.Class; import javax.xml.namespace.QName; public class Student { private String name; private int age; public void setName(String name) { this.name = name; } public String getName() { return name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Student() { System.out.println("無參數(shù)構(gòu)造方法"); } public Student(String name, int age) { System.out.println("帶參數(shù)的構(gòu)造方法"); this.name = name; this.age = age; } public void show() { System.out.println("我叫:" + name + ",年齡:" + age); } }注:
- 構(gòu)造方法的名稱必須和所在的類名稱完全一樣,就連大小寫也要一樣。
- 構(gòu)造方法不要寫返回值類型、void都不寫。
- 構(gòu)造方法不能
return一個(gè)具體的返回值。 - 如果沒有編寫任何構(gòu)造方法,那么編譯器將會(huì)默認(rèn)贈(zèng)送一個(gè)構(gòu)造方法,沒有參數(shù)、方法體什么事情都不做。
public Student() {} - 一旦編寫了至少一個(gè)構(gòu)造方法,那么編譯器將不再贈(zèng)送。
- 構(gòu)造方法也是可以進(jìn)行重載的。 重載:方法名稱相同,參數(shù)列表不同。
2.5 標(biāo)準(zhǔn)代碼——JavaBean
一個(gè)標(biāo)準(zhǔn)的類通常要擁有下面四個(gè)組成部分:
- 所有的成員變量都要使用private關(guān)鍵字修飾
- 為每一個(gè)成員變量編寫一對(duì)兒Getter/Setter方法
- 編寫一個(gè)無參數(shù)的構(gòu)造方法
- 編寫一個(gè)全參數(shù)的構(gòu)造方法
這樣標(biāo)準(zhǔn)的類也叫做Java Bean
- 編寫一個(gè)標(biāo)準(zhǔn)的類
package cn.fate.java_learn.basic.Class;
public class StandardStudent {
private String name;
private int age;
private boolean Male;
public StandardStudent() {
}
public StandardStudent(String name, int age, boolean male) {
this.name = name;
this.age = age;
Male = male;
}
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 boolean isMale() {
return Male;
}
public void setMale(boolean male) {
Male = male;
}
}
注 :
IDEA可以使用快捷鍵Alt+Insert快速生成Getter、Setter 及構(gòu)造方法
2.6 匿名對(duì)象
創(chuàng)建對(duì)象的標(biāo)準(zhǔn)格式:
類名稱 對(duì)象名 = new 類名稱();匿名對(duì)象就是只有右邊的對(duì)象,沒有左邊的名字和賦值運(yùn)算符。
new 類名稱();
注意事項(xiàng):匿名對(duì)象只能使用唯一的一次,下次再用不得不再創(chuàng)建一個(gè)新對(duì)象。
使用建議:如果確定有一個(gè)對(duì)象只需要使用唯一的一次,就可以用匿名對(duì)象。
import java.util.Scanner;
public class DemoAnonymous {
public static void main(String[] args) {
methodParam(new Scanner(System.in));
Scanner sc = methodReturn();
int num = sc.nextInt();
System.out.println("Input num is" + num);
methodParam(new Scannner); // 匿名對(duì)象充當(dāng)參數(shù)
}
public static void methodParam(Scanner sc){
int num = sc.nextInt();
System.out.printf("Input num is % d\n", num);
}
public static Scanner methodReturn(){
return new Scanner(System.in); // 返回匿名對(duì)象
}
}
3. 面向?qū)ο筇卣鳌^承
3.1 繼承的概念
繼承是java面向?qū)ο缶幊碳夹g(shù)的一塊基石,因?yàn)樗试S創(chuàng)建分等級(jí)層次的類。
繼承就是子類繼承父類的特征和行為,使得子類對(duì)象(實(shí)例)具有父類的實(shí)例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為。
3.2 類的繼承格式
在 Java 中通過 extends 關(guān)鍵字可以申明一個(gè)類是從另外一個(gè)類繼承而來的,一般形式如下:
class 父類 {
}
class 子類 extends 父類 {
}
3.3 繼承中的成員變量的關(guān)系
父子類的繼承關(guān)系當(dāng)中,如果成員變量重名,則創(chuàng)建子類對(duì)象時(shí),訪問有兩種方式:
直接通過子類對(duì)象訪問成員變量:
等號(hào)左邊是誰,就優(yōu)先用誰,沒有則向上找。間接通過成員方法訪問成員變量:
該方法屬于誰,就優(yōu)先用誰,沒有則向上找。當(dāng)出現(xiàn)三種情況時(shí)的調(diào)用關(guān)系:
- 局部變量:
直接寫成員變量名- 本類的成員變量:
this.成員變量名- 父類的成員變量:
super.成員變量名注意事項(xiàng):
無論是成員方法還是成員變量,如果沒有都是向上找父類,絕對(duì)不會(huì)向下找子類的
// 父類
public class Fu {
int num = 10;
}
// 子類
public class Zi extends Fu {
int num = 20;
public void method() {
int num = 30;
System.out.println(num); // 30,局部變量
System.out.println(this.num); // 20,本類的成員變量
System.out.println(super.num); // 10,父類的成員變量
}
}
3.4 重寫(Override)
重寫(Override)
概念:在繼承關(guān)系當(dāng)中,方法的名稱一樣,參數(shù)列表也一樣。
重寫(Override):方法的名稱一樣,參數(shù)列表【也一樣】。覆蓋、覆寫。
重載(Overload):方法的名稱一樣,參數(shù)列表【不一樣】。方法的覆蓋重寫特點(diǎn):創(chuàng)建的是子類對(duì)象,則優(yōu)先用子類方法。
方法覆蓋重寫的注意事項(xiàng):
必須保證父子類之間方法的名稱相同,參數(shù)列表也相同。
@Override:寫在方法前面,用來檢測(cè)是不是有效的正確覆蓋重寫。
這個(gè)注解就算不寫,只要滿足要求,也是正確的方法覆蓋重寫。子類方法的返回值必須【小于等于】父類方法的返回值范圍。
小擴(kuò)展提示:java.lang.Object類是所有類的公共最高父類(祖宗類),java.lang.String**就是Object的子類。子類方法的權(quán)限必須【大于等于】父類方法的權(quán)限修飾符。
小擴(kuò)展提示:public > protected > (default) > private
備注:(default)不是關(guān)鍵字default,而是什么都不寫,留空。
3.5 構(gòu)造方法的訪問特點(diǎn)
繼承關(guān)系中,父子類構(gòu)造方法的訪問特點(diǎn):
- 子類構(gòu)造方法當(dāng)中有一個(gè)默認(rèn)隱含的“
super()”調(diào)用,所以一定是先調(diào)用的父類構(gòu)造,后執(zhí)行的子類構(gòu)造。- 子類構(gòu)造可以通過
super關(guān)鍵字來調(diào)用父類重載構(gòu)造。super的父類構(gòu)造調(diào)用,必須是子類構(gòu)造方法的第一個(gè)語句。不能一個(gè)子類構(gòu)造調(diào)用多次super構(gòu)造總結(jié):
子類必須調(diào)用父類構(gòu)造方法,不寫則贈(zèng)送super();寫了則用寫的指定的super調(diào)用,super只能有一個(gè),還必須是第一個(gè)。
3.6 super關(guān)鍵字的三種用法:
- 在子類的成員方法中,訪問父類的成員變量。
- 在子類的成員方法中,訪問父類的成員方法。
- 在子類的構(gòu)造方法中,訪問父類的構(gòu)造方法。
3.7 this關(guān)鍵字的三種用法:
- 在本類的成員方法中,訪問本類的成員變量。
- 在本類的成員方法中,訪問本類的另一個(gè)成員方法。
- 在本類的構(gòu)造方法中,訪問本類的另一個(gè)構(gòu)造方法。
在第三種用法當(dāng)中要注意:
- this(...)調(diào)用也必須是構(gòu)造方法的第一個(gè)語句,唯一一個(gè)。
super和this兩種構(gòu)造調(diào)用,不能同時(shí)使用。總結(jié):
?
super關(guān)鍵字用來訪問父類內(nèi)容,而this關(guān)鍵字用來訪問本類內(nèi)容
3.8 Java 繼承的關(guān)系

3.9 抽象類
抽象方法:就是加上
abstract關(guān)鍵字,然后去掉大括號(hào),直接分號(hào)結(jié)束。
抽象類:抽象方法所在的類,必須是抽象類才行。在class之前寫上abstract即可。如何使用抽象類和抽象方法:
- 不能直接創(chuàng)建
new抽象類對(duì)象。- 必須用一個(gè)子類來繼承抽象父類。
- 子類必須覆蓋重寫抽象父類當(dāng)中所有的抽象方法。
覆蓋重寫(實(shí)現(xiàn)):子類去掉抽象方法的abstract關(guān)鍵字,然后補(bǔ)上方法體大括號(hào)。- 創(chuàng)建子類對(duì)象進(jìn)行使用。
// 父類
public abstract class Animal {
// 定義一個(gè)抽象方法
public abstract void eat();
// 定義一個(gè)普通的方法
public void method() {
System.out.printf("普通方法");
}
}
//子類
public class Cat extends Animal {
public void eat(){
System.out.println("Cat eats fish");
}
}
// Main
public class DemoAnimal {
public static void main(String[] args) {
Cat cat = new Cat();
cat.eat();
}
}
注意事項(xiàng):
- 抽象類不能創(chuàng)建對(duì)象,如果創(chuàng)建,編譯無法通過而報(bào)錯(cuò)。只能創(chuàng)建其非抽象子類的對(duì)象。
- 理解:假設(shè)創(chuàng)建了抽象類的對(duì)象,調(diào)用抽象的方法,而抽象方法沒有具體的方法體,沒有意義。
- 抽象類中,可以有構(gòu)造方法,是供子類創(chuàng)建對(duì)象時(shí),初始化父類成員使用的。
- 理解:子類的構(gòu)造方法中,有默認(rèn)的super(),需要訪問父類構(gòu)造方法。
抽象類中,不一定包含抽象方法,但是有抽象方法的類必定是抽象類。
- 理解:未包含抽象方法的抽象類,目的就是不想讓調(diào)用者創(chuàng)建該類對(duì)象,以滿足特殊類的需求。
抽象類的子類(除子類也為抽象類),必須重寫抽象父類中所有的抽象方法,否則,編譯無法通過而報(bào)錯(cuò)。
- 理解:假設(shè)不重寫所有抽象方法,則類中可能包含抽象方法沒有意義,無法被使用。
練習(xí):紅包隨機(jī)分割。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;
public class RandomSplit {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList();
list = divived(100, 20);
System.out.println(list);
}
public static ArrayList<Integer> divived(double money, int n) {
/*
* 紅包拆分方法
* @param money 被拆分的總金額 (單位元)
* @param n 被拆分的紅包個(gè)數(shù)
* @return 拆分后的每個(gè)紅包金額數(shù)組
*/
// 創(chuàng)建一個(gè)長(zhǎng)度的紅包數(shù)組
ArrayList<Integer> redList = new ArrayList<>();
int moneyFen = (int) (money * 100);
// 判斷紅包的總金額
if (money > 200) {
System.out.println("單個(gè)紅包不能超過200元");
return redList; // 返回空的紅包集合
}
if (moneyFen < n || moneyFen < 1) {
System.out.println("被拆分的總金額不能小于0.01元");
return redList; // 返回空的紅包集合
}
// 創(chuàng)建一個(gè)n長(zhǎng)的數(shù)組
Integer[] array = new Integer[n];
//1. 給每個(gè)包分0.01元,確保每個(gè)包有錢
Arrays.fill(array, 1);
moneyFen -= n; //總金額減去已分配的0.01 * n 元
//2. 進(jìn)行隨機(jī)分配
Random rand = new Random();
while (moneyFen > 1) {
int moneyCut = rand.nextInt(moneyFen); // 隨機(jī)選擇分配的包
int i = rand.nextInt(n); // 隨機(jī)選擇分配的包
array[i] += moneyCut; // 分配給每一個(gè)包并且轉(zhuǎn)換為元
moneyFen -= (int) moneyCut;
}
//把最后的包放到最后一個(gè)包里面
array[n - 1] += moneyFen ;
// 把分好的包放到redList里面
Collections.addAll(redList, array);
return redList;
}
}
4. 面向?qū)ο筇卣鳌鄳B(tài)
4.1 多態(tài)的概念
多態(tài)是同一個(gè)行為具有多個(gè)不同表現(xiàn)形式或形態(tài)的能力。
多態(tài)存在的三個(gè)必要條件:
- 繼承
- 重寫
- 父類引用指向子類對(duì)象
4.2 多態(tài)的個(gè)格式
格式:
父類名稱 對(duì)象名 = new 子類名稱(); // 或者: 接口名稱 對(duì)象名 = new 實(shí)現(xiàn)類名稱();
4.3 多態(tài)中的成員變量和成員方法
訪問成員變量的兩種方式:
- 直接通過對(duì)象名稱訪問成員變量:看等號(hào)左邊是誰,優(yōu)先用誰,沒有則向上找。
- 間接通過成員方法訪問成員變量:看該方法屬于誰,優(yōu)先用誰,沒有則向上找。
成員方法的訪問規(guī)則是:
看new的是誰,就優(yōu)先用誰,沒有則向上找。成員變量:編譯看左邊,運(yùn)行還看左邊。
成員方法:編譯看左邊,運(yùn)行看右邊。
口訣: 編譯看左邊,運(yùn)行看右邊。
4.4 對(duì)象的轉(zhuǎn)型
-
向上轉(zhuǎn)型:多態(tài)本身是子類類型向父類類型向上轉(zhuǎn)換的過程,這個(gè)過程是默認(rèn)的。當(dāng)父類引用指向一個(gè)子類對(duì)象時(shí),便是向上轉(zhuǎn)型 。
向上轉(zhuǎn)型是安全的,等于從小范圍轉(zhuǎn)向大的范圍。
格式:
父類類型 變量名 = new 子類類型(); // 比如 Animal a = new Cat(); -
向下轉(zhuǎn)型:父類類型向子類類型向下轉(zhuǎn)換的過程,這個(gè)過程是強(qiáng)制的。
注: 向下轉(zhuǎn)型的對(duì)象,之前的必須是通過向上轉(zhuǎn)型過來的,才能向下轉(zhuǎn)回原來的對(duì)象。
格式:
子類類型 變量名 = (子類類型) 父類變量名; // 比如: Cat c =(Cat) a;向下轉(zhuǎn)型的異常:
? 如果錯(cuò)誤的轉(zhuǎn)換為其他對(duì)象,編譯時(shí)會(huì)出現(xiàn)
ClassCastException的報(bào)錯(cuò)。為了確定向下轉(zhuǎn)型的正確性,我們可以使用關(guān)鍵字instanceof,進(jìn)行校驗(yàn)。校驗(yàn)格式:
變量名 instanceof 數(shù)據(jù)類型 如果變量屬于該數(shù)據(jù)類型,返回true。 如果變量不屬于該數(shù)據(jù)類型,返回false。實(shí)例:
public class Test { public static void main(String[] args) { // 向上轉(zhuǎn)型 Animal a = new Cat(); a.eat(); // 調(diào)用的是 Cat 的 eat // 向下轉(zhuǎn)型 if (a instanceof Cat) { Cat c = (Cat) a; c.catchMouse(); // 調(diào)用的是 Cat 的 catchMouse } else if (a instanceof Dog) { Dog d = (Dog) a; d.watchHouse(); // 調(diào)用的是 Dog 的 watchHouse } } }
5. Java中的接口
接口就是多個(gè)類的公共規(guī)范。
接口(Interface),在JAVA編程語言中是一個(gè)抽象類型,是抽象方法的集合,接口通常以interface來聲明。一個(gè)類通過繼承接口的方式,從而來繼承接口的抽象方法。
接口是一種引用數(shù)據(jù)類型,最重要的內(nèi)容就是其中的:抽象方法。
接口并不是類,編寫接口的方式和類很相似,但是它們屬于不同的概念。類描述對(duì)象的屬性和方法。接口則包含類要實(shí)現(xiàn)的方法。
除非實(shí)現(xiàn)接口的類是抽象類,否則該類要定義接口中的所有方法。
接口無法被實(shí)例化,但是可以被實(shí)現(xiàn)。一個(gè)實(shí)現(xiàn)接口的類,必須實(shí)現(xiàn)接口內(nèi)所描述的所有方法,否則就必須聲明為抽象類。另外,在 Java 中,接口類型可用來聲明一個(gè)變量,他們可以成為一個(gè)空指針,或是被綁定在一個(gè)以此接口實(shí)現(xiàn)的對(duì)象。
如果是Java 7,那么接口中可以包含的內(nèi)容有:
- 常量
- 抽象方法
如果是Java 8,還可以額外包含有:
- 默認(rèn)方法
- 靜態(tài)方法
如果是Java 9,還可以額外包含有:
- 私有方法
4.1 定義接口的格式
public interface 接口名稱 [extends 其他的接口名] {
// 聲明變量
// 抽象方法
}
接口有以下特性:
- 接口是隱式抽象的,當(dāng)聲明一個(gè)接口的時(shí)候,不必使用abstract關(guān)鍵字。
- 接口中每一個(gè)方法也是隱式抽象的,聲明時(shí)同樣不需要abstract關(guān)鍵字。
- 接口中的方法都是公有的。
4.2 接口的使用步驟
- 接口不能直接使用,必須有一個(gè)“實(shí)現(xiàn)類”來“實(shí)現(xiàn)”該接口。
格式:
public class 實(shí)現(xiàn)類名稱 implements 接口名稱 {
// ...
}
接口的實(shí)現(xiàn)類必須覆蓋重寫(override)接口中所有的抽象方法。
創(chuàng)建實(shí)現(xiàn)類的對(duì)象,進(jìn)行使用。
4.3 接口中抽象(abstract)方法
在任何版本的Java中,接口都能定義抽象方法。
格式:public abstract 返回值類型 方法名稱(參數(shù)列表){ //方法體 };注意事項(xiàng):
- 接口當(dāng)中的抽象方法,修飾符必須是兩個(gè)固定的關(guān)鍵字:
publicabstractpublicabstract關(guān)鍵字修飾符可以選擇性地省略。- 方法的三要素,可以隨意定義。
- 實(shí)現(xiàn)類并沒有覆蓋重寫接口中所有的抽象方法,那么這個(gè)實(shí)現(xiàn)類自己就必須是抽象類。
public interface MyInterfaceAbstract {
// 這是一個(gè)抽象方法
public abstract void methodAbs1();
// 這也是抽象方法
abstract void methodAbs2();
// 這也是抽象方法
public void methodAbs3();
// 這也是抽象方法
void methodAbs4();
}
4.4 接口中的默認(rèn)(default)方法
從Java 7開始,接口當(dāng)中允許定義Default方法。
接口中使用的默認(rèn)方法,可以解決接口升級(jí)的問題。默認(rèn)方法,實(shí)現(xiàn)類可以不重寫。
格式:
public default 返回值類型 方法名稱(參數(shù)列表) { 方法體 }注:
- 關(guān)鍵字
public修飾符可以選擇性地省略。- 接口的默認(rèn)方法,可以通過接口實(shí)現(xiàn)類對(duì)象,直接調(diào)用。
- 接口的默認(rèn)方法,也可以被接口實(shí)現(xiàn)類進(jìn)行覆蓋重寫。
public interface MyInterfaceDefault {
// 抽象方法
public abstract void methodAbstract();
// 默認(rèn)方法
public default void methodDefault() {
System.out.println("默認(rèn)方法");
}
}
4.5 接口中的私有(private)方法
從Java 9開始,接口當(dāng)中允許定義私有方法。
- 普通私有方法,解決多個(gè)默認(rèn)方法之間重復(fù)代碼問題
格式:
private 返回值類型 方法名稱(參數(shù)列表) { 方法體 }
- 靜態(tài)私有方法,解決多個(gè)靜態(tài)方法之間重復(fù)代碼問題
格式:private static 返回值類型 方法名稱(參數(shù)列表) { 方法體 }
public interface MyInterfacePrivate {
public default void methodDefault1() {
System.out.println("默認(rèn)方法1");
methodDefaultCommon();
}
public default void methodDefault2() {
System.out.println("默認(rèn)方法2");
methodDefaultCommon();
}
public static void methodStatic1() {
System.out.println("靜態(tài)方法1");
methodStaticCommon();
}
public static void methodStatic2() {
System.out.println("靜態(tài)方法2");
methodStaticCommon();
}
private static void methodStaticCommon() {
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
private void methodDefaultCommon() {
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
}
4.6 接口中的靜態(tài)(static)方法
從Java 8開始,接口當(dāng)中允許定義靜態(tài)方法。
格式:public static 返回值類型 方法名稱(參數(shù)列表) { 方法體 }注 :
- 關(guān)鍵字
public修飾符可以選擇性地省略。- 靜態(tài)方法的調(diào)用通過接口名稱直接調(diào)用,而不是使用實(shí)現(xiàn)類的對(duì)象進(jìn)行調(diào)用,因?yàn)殪o態(tài)和對(duì)象沒關(guān)系。
public interface MyInterfaceStatic {
public static void methodStatic() {
System.out.println("這是接口的靜態(tài)方法!");
}
}
4.7 接口中的常量的定義和使用
接口當(dāng)中也可以定義“成員變量”,但是必須使用
publicstaticfinal三個(gè)關(guān)鍵字進(jìn)行修飾。
從效果上看,這其實(shí)就是接口的【常量】。
格式:public static final 數(shù)據(jù)類型 常量名稱 = 數(shù)據(jù)值; // public static final 都可以省略 數(shù)據(jù)類型 常量名稱 = 數(shù)據(jù)值;備注:
一旦使用final關(guān)鍵字進(jìn)行修飾,說明不可改變。備注:
一旦使用final關(guān)鍵字進(jìn)行修飾,說明不可改變。注意事項(xiàng):
- 接口當(dāng)中的常量,可以省略
publicstaticfinal,注意:其實(shí)都可以省略。- 接口當(dāng)中的常量,必須進(jìn)行賦值;不能不賦值。
- 接口中常量的名稱,使用完全大寫的字母,用下劃線進(jìn)行分隔。(推薦命名規(guī)則)
- 調(diào)用常量時(shí)使用接口名稱去調(diào)用。
4.8 接口中方法的總結(jié)
- 成員變量其實(shí)是常量,格式:
[public] [static] [final] 數(shù)據(jù)類型 常量名稱 = 數(shù)據(jù)值;注意:
常量必須進(jìn)行賦值,而且一旦賦值不能改變。
常量名稱完全大寫,用下劃線進(jìn)行分隔。注意:
常量必須進(jìn)行賦值,而且一旦賦值不能改變。
常量名稱完全大寫,用下劃線進(jìn)行分隔。
- 接口中最重要的就是抽象方法,格式:
[public] [abstract] 返回值類型 方法名稱(參數(shù)列表);注意:實(shí)現(xiàn)類必須覆蓋重寫接口所有的抽象方法,除非實(shí)現(xiàn)類是抽象類。
注意:實(shí)現(xiàn)類必須覆蓋重寫接口所有的抽象方法,除非實(shí)現(xiàn)類是抽象類。
- 從Java 8開始,接口里允許定義默認(rèn)方法,格式:
[public] default 返回值類型 方法名稱(參數(shù)列表) { 方法體 }注意:默認(rèn)方法也可以被覆蓋重寫
注意:默認(rèn)方法也可以被覆蓋重寫
- 從Java 8開始,接口里允許定義靜態(tài)方法,格式:
[public] static 返回值類型 方法名稱(參數(shù)列表) { 方法體 }注意:應(yīng)該通過接口名稱進(jìn)行調(diào)用,不能通過實(shí)現(xiàn)類對(duì)象調(diào)用接口靜態(tài)方法
注意:應(yīng)該通過接口名稱進(jìn)行調(diào)用,不能通過實(shí)現(xiàn)類對(duì)象調(diào)用接口靜態(tài)方法
- 從Java 9開始,接口里允許定義私有很乏,格式:
普通私有方法:private 返回值類型 方法名稱(參數(shù)列表) { 方法體 }靜態(tài)私有方法:
private static 返回值類型 方法名稱(參數(shù)列表) { 方法體 }注意:private的方法只有接口自己才能調(diào)用,不能被實(shí)現(xiàn)類或別人使用。
4.9 類的繼承和實(shí)現(xiàn)接口的問題
類的繼承關(guān)系是單繼承的,但類可同時(shí)實(shí)現(xiàn)多個(gè)接口。
使用接口時(shí)的注意事項(xiàng):
- 接口是沒有者構(gòu)造方法的。
- 一個(gè)類的直接父類是唯一的,但是一個(gè)類可以同時(shí)實(shí)現(xiàn)多個(gè)接口。
- 實(shí)現(xiàn)類所實(shí)現(xiàn)的多個(gè)接口當(dāng)中,存在重復(fù)的抽象方法,只需要覆蓋重寫一次即可。
- 實(shí)現(xiàn)類沒有覆蓋重寫所有接口當(dāng)中的所有抽象方法,實(shí)現(xiàn)類就必須是一個(gè)抽象類。
- 實(shí)現(xiàn)類實(shí)現(xiàn)的多個(gè)接口當(dāng)中,存在重復(fù)的默認(rèn)方法,實(shí)現(xiàn)類一定要對(duì)沖突的默認(rèn)方法進(jìn)行覆蓋重寫。
- 一個(gè)類如果直接父類當(dāng)中的方法和接口當(dāng)中的默認(rèn)方法產(chǎn)生了沖突,優(yōu)先用父類當(dāng)中的方法。
4.10 接口之間的多繼承
在Java中,類的多繼承是不合法,但接口允許多繼承。
在接口的多繼承中extends關(guān)鍵字只需要使用一次,在其后跟著繼承接口。
格式:
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB { // 覆蓋重寫所有抽象方法 }注意事項(xiàng):
- 多個(gè)父接口當(dāng)中的抽象方法如果重復(fù),由于實(shí)現(xiàn)類中必重寫抽象方法,說以沒影響。
- 多個(gè)父接口當(dāng)中的默認(rèn)方法如果重復(fù),那么子接口必須進(jìn)行默認(rèn)方法的覆蓋重寫。
綜合案例
-
問題:
筆記本電腦(laptop)通常具備使用USB設(shè)備的功能。在生產(chǎn)時(shí),筆記本都預(yù)留了可以插入U(xiǎn)SB設(shè)備的USB接口,但具體是什么USB設(shè)備,筆記本廠商并不關(guān)心,只要符合USB規(guī)格的設(shè)備都可以。定義USB接口,具備最基本的開啟功能和關(guān)閉功能。鼠標(biāo)和鍵盤要想能在電腦上使用,那么鼠標(biāo)和鍵盤也必須遵守USB規(guī)范,實(shí)現(xiàn)USB接口,否則鼠標(biāo)和鍵盤的生產(chǎn)出來也無法使用。
-
分析:
- USB接口,包含開啟功能、關(guān)閉功能
- 筆記本類,包含運(yùn)行功能、關(guān)機(jī)功能、使用USB設(shè)備功能
- 鼠標(biāo)類,要實(shí)現(xiàn)USB接口,并具備點(diǎn)擊的方法
- 鍵盤類,要實(shí)現(xiàn)USB接口,具備敲擊的方法
// Usb接口 public interface Usb { public abstract void on(); public abstract void off(); } // Mouse 鼠標(biāo)類 public class Mouse implements Usb { @Override public void on() { System.out.println("開啟鼠標(biāo)"); } @Override public void off() { System.out.println("關(guān)閉鼠標(biāo)"); } public void click() { System.out.println("鼠標(biāo)點(diǎn)擊"); } } // 鍵盤類 public class Keboard implements Usb { @Override public void on() { System.out.println("開啟鍵盤"); } @Override public void off() { System.out.println("關(guān)閉鍵盤"); } public void inputs() { System.out.println("鍵盤輸出"); } } // 電腦類 public class Computer { public void powerOn() { System.out.println("開啟電腦"); } public void powerOff() { System.out.println("關(guān)閉電腦"); } public void useDevice(Usb usb) { // 開啟Usb設(shè)備 usb.on(); // 使用Usb設(shè)備 if (usb instanceof Keboard) { // 向下轉(zhuǎn)換為鍵盤 Keboard keboard = (Keboard) usb; keboard.inputs(); } else if (usb instanceof Mouse) { // 向下轉(zhuǎn)換為鼠標(biāo) Mouse mouse = (Mouse) usb; mouse.click(); } // 關(guān)閉usb設(shè)備 usb.off(); } } // 測(cè)試 public class DemoMain { public static void main(String[] args) { Computer computer = new Computer(); // 開啟電腦 computer.powerOn(); // 向上轉(zhuǎn)換出一個(gè)use Usb usb = new Mouse(); computer.useDevice(usb); // 直接傳入一個(gè)usb設(shè)備 Keboard keboard = new Keboard(); computer.useDevice(keboard); // 掉用過程: 參數(shù)傳過去先向上轉(zhuǎn)換, 再向下轉(zhuǎn)換。 // 關(guān)閉電腦 computer.powerOff(); } }