Java的面向對象和抽象類、接口、內部類以及OOP實戰

初識面向對象

面向過程&面向對象

面向過程思想java

  • 步驟清晰簡單,第一步作什麼,第二步作什麼....
  • 面向過程適合處理一些較爲簡單的問題...

面向對象思想編程

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

對於描述複雜的事物,爲了從宏觀上把握,從整理上合理分析,咱們須要使用面向對象的思路來分析整個系統。可是,具體到微觀操做,仍然須要面向過程去處理。安全

什麼是面向對象

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

  • 面向對象編程的本質是:以類的方式組織代碼,以對象的組織(封裝)數據ide

  • 抽象oop

  • 三大特性:學習

    • 封裝
    • 繼承:子類能夠繼承父類全部東西
    • 多態:同一個事物有多種形態

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

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

面向對象三大特徵

封裝

1.該露的露,該藏的藏設計

  • 咱們程序設計要求「高內聚,低耦合」。高內聚就是類的內部數據操做細節本身完成,不容許外部干涉;低耦合就是僅暴露少許的方法給外部使用

2.封裝(數據的隱藏)

  • 一般,應禁止直接訪問一個對象中數據的世紀標識,而應該經過操做接口來訪問,這稱爲信息隱藏

⭐️屬性私有,get/set

Student類

package com.oop.demo04;
//類   private:私有
public class Student {
    //屬性私有
    private String name;//名字
    private int id;//學號
    private char sex;//性別
    private int age;//年齡

    //提供一些能夠操做這個屬性的方法
    //提供一些public的get、set的方法

    //get得到這個數據
    public String getName(){
        return this.name;
    }
    //set給這個數據設置值
    public void setName(String name){
        this.name = name;
    }
    //alt+insert 自動生成get、set方法

    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;
        }
    }
    /*
    1.提升程序的安全性,保護數據
    2.隱藏代碼的實現細節
    3.統一接口
    4.系統可維護性增長了
     */
}

測試類

package com.oop;

import com.oop.demo03.Pet;
import com.oop.demo04.Student;

//一個項目應該只存在一個main方法
public class Application {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setName("沈小榆");
        System.out.println(s1.getName());//沈小榆
        s1.setAge(999);//不合法的 3
        System.out.println(s1.getAge());//3
    }
}

封裝的做用

  1. 提升程序的安全性,保護數據
  2. 隱藏代碼的實現細節
  3. 統一接口
  4. 系統可維護性增長了

繼承

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

extands的意思是「擴展」。子類是父類的擴展

Java中類只有單繼承,沒有多繼承:一個兒子只有一個爸爸,一個爸爸能夠有多個兒子

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

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

子類和父類之間,從意義上講應該具備「is a」的關係

object 類:在java中全部的類,都默認直接或者間接繼承Object

super注意點:

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

super和this對比

  • 表明的對象不一樣:

    • this:自己調用着這個對象
    • super:表明父類對象的應用
  • 前提:

    • this:沒有繼承也可使用
    • super:只能在繼承條件下才可使用
  • 構造方法的區別:

    • this()調用本類的構造
    • super()調用父類的構造

父類Person類

package com.oop.demo05;
//在java中全部的類,都默認直接或者間接繼承Object
//Person 人:父類
public class Person /*extends Object*/{
    private int money =10_0000_0000;
    protected String name ="shenxiaoyu";
    public void say(){
        System.out.println("Person");
    }
    public int getMoney() {
        return money;
    }

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

    public Person() {
        System.out.println("Person無參執行了");
    }
}

子類Student類

package com.oop.demo05;
//Student is Person 學生是人
//子類繼承了父類就會擁有父類的所有方法,私有的東西沒法被繼承
public class Student extends Person {
    //ctrl+H能夠查看繼承樹
    private String name ="moguyu";
    public void test1(String name){
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
    }
    public void say(){
        System.out.println("Student");
    }
    public void test2(){
        say();//Student
        this.say();//Student
        super.say();//Person
    }

    public Student() {
        //隱藏代碼:調用了父類的無參構造
        super();//調用父類的構造器,必需要在子類構造器的第一行
        //this()調用本身的構造器也須要放在代碼的第一行
        System.out.println("Student無參執行了");
    }
}

測試類

package com.oop;

import com.oop.demo03.Pet;
import com.oop.demo05.Person;
import com.oop.demo05.Student;

//一個項目應該只存在一個main方法
public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        /*
        Person無參執行了
        Student無參執行了
         */
        student.say();
        student.test1("沈小榆");
        /*
        沈小榆
        moguyu
        shenxiaoyu
         */
        student.test2();
    }
}

方法重寫

須要有繼承關係,子類重寫父類的方法

  1. 方法名必須相同
  2. 參數列表必須相同
  3. 修飾符:範圍能夠擴大 Public>Protected>Default>private
  4. 拋出的異常:範圍,能夠被縮小,但不能擴大

重寫,子類的方法和父類必須保持一致:方法體不一樣!

static方法,屬於類,它不屬於實例,不能被重寫

final 常量,被final修飾的也不能重寫 類若是被final,則他不能被繼承--->final以後斷子絕孫

private方法,私有,也不能重寫

重寫的意義:

  • 父類的功能,子類不必定須要,或者不必定知足

Alt+Insert:override

父類B類

package com.oop.demo05;
//重寫都是方法的重寫,和屬性無關
public class B {

    public void test1(){
        System.out.println("B=>test()");
    }
    public static void test2() {
        System.out.println("B=>test()");
    }
}

子類A類

package com.oop.demo05;
//繼承
public class A extends B{


    @Override//註解:有功能的註解
    //Override 重寫
    public void test1() {
        System.out.println("A=>test()");
    }
    public static void test2() {
        System.out.println("A=>test()");
    }
}

測試類

package com.oop;

import com.oop.demo05.A;
import com.oop.demo05.B;

//一個項目應該只存在一個main方法
public class Application {
    public static void main(String[] args) {
        //靜態方法的和非靜態方法區別很大
        //靜態方法:方法的調用只和左邊,定義的數據類型有關
        //重寫只和非靜態方法有關
        A a = new A();
        a.test1();//A=>test()
        a.test2();//A=>test()

        //父類的引用指向了子類
        B b = new A();
        b.test1();//A=>test() 子類重寫了父類的方法
        b.test2();//B=>test()
    }
}

多態

即同一方法能夠根據發送對象的不一樣而採用多種不一樣的行爲方式

一個對象的實際類型是肯定的,但能夠指向對象的引用的類型有不少

多態存在的條件

  • 有繼承條件
  • 子類重寫父類方法
  • 父類引用指向子類對象

注意:

  • 多態是方法的多態,屬性沒有多態性
  • 父類和子類,有聯繫 (類型轉換異常:ClassCastException)

父類Person類

package com.oop.demo06;

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

}

子類Student類

package com.oop.demo06;

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

測試類

package com.oop;

import com.oop.demo06.Person;
import com.oop.demo06.Student;

//一個項目應該只存在一個main方法
public class Application {
    public static void main(String[] args) {
        //Student student = new Student();
        //new Person();
        //一個對象的實際類型是肯定的
        //能夠指向的引用類型就不肯定了:父類的引用指向子類

        //Student 能調用的方法都是本身的或者父類的!
        Student s1 = new Student();
        //Person 父類型,能夠指向子類,可是不能調用子類獨有的方法
        Person s2 = new Student();
        Object s3 = new Student();
        //對象能執行哪些方法,主要看對象的類型和右邊關係不大
        s2.run();//son 子類重寫了父類的方法,執行了子類的方法
        s1.run();//son
        s1.eat();
    }
}

instanceof和類型轉換

instanceof:用來查看能不能經過編譯

package com.oop;

import com.oop.demo06.Person;
import com.oop.demo06.Student;
import com.oop.demo06.Teacher;

//一個項目應該只存在一個main方法
public class Application {
    public static void main(String[] args) {
        //Object>person>Student
        //Object>person>Teacher
        Object object = new Student();

        //System.out.println(X instanceof Y);能不能編譯經過
        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(person instanceof Student);//true
        System.out.println(person instanceof Person);//true
        System.out.println(person instanceof Object);//true
        //System.out.println(person instanceof Teacher);編譯報錯
        //System.out.println(person instanceof String);編譯報錯
    }
}

類型轉化

  • 父類的引用指向子類的對象
  • 把子類轉化爲父類,向上轉型
  • 把父類轉化爲子類,向下轉型:強制轉換
  • 方便方法的調用,減小重複的代碼!

子類Student類

package com.oop.demo06;

public class Student extends Person{
    public void go(){
        System.out.println("go");
    }
}

測試類

package com.oop;

import com.oop.demo06.Person;
import com.oop.demo06.Student;
import com.oop.demo06.Teacher;

//一個項目應該只存在一個main方法
public class Application {
    public static void main(String[] args) {
        //類型之間的轉化:父類 子類
        //高 ------->低  須要強制轉換
        Person obj = new Student();

        //student將這個對象轉換爲Student類型,咱們就可使用Student類型的方法了
        Student student = (Student) obj;
        student.go();//((Student) obj).go();

        Person person = student;
    }
}

方法回顧和加深

方法的定義

修飾符和返回類型

package com.oop.demo01;
//Demo01 類
public class Demo01 {
    //main方法
    public static void main(String[] args) {

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

    public String sayHello(){
        return "hello,world!";
    }
    public void hello(){
        return;
    }
    public int max(int a,int b){
        return a>b ? a : b;//三元運算符
    }
}

break和return區別

  • break跳出switch,結束循環
  • return表示方法結束

方法名:注意規範!見名知意

參數列表:(參數類型,參數名)....

異常拋出

方法的調用

靜態方法和非靜態方法

Demo02類

package com.oop.demo01;

public class Demo02 {

    public static void main(String[] args) {
        Student.say();
        //實例化這個類 new
        //對象類型 對象名 = 對象值
        Student student = new Student();
        student.said();
    }
}

Student類

package com.oop.demo01;
//學生類
public class Student {
    //靜態方法 static
    public static void say(){
        System.out.println("學生說話了");
    }
    //非靜態方法
    public void said(){
        System.out.println("學生說過話了");
    }
}

static方法和static方法能相互調用,非靜態方法和非靜態方法能相互調用。非靜態方法裏能夠直接調用靜態方法,可是,靜態方法裏不能直接調用非靜態方法

//和類一塊兒加載的
public static void a(){
    b();
    //不能直接調用c()和d()
}
public static void b(){
    a();
    //不能直接調用c()和d()
}

//類實例化以後才存在
public  void c(){
    a();
    b();
    d();
    
}
public void d(){
    a();
    b();
    c();
}

形參和實參

package com.oop.demo01;

public class Demo03 {
    public static void main(String[] args) {
        //形式參數和實際參數的類型要對應
        Demo03 demo03 = new Demo03();
        int add = demo03.add(1,2);//實際參數
        System.out.println(add);
    }
    
    public int add(int a,int 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=10;
    }
}

引用傳遞:

package com.oop.demo01;
//引用傳遞
public class Demo05 {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name);//油炸蘑菇魚
        Demo05.change(person);
        System.out.println(person.name);//沈小榆
    }
    public static void change(Person person){
        //person是一個對象:指向的----> Person person =new Person(); 這是一個具體的人,能夠改變屬性!
        person.name = "沈小榆";
    }
}
//定義了一個Person類,有一個屬性:name
class Person{
    String name="油炸蘑菇魚";
}

this關鍵字

對象的建立分析

類與對象的關係

類是一種抽象的數據類型,它是對某一類事物總體描述/定義,可是並不能表明某一個具體的事物

  • 動物、植物、手機、電腦...
  • Person類、Pet類、Car類,這些類都是用來描述/定義某一類具體的事物應該具有的特色和行爲

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

  • 張三就是人的一個具體的實例,張三家裏的旺財就是狗的一個具體的實例
  • 可以體現出特色,展示出功能的是具體的實例,而不是抽象的概念

建立與初始化對象

使用new關鍵字建立對象

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

Student類:

package com.oop.demo02;
//學生類
public class Student {
    //屬性:字段
    String name;
    int age;


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

Application類:

package com.oop.demo02;
//一個項目應該只存在一個main方法
public class Application {
    public static void main(String[] args) {
        //類:抽象的,須要實例化
        //類實例化後會返回一個本身的對象
        //xiaoyu對象就是一個Student類的具體實例
        Student xiaoyu = new Student();
        Student xiaofu = new Student();
        xiaoyu.name="魚魚";
        xiaoyu.age=6;
        xiaofu.name="付付";
        xiaofu.age=9;

        System.out.println(xiaoyu.name);//魚魚
        System.out.println(xiaoyu.age);//6
        System.out.println(xiaofu.name);//付付
        System.out.println(xiaofu.age);//9
    }
}

構造器詳解

類中構造器也稱爲構造方法,是在進行建立對象的時候必需要調用的。而且構造器有如下兩個特色:

  1. 必須和類的名字相同
  2. 必須沒有返回類型,也不能寫void
public class Person {
    public Person() {
    }
}

構造器做用:

  1. new本質在調用構造方法
  2. 初始化對象的值

注意點:

  • 定義有參構造以後,若是想使用無參構造,顯示定義一個無參構造

Person類

package com.oop.demo02;
//java---> class
public class Person {
    //一個類即便什麼都不寫,它也會存在一個方法,這個方法就是構造方法

    //顯示的定義構造器

    String name;
    //實例化初始值
    //1.使用new關鍵字,本質是在調用構造器
    //2.用來初始化值
    public Person(){
        this.name="小魚魚";//this.是當前的值,=後面是構造器傳進來的值
    }

    //有參構造:一旦定義有參構造,無參構造必須顯示定義
    public Person(String name){
        this.name=name;
    }
    //Alt+Inset會生成構造器 constructor--->--->0k---->有參
    //Alt+Inset會生成構造器 constructor--->--->select none---->無參

}

測試類

package com.oop.demo02;
//一個項目應該只存在一個main方法
public class Application {
    public static void main(String[] args) {
        //new實例化了一個對象
        Person person = new Person();
        Person person1 = new Person("XIAOYUYU");
        System.out.println(person.name);//小魚魚
        System.out.println(person1.name);//XIAOYUYU
    }
}

內存分析

Pet類

package com.oop.demo03;

public class Pet {
    public String name;//public能夠在不在一個包的時候也能調用
    public int age;
    //無參構造
    public void shout(){
        System.out.println("叫了一聲");
    }

}

Application類

package com.oop;

import com.oop.demo03.Pet;

//一個項目應該只存在一個main方法
public class Application {
    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);

        Pet cat = new Pet();
    }
}

內存分析圖片:

在這裏插入圖片描述

類與對象小結

類與對象

  • 類是一個模板:抽象,對象是一個具體的實例

對象的屬性:字段field 成員變量

  • 默認初始化:

    • 數字:0 0.0

    • char:u0000

    • oolean:false

    • 引用:null

  • 定義:

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

對象的建立和使用

  • 必須使用new 關鍵字創造對象,構造器 Person shenxiaoyu = new Person();
  • 對象的屬性 shenxiaoyu.name
  • 對象的方法 shenxiaoyu.sleep()

類裏有

  • 靜態的屬性 屬性
  • 動態的行爲 方法

Static關鍵字詳解

靜態變量和靜態方法

package com.oop.demo07;
//static
public class Student {
    private static int age;//靜態變量
    private double score;//非靜態變量

    public void run(){

    }
    public static void go(){

    }


    public static void main(String[] args) {
        Student s1 = new Student();
        System.out.println(age);
        //System.out.println(Student.score);非靜態變量不能直接調用
        System.out.println(s1.age);
        System.out.println(s1.score);
        go();
        s1.run();
    }
}

static代碼塊和匿名代碼塊

package com.oop.demo07;

public class Person {
    /*
    {
        //代碼塊(匿名代碼塊)
    }

    static{
        //靜態代碼塊
    }
     */

    //2:賦初始值
    {
        System.out.println("匿名代碼塊");
    }

    //1 只執行一次
    static{
        System.out.println("靜態代碼塊");
    }

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

    public static void main(String[] args) {
        Person p1 = new Person();
        /*
        靜態代碼塊
        匿名代碼塊
        構造方法
        */
        System.out.println("=============");
        Person p2 = new Person();
        /*
        匿名代碼塊
        構造方法
         */
    }
}

靜態導入包

package com.oop.demo07;
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);
    }
}

抽象類和接口

抽象類

abstract修飾符能夠用來修飾方法也能夠修飾類,那麼該方法就是抽象方法;若是修飾類,那麼該類就是抽象類

抽象類中能夠沒有抽象方法,可是有抽象方法的類必定要聲明爲抽象類

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

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

父類Action類

package com.oop.demo08;
//abstract 抽象類   extends 單繼承      接口能夠多繼承
public abstract class Action {
    //約束——有人幫咱們實現
    //abstract,抽象方法,只有方法名字,沒有方法的實現
    public abstract void doSomething();//有抽象方法必定要聲明抽象類
    //1.不能new這個抽象類,只能靠子類去實現它:約束!
    //2.抽象類中能夠寫普通方法
    //3.抽象方法必須寫在抽象類中

}

子類A類

package com.oop.demo08;
//抽象類的全部方法,繼承了他的子類,都必需要實現他的方法,除非子類也是abstract
public class A extends Action{
    @Override
    public void doSomething() {
        
    }
}

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

抽象類存在的意義:提升開發效率

接口

普通類:只有具體實現

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

接口:只有規範!本身沒法寫方法!約束和實現分離!

接口就是規範,定義的是一組規則,體現了現實世界中「若是你是...則必須能...」的思想。若是你是天使,則必須能飛。

接口的本質就是契約,就像咱們人間的法律同樣。制定好後你們都遵照

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

聲明類的關鍵字是class,聲明接口的關鍵字是interface

UserService接口:

package com.oop.demo09;
//interface 定義的關鍵字,接口都須要有實現類
public interface UserService {
    //接口中全部的屬性是 public static final
    int AEG = 99;

    //接口中全部的定義的方法其實都是抽象的 public abstract
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}

TimeService接口:

package com.oop.demo09;

public interface TimeService {
    void timer();
}

UserServiceImpl類用來實現接口:通常命名爲接口名+Impl

package com.oop.demo09;

//抽象類: 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. 定義一些方法,讓不一樣的人實現
  3. 接口的方法默認 public abstract
  4. 接口的常量默認 public static final
  5. 接口不能被實例化,接口中沒有構造方法
  6. implements能夠實現多個接口
  7. 在實現接口類中必需要重寫接口中的方法

內部類

內部類就是在一個類內部定義一個類。好比,A類中定義一個B類,那麼B類就是A類的內部類,A類就是B類的外部類

Outer類:內部類能夠得到外部類的私有屬性

package com.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 void getID(){
            System.out.println(id);
        }
    }

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

            }
        }
    }
}
//一個java類中能夠有多個class類,但只能有一個public class類
class A{

}

測試類:經過這個外部類來實例化內部類

package com.oop;

import com.oop.demo10.Outer;

//一個項目應該只存在一個main方法
public class Application {
    public static void main(String[] args) {
        Outer outer = new Outer();

        //經過這個外部類來實例化內部類
        Outer.Inner inner = outer.new Inner();
        inner.in();//這是內部類的方法
        inner.getID();//10
    }
}

Test類:沒有名字初始化類,不用將實例保存在變量中

package com.oop.demo10;

public class Test {
    public static void main(String[] args) {
        //沒有名字初始化類,不用將實例保存在變量中
        new Apple().eat();

        new UserService(){

            @Override
            public void hello() {

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

interface UserService{
    void hello();
}
相關文章
相關標籤/搜索