JavaSE-面向對象

面向對象

面向對象編程(Object-Oriented Programming, OOP)

初識面向對象

面向對象編程的本質就是:以類的方式組織代碼,以對象的形式組織封裝數據。

抽象

從認識論角度考慮是現有對象後有類。對象,是具體的事物。類,是抽象的,是對對象的抽象

從代碼運行角度考慮是先有類後有對象。類是對象的模版

三大特性:

封裝

繼承

多態

方法回顧和加深

修飾符

返回值類型

可以爲八大基本類型和引用類型,也可以爲void(無返回值),返回值類型爲void時,書寫return;

return 與 break區別:

break:跳出switch,結束循環

return:結束方法

參數列表:參數類型+參數名 以及可變長參數

拋出異常:

 public void readFile(String file) throws IOException {
        
    }

方法的調用

主要分爲有static修飾和無static修飾

當有static修飾符修飾的方法,是跟類一起加載的,即使類沒有被實例化也可以直接調用。類名.方法名 調用該方法

當無static修飾符修飾的方法,是類實例話後才加載的,不可以直接調用,需要實例化類後通過類的實例化對象進行調用

//學生類
public void say(){
  System.out.println("學生說話了");
}
//另一個demo類  
public static void main(String[] args) {

  //對象類型  對象名  = 對象值
  student student = new student();
  student.say();

}

值傳遞和引用傳遞

先來看值傳遞

//值傳遞
public class Demo04 {
    public static void main(String[] args) {
        int a = 1;
        int b = 2;

        System.out.println(a);
        System.out.println(b);

        System.out.println("===================change===================");
        Demo04.change1(a);
        System.out.println(a);  //1,因爲沒有把change方法中的值返回出來,所以並沒有發生變化
        b = Demo04.change2(b);
        System.out.println(b);

    }

    //返回值爲空
    public static void change1(int a){
        a = 10;
    }
    public static int change2(int b){
        b = 20;
        return b;

    }

引用傳遞

//引用傳遞:一般是傳遞一個對象,本質還是值傳遞
//一個class裏只能有一個public class,但可以有多個class
public class Demo05 {

    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name); //null


        //這裏不同於值傳遞,因爲在change方法中傳入的是person這個對象,修改的是person這個對象的.name屬性,所以成功了,
        Demo05.change(person);
        System.out.println(person.name);

    }


    public static void change(Person person){
        person.name = "Zh1z3ven";
    }


}

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

this關鍵字

代表當前這個類或者對象

對象的創建分析

使用new關鍵字創建對象

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

類中的構造器也稱爲構造方法,是在進行創建對象的時候必須調用的。並且構造器有以下兩個特點

1、必須和類的名字相同

2、必須沒有返回類型,也不能寫void

public class Student {

    //屬性:字段
    String name;    //創建實例化對象時默認爲null
    int age;    //0


    //方法
    public void study(){
        System.out.println(this.name + "is Learning...");
    }

}
public class Application {

    public static void main(String[] args) {
        //類是抽象的,需要實例化
        //類實例化後會返回一個自己的對象
        //stduent就是student類的具體實例

        Student xiaoming = new Student();
        Student agou = new Student();

        xiaoming.name = "小明";
        xiaoming.age = 18;

        System.out.println(xiaoming.name);
        System.out.println(xiaoming.age);


        agou.name = "阿狗";
        agou.age = 18;

        System.out.println(agou.name);
        System.out.println(agou.age);

    }

}

構造方法

1、和類名相同

2、沒有返回值

3、new的本質是在調用構造方法

4、初始化對象的值

5、定義有參構造之後,如果想使用無參構造,需要顯示的定義一個無參的構造,不然就只有有參構造方法

6、alt + insert 快捷鍵

public class Person {

    //一個類即使什麼都寫,他也會存在一個構造方法
    //構造方法用來初始化值
    /* 形如":
    public Person(){
    }
     */
    //顯示定義構造方法
    String name;

    //使用new關鍵字必須有構造方法,本質是在調用構造方法
    //無參構造方法
    public Person(){
        //可以幫助我們初始化對象的屬性值
        this.name = "Zh1z3ven";
    }

    //有參數構造:一旦定義了有參構造,無參構造方法必須顯示定義
    //this.name代表Person類的屬性name
    //後面的name爲有參構造方法傳遞的String name參數
    //alt+insert生成構造方法
    public Person(String name){
        this.name = name;
    }

    public static void main(String[] args) {

        //new 實例化了一個對象
        Person person = new Person();

        System.out.println(person.name);

    }

}

創建對象內存分析

代碼:

public class Pet {

    public String name;
    public int age;

    //無參構造
    

    public void shout(){
        System.out.println("叫了一聲");
    }

}


public class Application {
    public static void main(String[] args) {

        Pet dog = new Pet();
        dog.name = "旺財";
        dog.age = 3;
        dog.shout();

        System.out.println(dog.name);
        System.out.println(dog.age);

    }
}

首先會現在方法區加載Application類(類中包括其main()方法,常量池(存放字符串;但int型數字不算在常量池內)),並在棧中加載main方法

image-20210611201748506

main方法在棧的最低下,方法的調用執行都在棧中執行。之後運行到Pet dog = new Pet()時,先會在方法區實例化對象所需的模版,即加載一個Pet類,包括該類的屬性、常量池和非靜態方法。之後當加載完後 講賦值語句右邊的new Pet()賦值給左邊的Pet dog時,在棧中會加載一個dog的變量,dog變量暫時只是一個引用變量,引用在堆中生成的實例化對象,類似於指針,該引用指向該實例化對象在堆中的內存地址。

image-20210611202829021

而在實例化對象內的shout()是在引用方法區中Pet類中的shout()方法。之後執行到賦值語句時也就是

dog.name = "旺財";dog.age = 3;

這時會把Application類中的常量池中的旺財賦值給中的name ,之後3賦值給堆中的age ,同時shout()調用的是Pet類中的shout()方法(因爲並沒有參數傳遞,所以是同一個方法)

image-20210611203240461

在方法區中的靜態方法區內,這裏存放的是被static修飾符修飾的方法都會同類同時被加載,所以可以不用通過實例化對象就可以直接調用被static修飾的方法。

image-20210611203429557

簡單小結類與對象

類是一個模版,是實例化對象的模版

對象是一個具體的實例,是一個類的實例化對象

方法的定義

修飾符 返回值類型 方法名(參數類型 參數名){
方法體
...
return 返回值;
}

方法的調用

調用方法:對象名.方法名(實參列表)

Java支持兩種調用方法的方式,根據方法是否有返回值來選擇。

return不僅可以返回值,同樣可以結束這個方法。例:return 0;結束當前方法。

當方法返回一個值的時候,方法調用通常被當作一個值賦值給一個變量。

int larger = max(30, 40);

當方法返回值爲void時,方法調用一定是一條語句

System.out.println("Hello, Zh1z3ven!");

對象的引用

引用類型:

基本類型8個(byte、short、int、long、float、double、boolean、char)

剩下的都是引用類型,對象也是通過引用來操作的:棧-->堆(地址)

屬性:字段field 成員變量,默認初始化(數字:0,char:u000,boolean:false,引用:null)

屬性的定義:

修飾符 屬性類型 屬性名 = 屬性值

對象的創建和使用

必須使用new關鍵字創建對象 ,注意構造方法,Person zh1z3ven = new Person()

對象的屬性: zh1z3ven.name

對象的方法: zh1z3ven.sleep()

靜態的屬性:屬性

動態的行爲:方法

面向對象三大特性

封裝

程序設計追求“高內聚、低耦合”,高內聚就是類的內部數據操作細節自己完成,不允許外部干涉;低耦合:僅暴露少量的方法給外部使用。

屬性私有 get/set

屬性私有,即用private修飾屬性

get/set,對外提供get set方法使得外部可通過該方法控制屬性值

同時可在set方法中進行安全設置,提高程序的安全性

/*1、提高程序的安全性2、隱藏代碼的實現細節3、統一接口 get、set形成規範4、提高系統可維護性 */public class Student {    //屬性私有,加private關鍵字去修飾屬性    private String name;    private int id;    private char sex;    private int age;    //提供一些可以操作這個屬性的方法    //提供public的get或set方法    public String getName(){        return this.name;    }    public void setName(String name){        this.name = name;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public char getSex() {        return sex;    }    public void setSex(char sex) {        this.sex = sex;    }    public int getAge() {        return age;    }    public void setAge(int age) {        if (age > 120 || age < 0){            this.age = 3;        }else {            this.age = age;        }    }}public class Application {    public static void main(String[] args) {        Student s1 = new Student();        s1.setName("Zh1z3ven");        System.out.println(s1.getName());        //並不能通過形似s1.name直接訪問操作類的屬性,但是可以通過某些可被調用的外部方法去操作這個類的私有屬性值        //封裝:1、屬性私有。2、提供可被外部調用的方法去操作私有屬性        //alt+insert 選中getter and setter一鍵生成 get set方法,        //mac爲control+return,選中所需要設置的屬性即可直接生成        //或者右鍵選擇generate    }}

繼承

extends

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

Java中只有單繼承沒有多繼承

繼承就是擴展的意思,子類是對父類的擴展。

子類可以繼承父類的所有方法

繼承是類和類之間的一種關係,除此之外還有依賴,組合,聚合等

繼承關係的倆個類,一個爲子類(派生類)一個爲父類(基類)。子類繼承父類,使用關鍵字extends表示

子類和父類之間,從意義上講因該具有 is a 的關係

Ctrl + h 可以看該類的繼承關係

object類

在Java中所有的類都默認直接或間接繼承於Object

super

如果父類重寫了有參構造,最好也寫上無參構造,以便後續子類去繼承該父類(不然只能調用父類的有參構造方法,默認是調用無參的構造方法)

  1. super調用父類的構造方法必須在構造方法的第一個
  2. super必須只能出現在子類的方法或構造方法中
  3. super和this不能同時調用構造方法

this代表本身調用者的這個對象

super代表父類對象的引用

super必須存在繼承關係纔可以使用

this(); 代表本類的構造方法

super(); 代表父類的構造方法

//父類public class Person {    public Person(){        System.out.println("Person無參執行了");    }    public int money = 1000000000;    public void say(){        System.out.println("說了一句話");    }    protected String name = "Zh1z3ven";    public void print(){        System.out.println("Person");    }}
//子類public class Student extends Person {    //默認調用了父類的無參構造,調用父類的構造方法必須在子類構造方法的第一行    public Student(){        super();        //也可以不寫        System.out.println("Student無參執行了");    }    private String name = "zh1z3ven";    public void print(){        System.out.println("Student");    }    public void test1(){        print();        this.print();        super.print();    }    public void test(String name){        System.out.println(name);//傳遞的參數name        System.out.println(this.name);//student的屬性name        System.out.println(super.name);//父類的屬性name    }}
public class Application {    public static void main(String[] args) {        Student student = new Student();        student.test("zz");        student.test1();    }}

方法重寫

重寫都是非靜態方法的重寫(static方法屬於類的方法,不屬於實例的方法,重寫指的是重寫實例的方法)

final修飾的是常量池中的常量,不能被重寫。private方法不能被重寫。

子類重寫方法的權限修飾符要大於父類 public>protected>default>private

方法名必須相同、參數列表必須相同(不然就是重載了)

拋出異常的範圍與權限修飾符的範圍一致

子類的方法與父類的方法必須要一致,但是方法體不同

爲什麼需要重寫?

1.父類的功能,子類不一定需要,或者不一定滿足

  1. alt+insert / control + return @override
@Override  //註解:有功能的註釋    public void test() {        super.test();			//默認調用父類的方法,也可以自己重寫    }

當重寫一個非靜態父類方法時,在子類中contorl + return即可生成一個重寫方法

靜態方法是屬於類的方法,當下面test()方法爲static修飾的靜態方法時,那麼會各自調用自己類中的test()方法。因爲此時調用的是類中的靜態方法;而當沒有static修飾時,這時調用的都是A類中的test()方法,因爲這時調用的是A的實例化對象加載的test()方法(只有static修飾的方法纔會和類一起在方法區中同時加載)

可以簡單理解爲一旦子類重寫了父類的方法,就執行子類的方法

class A extends BA a = new A();a.test();//父類引用指向子類B b = new A();b.test()A類中test()實現:System.out.println("A=>test()");B類中test()實現:System.out.println("B=>test()");

多態

class Student extends PersonStudent s1 = new Student();Person s2 = new Student();Object s3 = new Student();

一個對象的實際類型是確定的(new Student();),但是可以指向的引用類型就不確定了(Student s1/Person s2/Object s3

多態注意事項:

  • 多態是方法的多態,屬性沒有多態
  • 父類和子類有聯繫. ClassCastException類型轉換異常
  • 多態存在的條件:繼承關係、方法需要重寫、父類的引用指向子類對象 Father f1 = new son();

Instanceof

判斷一個對象是什麼類型,可以判斷兩個類之間是否存在繼承關係

    					//Object > String        //Object > Person > Student        //Object > Person > Teacher        Object object = new Student();     //Object類型        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 Object);    //true        System.out.println(person instanceof Person);    //true        System.out.println(person instanceof Student);    //true        System.out.println(person instanceof Teacher);      //false        //System.out.println(person instanceof String);    //編譯報錯    }

類型轉換

public static void main(String[] args) {        //類型之間的轉化:  父      子        //低 --> 高 可以自動轉換                //高 --> 低 需要強制轉換          Person obj = new Student();                //student將這個對象轉換爲Student類型,就可以使用Studen類型的方法        Student student = (Student) obj;	//強制轉換        student.go();                ((Student) obj).go();							//強制轉換        Person person = student;        //自動轉化    }    

static關鍵字

static : 修飾成員變量或者方法,修飾爲靜態變量或者靜態方法

被static修飾的屬於類,非static的屬於對象

靜態變量屬於類的變量,存儲在方法區的靜態方法區內,是一塊固定的內存,隨着類的加載同時加載,當直接使用類去調用一個變量說明此變量就是靜態變量

非靜態方法也可以直接調用靜態方法

靜態方法可以直接調用,無需實例化對象

//static : 修飾成員變量或者方法,修飾爲靜態變量或者靜態方法//被static修飾的屬於類,非static的屬於對象public class Student {    //靜態變量屬於類的變量,存儲在方法區的靜態方法區內,是一塊固定的內存,隨着類的加載同時加載,當直接使用類去調用一個變量說明此變量就是靜態變量    private static int age;     //靜態變量    private double score;       //非靜態變量    public void run(){        go();                   //非靜態方法也可以直接調用靜態方法    }    public static void go(){    }    public static void main(String[] args) {        Student s1 = new Student();        System.out.println(Student.age);        System.out.println(s1.age);        System.out.println(s1.score);        s1.run();        Student.go();   //靜態方法可以直接調用,無需實例化對象        go();    }}
public static void main(String[] args) {        Student student = new Student();        System.out.println("==================");        Student student1 = new Student();    }    // 2    :賦初始值    {        System.out.println("匿名代碼塊");        //匿名代碼塊        //隨着對象的創建而創建,在構造方法之前    }    // 1    :   只執行一次,後面不會執行    static {        //靜態代碼快,方便加載初始化一些數據        //隨着類的加載而加載,永久只執行一次        System.out.println("靜態代碼快");    }    // 3    //alt+inset/contorl+return --> select none    public Student() {        System.out.println("構造方法");    }}輸出結果:靜態代碼快匿名代碼塊構造方法==================匿名代碼塊構造方法

利用static靜態導入包及常量

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

抽象類和接口

抽象類

abstract修飾符可以修飾方法也可以修飾類,如果修飾方法,那麼該方法就是抽象方法;如果修飾類,該類就是抽象類

抽象類中可以沒有抽象方法,但是抽象方法的類一定要聲明爲抽象類

抽象類,不能使用new關鍵字來創建對象,它是用來讓子類繼承的(類是單繼承)

抽象方法,只有方法的聲明,沒有方法的實現,它是用來讓子類方法去實現的

子類繼承抽象類,那麼就必須要實現抽象類沒有實現的抽象方法,否則該子類也要聲明爲抽象類

public  abstract class Action {    //抽象方法,只有方法名字,沒有方法的實現    public abstract void doSomething();    //抽象類不能new,只能靠子類去實現    //抽象類可以寫普通方法    //抽象類存在構造方法嗎?    //抽象類存在的意義?提高開發的可擴展性}//繼承抽象類的子類必須重寫抽象方法並實現,除非子類也是abstractpublic class A extends Action{    @Override    public void doSomething() {    }}

接口

聲明接口的關鍵字是interface

接口可以多繼承

普通類:只有具體的實現

抽象類:具體實現和規範(抽象方法)都有

接口:只有規範。約束和實現分離(面向接口編程)

接口就是規範,定義的是一組規則,體現了現實世界中“如果你是。。。你必須能。。”的思想。如果你是天使你必須能飛,如果你是汽車,你必須能跑。

接口的本質是契約,就像我們人間的法律一樣。制定好後大家都遵守。

OO的精髓,是對對象的抽象,最能體現這一點的就是接口。

//interface 定義的關鍵字public interface UserService {    //接口中的所有定義其實都是抽象的,不能在接口中實現方法    //修飾符默認爲 public abstract    //常量。默認修飾符爲 public static final    int AGE = 99;    void add(String name);    void delete(String name);    void update(String name);    void select(String name);}
//實現接口需要重寫裏面的方法,類可以實現接口//public class 類名(一般以Impl結尾) 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 select(String name) {    }    @Override    public void timer() {    }}
public interface TimeService {    void timer();}

接口小結

  • 接口是一種規範、約束
  • 只有方法的定義,沒有方法的實現
  • 方法默認修飾符爲public abstract
  • 常量默認修飾符爲public static final
  • 接口不能被實例話,接口沒有構造方法
  • implements可以實現多個接口
  • 繼承接口的類必須重寫實現接口的方法

內部類

內部類主要分爲四種:成員內部類、局部內部類、靜態內部類、匿名內部類

內部類就是在一個類的內部定義一個類,比如,A類中定義一個B類,那麼B類相對A類來說就稱爲內部類,而A類相對B類來說就是外部類了。

成員內部類

public class Outer {    private int id = 10;    public void out(){        System.out.println("這是外部類的方法");    }    public class Inner{        public void in(){            System.out.println("這是內部類的方法");        }        //內部類訪問外部私有變量        public void getID(){            System.out.println(id);        }    }}
public static void main(String[] args) {        Outer outer = new Outer();        outer.out();        //通過外部類實例話內部類:成員內部類        Outer.Inner inner = outer.new Inner();        inner.in();        inner.getID();            }

靜態內部類

靜態內部類無法直接訪問外部類的非靜態屬性

public class Outer {    private int id = 10;    public void out(){        System.out.println("這是外部類的方法");    }    public static class Inner{        public void in(){            System.out.println("這是內部類的方法");        }        //內部類訪問外部私有變量        public void getID(){            System.out.println(id);        }    }}

還可以在java文件中聲明另一個類

public class Outer {    private int id = 10;    public void out(){        System.out.println("這是外部類的方法");    }    public class Inner{        public void in(){            System.out.println("這是內部類的方法");        }        //內部類訪問外部私有變量        public void getID(){            System.out.println(id);        }    }}//一個java文件裏面只能有一個public class,但是可以有多個classclass A{    }

局部內部類

在類的方法中創建一個類

public class Outer {    public void method(){            //局部內部類        class Inner{                    }    }}

匿名內部類

沒有類名的內部類

public class Test {    public static void main(String[] args) {        //沒有名字初始化類        //匿名對象的使用,不用把實例保存在變量中       new Apple().eat();             UserService userService = new UserService(){           @Override           public void hello() {                          }       };            }    }class Apple{    public void eat(){        System.out.println("1");    }}interface UserService{    void hello();}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章