此對象非彼對象(面向對象)2

java13面向對象深刻2

大綱

在這裏插入圖片描述

package與import

package

概述

package存在的意義是防止命名衝突形成使用不便。java

package相似一個文件夾,文件夾內有各類文件。package與package的附屬關係用「.」鏈接,相似父文件夾中的子文件夾。好比說 java.lang.String就是java文件夾中的lang文件夾中的String文件。java.io.InputStream則是java文件夾中的io文件夾中的InputStream文件。c++

同一個文件夾內沒法存在同名的文件,而不一樣名的文件夾裏容許存在同名文件,所以不一樣文件夾(即不一樣package中容許出現相同class名)。程序員

<font color='red'>爲了便於管理大型軟件系統中數目衆多的類,解決類的命名衝突問題,Java 引入包(package)機制,提供類的多重類命名空間。 </font>算法

在這裏插入圖片描述

格式

通常的命名爲:<font color="blue">公司域名倒寫+功能名|模塊名。</font>sql

package 語句做爲 Java 源文件的第一條語句,指明該文件中定義的類所在的包。(若缺省該語句,則指定爲無名包)。數據庫

package pkg1[.pkg2[.pkg3…]];

例:編程

package com.java01.test;

Java 編譯器把包對應於文件系統的目錄管理,package 語句中,用’.’來指明包(目錄)的層次,例如使用語句: package com.java01 ,則該文件中全部的類位於.comjava01 目錄下 網絡

注意:併發

  • 不要定義與 jdk 相同的包,相同的類,不然會引發不少你以爲莫名其妙的問題
  • 寫項目時都要加包,不要使用默認包。
  • com.oop和com.oop.test,這兩個包沒有包含關係,是兩個徹底獨立的包。只是邏輯上看起來後者是前者的一部分。

import

若是一個類存在包名,則在其餘包下使用該類時,必須使用全額限定名(簡稱全名或完整類名,com.java01.MyClass),編譯器才能找到該類;也可使用 import 在文件的開頭引入要使用到的類。jvm

import java.util.Scanner;
import java.io.*; //模糊匹配當前io包下全部類
public class ImportDemo {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in); //由於使用import關鍵字導包,可使用
        java.util.ArrayList list=new java.util.ArrayList(); //權限定名
        //導入集合 注意:導入是不要導錯包
        //使用*,模糊匹配
        File file=new File("D://test.txt");
        InputStream isInputStream=new FileInputStream(file);
    }
}

不須要使用 import 的類有:

  1. 語言包 (java.lang)下的類 (String,System...)
  2. 同包下的類

靜態導入:
import 語句不只能夠導入類,還增長了導入靜態方法的功能

//導入靜態屬性
import static java.lang.Math.PI;
import static java.lang.System.out;
//導入靜態方法
import static java.lang.Math.sin;

public class ImportDemo {
    public static void main(String[] args) {
        out.println(PI);
        sin(1.1);
    }
}

總結

  • 若是想將一個類放入包中,在類的源文件首行使用package
  • 必須保證該類的 class 文件位於正確的目錄下
  • 另外的類想訪問的話:

    1. 寫全名
    2. 引入

      • 模糊匹配(會將該包下全部用到的類引入進來),會下降編譯速度,可是不會影響運行速度
      • 具體類名
      • 靜態導入
    3. 同包下的類不須要導入


JDK 中經常使用的包簡單介紹:

  1. java.lang –語言包:語言中經常使用的功能,如:String、Math、System、Integer、Thread…
  2. java.util – 工具包:提供一些實用的工具類,如:容器(List、Set、Map…),日期類
  3. java.io – 輸入輸出包:提供操做讀取文件的相關類,如:File、InputStream、OutputStrem…
  4. java.net – 網絡包: 操 做 遠 程 資 源 的 類 , 如:InetSocketAddress、 DatagramPacket、 ServerSocket…
  5. java.sql – 數據庫包:操做JDBC的類,Connection、Statement、ResultSet….

垃圾回收機制(gc)

概述

Garbage Collection 垃圾回收機制

每一個程序員都遇到過內存溢出的狀況,程序運行時,內存空間是有限的,那麼如何及時的把再也不使用的對象清除將內存釋放出來,這就是GC要作的事。

提及垃圾回收機制(GC),大部分人都把這項技術當作Java語言的伴生產物。事實上,GC的歷史比Java久遠,早在1960年Lisp這門語言中就使用了內存動態分配和垃圾回收技術。

![在這裏插入圖片描述](https://img-blog.csdnimg.cn/2020052220581587.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RpcmZ0X2Rpbg==,size_16,color_FFFFFF,t_70)

程序員們知道,jvm內存結構分爲五大區域:程序計數器、虛擬機棧、本地方法棧、堆區、方法區。其中虛擬機棧、本地方法棧與程序計數器這3個區域隨線程而生、隨線程而滅,所以就不須要考慮過多內存垃圾回收問題,由於一個方法調用結束或者線程結束時,內存天然就跟隨着回收了。

咱們就把重點放在方法區與堆區,這部份內存的分配和回收是動態的,正是垃圾收集器所需關注的部分。

GC主要作了清理對象,整理內存的工做。

不一樣語言下對象空間的釋放:

  • 傳統的C/C++語言,須要程序員負責回收已經分配內存。顯式回收垃圾回收的缺點:

    1. 程序忘記及時回收,從而致使內存泄露,下降系統性能。
    2. 程序錯誤回收程序核心類庫的內存,致使系統崩潰。
  • Java語言不須要程序員直接控制內存回收,是由JRE在後臺自動回收再也不使用的內存,稱爲垃圾

    回收機制(Garbage Collection)。

    1. 能夠提升編程效率。
    2. 保護程序的完整性。
    3. 其開銷影響性能。Java虛擬機必須跟蹤程序中有用的對象,肯定哪些是無用的。

垃圾回收機制關鍵點:

  • 垃圾回收機制只回收JVM堆內存裏的對象空間。
  • 對其餘物理鏈接,好比數據庫鏈接、輸入流輸出流、Socket鏈接無能爲力
  • 如今的JVM有多種垃圾回收實現算法,表現各異。
  • 垃圾回收發生具備不可預知性,程序沒法精確控制垃圾回收機制執行。
  • 能夠將對象的引用變量設置爲null,暗示垃圾回收機制能夠回收該對象。
  • 程序員能夠經過System.gc()或者Runtime.getRuntime().gc()來通知系統進行垃圾回收,會有一些效果,可是系統是否進行垃圾回收依然不肯定。
  • 垃圾回收機制回收任何對象以前,總會先調用它的finalize方法(若是覆蓋該方法,讓一個新的引用變量從新引用該對象,則會從新激活對象)。
  • 永遠不要主動調用某個對象的finalize方法,應該交給垃圾回收機制調用。

block與debug

block

塊{},在java中自成做用域,能夠分爲

靜態代碼塊 構造代碼塊 普通語句塊 同步代碼塊
聲明位置 類中,方法外 類中,方法外 方法中 fynchronized(){}
做用 整個類進行某些初始化操做(靜態成員屬性賦值...) 構造代碼塊是爲對象初始化操做(爲靜態或非靜態成員屬性賦值...) 聲明一些臨時變量等.. 控制併發
執行時機 類第一次加載時,只執行一次,若是多個靜態塊,從上倒下一次執行 建立對象時,執行構造器代碼以前執行,若有多個,從上倒下一次執行 跟隨方法執行 跟對方法執行

注意:

  • 類第一次被載入時先執行static代碼塊;類屢次載入時,static代碼塊只執行一次;static塊常常用來進行static變量的初始化。
  • 是在類初始化時執行,不是在建立對象時執行。
  • 靜態初始化塊中不能訪問非static成員。
  • 構造塊被被編譯到將要執行的構造器代碼以前執行

靜態塊,僅在類的第一次使用時加載。
構造塊,先於構造器執行,每建立一個對象執行一次

debug

在學習或開發過程當中,遇到bug是避免不了的,爲了可以快速調試,可使用debug調試工具。

調試一個Java程序很是簡單的,主要有設置斷點、啓動調試、單步執行、結束調試幾步。

debug界面窗口:

1)設置斷點
在這裏插入圖片描述

2)啓動調試

Eclipse提供幾種方式來啓動程序(Launch)的調試,分別是經過菜單(Run –> Debug)、圖標(「綠色臭蟲」)、右鍵->Debug As。

在這裏插入圖片描述

彈出提示,須要切換到調試(Debug)工做區,勾選「Remember my decision」,記住選擇,則下次再也不提示,而後點擊【Yes】。

在這裏插入圖片描述

3)單步執行

主要使用前面講過的幾個視圖進行調試,其中debug視圖中的幾個按鈕有快捷鍵:

Step Return(F7) : 表示退出當前方法,返回到調用層。

Step Over (F6) : 表示運行下一行代碼。

Step Into (F5) : 表示進入當前方法。

在這裏插入圖片描述

4)結束調試

經過Terminate命令終止對本地程序的調試。

面向對象-繼承性

繼承

「樹上一隻鳥樹下兩隻兔子,請問幾種動物 , 請問幾種生物?」 這裏面就存在了繼承的概念。

在這裏插入圖片描述
繼承:子承父業

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

繼承的做用 : 使用繼承能夠提升代碼的複用性。

如何使用繼承:

父類|超類|基類:根據一些列子類抽象,抽取像的部分,定義在父類中

子類|派生類:子類繼承父類,有權使用父類中的內容,能夠定義子類新增內容,因此說子類是父類的延續+擴展

extends 關鍵字的意思是「擴展」。子類是父類的擴展。

java 中使用 <font color="red">extends </font>關鍵字實現類的繼承機制,語法規則:

<modifier> class <name> [extends <superclass>]{}
//父類
class Person{
    public String name;
    public int age;
    
    public void sleep(){
        System.out.println("休息");
    }
}
//子類
//教師類
class Teacher extends Person{
    public String subject;
    
    public Teacher() {
    }
    
    public void teach(){
        System.out.println("傳授知識");
    }
    
}

//學生類
class Student extends Person{
    public String school;
    
    public Student() {
    }
    
    public void study(){
        System.out.println("在知識的海洋暢遊!");
    }
}

注意:

  • 子類繼承父類的成員變量和成員方法,但不繼承父類的構造方法
  • java中只有單繼承 ,沒有像c++那樣的多繼承。多繼承會引發混亂,使得繼承鏈過於複雜,系統難於維護。就像咱們現實中,若是你有多個父母親,那是一個多麼混亂的世界啊。多繼承,就是爲了實現代碼的複用性,卻引入了複雜性,使得系統類之間的關係混亂。
  • java中的多繼承,能夠經過接口來實現
  • 若是定義一個類時,沒有調用extends,則它的父類是:java.lang.Object。

繼承的特色:

優勢:

  • 經過繼承能夠簡化類的定義,實現代碼的重用|提升代碼複用性
  • 能夠更好的擴展程序
  • 子類一旦繼承父類,能夠有權使用父類中的成員,也能夠擴展定義子類獨有內容
  • java是單繼承繼承,實現簡單

缺點:

  • 子類與父類之間緊密耦合(耦合度高),子類依賴於父類的實現,子類缺少獨立性。
  • 不便於後期維護
  • 單繼承一個子類只能有一個父類,不夠靈活,不便於後期維護

super關鍵字

super

super是指向父類的引用。

super能夠在子類構造器中調用父類某個構造器

若是構造方法沒有顯示地調用父類的構造方法,那麼編譯器會自動爲它加上一個默認的super()方法調用。若是父類由沒有默認的無參構造方法,編譯器就會報錯,super()語句必須是構造方法的第一個子句。

super能夠用來區分子父類中同名成員

若是不存在同名問題,能夠直接在子類中調用父類內容,super默認省略

若是存在同名問題,在子類中調用同名成員,默認this.恆源 調用當前子類同名成員,先要調用父類同名成員,必須定義爲super.成員

//父類
public class Animal {
    int eye = 2;
    public Animal(){
        super();
        System.out.println("動物");
    }
    
    public void run(){
        System.out.println("動物有不一樣走路方式");
    }
    
    public static void main(String[] args) {
        Bird b = new Bird();
        b.run();
    }
}
//子類
class Bird extends Animal{
    public Bird(){
        super();
        System.out.println("鳥類");
    }

    public void run() {
        super.run(); // 經過super能夠用父類方法和屬性
        System.out.println("鳥是飛飛飛飛飛飛");
        System.out.println("鳥類有"+super.eye+"隻眼睛");
    }
   
}

Bird--> Animal --> Object 圖形分析以下
在這裏插入圖片描述

構造方法調用順序:

  • 根據super的說明,構造方法第一句 老是:super(…)來調用父類對應的構造方法。
  • 先向上追溯到Object,而後再依次向下執行類的初始化塊和構造方法,直到當前子類爲止。

this和super之間的區別

相同點:

  1. this和super都能用來調動其餘共構造器,都要在首行出現
  2. this和super均可以用來區分同名問題,不區分同名時候能夠省略
  3. this和super都指的是對象,因此,均不能夠在static環境中使用。包括:static變量,static方法,static語句

塊。

不一樣點:

  1. this(參數)構造器第一行調用本類中其餘構造器,super(參數)構造器第一行調用父類中某個構造器
  2. this用來區分紅員和局部同名問題,super用來區分子父類中同名問題

注意:

  • this和super不能同時出如今一個構造函數裏面,由於this必然會調用其它的構造函數,其它的構造函數必然也會有super語句的存在,因此在同一個構造函數裏面有相同的語句,就失去了語句的意義,編譯器也不會過。
  • 從本質上講,this是一個指向本對象的指針, 然而super是一個Java關鍵字

重寫與final關鍵字

重寫Override

父類的功能實現不知足子類的要求,能夠在子類中按需改寫,這就是方法的重寫。

實現重寫的三個條件:

  • 不一樣的兩個類
  • 繼承關係|實現關係
  • 方法簽名相同

@Override:註解,強制檢查是否爲重寫方法

注意:

  • 子類重寫的方法會對父類的方法進行屏蔽。
  • 當子類對象調用時,會調用子類中重寫的方法,子類沒有找父類。
public class OverrideTest {
    public static void main(String[] args) {
        Sicong sicong=new Sicong();
        sicong.getMoney(); //調用子類中重寫方法
    }
}
//父類
class Jianlin{
    public void getMoney(){
        System.out.println("先定一個小目標,賺他個一個億");
    }
}
//子類
class Sicong extends Jianlin{
    @Override  //強制檢查是否爲重寫方法
    public void getMoney(){
        super.getMoney();//在父類的原賺錢方法上擴展新功能,老功能不變
        System.out.println("我認識的人都沒我有錢");
    }
}

重寫的三個"=" :
「==」:方法名、形參列表相同。

「≤」:拋出的異常類型與返回值類型,返回值類型若是爲基本類型必須相同,引用數據類型子類小於等於父類。

「≥」:訪問權限,子類大於等於父類。

如下修飾符、修飾的內容不能重寫:

  1. private修飾的方法不能被重寫
  2. final修飾的方法不能被重寫
  3. static修飾的方法不能被重寫(子類若是出現和父類靜態方法同名狀況,那麼子類中的方法也必須爲靜態的)

final關鍵字

final 表示最終的。

final能夠用來修飾變量,方法,類。

修飾變量:變量一旦被初始化便不可改變,至關定義了一常量。

final int x=3;
//x=4; 常量不能改變

修飾方法 : final方法是在子類中不能被覆蓋的方法

final void eat() { … }

修飾類,表示該類不能被繼承

final class Person{ … }

Object類

Object 類是全部 Java 類的根基類

若是在類的聲明中未使用 extends 關鍵字指明其基類,則默認基類爲 Object 類
在這裏插入圖片描述

toString(): 當打印對象的引用時,默認調用toString()方法

  • 默認返回:包名+類名+@+哈希碼(根據對象的內存地址生成,惟一不重複)
  • 能夠重寫,實現義字符串的形式返回對對象(打印對象全部成員屬性的值)
User p1=new User("張三",20);
System.out.println(p1);
//至關於
System.out.println(p1.toString());

equals:比較相等是否相等**

  • 默認地址比較(」第一個盒子的比較」)
  • 重寫能夠是實現比較兩對象的內容是否一致
object1.equals(object2) 
 如 : p1.equals(p2)
• 比較所指對象的內容是否同樣,具體看equals的方法重寫
 object1 == object2
 如:p1==p2
• 比較p1和p2的值即內存地址是否相等,便是否是指向同一對象。

注意:自定義類須重寫equals(),不然沒法實現比較其內容

class User{
    String name;
    int age;
    public User() {
        // TODO Auto-generated constructor stub
    }
    public User(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    //重寫toString
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + "]";
    }
    //重寫equals
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        User other = (User) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}
super();
    this.name = name;
    this.age = age;
}
//重寫toString
@Override
public String toString() {
    return "User [name=" + name + ", age=" + age + "]";
}
//重寫equals
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    User other = (User) obj;
    if (age != other.age)
        return false;
    if (name == null) {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    return true;
}

}

相關文章
相關標籤/搜索