Java物件導向

qing集發表於2024-03-05

程序導向&物件導向

  1. 程序導向:
  • 步驟簡單清晰,第一步->第二步->....
  • 程序導向適合處理一些較為簡單的問題
  1. 物件導向:
  • 分類的思維模式
  • 物件導向適合處理複雜的問題
  1. 對於描述複雜的事物,使用物件導向的思維去宏觀上把握、整體上分析,使用程序導向的思維去處理圍觀操作

什麼是物件導向

  1. 物件導向程式設計:(Object-Oriented Programming,OOP)
  2. 物件導向程式設計的本質就是:以類的方式組織程式碼,以物件的方式組織資料
  3. 3大特性:封裝,繼承和多型
  4. 從程式碼執行的角度考慮是先有類後有物件,類是物件的模板

回顧方法的定義

  • 修飾符
  • 返回型別
  • break和return的區別:break 跳出switch選擇或者跳出當前迴圈;return結束方法和返回返回值
  • 方法名:注意駝峰命名原則,見名知意
  • 引數列表:引數型別、引數名;...可變引數->類似於可變陣列
  • 異常丟擲:常見的有陣列下標越界 ArrayIndexOutOfBounds
package com.oop.demo01;
//Demo01類
public class Demo01 {
    //main方法
    public static void main(String[] args) {
        Demo01 demo01 = new Demo01();
        String str = demo01.sayHello();
        System.out.println(str);
        int max = demo01.max(2,1);
        System.out.println(max);
    }
    /*
    修飾符 返回值型別 方法名(引數列表){
        //方法體
        return 返回值;
    }
     */
    public String sayHello(){
        return "hello!";
    }
    public int max(int a,int b){
        return a>b ? a : b;         //三元運算子
    }

}

回顧方法的呼叫:遞迴

  • 靜態方法、非靜態方法
package com.oop.demo01;
//情況1
public class Student {
    //非靜態方法
    public void say(){
        System.out.println("學生說話了");
    }
}
public class Demo02 {
    public static void main(String[] args) {
        //例項化這個類 new
        //物件型別 物件名 = 物件值
        Student student = new Student();
        student.say();
        Demo02.a();
    }
    //靜態方法和類一起載入
    public static void a(){
        Demo02.b();
    }
	//靜態方法和類一起載入
    public static void b(){
        System.out.println("b");
    }

}
package com.oop.demo01;
//情況2
public class Student {
    //非靜態方法
    public void say(){
        System.out.println("學生說話了");
    }
}
public class Demo02 {
    public static void main(String[] args) {
        //例項化這個類 new
        //物件型別 物件名 = 物件值
        Student student = new Student();
        student.say();
        Demo02.a();


    }
    //靜態方法和類一起載入
    public static void a(){
        Demo02 demo02 = new Demo02();
        demo02.b();
    }
    //類例項化後才存在
    public void b(){
        System.out.println("b");
    }

}
  • 形參和實參
package com.oop.demo01;
public class Demo03 {
    //實際引數與形式引數要對應
    public static void main(String[] args) {
        int add = Demo03.add(1,2);					//1,2是實際引數
        System.out.println(add);
    }
    public static int add(int a, int b){   			//a,b是形式引數
        return a+b;
    }
}
  • 值傳遞和引用傳遞
package com.oop.demo01;
public class Demo04 {
    public static void main(String[] args) {
        int a = 1;
        System.out.println(a);              //1
        Demo04.change(a);                   //值傳遞
        System.out.println(a);              //1
    }
    //返回值為空
    public static void change(int a){       //a是區域性變數,只能在方法裡生存
        a = 10;
    }
}
package com.oop.demo01;
//引用傳遞:物件,本質還是值傳遞
public class Demo05 {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name);
        System.out.println(person.age);
        Demo05.change(person);
        System.out.println(person.name);
        System.out.println(person.age);
    }
    public static void change(Person person){   //person是例項變數,從屬於物件Demo05
        person.name = "huangshen";
        person.age = 20;
    }
}

//定義了一個Person類,有一個屬性:name
class Person{
    String name;                                //null
    int age;                                    //0
}

類與物件的建立

  • 類是一種抽象的資料型別,它是對某一類事物整體描述/定義,但是並不能代表某一個具體的事物
  • 物件是抽象概念的具體例項
package com.oop.demo02;
public class Student {
    //屬性
    String name;        //null
    int age;            //0

    //方法
    public void study(String name){
        System.out.println(this.name+"在學習");
    }
}
public class Aplication {
    public static void main(String[] args) {
        //類:抽象的,需要例項化
        //類例項化後會返回一個自己的物件
        //student物件就是一個Student類的具體例項
        Student xm = new Student();     //建立小明
        xm.name = "小明";
        xm.age = 3;
        System.out.println(xm.name);
        System.out.println(xm.age);
        xm.study(xm.name);

        Student xh = new Student();     //建立小紅
        xh.name = "小紅";
        xh.age = 3;
        System.out.println(xh.name);
        System.out.println(xh.age);
        xh.study(xh.name);
    }
}

構造器詳解

  • 使用new關鍵字建立物件
  • 使用new關鍵字建立的時候,除了分配記憶體空間之外,還會給建立好的物件,進行預設的初始化以及對類中構造器的呼叫
  • 類中的構造器也稱為構造方法,是在進行建立物件的時候必須要呼叫的。
  • 並且構造器有以下兩個特點:
  1. 必須和類的名字相同
  2. 必須沒有返回型別,也不能寫void
  • 構造器的作用:
  1. new本質在呼叫構造方法
  2. 初始化物件的值
  • 注意點:
  1. 定義有參構造後如果想使用無參構造,必須顯示的定義一個無參構造
  • Alt + Insert:可以快速定義構造器

  • this. = 可以快速初始化物件的值

package com.oop.demo02;
//java->class
public class Person {
    //一個類即使什麼都不寫,它也會存在一個方法
    //顯示的定義構造器
    String name;
    int age;

    //無參構造
    public Person() {
    }

    //含有一個引數的有參構造
    public Person(String name) {
        this.name = name;
    }

    //含有兩個引數的有參構造
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
//一個專案只存一個main方法
public class Aplication {
    public static void main(String[] args) {
        //new例項化一個物件
        Person person = new Person("huangshen",20);
        System.out.println(person.name);
        System.out.println(person.age);
    }
}

建立物件記憶體分析

package com.oop.demo03;

public class Pet {
    String name;
    int age;
    //無參構造
    public void shout(){
        System.out.println("叫了一聲");
    }
}
package com.oop.demo03;

public class Aplication {
    public static void main(String[] args) {
        Pet dog = new Pet();
        dog.name = "旺財";
        dog.age = 3;
        System.out.println(dog.name);
        System.out.println(dog.age);
        dog.shout();
        Pet cat = new Pet();
        System.out.println(cat.name);
        System.out.println(cat.age);
        cat.shout();
    }
}

封裝

  • 屬性私有,get/set
  • 封裝作用:
  1. 提高程式的安全性,保護資料
  2. 隱藏程式碼的實現細節
  3. 統一介面
  4. 系統可維護性增強
package com.oop.demo04;

public class Pet {
    private String name;
    private int age;
    //無參構造
    public void shout(){
        System.out.println("叫了一聲");
    }
    //getName
    public String getName() {
        return name;
    }
    //setName
    public void setName(String name) {
        this.name = name;
    }
    //getAge
    public int getAge() {
        return age;
    }
    //setAge
    public void setAge(int age) {
        this.age = age;
    }
}
package com.oop.demo04;

public class Aplication {
    public static void main(String[] args) {
        Pet dog = new Pet();
        dog.setName("旺財");
        System.out.println(dog.getName());
        dog.setAge(3);
        System.out.println(dog.getName()+dog.getAge()+"歲了");
        dog.shout();

        Pet cat = new Pet();
        cat.setName("嘟嘟");
        System.out.println(cat.getName());
        cat.setAge(3);
        System.out.println(cat.getName()+cat.getAge()+"歲了");
        cat.shout();
    }

繼承

  1. 繼承的特點:
  • 繼承的本質是對某一批類的抽象
  • extends的意思是"擴充"。子類是父類的擴充
  • JAVA中只有單繼承,沒有多繼承
  • 繼承是類和類的一種關係。除此以外,類和類之間的關係還有依賴、組合、聚合等
  • 繼承關係的兩個類,一個為子類,一個為父類。子類繼承父類,使用關鍵字extends來表示
  • 子類和父類之間,從意義上應該具有"is a"的關係

object類

package com.oop.demo05;
//在JAVA中,所有的類都預設直接或者間接繼承Object類
//Person是父類
//Ctrl + H 可以檢視繼承樹
public class Person {
    //屬性一般是私有的
    //要想使用屬性則需要使用封裝時留下的方法get/set
    private int money = 10_0000_0000;
    public void say(){
        System.out.println("我喜歡錢!");
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
}
package com.oop.demo05;

public class Student extends Person{
}
package com.oop.demo05;

public class Aplication {
    public static void main(String[] args) {
        Student student = new Student();
        student.say();
        student.setMoney(10_0000);
        System.out.println("student有"+student.getMoney()+"元");
    }
}

super

super注意點:
    1.super呼叫父類的構造方法,必須在構造方法的第一個
    2.super 必須只能出現在子類的方法和或者構造方法中!
    3.super和this 不能同時呼叫構造方法

VS this:
    1.代表的物件不同:
        this:本身呼叫者這個物件
        super: 代表父類物件的引用
    2.前提:
        this: 沒有繼承也可以使用
        super: 只能在繼承條件才可以使用
    3.構造方法:
        this();本類的構造
        super();父類的構造
package com.oop.demo06;

public class Person {

    public Person(){        //Person的無參構造
        System.out.println("Person的無參構造");
    }
    /*Person的有參構造,如果在子類Student預設呼叫,則無法呼叫,除非呼叫Person的無參構造
    public Person(String name){
        System.out.println("Person的無參構造");
    }*/
    //如果name是私有的則子類無法繼承
    protected String name = "huangshen";
    public void print(){
        System.out.println("Person");
    }
}
package com.oop.demo06;

public class Student extends Person {
    public Student(){              //Student的無參構造
        //隱藏程式碼:呼叫了父類的無參構造
        //super("Student");        //呼叫父類的構造器,必須在子類構造器的第一行
        //this();                  //呼叫自己的構造器也必須放在第一行但是必須先呼叫父類的構造器
        System.out.println("Student的無參構造");
    }
    private String name = "huangyilin";
    public void print(){
        System.out.println("Student");
    }
    //this表示當前類,super表示父類
    public void test1(){
        print();            //Student
        this.print();       //Student
        super.print();      //Person
    }
    public void test(String name){
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);

    }
}
package com.oop.demo06;

public class Aplication {
    public static void main(String[] args) {
        Student student = new Student();
        student.test("hyl");
        student.test1();
    }
}

方法重寫

重寫:需要有繼承關係,子類重寫父類的方法
    1.方法名必須相同
    2.引數列表必須相同
    3.修飾符:範圍可以擴大但不能縮小:public>protected>default>private
    4.丟擲的異常:範圍可以縮小但不能擴大:ClassNotFoundException-->Exception大
重寫:子類的方法和父類必須一致,方法體不同!

為什麼需要重寫:
    1.父類的功能,子類不一定需要或者不一定滿足
    Alt + Insert : override;
package com.oop.demo07;

//重寫都是方法的重寫與屬性無關!!!
public class B {
    public  void test(){
        System.out.println("B->test");
    }
}
package com.oop.demo07;

//繼承
public class A extends B {
    @Override //註解:有功能的註釋
    public void test() {
        System.out.println("A->test");
    }
}package com.oop.demo07;


//靜態方法:方法的呼叫只和左邊的資料型別有關
//非靜態方法: 重寫
public class Aplication {
    public static void main(String[] args) {
        A a = new A();
        a.test();   //A
        //父類的引用指向了子類
        B b = new A();      //子類重寫了父類的方法
        b.test();   //B
    }
}


多型

  • 多型的注意事項:
  1. 多型是方法的多型,屬性沒有多型
  2. 父類和子類,有聯絡 ,型別轉化異常!ClassCastException
  3. 存在條件:繼承關係,方法需要重寫,父類引用指向子類物件!Father f1 = new Son();
  • static 方法,屬於類,不屬於例項

  • final 常量

  • private方法

  • 型別轉換:

  1. 父類引用指向子類的物件

  2. 把子類轉換為父類,向上轉型;

  3. 把父類轉換為子類,向下轉型;強制轉換

  4. 方便方法的呼叫,減少重複的程式碼!

package com.oop.demo08;

public class Person {
    public void run(){
        System.out.println("run");
    }
}
package com.oop.demo08;

public class Student extends Person {
    @Override
    public void run() {
        System.out.println("son");
    }
    public void eat(){

        System.out.println("eat");
    }
}
package com.oop.demo08;

public class Aplication {
    public static void main(String[] args) {
        //一個物件的實際型別是確定的
        //new Student
        //new Person

        //可以指向的引用型別就不確定了:父類的引用指向子類

        //Student 能呼叫的方法都是自己的或者繼承父類的!
        Student s1 = new Student();
        //Person 父型別,可以指向子類,但是不能呼叫子類獨有的方法
        Person s2 = new Student();
        Object s3 = new Student();

        //物件能執行哪些方法,主要看物件左邊的型別,和右邊關係不大!
        s1.eat();
        s2.run();   //子類會重寫父類的方法,執行子類的方法
    }
}

instanceof

  • 判斷兩個型別之間是否存在父子關係
  • (物件)instanceof(型別)

static關鍵字詳解

package com.oop.demo09;

//public final class Person {},則Person沒有子類
public  class Person {
    //賦初值;
    //2.
    {
        System.out.println("匿名程式碼塊");
    }
    //只載入一次
    //1.
    static {
        System.out.println("靜態程式碼塊");
    }
    //3.
    public Person(){
        System.out.println("構造方法");
    }

    public static void main(String[] args) {
        Person person1 = new Person();
        Person person2 = new Person();
    }

}
package com.oop.demo09;

public class Student {
    private static int age; //靜態的變數,多執行緒!
    private double score;   //非靜態變數

    public void run(){      //非靜態方法,從屬於物件
        go();
    }
    public static void go(){    //靜態方法從屬於類,只載入一次
        System.out.println("go!");
    }

    public static void main(String[] args) {
        Student.go();;
    }
}
package com.oop.demo09;

//靜態匯入包~
import static java.lang.Math.random;
import static java.lang.Math.PI;

public class Test {
    public static void main(String[] args) {
        System.out.println(random());
        System.out.println(PI);
    }
}

抽象類

package com.oop.demo10;
//abstract 抽象類:extends: 單繼承 (介面可以多繼承)
public abstract class Action {
    //約束~有人幫我們實現
    //abstract ,抽象方法,只有方法名字 , 沒有方法的實現
    private String name = "Action";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Action(){
        System.out.println("Action 的構造器");
    }

    public abstract void doSomething();
    public void print(){
        System.out.println("print");
    }
    public void run(){
        System.out.println("run");
    }
    /* 抽象類的特點:
     * 1.不能new這個抽象類,只能靠子類去實現!
     * 2.抽象類中可以寫普通的方法!
     * 3.抽象方法必須在抽象類中!
     * 思考:
     * 1.new 抽象類的子類,原抽象類中存在構造器嗎?
     * 存在構造器,而且如果new 子類的一個物件會先呼叫抽象類的構造器,然後呼叫子類的構造器
     * 2.抽象類存在的意義是什麼?
     * 抽象類有很多的抽象方法,子類必須根據自己的要求重寫這些抽象方法,而不同於抽象類的普通方法
     */
}
package com.oop.demo10;

public class B extends Action {
    //抽象類的所有抽象方法,繼承了它的子類,都必須要實現~除非該類又是一個抽象類

    public B(){
        System.out.println("B 的構造器");
    }
    @Override
    public void doSomething() {
        System.out.println("BdoSomething");
    }

    @Override
    public void print() {
        System.out.println("Bprint");
    }

}
package com.oop.demo10;

public class A extends Action{
    //抽象類的所有抽象方法,繼承了它的子類,都必須要實現~除非該類又是一個抽象類

    public A(){
        System.out.println("A 的構造器");
    }
    @Override
    public void doSomething() {
        System.out.println("AdoSomething");
    }

    @Override
    public void print() {
        System.out.println("Aprint");
    }
}
package com.oop.demo10;

public class Test {
    public static void main(String[] args) {
        A a = new A();          //a屬於A類
        a.doSomething();        //a呼叫子類重寫抽象類的抽象方法
        B b = new B();          //B屬於B類
        b.doSomething();        //b呼叫子類重寫抽象類的抽象方法
        Action a1 = new A();    //a1屬於A類
        a1.print();             //a1呼叫子類重寫抽象類的方法(多型)
        Action b1 = new B();    //b1屬於B類
        b1.print();             //b1呼叫子類重寫抽象類的方法(多型)
        b1.run();               //b1呼叫繼承父類的方法
        b1.setName("B");        //name屬於Action類的私有屬性,故只能採用封裝的思想使用
        System.out.println(b1.getName());
    }
}

介面的定義和實現

  • 普通類:只有具體實現
  • 抽象類:具體實現和規範(抽象方法)都有!
  • 介面:只有規範!以自己無法寫方法~專業的約束! 約束和實現分離:面向介面程式設計~
  • 介面就是規範,定義的是一組規則,體現了現實世界中"如果你是...則必須能..."的思想
  • 介面的本質是契約,就像人間的法律一樣,如果制定,必須遵守
  • OO的精髓,是對物件的抽象,最能體現這一點的就是介面。為什麼討論設計模式都只針對具備抽象能力的語言(比如C++,Java,C#等),就是因為設計模式所研究的,實際上就是如何合理的去抽象
package com.oop.demo11;

public interface TimeService {
    void timer();
}
package com.oop.demo11;

//interface 定義的關鍵字
public interface UserService {
    //常量:public static final
    int AGE = 99;
    //介面中的所有定義其實都是抽象的 public abstract
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}
package com.oop.demo11;

//抽象類:extends~
//類 可以實現介面 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() {

    }
}

介面的作用

1.約束,只能規範

2.介面中定義的方法:public abstract

3.介面中定義的屬性:public static final

4.介面不能被例項化,介面不是類沒有構造方法

5.implements 可以實現多個介面

6.一旦繼承了介面,必須要重寫介面中的方法

N種內部類

成員內部類、靜態內部類

  1. 成員內部類:外部類裡包含一個內部類,直接載入內部類(可以獲得外部類的私有屬性)解決一些問題(封裝)
  2. 靜態內部類:外部類裡包含一個內部類,直接載入內部類(不可以獲得外部類的私有屬性)解決一些問題(封裝)
package com.oop.demo12;

public class Outer {
    private int id = 10086;
    public void out(){
        System.out.println("外部類方法");
    }
    //成員內部類
    //public static Inner{} 靜態內部類 -> 無法使用外部類的非靜態屬性
    public  class Inner{
        public void in(){
            System.out.println("內部類方法");
        }
        //可以獲得外部類的私有屬性
        public void getID(){
            System.out.println(id);
        }
    }
}
package com.oop.demo12;

public class Aplication {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.out();
        //透過外部類Outer來例項化內部類Inner
        Outer.Inner inner = outer.new Inner();
        inner.in();
        inner.getID();

    }
}

區域性內部類、匿名內部類

  1. 匿名內部類:載入類的方法,使用區域性內部類解決問題(封裝細節)
/*區域性內部類*/
package com.oop.demo13;

public class Outer {

    public void method(){
        //區域性內部類
        class Inner{
            public void in(){
                System.out.println("區域性內部類");
            }
        }

        Inner inner = new Inner();
        inner.in();
    }
}
package com.oop.demo13;

public class Test {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.method();

    }
}

  1. 匿名內部類:節省空間
/*匿名內部類*/
package com.oop.demo14;

public class Outer {
    public static void main(String[] args) {
        //沒有名字初始化類,不用將例項儲存到變數中
        new Apple().eat();
        UserService userService = new UserService(){
            @Override
            public void hello() {
                System.out.println("hello");
            }
        };
        userService.hello();

    }
}

//匿名內部類
class Apple{
    public void eat(){
        System.out.println("eat Apple");
    }
}
//匿名內部介面
interface UserService{
    void hello();
}

異常

捕獲和丟擲異常

  1. 異常處理機制
  • 丟擲異常
  • 捕獲異常
  1. 異常處理五個關鍵字
  • try、catch、finally、throw、throws
package com.exception;

public class Demo01 {
    public static void main(String[] args) {
        int a = 1;
        int b = 0;

        try {                               // try監控區域
            System.out.println(a/b);
        }catch (ArithmeticException e){     //catch 捕獲異常
            System.out.println("程式出現異常,變數b不能為0");
        }finally {                          //finally可以不要,假設I/O,資源出現異常,可以使用finally關閉
            System.out.println("finally");
        }


    }
}
package com.exception;

public class Demo02 {
    public static void main(String[] args) {
        int a = 1;
        int b = 0;
        //假設要捕獲多個異常,從小到大!
        try {
            Demo02 demo02 = new Demo02();
            demo02.a();
        }catch (Exception e){
            System.out.println("Exception");
        }catch (Error e){
            System.out.println("Error");
        }catch (Throwable e){
            System.out.println("Throwable");
        }finally {
            System.out.println("finally");
        }
    }
    public void a(){b();}
    public void b(){a();}
}
package com.exception;

public class Demo03 {
    public static void main(String[] args) {
        int a = 1;
        int b = 0;
        //選中要監控的程式碼 Ctrl + Alt + T
        try {
            System.out.println(a/b);
        } catch (Exception e) {
            e.printStackTrace(); //列印錯誤的棧資訊
        } finally {              // finally處理善後資訊
        }


    }
}
package com.exception;

public class Demo04 {
    public static void main(String[] args) {
        new Demo04().test(1,0);
    }

    public void test(int a,int b){
        if (b==0){  //throw
            throw new ArithmeticException();//主動丟擲異常,一般在方法中使用
        }
    }
}
package com.exception;

public class Demo05 {
    public static void main(String[] args) {
        new com.exception.Demo04().test(1,0);
    }
    //假設這個方法中,處理不了這個異常,就在方法上丟擲異常
    public void test(int a,int b) throws ArithmeticException {}
}

自定義異常及經驗小結

package com.exception.finaldemo;

//定義的異常類
public class MyException extends Exception{
    //傳遞數字10;
    private int detail;

    public MyException(int a){
        this.detail = a;
    }

    //返回異常的資訊
    @Override
    public String toString() {
        return "MyException{" + detail + '}';
    }

}
package com.exception.finaldemo;

public class Test {
    //可能會存在異常的方法
    public static void test(int a)throws MyException{
        System.out.println("傳遞的引數為:"+a);
        if (a>10){
            //在這個方法中處理不了這個異常,,就在方法上丟擲異常
            throw new MyException(a);
        }
        System.out.println("ok!");
    }

    public static void main(String[] args) {
        try {
            test(20);
        } catch (MyException e) {
            //增加一些處理異常的程式碼
            System.out.println(e);
        }
    }
}

相關文章