JavaSE-07 Opp面向對象(完整版)

語言: CN / TW / HK

JavaSE-07 Opp 面向對象(完整版)

1.方法的調用補充:package com.fenfen.oop.Demo1

1.1非靜態方法下方法調用(不同的類)

①在Student的類中建立study的方法
        package com.fenfen.oop.Demo1;
        //學生類的方法
        public class Student {
            //方法
            public void study(){
                System.out.println("學生在學習");
            }
        }

        ②在Demo2類中調用Student類中的student方法
        //在別的類中調用
        package com.fenfen.oop.Demo1;

        public class Demo2 {
            public static void main(String[] args) {
                //在方法非靜態下:實例化這個類
                //對象類型 對象名 = 對象值
                Student student = new Student();
                student.say();
                }
            }

1.2非靜態方法下的方法調用(同個類)

public class Demo2 {

          //static和類(class:Demo2)一起加載
            public static void a(){
                b();//會報錯原因:可以理解為:存在的去調用不存在的了
            }
            //沒有static:這個得等到類實例化(new 後)才存在
            public void b(){
                a();
            }
        }

1.3 值傳遞:

//值傳遞
        public class Demo4 {
            public static void main(String[] args) {
                int a = 1;
                change(a);
                System.out.println(a);//輸出仍然是a = 1
            }

            //無返回值
            public static void change(int a){
                //原因:a只是一個形式參數,a=10後沒有返回值給到a,於是回到了主方法,主方法中有int a = 1,因此輸出就是1了
                a = 10;
            }

            /*
            更加高端的解釋:
                ①change方法調用完畢就出棧了,main方法還在棧中
                ②對於基本數據類型來説,給形參傳遞的是實參值的副本
                    而對於引用數據類型來説,傳遞則是地址的副本,但由於地址的副本和原來的相似,因此傳遞過去後的形參也指向同一個內存空間
             */

1.4 引用傳遞:

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

            change(person);
            System.out.println(person.name);//fenfen
        }

        //寫個方法
        public static void change(Person person){
            person.name = "fenfen";//原因:引用傳遞:指針修改,因為引用指向原對象在內存中的區域,所以可以修改原對象的值

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

2. 對象的創建與分析:com.fenfen.oop.Demo2

2.1 類和方法的創建:Student,Application

//學生類
        public class Student {
            //①屬性:字段
            String name;//未賦任何值,默認初始化為null
            int age;//為賦任何值,初始化為0

            //②方法
            public void study(){
                System.out.println(this.name+"學生在學習");//this表示當前這個類
            }
        }
public class Application {

            public static void main(String[] args) {
                //實例化:student對象就是一個Student類的具體實例
                Student student = new Student();
                Student xiaoming = new Student();
                Student xiaohong = new Student();

                //給對象賦值:        
                xiaoming.name = "小明";
                xiaoming.age = 3;

                //打印賦值後的對象屬性:未賦值出來是null和0
                Person person = new Person();
                System.out.println(person.name);
                }
            }

2.2 構造器詳解

2.2.1 無參構造器

public class Person {            
            String name;
            //1、一個類即使什麼都不寫,也會存在構造方法(和類名相同,且無返回值),即構造器:無參構造器
            //構造器的作用:實例化初始值:使用new對象,本質是在調用構造器
            public Person(){
                this.name = "fenfen";
                        }
public class Application {

            public static void main(String[] args) {

                Person person = new Person();
                System.out.println(person.name);//fenfen
            }

2.2.2 有參構造器

public class Person {            
            String name;
            //2、有參構造器:一旦定義了有參構造,無參就必須顯示定義(就是有了有參,無參不能刪,空着就好)

            public Person(){
                }

            public Person(String name){
                this.name = name;
            }
public class Application {

            public static void main(String[] args) {

        //實例化了一個對象:走的無參構造器
        Person person = new Person();
        System.out.println(person.name);

        //走有參構造器
        Person person1 = new Person("fenfen");
        System.out.println(person1.name);
            }
        }   

        //注:快捷鍵alt+insert然後點擊constructor,可以選擇無參或有參快速生成構造器

2.3 創建對象內存分析:com.fenfen.oop.Demo3

棧的概念是彈壓,就像子彈殼裝彈,一粒一粒壓進去,但是打出來的時候是從上面打出來的,最先壓進去的最後彈出來,如果進去順序是123,打出來順序是321,這就是後進先出

隊列的概念就是我們平時排隊,按次序來,你排在第1個,那你就第一個輪到,就是先進先出,先到先來

2.3.1 對應代碼

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 =1;
                dog.shout();

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

2.3.2 對應內存順序圖:

3. 三大特性

3.1 封裝:com.fenfen.oop.Demo4

3.1.1 相關概念:

原因:
a.程序設計應”高內聚,低耦合“,即類的內部數據操作細節不允許外界干涉,以及僅暴露少量方法給外部使用
b.封裝:應禁止直接訪問一個對象中數據的實際顯示,通過操作接口去訪問,以便信息隱藏

3.1.2 封裝

//封裝:屬性私有 get/set
        public class Student2 {
            //名字、姓名、學號:一般封裝對於屬性來説比較多,對於方法少一些
            //學習、睡覺
            private String name;
            private int id;
            private char sex;
            private int age;

            //提供一些可以操作的這個屬性的方法:因為上面private了
            //提供一些public的get、set的方法

            //①get獲得這個數據
            public String getName() {
                return this.name;
            }

            //②set  給這個數據設置值
            public void setName(String name){
                this.name = name;

            }
            //注:快捷鍵alt+insert然後點擊setter and getter,可以快速生成

            //③甚至可以在set裏面寫if判斷來進行安全性檢查
            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) {       

            Student2 s1 = new Student2();

            //s1.name = "fenfen";私有的不可調用
            String name = s1.getName();//get
            s1.setName("fenfen");
            System.out.println(s1.getName());//s1.getName().sout

            s1.setAge(999);
            System.out.println(s1.getAge());
                }
            }

3.1.3 封裝的意義:

封裝的意義:
        1、提高程序的安全性,保護數據
        2、隱藏代碼的實現細節
        3、統一接口
        4、提高系統的可維護性
        5、封裝和重載一般一起用的比較多

3.2 繼承:com.fenfen.oop.Demo5

3.2.1 子類繼承父類的方法與屬性

public class Person {
            public int money = 10_0000_0000;
            public void say(){
            System.out.println("説了一句話");
            }
        }
public class Student extends Person{
            public static void main(String[] args) {
                Student student = new Student();
                student.say();
                System.out.println(student.money);
            }//子類繼承父類,就會擁有父類的方法

3.2.2 子類繼承父類私有的屬性

public class Person {
            private int money2 = 99999999;  

            //get和set方法針對private搞個封裝
            public int getMoney2() {
                return money2;
            }
            public void setMoney2(int money2) {
                this.money2 = money2;
            }
        }
public class Student extends Person{

            public static void main(String[] args) {    

                 Student student = new Student();
                 //針對private的封裝方法的調用
                student.setMoney2(99);
                System.out.println(student.getMoney2());
            }
        }
        //注:   //ctrl+h可以彈出繼承樹

3.2.3 super詳解

  1. super在屬性上的運用
  • 父類
public class Person {
            //protected
            protected String name = "fenfen父類";
        }
  • 子類
public class Student extends Person{
            private String name = "fenfen子類";

            public void test(String name){
                System.out.println(name);//main傳遞過來的參數
                System.out.println(this.name);
                System.out.println(super.name);//super去調用父類的
            }
        }
  • Application類
public class Application {
             public static void main(String[] args) {
                com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student();
                student1.test("fenfenmain類");
                     }
                }
  1. super在方法上的運用
  • 父類
public class Person {
            public void print(){//如果是私有的方法,子類就不能直接訪問了
            System.out.println("Person");
            }
        }
  • 子類
public class Student extends Person{

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

            public void test1(){
                print();//當前方法
                this.print();//當前方法
                super.print();//父類的方法
    }

        }
  • Application類
public class Application {

            public static void main(String[] args) {
                com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student();
                student1.test1();
            }
         }
  1. super在無參構造器上的運用
  • 父類
public class Person {
            public Person(){
            System.out.println("Person無參執行了");
        }

            protected String name = "fenfen父類";
        }
  • 子類
public class Student extends Person{
            public Student() {
                //隱藏代碼:調用了父類的無參構造
                //即有一行:super();且調用父類的構造器必須在子類的第一行
            System.out.println("子類的無參執行了");
            }

            private String name = "fenfen子類";

        }
  • Application類:
public class Application {
             public static void main(String[] args) {
                com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student();
                     }
                }
        /*
        Person無參執行了
        子類的無參執行了
        */
  1. super在有參構造器上的運用
  • 父類
public class Person {

            //整一個有參構造器
            public Person(String name){
                System.out.println("Person無參執行了");
                }
            }
  • 子類
public class Student extends Person{

            public Student() {
                super(name:"name");//記得寫參數,才會去調用有參的
                System.out.println("子類的無參執行了");
            }

                private String name = "fenfen子類";

                }
  • Application類:
public class Application {
             public static void main(String[] args) {
                com.fenfen.oop.Demo5.Student student1 = new com.fenfen.oop.Demo5.Student();
                     }
                }

3.2.4 方法的重寫:com.fenfen.oop.Demo5

  1. 提前介紹多態:有static
  • 父類
public class B {
            public static void test(){

                System.out.println("B=>test");
            }
        }
  • 子類
public class A extends B {
            public static void test(){

                System.out.println("A=>test");
            }
        }
  • Application類
public class C {
            public static void main(String[] args) {
                //方法的調用只和左邊的類型有關,定義的數據類型有關
                A a = new A();
                a.test();//走的是A類的方法

                //A繼承B,父類的引用指向子類
                B b = new A();
                b.test();//走的B類的方法
            }

        }
  1. 方法重寫:非靜態
  • 父類
public class B {
            public void test(){

                System.out.println("B=>test");
                }

            }
  • 子類
public class A extends B{
            //重寫1
            @Override//把static去掉,這個就是註解:有功能的註釋
            public void test() {
                System.out.println("A=>test");
                }
            }
  • Application
public class C {
            public static void main(String[] args) {

                A a = new A();
                a.test();//A=>test

                B b = new A();
                b.test();//A=>test
            }
        }

總結看看:

/*第二次用重寫的沒有static的結果截然不同:
        有static靜態時:b調用的是B類的方法,因為b是用B類去定義的
        沒有static靜態時:b調用的是對象的方法,b是用A類new的

        重寫:需要有繼承關係,而且是子類重寫父類
        1、方法名必須相同
        2、參數列表必須相同
        3、修飾符:範圍可以擴大:
            private--->default---->protected---->public
        4、重寫可能會拋出異常:範圍可以被縮小,但不能被擴大
            ClassNotFoundException

        注意:子類的方法和父類必要一致:方法體不同

        為啥要重寫:override
        1、父類的功能子類不一定需要,或者不一定滿足

3.3 多態:com.fenfen.oop.Demo6

3.3.1 多態的創建

public class Main {
            public static void main(String[] args) {
                //一個對象的實際類型是確定的
                //new Student();
                //new Person();

                //可以指向的引用類型就不確定了
                Student s1 = new Student();//Student能調用的方法都是自己或者是繼承來的:Student類繼承了Person類
                //①父類的引用指向子類的類型
                Person s2 = new Student();//父類的可以指向子類,但是不能調用子類特定的方法
                //②指向Object
                Object s3 = new Student();
                    }
            }

3.3.2 多態方法的調用

  • 父類
public class Person {
            public void run(){
                System.out.println("run");
                }

                }
  • 子類
public class Student extends Person{
        //重寫下父類的方法

            @Override
            public void run() {
                System.out.println("son");
            }

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

            public void go(){
                System.out.println("go");
            }
        }
  • Application
public class Main {     
            public static void main(String[] args) {

            Student s1 = new Student();

            Person s2 = new Student();

            s2.run();//子類重寫了父類的方法,因此父類的方法調用的時候變成子類了
            s1.run();
            s1.eat();
            ((Student)s2).eat();//強制轉換(高類型轉成) ,Person裏面沒有eat方法,所以強制轉換成Student去調用
                }
            }

總結一下 :

/*
        多態注意事項:
        1、多態是方法的多態,屬性沒有多態
        2、父類和子類,有聯繫   如不符合:會出現異常ClassCastException!
        3、存在條件:①繼承關係②方法需要重寫③父類引用指向子類對象 Father f1 = new Student();
           有些方法不能重寫:
           ①static靜態,修飾的方法,屬於類,不屬於實例
           ②final常量,修飾的
           ③private方法:
        */

3.3.3 instance of和類型轉換

  1. instance of
public static void main(String[] args) {
        //Object > String
        //Object > Person > Student
        //Object > Person > Teacher

        Object student2 = new Student();
        //instanceof判斷左邊對象是否是右邊類的一個實例
        System.out.println(student2 instanceof Student);//看看是不是Student類型呢true
        System.out.println(student2 instanceof Person);//看看是不是Student類型呢true
        System.out.println(student2 instanceof Object);//看看是不是Student類型呢true
        System.out.println(student2 instanceof Teacher);//看看是不是Student類型呢false     
                                                        //因為沒有new:object和Teacher
        System.out.println(student2 instanceof String);//看看是不是Student類型呢false

                }
        }
       /*總結一波:
        System.out.println(X instanceof Y);能不能編譯通過取決於X、Y有沒有父子關係
         */
  1. 類型轉換
  • 父類
public class Person {
            public void run(){
                System.out.println("run");
                }

                }
  • 子類
public class Student extends Person{
            public void go(){
                System.out.println("go");
            }
        }
  • Application類
public class Main3 {
            public static void main(String[] args) {

                //父類                子類
                //高                  低
                Person student = new Student();
                //student.go();報錯原因:student屬於Person,Person中沒有go
                //student將這個對象轉換未Student類型,我們就可以使用Student類型的方法了:高往低走

                Student student1 = (Student) student;//(Student)student;
                student1.go();
                ((Student)student).go();//前面寫成一句話完成類型轉換

                //低                 高
                //子類轉換為父類,可能回丟失原來自己的方法
                Student student2 = new Student();
                student2.go();
                //把student變成person類型
                Person person = student2;
                //person.go();就用不了了

                }
            }

3.3.4 static關鍵字詳解:com.fenfen.oop.Demo7

  1. static在屬性上的使用
public class Student {
            //靜態屬性
            private static int age;//靜態的變量
            private double score;//非靜態變量
public static void main(String[] args) {
                student student = new Student();

                //用對象輸出
                System.out.println(student.score);//student.score.sout
                //用類輸出
                System.out.println(Student.age);
                //System.out.println(Student.score);沒有static這個就不行
                //或者直接輸出
                System.out.println(age+"kkkkk");
                     }
                }
  1. static在方法上的使用
public class Student {
            //靜態方法
            public void run(){
            }

            public static void go(){
            }
public static void main(String[] args) {
                Student student = new Student();
                //方法調用
                //用對象調
                student.run();
                student.go();
                //用類調
                Student.go();
                //Student.run();沒有static這個就不行:具體原因,現在是靜態方法,只能去調靜態方法的
                //直接調
                go();
                }
            }
  1. static在代碼塊、構造器上的運用
public class Person {

            //代碼塊
            {
                System.out.println("匿名代碼塊兒,一般會根據對象每次都跑,所以會被用來賦予初始值");
            }
            //靜態代碼塊
            static {
                System.out.println("靜態代碼塊兒,這個反而執行的時候是最先的,而且我就跑一次,後面不玩了");
            }
            //構造器

            public Person() {
                System.out.println("構造方法");
            }

            public static void main(String[] args) {

                Person person1 = new Person();
                System.out.println("===============");
                Person person2 = new Person();
            }
        }
  1. static在靜態導入包的使用
package com.fenfen.oop.Demo7;

        //靜態導入包的方法和常量
        import static java.lang.Math.random;
        import static java.lang.Math.PI;

        public class Test {
            public static void main(String[] args) {
                //System.out.println(Math.random());  不想怎麼寫可以在前面直接導包,但是記得寫static
                System.out.println(random());
            }

4. 抽象類和接口:com.fenfen.oop.Demo8

4.1 抽象類

4.1.1 抽象對象和方法的建立

public abstract class Action {

            //約束
            //abstrct ,抽象方法,只有方法名字,沒有具體的方法內容實現,並且抽象方法跟抽象類
            public abstract void doSomething();

            /*
            1、不能在這個抽象類new(在main中都不給new,只能靠子類去實現它(重寫?
            2、抽象類中可以寫普通的方法
            3、抽象方法必須在抽象類中
            抽象的抽象:約束

            抽象存在的意義:
                    例如遊戲中,抽象出一定的內容,每創建一個角色就去繼承這個抽象類,直接重寫部分方法,改掉一些不必要的東西即可

             */

4.1.2 無法在其他類中new一個抽象類的對象

public class Main {
            public static void main(String[] args) {
               // new Action(); 不給new
            }
        }

4.1.3重寫抽象的方法

public class A extends Action{
            //繼承用了abstract的類會報錯,必須得重寫一下才可以
            //抽象類得所有方法,繼承了他的子類,都必須要實現他的方法
            @Override
            public void doSomething() {
            }
        }

4.2 接口:com.fenfen.oop.Demo9

4.2.1 創建接口以及基本方法

//接口:用interface
        // 寫簡單方法,然後有一個對應實現類UserServiceimp
        public interface UserService {

            //public void run(){   此處需要加上abstract不然不給寫方法
            //}

            //接口中的所有定義其實都是抽象的 public abstract的方法
            public abstract void run();
            void add(String name);
            void delete(String name);
            void update(String name);
            void query(String name);
            //接口中定義屬性:就是一個常量,很少在接口中定義常量:默認public static final
            public static final int AGE = 99;
        }       

        public interface TimeService {
        void timer();

        }

4.2.2 接口對應的實現類

//一個類實現接口 implemnts 接口:可以繼承多個接口
        //實現了接口中的類,就需要重寫接口中的方法
        public class UserServiceimp implements UserService,TimeService{//可以實現多個接口,實現多繼承

            //右擊generate:implement methods或者ctrl+i快捷鍵

            @Override
            public void run() {

            }

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

            }

5 內部類:com.fenfen.oop.Demo10

5.1 類中類

5.1.1創建內中類

public class Outer {

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

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

                //獲得外部類的私有屬性:外部出現的id = 10
                public void getID(){
                System.out.println(id);
            }

            //可以在內部類Inner前加上static:
                // 但是會出現:靜態的內部類無法訪問非靜態的內部屬性
            }
        }

5.1.2 實例化並調用類中類

public class Main {
            public static void main(String[] args) {
                //new
                Outer outer = new Outer();

                //通過這個外部類來實例化內部類
                Outer.Inner inner = outer.new Inner();//outer.new Inner();
                inner.in();
                inner.getID();
            }
        }

5.2 局部內部類(方法中的類)

public class Outer3 {
            //方法中的類:叫做局部內部類
            public void method(){

                class Inner{
                    public void in(){
                    }
                }
            }
        }

5.3 匿名內部類

public class Outer4 {

            public static void main(String[] args) {

                //一般是Apple apple = new Apple();
                //也可以是:沒有名字初始類,不用將實例保存到變量中
                new Apple().eat();

                //接口重寫下方法
                new UserService()
                //實際寫全是:UserService userService = new UserService()
                {

                    @Override
                    public void hello() {

                    }
                };
            }
        }

        class Apple{
            public void eat(){
                System.out.println("1");
            }
        }
        //整一個接口
        interface UserService{
            void hello();

        }