連通性
Java的核心思想就是OOP,面向物件程式設計
面向過程
以過程為中心,以正在發生什麼為主要目標進行程式設計,第一步做什麼、第二步做什麼......
面向物件
-
物以類聚,使用分類的思維模式去思考問題,首先要解決哪些問題需要怎樣分類,對這些分類進行單獨思考,最後,對某個分類下的細節進行面向過程的探索。
-
本質:以類的方式去組織程式碼,以物件的形式封裝資料
2、類和物件
2.1、類和物件關係
-
類是一種抽象的資料型別,它是對某一類事物整體描述定義,但是並不能代表某一個具體的事物
-
動物、植物、手機、電腦
-
-
物件是類的具體例項
-
張三是人類的一個具體例項
-
玫瑰是植物的一個具體例項
-
-
從認識論角度上看,先有物件後有類,物件是具體的事物,如某個人和某個動物,類是抽象的,是對物件的抽象,如人類和動物類
-
從程式碼執行角度來看,先有類再有物件,類是物件的模板。
2.2、類的組成和建立
組成
-
屬性:靜態的特徵
這個類應有的一些共同特徵,如人類會有姓名、性別、年齡、國籍......這些特徵
-
方法:動態的行為
這個類會有的一些行為動作,如吃飯、健身、唱歌......
建立
//語法
修飾符(一般用public) class 類名{
//屬性
//方法
}
//示例
public class Person {
//屬性
public String name;
public int age;
//eating方法
public void eating(){
System.out.println(name + "在吃東西...");
}
}
2.3、物件的建立、初始化和使用
建立
在建立好類之後,使用new關鍵字來建立物件例項
//語法
類名 物件名 = new 類名();
//示例
Person zhangSan = new Person();
初始化
使用new關鍵字建立物件,會給建立好的物件的屬性進行預設的初始化
zhangSan這個物件有Person類中的兩個屬性:
-
String型別的name,使用new關鍵字後,name的預設值就是null
-
int型別的age,使用new關鍵字後,age的預設值就是0
public class Test {
public static void main(String[] args) {
Person zhangSan = new Person();
System.out.println(zhangSan.name);//結果為:null
System.out.println(zhangSan.age);//結果為:0
}
}
使用
-
類中屬性的使用
//語法
物件名.屬性名;
//注意:因為屬性有資料型別,所以呼叫屬性時,會有返回值,需要有一個相同資料型別的變數去接受返回值
//示例
Person zhangSan = new Person();
String name = zhangSan.name;
String age = zhangSan.age;
-
類中方法的使用
//語法
物件名.方法名();
//注意:若方法沒有返回值,可以不用變數接
//但是方法要是有返回值,則可以用一個相同資料型別的變數去接受返回值
/*
示例1:eating()方法沒有返回值
public void eating(){
System.out.println(name + "在吃東西...");
}
*/
Person zhangSan = new Person();
zhangSan.eating();
/*
示例2:running()方法有int型別的返回值
public int running(int i){
return i;
}
*/
Person zhangSan = new Person();
//可以使用int runningSteps來接受返回值
int runningSteps = zhangSan.running(12000);
2.4、構造器
-
構造器也稱為構造方法,是在建立物件時必須要呼叫的
-
特點:
-
名字必須和類的名字相同
-
沒有返回型別
-
-
無參構造和有參構造:
無參構造方法
每一個類在建立好之後預設帶有一個無參構造方法
//語法
public class 方法名(){}
//示例
public class Person {
//預設無參構造方法
public Person(){};
}
有參構造方法
-
使用者可以自定義有參構造方法
-
使用者自定義有參構造方法後,會覆蓋預設的無參構造方法,所以如果定義了有參構造方法後,還想使用無參構造方法就要顯示地寫上無參構造方法
-
有參構造方法相當於方法的過載
//語法
public class 方法名(){}
//示例
public class Person {
//屬性
public String name;
public int age;
//有參構造方法1
public Person(String name){
this.name = name;
};
//有參構造方法2
public Person(String name,int age){
this.name = name;
this.age = age;
};
}
構造方法的作用
-
new方法去建立物件的本質就是在呼叫構造方法
-
初始化物件中屬性的值
-
無參構造方法初始化物件中屬性的值
//Person類
public class Person {
//屬性
public String name;
public int age;
//無參構造方法
public Person(){
this.name = "張三";
this.age = 33;
};
}
//物件
public static void main(String[] args) {
//使用無參構造方法初始化物件中屬性的值,不管建立多少個物件,每個物件中的屬性值都是一樣的
Person person1 = new Person();
//輸出結果為:person1的姓名為:張三
System.out.println("person1的姓名為:" + person1.name);
//輸出結果為:person1的年齡為:33
System.out.println("person1的年齡為:" + person1.age);
Person person2 = new Person();
//輸出結果為:person2的姓名為:張三
System.out.println("person2的姓名為:" + person2.name);
//輸出結果為:person2的姓名為:33
System.out.println("person2的姓名為:" + person2.age);
} -
有參構造方法初始化物件中屬性的值
public class Person {
//屬性
public String name;
public int age;
//有參構造方法
public Person(String name,int age){
this.name = name;
this.age = age;
}
}
public static void main(String[] args) {
/*
使用有參構造方法初始化物件中屬性的值
可以在使用new關鍵字建立物件的時候給物件中的屬性賦值
每個物件中屬性的值由建立物件時所賦的值而定
*/
Person person1 = new Person("張三",33);
//輸出結果為:person1的姓名為:張三
System.out.println("person1的姓名為:" + person1.name);
//輸出結果為:person1的年齡為:33
System.out.println("person1的年齡為:" + person1.age);
Person person2 = new Person("李四",22);
//輸出結果為:person2的姓名為:李四
System.out.println("person2的姓名為:" + person2.name);
//輸出結果為:person2的姓名為:22
System.out.println("person2的姓名為:" + person2.age);
}
-
2.5、從記憶體中分析類和物件建立以及使用的過程
簡易過程圖如下:
3、面向物件三大特性
3.1、封裝
-
程式設計的思想
-
高內聚:
類的內部操作細節自己完成,不允許外部干涉
-
低耦合:
僅暴漏少量的方法給外部使用
-
-
封裝:
-
屬性私有化,禁止直接訪問一個物件中的資料,而應通過介面來訪問,實現資訊隱藏
-
getter / setter方法
//1、屬性私有化
private String name;
private int age;
//2、給屬性設定setter和getter方法
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
//通過呼叫setter和getter方法來操作資料
Person person = new Person();
person.setName("張三");
System.out.println(person.getName());
person.setAge(7);
System.out.println(person.getAge()); -
-
作用
-
提高程式的安全性,保護資料
-
隱藏程式碼的實現細節
-
統一介面
-
增加系統的可維護性
-
3.2、繼承
-
使用extends表示繼承關係,繼承意味著擴充套件,子類是父類的一個擴充套件
-
子類:繼承其他類的類稱為子類
-
父類:被別人繼承的類稱為父類
//Student為子類,Person類為父類
public class Student extends Person {} -
子類可以繼承父類中除了私有化(private修飾)之外的屬性和方法
-
-
Java中只有單繼承
Object類
在Java中,所有的類都直接或間接地繼承Object類
super、this
-
super:父類的
-
this:當前物件的
-
super和this呼叫屬性對比
//Person父類
public class Person {
protected String name = "parent";
}
//Student子類
public class Student extends Person {
public String name = "children";
public void testName(String name){
System.out.println("name = " + name);
System.out.println("this.name = " + this.name);
System.out.println("super.name = " + super.name);
}
}
//test測試類
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.testName("hmx");
}
}
/*輸出結果及分析
name = hmx
this.name = children
super.name = parent
System.out.println(name)中的name代表的是實參name
this.name代表的是當前物件Student中的屬性name
super.name代表的是父類物件Parent中的屬性name
*/ -
super和this呼叫方法對比
//Person父類
public class Person {
public void print(){
System.out.println("parent --> print");
}
}
//Student子類
public class Student extends Person {
public void print(){
System.out.println("children --> print");
}
public void testPrint(){
print();
this.print();
super.print();
}
}
//test測試類
public class Test {
public static void main(String[] args) {
student.testPrint();
}
}
/*輸出結果及分析
children --> print
children --> print
parent --> print
print();代表的是當前物件的print方法
this.print();代表的是當前物件的print方法
super.print();代表的是父類物件的print方法
*/ -
super和this呼叫構造器方法對比
-
super():呼叫父類的構造方法
//Person父類
public class Person {
public Person(){
System.out.println("Person的無參構造執行了...");
}
}
//Student子類
public class Student extends Person {
public Student(){
//super();
System.out.println("Student的無參構造執行了...");
}
}
//test測試類
public class Test {
public static void main(String[] args) {
Student student = new Student();
}
}
/*輸出結果及分析
Person的無參構造執行了...
Student的無參構造執行了...
父類的無參構造先執行,說明子類的無參構造中有一條預設語句super(),預設呼叫父類無參構造
如果顯式書寫super()這條語句,則它必須在子類無參構造的第一行
若父類中沒有無參構造方法,則子類也不能有無參構造,自然也不能通過super()呼叫父類無參構造方法
*/ -
this():呼叫自己的構造方法
-
如果顯式寫,也要寫在方法的第一行
-
-
方法重寫
-
為什麼要方法重寫?
父類中的方法,子類不一定需要或者不一定滿足
-
什麼是方法重寫?
有繼承關係的兩個類中,子類可以重寫父類方法,方法名相同,方法體不相同。
-
重寫規則
-
方法名相同
-
引數列表相同
-
修飾符:範圍可以擴大不可以縮小
-
丟擲的異常:範圍可以縮小,不可以擴大
-
-
被static 或 final 或 private修飾的方法不能被重寫
-
static:靜態方法
-
final:常量,一經確定,不能被改變
-
private:父類私有方法不能被繼承,自然不能被重寫
-
//父類
public class Person {
public void run(){
System.out.println("父類中的run方法被執行了...");
}
}
//子類
public class Student extends Person {
}
//測試類
public class Test {
public static void main(String[] args) {
Student student = new Student();
student.run();
}
}
//此時結果為:父類中的run方法被執行了...
//修改子類,重寫run方法
public class Student extends Person {
public void run(){
System.out.println("父類中的run方法被執行了...");
}
}
//此時結果為:子類中的run方法被執行了...,說明子類中重寫的run方法覆蓋了父類中的run方法。
3.3、多型
-
同一方法可以根據傳送物件的不同而採取不同的行為方式
-
一個物件的實際型別是確定的,但是可以指向物件的引用型別有很多,但是必須是存在繼承關係的類,或者其他有聯絡的類
//物件的引用型別 = 物件的實際型別
Student student = new Student();
Person person = new Student();//Student類直接繼承Person類
Object object = new Student();//Person類繼承object,所以Student類間接繼承Object類 -
多型存在的條件
-
有繼承關係
-
子類重寫父類方法
-
父類引用指向子類物件
-
-
多型中子父類方法呼叫
-
多型中父類引用型別可以呼叫自身方法,但是不可以呼叫子類的方法,如果自身方法被子類覆蓋,則呼叫的是子類的該方法
-
多型中子類引用型別可以呼叫自身方法,也可以呼叫父類中沒有重寫的方法
-
//父類
public class Person {
//父類方法running
public void running(){
System.out.println("人類在奔跑...");
}
//父類方法swimming
public void swimming(){
System.out.println("人類在游泳...");
}
}
//子類
public class Student extends Person {
//子類重寫父類方法running
public void running(){
System.out.println("學生在奔跑...");
}
//子類方法eating
public void eating(){
System.out.println("學生在吃飯...");
}
}
//測試類
public class Test {
public static void main(String[] args) {
Student student = new Student();
//子類呼叫父類方法swimming,結果為:人類在游泳...
student.swimming();
//子類呼叫重寫方法running,結果為:學生在奔跑...
student.running();
//子類自身方法eating,結果為:學生在吃飯...
student.eating();
Person person = new Student();
//父類呼叫自身方法running,但是被子類重寫方法覆蓋,所以結果為:學生在奔跑...
person.running();
//父類呼叫沒有被子類重寫的自身方法running,結果為:人類在游泳...
person.swimming();
}
}
-
物件之間的型別轉換
instanceof
判斷兩個物件的型別是否相似
//語法
物件名A instanceof 類B//當A所指向的實際型別和B存在父子關係時,結果為true
//示例
Person person = new Student();
boolean flag = (person instanceof Student);型別轉換
//父類
public class Person {
public void running(){
System.out.println("人類在奔跑...");
}
}
//子類
public class Student extends Person {
public void Studying(){
System.out.println("學生在學習...");
}
}
//測試類
public class Test {
public static void main(String[] args) {
//子類轉父類(向上轉型,低到高,預設轉換)
Student s1 = new Student();
Person p1 = s1;
//發現子類轉換成父類之後,無法呼叫子類Student自身的方法Studying()
//向上轉型會出現資料丟失問題
p1.running();
//父類轉子類(向下轉型,高到低,強制轉換)
//父類想要用子類的方法,就直接轉換成子類即可
Person p2 = new Student();
Student s2 = (Student) p2;
//父類轉型成子類之後,可以像子類一樣呼叫父類和子類的方法
s2.running();
s2.Studying();
}
}
4、抽象方法和抽象類
4.1、抽象類
//定義
許可權修飾符 abstract class 類名{
//屬性
//方法
}
//示例
public abstract class Test {
}
-
抽象類中可以有抽象方法,也可以沒有
-
抽象類可以有構造方法,但是不可以通過new關鍵類來例項化物件
-
抽象類構造方法的作用
-
抽象類的構造方法和普通類的構造方法一樣,都是用來初始化類的
-
只是抽象類的構造方法不能直接呼叫 ,因為抽象類不能實現例項
-
但是繼承了抽象類的類可以在自己的構造方法中呼叫抽象類的構造方法
-
-
原因:
-
抽象類只是分配了在棧記憶體中的引用地址,沒有在堆記憶體中分配空間
-
抽象類中可能存在抽象方法,當然如果抽象類中沒有抽象方法,那這個類被設計成為抽象類就沒有意義了,抽象方法中沒有方法的具體實現,無法具體地給他分配記憶體空間,為了安全,Java不允許通過new關鍵類來例項化抽象類。
-
-
4.2、抽象方法
//定義
public abstract 返回值 方法名();
//示例
public abstract void run();
-
抽象方法只是一個約束,沒有方法的具體實現
-
抽象方法一定要定義在抽象類中
4.3、繼承完成抽象類中抽象方法的具體實現
-
普通類繼承抽象類,則必須實現抽象類中的抽象方法,否則就會報錯
-
抽象類繼承抽象類,則不用實現抽象類中的抽象方法
//抽象父類
public abstract class Person1 {
//抽象方法run
public abstract void run();
//普通方法eating
public void eating(){
System.out.println("人類在吃飯...");
}
}
//普通子類,必須實現run()方法
public class Student1 extends Person1 {
4.4、思考抽象類存在的意義?
5、介面
-
介面就是規範,定義的是一組規則,體現了現實世界中 “如果你是......,那麼你能......” 的思想
-
介面中的屬性都是public static final修飾的
-
介面中的方法都是public abstract修飾的
-
介面沒有構造方法,不可以通過new關鍵類來例項化物件
-
實現介面的類必須實現介面中的所有方法
-
Java可以通過介面實現偽多繼承
介面的定義
//定義
public interface 介面名{
//屬性
//方法
}
//示例
public interface Person2 {
void run();
void eat();
}
介面的實現
//定義
public class 類名 implements 介面名{
//方法的具體實現
}
//示例
public class Student2 implements Person2 {