Java面向對象

Java面向對象

面向過程&面向對象

面向過程:

  • 步驟清晰簡單,第一步做什麼,第二步做什麼……
  • 面向過程適合處理一些較為簡單的事情

面向對象:

  • 物以類聚,分類的思維模式。思考問題首先會解決問題需要哪些分類,然後對這些分類進行單獨思考。最後,才對某個分類下的細節進行面向過程的思索。
  • 面向對象適合處理複雜的問題,適合處理需要多人協作的問題。

概述:對於描述複雜的事物,為了從宏觀上把握、從整體上合理分析,我們需要使用面向對象的思路來分析整個系統。但是,具體到微觀操作,仍然需要面向過程的思路去處理。

什麼是面向對象?

面向對象(Object-Oriented Programming, OOP)的本質是以的方式組織程式碼,以對象的方式封裝數據

三大特性:

  • 封裝
  • 繼承
  • 多態

注意:

  • 從認識論的角度考慮,是先有對象後有類。因為對象是具體的,而類是抽象的。類是對對象的抽象。
  • 從程式碼運行的角度考慮,是先有類後有對象。類是對象的模板。

類與對象的關係

是一種抽象的數據類型。它是對某一類事物的整體描述或定義,但並不能代表某一個具體的事物。

  • 如:人、動物、植物、電腦、手機,等等……

對象是抽象概念的具體實例

  • 如:張三、隔壁家的小花貓咪咪、《唐伯虎點秋香》里的那隻名叫旺財的狗

初始化與創建對象

創建的方式:使用new關鍵字創建對象

使用new關鍵字創建對象的時候,除了分配記憶體空間之外,還會給創建好的對象賦默認值進行初始化,以及調用類中的構造器

示例:

Student類

package com.wmwx.oop.Demo01;

//學生類
public class Student {
    //屬性:欄位
    String name;
    int age;

    //方法
    public void study(){
        System.out.println("學生"+this.name+"在學習。");
    }
}

Application類(啟動類)

package com.wmwx.oop.Demo01;

//啟動類
public class Application {
    //一個項目應該只存在一個main方法
    public static void main(String[] args) {
        //類是抽象的,需要實例化
        //類實例化後會返回一個自己的對象
        //student對象是Student類的一個實例
        Student student = new Student();
        student.study();        //輸出"學生null在學習。"
        student.name = "小明";
        student.study();        //輸出"學生小明在學習。"
    }
}

構造方法

當一個對象被創建時候,構造方法用來初始化該對象。構造方法和它所在類的名字相同,但構造方法沒有返回值

一個類即使什麼都不寫,也會存在一個構造方法。因為 Java 自動提供了一個默認構造方法,其訪問修飾符和類的訪問修飾符相同。

一旦自己定義了構造方法,默認的構造方法就會失效。

示例:

Person類:

package com.wmwx.oop.Demo01;

public class Person {
    String name;
    //使用快捷鍵alt+insert可以自動生成構造方法
    //無參構造
    public Person(){
        this.name = "一個無名氏";
    }

    //有參構造(一旦定義有參構造,就必須顯式定義無參構造)
    public Person(String name){
        this.name = name;
    }
}

Application類:

package com.wmwx.oop.Demo01;

public class Application {
    public static void main(String[] args) {
        //使用new關鍵字,本質是在調用構造方法
        Person person1 = new Person();                      //調用無參構造
        System.out.println(person1.name);                   //輸出"一個無名氏"
        //利用構造方法,可以初始化對象
        Person person2 = new Person("惟妙惟霄");       		 //調用有參構造
        System.out.println(person2.name);                   //輸出"惟妙惟霄"
    }
}

記憶體分析

過程如下:

  1. 創建類
  2. 在堆中存放類和類中的靜態方法
  3. 創建對象
  4. 在堆中為對象開闢空間
  5. 在棧中存放對象的引用變數名
  6. 令對象的引用變數名指向堆中開闢的空間

封裝

所謂封裝,即該露的露,該藏的藏。程式設計要追求「高內聚,低耦合」

高內聚:類的內部數據操作細節自己完成,不允許外部干涉。

低耦合:僅暴露少量的方法給外部使用。

對於程式碼而言,總結起來就一句話:屬性私有,get/set。

意義:

  • 提升程式的安全性,保護數據
  • 隱藏程式碼的實現細節
  • 統一介面
  • 提高了系統的可維護性

示例:

Student類:

package com.wmwx.oop.Demo03;

public class Student {
    //屬性私有
    private String name;
    private int id;
    private String gender;
    private int age;

    //需要提供共有的get和set方法
    //get方法:獲取數據
    public String getName() {
        return name;
    }
    //set方法:設置數據
    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age<0||age>120){
            this.age = 3;
        }else{
            this.age = age;
        }
    }
}

Application類:

package com.wmwx.oop;

import com.wmwx.oop.Demo03.Student;

//啟動類
public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.setName("惟妙惟霄");
        student.setId(123456);
        student.setGender("男");
        student.setAge(130);
        System.out.println(student.getAge());   //輸出3
    }
}

繼承

繼承的本質是對某一批類的抽象,從而實現對現實世界更好的建模。

在 Java 中通過 extends 關鍵字可以聲明一個類是從另外一個類繼承而來的,其語法如下:

class 子類 extends 父類 {
}

extends的意思是擴展,子類是對父類的擴展

繼承的注意事項:

  • Java只有單繼承,沒有多繼承。

  • 在Java中,所有類都默認直接或間接繼承自Object類

在Java中,可以使用this指代當前類,並使用super指代父類

super的注意事項:

  • super調用父類的構造方法,必須在構造方法的第一行
  • super只能出現在子類的方法或構造方法中。
  • super和this不能同時調用構造方法。

重寫是子類對父類的允許訪問的方法的實現過程進行重新編寫, 返回值和形參都不能改變。重寫的好處在於子類可以根據需要,定義特定於自己的行為。 也就是說,子類能夠根據需要實現父類的方法。重寫需要遵守以下規則:

  • 方法名必須相同
  • 參數列表必須相同
  • 修飾符的範圍可以擴大,但不能縮小
  • 拋出的異常可以被縮小,但不能擴大

示例:

Person類:

package com.wmwx.oop.Demo04;

//父類:人類
public class Person {
    private int money = 10_0000_0000;
    protected String name = "惟妙惟霄";

    public Person() {
        System.out.println("Person的無參構造方法執行了!");
    }

    public void say(){
        System.out.println("說了一句話。");
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    public void print(){
        System.out.println("Person");
    }
}

Student類:

package com.wmwx.oop.Demo04;

//子類:學生類
public class Student extends Person{
    private String name = "妙霄";

    public Student() {
        //隱藏程式碼:super();
        //父類的構造方法必須要在子類的構造方法的第一行
        System.out.println("Student的無參構造方法執行了!");
    }

    public void test1(String name){
        System.out.println(name);           //輸出參數
        System.out.println(this.name);      //輸出當前類的name
        System.out.println(super.name);     //輸出父類的name
    }

    //重寫都是方法的重寫,與屬性無關
    //只允許重寫public方法
    //可以使用快捷鍵alt+insert來插入重寫方法
    @Override
    public void print() {
        System.out.println("Student");
    }

    public void test2(){
        print();
        this.print();
        super.print();
    }
}

Application類:

package com.wmwx.oop;

import com.wmwx.oop.Demo04.Person;
import com.wmwx.oop.Demo04.Student;

//啟動類
public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        //第一行輸出"Person的無參構造方法執行了!"
        //第二行輸出"Student的無參構造方法執行了!"
        student.say();      //子類繼承父類,就會擁有父類的public方法
        System.out.println(student.getMoney()); //可以用父類的get/set方法對屬性進行操作
        //可以使用快捷鍵ctrl+H來查看繼承樹
        student.test1("MiaoXiao");
        //第一行輸出"MiaoXiao"
        //第二行輸出"妙霄"
        //第三行輸出"惟妙惟霄"
        student.test2();
        //第一行輸出"Student"
        //第二行輸出"Student"
        //第三行輸出"Person"
        Student stu1 = new Student();
        stu1.print();   //輸出"Student"
        //父類的引用指向了子類
        Person stu2 = new Student();
        stu2.print();   //輸出"Student"
    }
}

多態

多態是同一個行為具有多個不同表現形式或形態的能力。當使用多態方式調用方法時,首先檢查父類中是否有該方法,如果沒有,則編譯錯誤;如果,再去調用子類的同名方法。

多態存在的三個必要條件

  • 繼承
  • 重寫
  • 父類引用指向子類對象:Parent p = new Child();

不能被重寫的方法:

  • static 方法
  • final 方法
  • private 方法

示例:

Person類:

package com.wmwx.oop.Demo05;

public class Person {
    public void run(){
        System.out.println("人在跑步。");
    }
}

Student類:

package com.wmwx.oop.Demo05;

public class Student extends Person{
    @Override
    public void run() {
        System.out.println("學生在跑步。");
    }

    public void eat(){
        System.out.println("學生在吃東西。");
    }
}

Application類:

package com.wmwx.oop;

import com.wmwx.oop.Demo05.Person;
import com.wmwx.oop.Demo05.Student;

//啟動類
public class Application {
    public static void main(String[] args) {
        //一個對象的實際類型是確定的
        //但可以指向的引用類型是不確定的
        Student s1 = new Student();
        Person s2 = new Student();      //父類的引用指向子類
        Object s3 = new Student();
        s1.run();       //輸出"學生在跑步"
        s2.run();       //子類重寫父類方法,將執行子類方法,輸出"學生在跑步。"
        s1.eat();       //輸出"學生在吃東西"
        //s2.eat();     //不能調用。對象能使用哪些方法,要看左邊的類型。
        ((Student)s2).eat();    //強制類型轉換。輸出"學生在吃東西。"
    }
}

instanceof

Java中的instanceof關鍵字可以用來判斷某一個對象是不是某一個類是實例。如果是,返回true;如果不是,返回false;如果二者無關,則編譯不通過。

示例:

package com.wmwx.oop;

import com.wmwx.oop.Demo06.Person;
import com.wmwx.oop.Demo06.Student;
import com.wmwx.oop.Demo06.Teacher;

//啟動類
public class Application {
    public static void main(String[] args) {
        //繼承關係如下:
        //Object -> Person -> Student
        //Object -> Person -> Teacher
        //Object -> String
        Object object = new Student();
        System.out.println(object instanceof Student);  //輸出true
        System.out.println(object instanceof Person);   //輸出true
        System.out.println(object instanceof Object);   //輸出true
        System.out.println(object instanceof Teacher);  //輸出false
        System.out.println(object instanceof String);   //輸出false
        System.out.println("=====");
        Person person = new Student();
        System.out.println(person instanceof Student);  //輸出true
        System.out.println(person instanceof Person);   //輸出true
        System.out.println(person instanceof Object);   //輸出true
        System.out.println(person instanceof Teacher);  //輸出false
        //System.out.println(person instanceof String); //編譯時報錯
        System.out.println("=====");
        Student student = new Student();
        System.out.println(student instanceof Student);  //輸出true
        System.out.println(student instanceof Person);   //輸出true
        System.out.println(student instanceof Object);   //輸出true
        //System.out.println(student instanceof Teacher);//編譯時報錯
        //System.out.println(student instanceof String); //編譯時報錯
    }
}

類型轉換

  • 子類轉換為父類,是向轉型,可自動轉換。
  • 父類轉換為子類,是向轉型,需強制轉換。

示例:

Person類:

package com.wmwx.oop.Demo06;

public class Person {
    public void run(){
        System.out.println("人在跑步。");
    }
}

Student類:

package com.wmwx.oop.Demo06;

public class Student extends Person{
    public void walk(){
        System.out.println("學生在走路。");
    }
}

Application類:

package com.wmwx.oop;

import com.wmwx.oop.Demo06.Person;
import com.wmwx.oop.Demo06.Student;

//啟動類
public class Application {
    public static void main(String[] args) {
        //高 ----------------- 低
        Person person = new Student();
        ((Student)person).walk();   //強制類型轉換

        Student student = new Student();
        Person obj = student;       //子類轉換為父類,可能會丟失一些方法
        //obj.walk();               //編譯時報錯
    }
}

靜態程式碼塊

靜態程式碼塊會在類載入時執行,且只會執行一次。

示例:

Person類:

package com.wmwx.oop.Demo07;

public class Person {
    //第二個執行,可在這裡賦初始值
    {
        System.out.println("匿名程式碼塊");
    }

    //第一個執行,只執行一次
    static {
        System.out.println("靜態程式碼塊");
    }

    //第三個執行
    public Person() {
        System.out.println("構造方法");
    }
}

Application類:

package com.wmwx.oop;

import com.wmwx.oop.Demo07.Person;

//啟動類
public class Application {
    public static void main(String[] args) {
        Person person = new Person();
        //第一行輸出"靜態程式碼塊"
        //第二行輸出"匿名程式碼塊"
        //第三行輸出"構造方法"
    }
}

抽象類

在Java語言中使用abstract 來定義抽象類,其基本語法如下:

abstract class 類名{
    //屬性
    //方法
}

抽象類除了不能實例化對象之外,類的其它功能依然存在,成員變數、成員方法和構造方法的訪問方式和普通類一樣。

由於抽象類不能實例化對象,所以抽象類必須被繼承,才能被使用。在Java中一個類只能繼承一個抽象類,但一個類可以實現多個介面

在Java語言中使用abstract 來定義抽象方法,其基本語法如下:

abstract 訪問修飾符 返回值類型 方法名(參數);

抽象類與抽象方法的規則:

  • 抽象類不能被實例化(即不能被 new ),只有抽象類的非抽象子類可以創建對象。
  • 抽象類中不一定包含抽象方法,但是有抽象方法的類必定是抽象類。
  • 抽象類中的抽象方法只是聲明,不包含方法體,也就是不給出方法的具體實現。
  • 構造方法、類方法(用 static 修飾的方法)不能聲明為抽象方法。
  • 抽象類的子類必須給出抽象類中的抽象方法的具體實現,除非該子類也是抽象類

示例:

Action類:

package com.wmwx.oop.Demo08;

//使用abstract聲明抽象類
public abstract class Action {
    //抽象方法,只有方法名,沒有方法體
    //僅作約束,期待他人實現
    public abstract void doSomething();
}

A類:

package com.wmwx.oop.Demo08;

public class A extends Action{
    //子類必須實現父類的抽象方法
    //除非該子類是抽象類
    @Override
    public void doSomething() {

    }
}

介面

介面在JAVA程式語言中是一個抽象類型,是抽象方法的集合,通常以 interface 來聲明。其基本語法如下:

[訪問修飾符] interface 介面名稱 [extends 其他的介面名稱] {
        // 抽象方法
}

介面的特性:

  • 介面中每一個方法都是隱式抽象的,介面中的方法會被隱式地指定為 public abstract,並且只能是 public abstract。
  • 介面中可以含有變數,但是介面中的變數會被隱式地指定為 public static final ,並且只能是 public static final。
  • 介面中的方法不能在介面中實現,只能由實現介面的來實現介面中的方法。
  • 一個介面能繼承另一個介面,使用 extends 關鍵字.子介面會繼承父介面的方法。

當類實現介面的時候,需要實現介面中所有的方法。否則,類必須聲明為抽象的類。Java中使用 implements 關鍵字實現介面,其基本語法如下:

class 類名 implements 方法名{
    //實現介面中的抽象方法
}

示例:

UserService介面:

package com.wmwx.oop.Demo09;

//定義介面使用關鍵字interface
public interface UserService {
    //介面中的所有屬性都是public static final
    //一般不在介面中定義屬性
    int age = 60;

    //介面中的所有方法都是public abstract
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}

TimeService介面:

package com.wmwx.oop.Demo09;

public interface TimeService {
    void timer();
}

UserServiceImpl類:

package com.wmwx.oop.Demo09;

//類使用關鍵字implements來實現介面
//實現了介面的類,需要重寫介面的所有方法
//一個類可以實現多個介面
public class UserServiceImpl implements UserService, TimeService{

    @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() {

    }
}

內部類

所謂內部類,就是在一個類的內部再定義一個類。

示例:

Outer類:

package com.wmwx.oop.Demo10;

//外部類
public class Outer {
    private int id=10;
    public void out(){
        System.out.println("這是外部類的方法!");
    }

    public class Inner{
        public void in(){
            System.out.println("這是內部類的方法!");
        }

        //獲得外部類的私有屬性
        public int getId(){
            return id;
        }
    }

    public void method(){
        //局部內部類,在外部類的方法之中
        class Inner{

        }
    }
}

//一個java文件可以有多個class,但是只能有一個public class
class A{

}

Application類:

package com.wmwx.oop;

import com.wmwx.oop.Demo09.UserService;
import com.wmwx.oop.Demo10.Outer;

//啟動類
public class Application {
    public static void main(String[] args) {
        //外部類使用new關鍵字
        Outer outer = new Outer();
        outer.out();
        //內部類通過外部類來實例化
        Outer.Inner inner = outer.new Inner();
        inner.in();
        System.out.println(inner.getId());
        //匿名類,不用將實例保存到變數中
        new Outer().out();
        //使用匿名類實現介面
        UserService userService = new UserService() {
            @Override
            public void add(String name) {

            }

            @Override
            public void delete(String name) {

            }

            @Override
            public void update(String name) {

            }

            @Override
            public void query(String name) {

            }
        }
    }
}
Tags: