日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

【转】Java基础知识整理

發(fā)布時(shí)間:2025/4/9 java 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】Java基础知识整理 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本博文內(nèi)容參考相關(guān)博客以及《Java編程思想》整理而成,如有侵權(quán),請(qǐng)聯(lián)系博主。

轉(zhuǎn)載請(qǐng)注明出處:http://www.cnblogs.com/BYRans/

PDF版下載鏈接:《Java基礎(chǔ)知識(shí)總結(jié)》。

?

一:java概述:

1,JDK:Java Development Kit,java的開(kāi)發(fā)和運(yùn)行環(huán)境,java的開(kāi)發(fā)工具和jre。

2,JRE:Java Runtime Environment,java程序的運(yùn)行環(huán)境,java運(yùn)行的所需的類庫(kù)+JVM(java虛擬機(jī))。

3,配置環(huán)境變量:讓java jdk\bin目錄下的工具,可以在任意目錄下運(yùn)行,原因是,將該工具所在目錄告訴了系統(tǒng),當(dāng)使用該工具時(shí),由系統(tǒng)幫我們?nèi)フ抑付ǖ哪夸洝?/p>

環(huán)境變量的配置:

1):永久配置方式:JAVA_HOME=%安裝路徑%\Java\jdk

???? path=%JAVA_HOME%\bin

????2):臨時(shí)配置方式:set path=%path%;C:\Program Files\Java\jdk\bin

特點(diǎn):系統(tǒng)默認(rèn)先去當(dāng)前路徑下找要執(zhí)行的程序,如果沒(méi)有,再去path中設(shè)置的路徑下找。

classpath的配置:

1):永久配置方式:classpath=.;c:\;e:\

????2):臨時(shí)配置方式:set classpath=.;c:\;e:\

?

注意:在定義classpath環(huán)境變量時(shí),需要注意的情況

如果沒(méi)有定義環(huán)境變量classpath,java啟動(dòng)jvm后,會(huì)在當(dāng)前目錄下查找要運(yùn)行的類文件;

如果指定了classpath,那么會(huì)在指定的目錄下查找要運(yùn)行的類文件。

還會(huì)在當(dāng)前目錄找嗎?兩種情況:

????

CLASSPATH是什么?它的作用是什么?

它是javac編譯器的一個(gè)環(huán)境變量。它的作用與import、package關(guān)鍵字有關(guān)。當(dāng)你寫下improt java.util.*時(shí),編譯器面對(duì)import關(guān)鍵字時(shí),就知道你要引入java.util這個(gè)package中的類;但是編譯器如何知道你把這個(gè)package放在哪里了呢?所以你首先得告訴編譯器這個(gè)package的所在位置;如何告訴它呢?就是設(shè)置CLASSPATH啦 :) 如果java.util這個(gè)package在c:/jdk/ 目錄下,你得把c:/jdk/這個(gè)路徑設(shè)置到CLASSPATH中去!當(dāng)編譯器面對(duì)import java.util.*這個(gè)語(yǔ)句時(shí),它先會(huì)查找CLASSPATH所指定的目錄,并檢視子目錄java/util是否存在,然后找出名稱吻合的已編譯文件(.class文件)。如果沒(méi)有找到就會(huì)報(bào)錯(cuò)!CLASSPATH有點(diǎn)像c/c++編譯器中的INCLUDE路徑的設(shè)置哦,是不是?當(dāng)c/c++編譯器遇到include 這樣的語(yǔ)句,它是如何運(yùn)作的?哦,其實(shí)道理都差不多!搜索INCLUDE路徑,檢視文件!當(dāng)你自己開(kāi)發(fā)一個(gè)package時(shí),然后想要用這個(gè)package中的類;自然,你也得把這個(gè)package所在的目錄設(shè)置到CLASSPATH中去!CLASSPATH的設(shè)定,對(duì)JAVA的初學(xué)者而言是一件棘手的事。所以Sun讓JAVA2的JDK更聰明一些。你會(huì)發(fā)現(xiàn),在你安裝之后,即使完全沒(méi)有設(shè)定CLASSPATH,你仍然能夠編譯基本的JAVA程序,并且加以執(zhí)行。

?

PATH環(huán)境變量

PATH環(huán)境變量。作用是指定命令搜索路徑,在命令行下面執(zhí)行命令如javac編譯java程序時(shí),它會(huì)到PATH變量所指定的路徑中查找看是否能找到相應(yīng)的命令程序。我們需要把jdk安裝目錄下的bin目錄增加到現(xiàn)有的PATH變量中,bin目錄中包含經(jīng)常要用到的可執(zhí)行文件如javac/java/javadoc等待,設(shè)置好PATH變量后,就可以在任何目錄下執(zhí)行javac/java等工具了。

?

4,javac命令和java命令做什么事情呢?

????要知道java是分兩部分的:一個(gè)是編譯,一個(gè)是運(yùn)行。

????javac:負(fù)責(zé)的是編譯的部分,當(dāng)執(zhí)行javac時(shí),會(huì)啟動(dòng)java的編譯器程序。對(duì)指定擴(kuò)展名的.java文件進(jìn)行編譯。 生成了jvm可以識(shí)別的字節(jié)碼文件。也就是class文件,也就是java的運(yùn)行程序。

????java:負(fù)責(zé)運(yùn)行的部分.會(huì)啟動(dòng)jvm.加載運(yùn)行時(shí)所需的類庫(kù),并對(duì)class文件進(jìn)行執(zhí)行.

????一個(gè)文件要被執(zhí)行,必須要有一個(gè)執(zhí)行的起始點(diǎn),這個(gè)起始點(diǎn)就是main函數(shù).

?

二:java語(yǔ)法基礎(chǔ):

?

  • 標(biāo)示符:
  • ????1),數(shù)字不可以開(kāi)頭。

    ????2),不可以使用關(guān)鍵字。

    ?

  • 變量的作用域和生存期:

    變量的作用域:

    作用域從變量定義的位置開(kāi)始,到該變量所在的那對(duì)大括號(hào)結(jié)束;

    生命周期:

    變量從定義的位置開(kāi)始就在內(nèi)存中活了;

    變量到達(dá)它所在的作用域的時(shí)候就在內(nèi)存中消失了;

    ?

  • 數(shù)據(jù)類型:
  • ????1):基本數(shù)據(jù)類型:byte、short、int、long、float、double、char、boolean

    簡(jiǎn)單類型

    boolean?

    byte?

    char?

    short?

    int

    long

    float?

    double?

    void?

    二進(jìn)制位數(shù)

    1?

    8?

    16?

    16?

    32?

    64?

    32?

    64?

    --?

    封裝器類

    Boolean?

    Byte?

    Character?

    Short?

    Integer?

    Long?

    Float?

    Double?

    Void?

    ?

  • 運(yùn)算符號(hào):
  • ????4)、邏輯運(yùn)算符。

    ????????& | ^ ! && ||

    ????????邏輯運(yùn)算符除了 ! 外都是用于連接兩個(gè)boolean類型表達(dá)式。

    ????????&: 只有兩邊都為true結(jié)果是true。否則就是false。

    ????????|:只要兩邊都為false結(jié)果是false,否則就是true

    ????????^:異或:和或有點(diǎn)不一樣。

    ???????????? 兩邊結(jié)果一樣,就為false。

    ???????????? 兩邊結(jié)果不一樣,就為true.

    ????????& 和 &&區(qū)別:?& :無(wú)論左邊結(jié)果是什么,右邊都參與運(yùn)算。

    ?????????????????????&&:短路與,如果左邊為false,那么右邊不參數(shù)與運(yùn)算。

    ????????| 和|| 區(qū)別:|:兩邊都運(yùn)算。

    ????????????????????||:短路或,如果左邊為true,那么右邊不參與運(yùn)算。

    ????5)、位運(yùn)算符:用于操作二進(jìn)制位的運(yùn)算符。

    ????????& | ^

    ????????<< >> >>>(無(wú)符號(hào)右移)

    ????練習(xí):對(duì)兩個(gè)變量的數(shù)據(jù)進(jìn)行互換。不需要第三方變量。

    ????????????int a = 3,b = 5;-->b = 3,a = 5;

    ????????方法一:

    ????????????a = a + b;?a = 8;

    ????????????b = a - b;?b = 3;

    ????????????a = a - b;?a = 5;

    ????????方法二:

    ????????????a = a ^ b;//

    ????????????b = a ^ b;//b = a ^ b ^ b = a

    ????????????a = a ^ b;//a = a ^ b ^ a = b;

    ????????練習(xí):高效的算出 2*8 = 2<<3;

    ?

    重載的定義是:在一個(gè)類中,如果出現(xiàn)了兩個(gè)或者兩個(gè)以上的同名函數(shù),只要它們的參數(shù)的個(gè)數(shù),或者參數(shù)的類型不同,即可稱之為該函數(shù)重載了。

    如何區(qū)分重載:當(dāng)函數(shù)同名時(shí),只看參數(shù)列表。和返回值類型沒(méi)關(guān)系。

    重寫:父類與子類之間的多態(tài)性,對(duì)父類的函數(shù)進(jìn)行重新定義。如果在子類中定義某方法與其父類有相同的名稱和參數(shù),我們說(shuō)該方法被重寫 (Overriding)。

    ?

  • Java內(nèi)存管理

    Java內(nèi)存管理:深入Java內(nèi)存區(qū)域

  •   Java與C++之間有一堵由內(nèi)存動(dòng)態(tài)分配和垃圾收集技術(shù)所圍成的高墻,墻外面的人想進(jìn)去,墻里面的人卻想出來(lái)。

  • 概述:
  •   對(duì)于從事C和C++程序開(kāi)發(fā)的開(kāi)發(fā)人員來(lái)說(shuō),在內(nèi)存管理領(lǐng)域,他們既是擁有最高權(quán)力的皇帝,又是從事最基礎(chǔ)工作的勞動(dòng)人民—既擁有每一個(gè)對(duì)象的"所有權(quán)",又擔(dān)負(fù)著每一個(gè)對(duì)象生命開(kāi)始到終結(jié)的維護(hù)責(zé)任。

    對(duì)于Java程序員來(lái)說(shuō),在虛擬機(jī)的自動(dòng)內(nèi)存管理機(jī)制的幫助下,不再需要為每一個(gè)new操作去寫配對(duì)的delete/free代碼,而且不容易出現(xiàn)內(nèi)存泄漏和內(nèi)存溢出問(wèn)題,看起來(lái)由虛擬機(jī)管理內(nèi)存一切都很美好。不過(guò),也正是因?yàn)镴ava程序員把內(nèi)存控制的權(quán)力交給了Java虛擬機(jī),一旦出現(xiàn)內(nèi)存泄漏和溢出方面的問(wèn)題,如果不了解虛擬機(jī)是怎樣使用內(nèi)存的,那排查錯(cuò)誤將會(huì)成為一項(xiàng)異常艱難的工作。

  • 運(yùn)行時(shí)數(shù)據(jù)區(qū)域
  •   Java虛擬機(jī)在執(zhí)行Java程序的過(guò)程中會(huì)把它所管理的內(nèi)存劃分為若干個(gè)不同的數(shù)據(jù)區(qū)域。這些區(qū)域都有各自的用途,以及創(chuàng)建和銷毀的時(shí)間,有的區(qū)域隨著虛擬機(jī)進(jìn)程的啟動(dòng)而存在,有些區(qū)域則是依賴用戶線程的啟動(dòng)和結(jié)束而建立和銷毀。根據(jù)《Java虛擬機(jī)規(guī)范(第2版)》的規(guī)定,Java虛擬機(jī)所管理的內(nèi)存將會(huì)包括以下幾個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)域,如下圖所示:

              

  • 程序計(jì)數(shù)器     
  •   程序計(jì)數(shù)器(Program Counter Register)是一塊較小的內(nèi)存空間,它的作用可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。在虛擬機(jī)的概念模型里(僅是概念模型,各種虛擬機(jī)可能會(huì)通過(guò)一些更高效的方式去實(shí)現(xiàn)),字節(jié)碼解釋器工作時(shí)就是通過(guò)改變這個(gè)計(jì)數(shù)器的值來(lái)選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個(gè)計(jì)數(shù)器來(lái)完成。?由于Java虛擬機(jī)的多線程是通過(guò)線程輪流切換并分配處理器執(zhí)行時(shí)間的方式來(lái)實(shí)現(xiàn)的,在任何一個(gè)確定的時(shí)刻,一個(gè)處理器(對(duì)于多核處理器來(lái)說(shuō)是一個(gè)內(nèi)核)只會(huì)執(zhí)行一條線程中的指令。因此,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要有一個(gè)獨(dú)立的程序計(jì)數(shù)器,各條線程之間的計(jì)數(shù)器互不影響,獨(dú)立存儲(chǔ),我們稱這類內(nèi)存區(qū)域?yàn)?#34;線程私有"的內(nèi)存。?如果線程正在執(zhí)行的是一個(gè)Java方法,這個(gè)計(jì)數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令的地址;如果正在執(zhí)行的是Natvie方法,這個(gè)計(jì)數(shù)器值則為空(Undefined)。此內(nèi)存區(qū)域是唯一一個(gè)在Java虛擬機(jī)規(guī)范中沒(méi)有規(guī)定任何OutOfMemoryError情況的區(qū)域。

  • Java虛擬機(jī)棧
  •   與程序計(jì)數(shù)器一樣,Java虛擬機(jī)棧(Java Virtual Machine Stacks)也是線程私有的,它的生命周期與線程相同。虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個(gè)方法被執(zhí)行的時(shí)候都會(huì)同時(shí)創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲(chǔ)局部變量表、操作棧、動(dòng)態(tài)鏈接、方法出口等信息。每一個(gè)方法被調(diào)用直至執(zhí)行完成的過(guò)程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中從入棧到出棧的過(guò)程。

    經(jīng)常有人把Java內(nèi)存區(qū)分為堆內(nèi)存(Heap)和棧內(nèi)存(Stack),這種分法比較粗糙,Java內(nèi)存區(qū)域的劃分實(shí)際上遠(yuǎn)比這復(fù)雜。這種劃分方式的流行只能說(shuō)明大多數(shù)程序員最關(guān)注的、與對(duì)象內(nèi)存分配關(guān)系最密切的內(nèi)存區(qū)域是這兩塊。其中所指的"堆"在后面會(huì)專門講述,而所指的"棧"就是現(xiàn)在講的虛擬機(jī)棧,或者說(shuō)是虛擬機(jī)棧中的局部變量表部分。

    局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類型(boolean、byte、char、short、int、float、long、double)、對(duì)象引用(reference類型),它不等同于對(duì)象本身,根據(jù)不同的虛擬機(jī)實(shí)現(xiàn),它可能是一個(gè)指向?qū)ο笃鹗嫉刂返囊弥羔?#xff0c;也可能指向一個(gè)代表對(duì)象的句柄或者其他與此對(duì)象相關(guān)的位置)和returnAddress類型(指向了一條字節(jié)碼指令的地址)。

    其中64位長(zhǎng)度的long和double類型的數(shù)據(jù)會(huì)占用2個(gè)局部變量空間(Slot),其余的數(shù)據(jù)類型只占用1個(gè)。局部變量表所需的內(nèi)存空間在編譯期間完成分配,當(dāng)進(jìn)入一個(gè)方法時(shí),這個(gè)方法需要在幀中分配多大的局部變量空間是完全確定的,在方法運(yùn)行期間不會(huì)改變局部變量表的大小。?在Java虛擬機(jī)規(guī)范中,對(duì)這個(gè)區(qū)域規(guī)定了兩種異常狀況:如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常;如果虛擬機(jī)棧可以動(dòng)態(tài)擴(kuò)展(當(dāng)前大部分的Java虛擬機(jī)都可動(dòng)態(tài)擴(kuò)展,只不過(guò)Java虛擬機(jī)規(guī)范中也允許固定長(zhǎng)度的虛擬機(jī)棧),當(dāng)擴(kuò)展時(shí)無(wú)法申請(qǐng)到足夠的內(nèi)存時(shí)會(huì)拋出OutOfMemoryError異常。

  • 本地方法棧
  •   本地方法棧(Native Method Stacks)與虛擬機(jī)棧所發(fā)揮的作用是非常相似的,其區(qū)別不過(guò)是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù),而本地方法棧則是為虛擬機(jī)使用到的Native方法服務(wù)。虛擬機(jī)規(guī)范中對(duì)本地方法棧中的方法使用的語(yǔ)言、使用方式與數(shù)據(jù)結(jié)構(gòu)并沒(méi)有強(qiáng)制規(guī)定,因此具體的虛擬機(jī)可以自由實(shí)現(xiàn)它。甚至有的虛擬機(jī)(譬如Sun HotSpot虛擬機(jī))直接就把本地方法棧和虛擬機(jī)棧合二為一。與虛擬機(jī)棧一樣,本地方法棧區(qū)域也會(huì)拋出StackOverflowError和OutOfMemoryError異常。

  • Java堆
  •   對(duì)于大多數(shù)應(yīng)用來(lái)說(shuō),Java堆(Java Heap)是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊。Java堆是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存。這一點(diǎn)在Java虛擬機(jī)規(guī)范中的描述是:所有的對(duì)象實(shí)例以及數(shù)組都要在堆上分配,但是隨著JIT編譯器的發(fā)展與逃逸分析技術(shù)的逐漸成熟,棧上分配、標(biāo)量替換優(yōu)化技術(shù)將會(huì)導(dǎo)致一些微妙的變化發(fā)生,所有的對(duì)象都分配在堆上也漸漸變得不是那么"絕對(duì)"了。

      Java堆是垃圾收集器管理的主要區(qū)域,因此很多時(shí)候也被稱做"GC堆"(Garbage Collected Heap,幸好國(guó)內(nèi)沒(méi)翻譯成"垃圾堆")。如果從內(nèi)存回收的角度看,由于現(xiàn)在收集器基本都是采用的分代收集算法,所以Java堆中還可以細(xì)分為:新生代和老年代;再細(xì)致一點(diǎn)的有Eden空間、From Survivor空間、To Survivor空間等。如果從內(nèi)存分配的角度看,線程共享的Java堆中可能劃分出多個(gè)線程私有的分配緩沖區(qū)(Thread Local Allocation Buffer,TLAB)。不過(guò),無(wú)論如何劃分,都與存放內(nèi)容無(wú)關(guān),無(wú)論哪個(gè)區(qū)域,存儲(chǔ)的都仍然是對(duì)象實(shí)例,進(jìn)一步劃分的目的是為了更好地回收內(nèi)存,或者更快地分配內(nèi)存。在本章中,我們僅僅針對(duì)內(nèi)存區(qū)域的作用進(jìn)行討論,Java堆中的上述各個(gè)區(qū)域的分配和回收等細(xì)節(jié)將會(huì)是下一章的主題。

      根據(jù)Java虛擬機(jī)規(guī)范的規(guī)定,Java堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上是連續(xù)的即可,就像我們的磁盤空間一樣。在實(shí)現(xiàn)時(shí),既可以實(shí)現(xiàn)成固定大小的,也可以是可擴(kuò)展的,不過(guò)當(dāng)前主流的虛擬機(jī)都是按照可擴(kuò)展來(lái)實(shí)現(xiàn)的(通過(guò)-Xmx和-Xms控制)。如果在堆中沒(méi)有內(nèi)存完成實(shí)例分配,并且堆也無(wú)法再擴(kuò)展時(shí),將會(huì)拋出OutOfMemoryError異常。

  • 方法區(qū)
  •   方法區(qū)(Method Area)與Java堆一樣,是各個(gè)線程共享的內(nèi)存區(qū)域,它用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。雖然Java虛擬機(jī)規(guī)范把方法區(qū)描述為堆的一個(gè)邏輯部分,但是它卻有一個(gè)別名叫做Non-Heap(非堆),目的應(yīng)該是與Java堆區(qū)分開(kāi)來(lái)。

      對(duì)于習(xí)慣在HotSpot虛擬機(jī)上開(kāi)發(fā)和部署程序的開(kāi)發(fā)者來(lái)說(shuō),很多人愿意把方法區(qū)稱為"永久代"Permanent Generation),本質(zhì)上兩者并不等價(jià),僅僅是因?yàn)镠otSpot虛擬機(jī)的設(shè)計(jì)團(tuán)隊(duì)選擇把GC分代收集擴(kuò)展至方法區(qū),或者說(shuō)使用永久代來(lái)實(shí)現(xiàn)方法區(qū)而已。對(duì)于其他虛擬機(jī)(如BEA JRockit、IBM J9等)來(lái)說(shuō)是不存在永久代的概念的。即使是HotSpot虛擬機(jī)本身,根據(jù)官方發(fā)布的路線圖信息,現(xiàn)在也有放棄永久代并"搬家"至Native Memory來(lái)實(shí)現(xiàn)方法區(qū)的規(guī)劃了。

      Java虛擬機(jī)規(guī)范對(duì)這個(gè)區(qū)域的限制非常寬松,除了和Java堆一樣不需要連續(xù)的內(nèi)存和可以選擇固定大小或者可擴(kuò)展外,還可以選擇不實(shí)現(xiàn)垃圾收集。相對(duì)而言,垃圾收集行為在這個(gè)區(qū)域是比較少出現(xiàn)的,但并非數(shù)據(jù)進(jìn)入了方法區(qū)就如永久代的名字一樣"永久"存在了。這個(gè)區(qū)域的內(nèi)存回收目標(biāo)主要是針對(duì)常量池的回收和對(duì)類型的卸載,一般來(lái)說(shuō)這個(gè)區(qū)域的回收"成績(jī)"比較難以令人滿意,尤其是類型的卸載,條件相當(dāng)苛刻,但是這部分區(qū)域的回收確實(shí)是有必要的。在Sun公司的BUG列表中,  曾出現(xiàn)過(guò)的若干個(gè)嚴(yán)重的BUG就是由于低版本的HotSpot虛擬機(jī)對(duì)此區(qū)域未完全回收而導(dǎo)致內(nèi)存泄漏。根據(jù)Java虛擬機(jī)規(guī)范的規(guī)定,當(dāng)方法區(qū)無(wú)法滿足內(nèi)存分配需求時(shí),將拋出OutOfMemoryError異常。

  • 運(yùn)行時(shí)常量池
  •   運(yùn)行時(shí)常量池(Runtime Constant Pool)是方法區(qū)的一部分。Class文件中除了有類的版本、字段、方法、接口等描述等信息外,還有一項(xiàng)信息是常量池(Constant Pool Table),用于存放編譯期生成的各種字面量和符號(hào)引用,這部分內(nèi)容將在類加載后存放到方法區(qū)的運(yùn)行時(shí)常量池中。?Java虛擬機(jī)對(duì)Class文件的每一部分(自然也包括常量池)的格式都有嚴(yán)格的規(guī)定,每一個(gè)字節(jié)用于存儲(chǔ)哪種數(shù)據(jù)都必須符合規(guī)范上的要求,這樣才會(huì)被虛擬機(jī)認(rèn)可、裝載和執(zhí)行。但對(duì)于運(yùn)行時(shí)常量池,Java虛擬機(jī)規(guī)范沒(méi)有做任何細(xì)節(jié)的要求,不同的提供商實(shí)現(xiàn)的虛擬機(jī)可以按照自己的需要來(lái)實(shí)現(xiàn)這個(gè)內(nèi)存區(qū)域。不過(guò),一般來(lái)說(shuō),除了保存Class文件中描述的符號(hào)引用外,還會(huì)把翻譯出來(lái)的直接引用也存儲(chǔ)在運(yùn)行時(shí)常量池中。運(yùn)行時(shí)常量池相對(duì)于Class文件常量池的另外一個(gè)重要特征是具備動(dòng)態(tài)性,Java語(yǔ)言并不要求常量一定只能在編譯期產(chǎn)生,也就是并非預(yù)置入Class文件中常量池的內(nèi)容才能進(jìn)入方法區(qū)運(yùn)行時(shí)常量池,運(yùn)行期間也可能將新的常量放入池中,這種特性被開(kāi)發(fā)人員利用得比較多的便是String類的intern()方法。既然運(yùn)行時(shí)常量池是方法區(qū)的一部分,自然會(huì)受到方法區(qū)內(nèi)存的限制,當(dāng)常量池?zé)o法再申請(qǐng)到內(nèi)存時(shí)會(huì)拋出OutOfMemoryError異常。

  • 對(duì)象訪問(wèn)
  •   介紹完Java虛擬機(jī)的運(yùn)行時(shí)數(shù)據(jù)區(qū)之后,我們就可以來(lái)探討一個(gè)問(wèn)題:在Java語(yǔ)言中,對(duì)象訪問(wèn)是如何進(jìn)行的?對(duì)象訪問(wèn)在Java語(yǔ)言中無(wú)處不在,是最普通的程序行為,但即使是最簡(jiǎn)單的訪問(wèn),也會(huì)卻涉及Java棧、Java堆、方法區(qū)這三個(gè)最重要內(nèi)存區(qū)域之間的關(guān)聯(lián)關(guān)系,如下面的這句代碼:

              Object obj = new Object();

    假設(shè)這句代碼出現(xiàn)在方法體中,那"Object obj"這部分的語(yǔ)義將會(huì)反映到Java棧的本地變量表中,作為一個(gè)reference類型數(shù)據(jù)出現(xiàn)。而"new Object()"這部分的語(yǔ)義將會(huì)反映到Java堆中,形成一塊存儲(chǔ)了Object類型所有實(shí)例數(shù)據(jù)值(Instance Data,對(duì)象中各個(gè)實(shí)例字段的數(shù)據(jù))的結(jié)構(gòu)化內(nèi)存,根據(jù)具體類型以及虛擬機(jī)實(shí)現(xiàn)的對(duì)象內(nèi)存布局(Object Memory Layout)的不同,這塊內(nèi)存的長(zhǎng)度是不固定的。另外,在Java堆中還必須包含能查找到此對(duì)象類型數(shù)據(jù)(如對(duì)象類型、父類、實(shí)現(xiàn)的接口、方法等)的地址信息,這些類型數(shù)據(jù)則存儲(chǔ)在方法區(qū)中。

      由于reference類型在Java虛擬機(jī)規(guī)范里面只規(guī)定了一個(gè)指向?qū)ο蟮囊?#xff0c;并沒(méi)有定義這個(gè)引用應(yīng)該通過(guò)哪種方式去定位,以及訪問(wèn)到Java堆中的對(duì)象的具體位置,因此不同虛擬機(jī)實(shí)現(xiàn)的對(duì)象訪問(wèn)方式會(huì)有所不同,主流的訪問(wèn)方式有兩種:使用句柄和直接指針。?如果使用句柄訪問(wèn)方式,Java堆中將會(huì)劃分出一塊內(nèi)存來(lái)作為句柄池,reference中存儲(chǔ)的就是對(duì)象的句柄地址,而句柄中包含了對(duì)象實(shí)例數(shù)據(jù)和類型數(shù)據(jù)各自的具體地址信息,如下圖所示:

          

      如果使用的是直接指針訪問(wèn)方式,Java?堆對(duì)象的布局中就必須考慮如何放置訪問(wèn)類型數(shù)據(jù)的相關(guān)信息,reference中直接存儲(chǔ)的就是對(duì)象地址,如下圖所示:

          

      這兩種對(duì)象的訪問(wèn)方式各有優(yōu)勢(shì),使用句柄訪問(wèn)方式的最大好處就是reference中存儲(chǔ)的是穩(wěn)定的句柄地址,在對(duì)象被移動(dòng)(垃圾收集時(shí)移動(dòng)對(duì)象是非常普遍的行為)時(shí)只會(huì)改變句柄中的實(shí)例數(shù)據(jù)指針,而reference本身不需要被修改。使用直接指針訪問(wèn)方式的最大好處就是速度更快,它節(jié)省了一次指針定位的時(shí)間開(kāi)銷,由于對(duì)象的訪問(wèn)在Java中非常頻繁,因此這類開(kāi)銷積少成多后也是一項(xiàng)非常可觀的執(zhí)行成本。就本書討論的主要虛擬機(jī)Sun HotSpot而言,它是使用第二種方式進(jìn)行對(duì)象訪問(wèn)的,但從整個(gè)軟件開(kāi)發(fā)的范圍來(lái)看,各種語(yǔ)言和框架使用句柄來(lái)訪問(wèn)的情況也十分常見(jiàn)。

    ?

    三:面向?qū)ο?#xff1a;★★★★★

    匿名對(duì)象使用場(chǎng)景

    1當(dāng)對(duì)方法只進(jìn)行一次調(diào)用的時(shí)候,可以使用匿名對(duì)象。

    2當(dāng)對(duì)象對(duì)成員進(jìn)行多次調(diào)用時(shí),不能使用匿名對(duì)象。必須給對(duì)象起名字。

    ?

    類中怎么沒(méi)有定義主函數(shù)呢?

    注意:主函數(shù)的存在,僅為該類是否需要獨(dú)立運(yùn)行,如果不需要,主函數(shù)是不用定義的。

    主函數(shù)的解釋:保證所在類的獨(dú)立運(yùn)行,是程序的入口,被jvm調(diào)用。

    ?

    成員變量和局部變量的區(qū)別:

    1:成員變量直接定義在類中。

    局部變量定義在方法中,參數(shù)上,語(yǔ)句中。

    2:成員變量在這個(gè)類中有效。

    局部變量只在自己所屬的大括號(hào)內(nèi)有效,大括號(hào)結(jié)束,局部變量失去作用域。

    3:成員變量存在于堆內(nèi)存中,隨著對(duì)象的產(chǎn)生而存在,消失而消失。

    局部變量存在于棧內(nèi)存中,隨著所屬區(qū)域的運(yùn)行而存在,結(jié)束而釋放。

    ?

    構(gòu)造函數(shù):用于給對(duì)象進(jìn)行初始化,是給與之對(duì)應(yīng)的對(duì)象進(jìn)行初始化,它具有針對(duì)性,函數(shù)中的一種。

    特點(diǎn)

    1該函數(shù)的名稱和所在類的名稱相同。

    2不需要定義返回值類型。

    3該函數(shù)沒(méi)有具體的返回值。

    記住:所有對(duì)象創(chuàng)建時(shí),都需要初始化才可以使用。

    ?

    注意事項(xiàng):一個(gè)類在定義時(shí),如果沒(méi)有定義過(guò)構(gòu)造函數(shù),那么該類中會(huì)自動(dòng)生成一個(gè)空參數(shù)的構(gòu)造函數(shù),為了方便該類創(chuàng)建對(duì)象,完成初始化。如果在類中自定義了構(gòu)造函數(shù),那么默認(rèn)的構(gòu)造函數(shù)就沒(méi)有了。

    ?

    一個(gè)類中,可以有多個(gè)構(gòu)造函數(shù),因?yàn)樗鼈兊暮瘮?shù)名稱都相同,所以只能通過(guò)參數(shù)列表來(lái)區(qū)分。所以,一個(gè)類中如果出現(xiàn)多個(gè)構(gòu)造函數(shù)。它們的存在是以重載體現(xiàn)的。

    ?

    構(gòu)造代碼塊和構(gòu)造函數(shù)有什么區(qū)別?

    構(gòu)造代碼塊:是給所有的對(duì)象進(jìn)行初始化,也就是說(shuō),所有的對(duì)象都會(huì)調(diào)用一個(gè)代碼塊。只要對(duì)象一建立。就會(huì)調(diào)用這個(gè)代碼塊。

    構(gòu)造函數(shù):是給與之對(duì)應(yīng)的對(duì)象進(jìn)行初始化。它具有針對(duì)性。

  • 執(zhí)行順序:(優(yōu)先級(jí)從高到低。)靜態(tài)代碼塊>mian方法>構(gòu)造代碼塊>構(gòu)造方法。其中靜態(tài)代碼塊只執(zhí)行一次。構(gòu)造代碼塊在每次創(chuàng)建對(duì)象是都會(huì)執(zhí)行。
  • 靜態(tài)代碼塊的作用:比如我們?cè)谡{(diào)用C語(yǔ)言的動(dòng)態(tài)庫(kù)時(shí)會(huì)可把.so文件放在此處。?
  • 構(gòu)造代碼塊的功能:(可以把不同構(gòu)造方法中相同的共性的東西寫在它里面)。例如:比如不論任何機(jī)型的電腦都有開(kāi)機(jī)這個(gè)功能,此時(shí)我們就可以把這個(gè)功能定義在構(gòu)造代碼塊內(nèi)。
  • ?

    Person p = new Person();

    創(chuàng)建一個(gè)對(duì)象都在內(nèi)存中做了什么事情?

    1先將硬盤上指定位置的Person.class文件加載進(jìn)內(nèi)存。

    2執(zhí)行main方法時(shí),在棧內(nèi)存中開(kāi)辟了main方法的空間(壓棧-進(jìn)棧),然后在main方法的棧區(qū)分配了一個(gè)變量p。

    3在堆內(nèi)存中開(kāi)辟一個(gè)實(shí)體空間,分配了一個(gè)內(nèi)存首地址值。new

    4在該實(shí)體空間中進(jìn)行屬性的空間分配,并進(jìn)行了默認(rèn)初始化。

    5對(duì)空間中的屬性進(jìn)行顯示初始化。

    6進(jìn)行實(shí)體的構(gòu)造代碼塊初始化。

    7調(diào)用該實(shí)體對(duì)應(yīng)的構(gòu)造函數(shù),進(jìn)行構(gòu)造函數(shù)初始化。()

    8將首地址賦值給p?,p變量就引用了該實(shí)體。(指向了該對(duì)象)

    ?

    ?

    封 裝(面向?qū)ο筇卣髦?#xff09;:是指隱藏對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外提供公共訪問(wèn)方式。

    好處:將變化隔離;便于使用;提高重用性;安全性。

    封裝原則:將不需要對(duì)外提供的內(nèi)容都隱藏起來(lái),把屬性都隱藏,提供公共方法對(duì)其訪問(wèn)。

    ?

    this:代表對(duì)象。就是所在函數(shù)所屬對(duì)象的引用。

    this到底代表什么呢?哪個(gè)對(duì)象調(diào)用了this所在的函數(shù),this就代表哪個(gè)對(duì)象,就是哪個(gè)對(duì)象的引用。

    開(kāi)發(fā)時(shí),什么時(shí)候使用this呢?

    在定義功能時(shí),如果該功能內(nèi)部使用到了調(diào)用該功能的對(duì)象,這時(shí)就用this來(lái)表示這個(gè)對(duì)象。

    ?

    this 還可以用于構(gòu)造函數(shù)間的調(diào)用。

    調(diào)用格式:this(實(shí)際參數(shù));

    this對(duì)象后面跟上?.?調(diào)用的是成員屬性和成員方法(一般方法);

    this對(duì)象后面跟上 () 調(diào)用的是本類中的對(duì)應(yīng)參數(shù)的構(gòu)造函數(shù)。

    ?

    注意:用this調(diào)用構(gòu)造函數(shù),必須定義在構(gòu)造函數(shù)的第一行。因?yàn)闃?gòu)造函數(shù)是用于初始化的,所以初始化動(dòng)作一定要執(zhí)行。否則編譯失敗。

    ?

    static:★★★?關(guān)鍵字,是一個(gè)修飾符,用于修飾成員(成員變量和成員函數(shù))。

    特點(diǎn):

    1、static變量

     按照是否靜態(tài)的對(duì)類成員變量進(jìn)行分類可分兩種:一種是被static修飾的變量,叫靜態(tài)變量或類變量;另一種是沒(méi)有被static修飾的變量,叫實(shí)例變量。兩者的區(qū)別是:

     對(duì)于靜態(tài)變量在內(nèi)存中只有一個(gè)拷貝(節(jié)省內(nèi)存),JVM只為靜態(tài)分配一次內(nèi)存,在加載類的過(guò)程中完成靜態(tài)變量的內(nèi)存分配,可用類名直接訪問(wèn)(方便),當(dāng)然也可以通過(guò)對(duì)象來(lái)訪問(wèn)(但是這是不推薦的)。

     對(duì)于實(shí)例變量,沒(méi)創(chuàng)建一個(gè)實(shí)例,就會(huì)為實(shí)例變量分配一次內(nèi)存,實(shí)例變量可以在內(nèi)存中有多個(gè)拷貝,互不影響(靈活)。

    2、靜態(tài)方法

     靜態(tài)方法可以直接通過(guò)類名調(diào)用,任何的實(shí)例也都可以調(diào)用,因此靜態(tài)方法中不能用this和super關(guān)鍵字,不能直接訪問(wèn)所屬類的實(shí)例變量和實(shí)例方法(就是不帶static的成員變量和成員成員方法),只能訪問(wèn)所屬類的靜態(tài)成員變量和成員方法。因?yàn)閷?shí)例成員與特定的對(duì)象關(guān)聯(lián)!這個(gè)需要去理解,想明白其中的道理,不是記憶!!!

     因?yàn)閟tatic方法獨(dú)立于任何實(shí)例,因此static方法必須被實(shí)現(xiàn),而不能是抽象的abstract。

    3、static代碼塊

     static代碼塊也叫靜態(tài)代碼塊,是在類中獨(dú)立于類成員的static語(yǔ)句塊,可以有多個(gè),位置可以隨便放,它不在任何的方法體內(nèi),JVM加載類時(shí)會(huì)執(zhí)行這些靜態(tài)的代碼塊,如果static代碼塊有多個(gè),JVM將按照它們?cè)陬愔谐霈F(xiàn)的先后順序依次執(zhí)行它們,每個(gè)代碼塊只會(huì)被執(zhí)行一次。

    4、static和final一塊用表示什么

    static final用來(lái)修飾成員變量和成員方法,可簡(jiǎn)單理解為"全局常量"!

    對(duì)于變量,表示一旦給值就不可修改,并且通過(guò)類名可以訪問(wèn)。

    對(duì)于方法,表示不可覆蓋,并且可以通過(guò)類名直接訪問(wèn)。

    ?

    備注:

    1,有些數(shù)據(jù)是對(duì)象特有的數(shù)據(jù),是不可以被靜態(tài)修飾的。因?yàn)槟菢拥脑?#xff0c;特有數(shù)據(jù)會(huì)變成對(duì)象的共享數(shù)據(jù)。這樣對(duì)事物的描述就出了問(wèn)題。所以,在定義靜態(tài)時(shí),必須要明確,這個(gè)數(shù)據(jù)是否是被對(duì)象所共享的。

    2,靜態(tài)方法只能訪問(wèn)靜態(tài)成員,不可以訪問(wèn)非靜態(tài)成員。

    (這句話是針對(duì)同一個(gè)類環(huán)境下的,比如說(shuō),一個(gè)類有多個(gè)成員(屬性,方法,字段),靜態(tài)方法A,那么可以訪問(wèn)同類名下其他靜態(tài)成員,你如果訪問(wèn)非靜態(tài)成員就不行)

    因?yàn)殪o態(tài)方法加載時(shí),優(yōu)先于對(duì)象存在,所以沒(méi)有辦法訪問(wèn)對(duì)象中的成員。

    3,靜態(tài)方法中不能使用this,super關(guān)鍵字。

    因?yàn)?strong>this代表對(duì)象,而靜態(tài)在時(shí),有可能沒(méi)有對(duì)象,所以this無(wú)法使用。

    4,主函數(shù)是靜態(tài)的。

    ?

    成員變量和靜態(tài)變量的區(qū)別:

    1,成員變量所屬于對(duì)象。所以也稱為實(shí)例變量。

    靜態(tài)變量所屬于類。所以也稱為類變量。

    2,成員變量存在于堆內(nèi)存中。

    靜態(tài)變量存在于方法區(qū)中。

    3,成員變量隨著對(duì)象創(chuàng)建而存在。隨著對(duì)象被回收而消失。

    靜態(tài)變量隨著類的加載而存在。隨著類的消失而消失。

    4,成員變量只能被對(duì)象所調(diào)用 。

    靜態(tài)變量可以被對(duì)象調(diào)用,也可以被類名調(diào)用。

    所以,成員變量可以稱為對(duì)象的特有數(shù)據(jù),靜態(tài)變量稱為對(duì)象的共享數(shù)據(jù)。

    ?

    靜態(tài)代碼塊:就是一個(gè)有靜態(tài)關(guān)鍵字標(biāo)示的一個(gè)代碼塊區(qū)域。定義在類中。

    作用:可以完成類的初始化。靜態(tài)代碼塊隨著類的加載而執(zhí)行,而且只執(zhí)行一次(new 多個(gè)對(duì)象就只執(zhí)行一次)。如果和主函數(shù)在同一類中,優(yōu)先于主函數(shù)執(zhí)行。

    ?

    final

     根據(jù)程序上下文環(huán)境,Java關(guān)鍵字final有"這是無(wú)法改變的"或者"終態(tài)的"含義,它可以修飾非抽象類、非抽象類成員方法和變量。你可能出于兩種理解而需要阻止改變、設(shè)計(jì)或效率。

    final類不能被繼承,沒(méi)有子類,final類中的方法默認(rèn)是final的。

    final方法不能被子類的方法覆蓋,但可以被繼承。

    final成員變量表示常量,只能被賦值一次,賦值后值不再改變。

    final不能用于修飾構(gòu)造方法。

    注意:父類的private成員方法是不能被子類方法覆蓋的,因此private類型的方法默認(rèn)是final類型的。

    1、final類

    final類不能被繼承,因此final類的成員方法沒(méi)有機(jī)會(huì)被覆蓋,默認(rèn)都是final的。在設(shè)計(jì)類時(shí)候,如果這個(gè)類不需要有子類,類的實(shí)現(xiàn)細(xì)節(jié)不允許改變,并且確信這個(gè)類不會(huì)載被擴(kuò)展,那么就設(shè)計(jì)為final類。

    2、final方法

    如果一個(gè)類不允許其子類覆蓋某個(gè)方法,則可以把這個(gè)方法聲明為final方法。

    使用final方法的原因有二:

    第一、把方法鎖定,防止任何繼承類修改它的意義和實(shí)現(xiàn)。

    第二、高效。編譯器在遇到調(diào)用final方法時(shí)候會(huì)轉(zhuǎn)入內(nèi)嵌機(jī)制,大大提高執(zhí)行效率。

    3、final變量(常量)

     用final修飾的成員變量表示常量,值一旦給定就無(wú)法改變!

     final修飾的變量有三種:靜態(tài)變量、實(shí)例變量和局部變量,分別表示三種類型的常量。

     從下面的例子中可以看出,一旦給final變量初值后,值就不能再改變了。

     另外,final變量定義的時(shí)候,可以先聲明,而不給初值,這中變量也稱為final空白,無(wú)論什么情況,編譯器都確保空白final在使用之前必須被初始化。但是,final空白在final關(guān)鍵字final的使用上提供了更大的靈活性,為此,一個(gè)類中的final數(shù)據(jù)成員就可以實(shí)現(xiàn)依對(duì)象而有所不同,卻有保持其恒定不變的特征。

    4、final參數(shù)

    當(dāng)函數(shù)參數(shù)為final類型時(shí),你可以讀取使用該參數(shù),但是無(wú)法改變?cè)搮?shù)的值。

    ?

    ?

    生成Java幫助文檔:命令格式:javadoc –d 文件夾名 –auther –version *.java

    /** //格式

    *類描述

    *@author 作者名

    *@version 版本號(hào)

    */

    /**

    *方法描述

    *@param 參數(shù)描述

    *@return 返回值描述

    */

    ?

    ?

    繼 承(面向?qū)ο筇卣髦?#xff09;

    java中對(duì)于繼承,java只支持單繼承。java雖然不直接支持多繼承,但是可實(shí)現(xiàn)多接口。

    ?

    1:成員變量。

    ???? 當(dāng)子父類中出現(xiàn)一樣的屬性時(shí),子類類型的對(duì)象,調(diào)用該屬性,值是子類的屬性值。

    ???? 如果想要調(diào)用父類中的屬性值,需要使用一個(gè)關(guān)鍵字:super

    ?????This:代表是本類類型的對(duì)象引用。

    ?????Super:代表是子類所屬的父類中的內(nèi)存空間引用。

    ???? 注意:子父類中通常是不會(huì)出現(xiàn)同名成員變量的,因?yàn)楦割愔兄灰x了,子類就不用在定義了,直接繼承過(guò)來(lái)用就可以了。

    2:成員函數(shù)。

    當(dāng)子父類中出現(xiàn)了一模一樣的方法時(shí),建立子類對(duì)象會(huì)運(yùn)行子類中的方法。好像父類中的方法被覆蓋掉一樣。所以這種情況,是函數(shù)的另一個(gè)特性:重寫

    3:構(gòu)造函數(shù)。

    發(fā)現(xiàn)子類構(gòu)造函數(shù)運(yùn)行時(shí),先運(yùn)行了父類的構(gòu)造函數(shù)。為什么呢?

    原因:子類的所有構(gòu)造函數(shù)中的第一行,其實(shí)都有一條隱身的語(yǔ)句super();

    super():?表示父類的構(gòu)造函數(shù),并會(huì)調(diào)用于參數(shù)相對(duì)應(yīng)的父類中的構(gòu)造函數(shù)。而super():是在調(diào)用父類中空參數(shù)的構(gòu)造函數(shù)。

    為什么子類對(duì)象初始化時(shí),都需要調(diào)用父類中的函數(shù)?(為什么要在子類構(gòu)造函數(shù)的第一行加入這個(gè)super()?)

    因?yàn)樽宇惱^承父類,會(huì)繼承到父類中的數(shù)據(jù),所以必須要看父類是如何對(duì)自己的數(shù)據(jù)進(jìn)行初始化的。所以子類在進(jìn)行對(duì)象初始化時(shí),先調(diào)用父類的構(gòu)造函數(shù),這就是子類的實(shí)例化過(guò)程

    ?

    注意:子類中所有的構(gòu)造函數(shù)都會(huì)默認(rèn)訪問(wèn)父類中的空參數(shù)的構(gòu)造函數(shù),因?yàn)槊恳粋€(gè)子類構(gòu)造內(nèi)第一行都有默認(rèn)的語(yǔ)句super();

    如果父類中沒(méi)有空參數(shù)的構(gòu)造函數(shù),那么子類的構(gòu)造函數(shù)內(nèi),必須通過(guò)super語(yǔ)句指定要訪問(wèn)的父類中的構(gòu)造函數(shù)。

    如果子類構(gòu)造函數(shù)中用this來(lái)指定調(diào)用子類自己的構(gòu)造函數(shù),那么被調(diào)用的構(gòu)造函數(shù)也一樣會(huì)訪問(wèn)父類中的構(gòu)造函數(shù)。

    ?

    問(wèn)題:

    super()和this()是否可以同時(shí)出現(xiàn)的構(gòu)造函數(shù)中?

    兩個(gè)語(yǔ)句只能有一個(gè)定義在第一行,所以只能出現(xiàn)其中一個(gè)。

    super()或者this():為什么一定要定義在第一行?

    因?yàn)閟uper()或者this()都是調(diào)用構(gòu)造函數(shù),構(gòu)造函數(shù)用于初始化,所以初始化的動(dòng)作要先完成。

    ?

    在方法覆蓋時(shí),注意兩點(diǎn):

    1:子類覆蓋父類時(shí),必須要保證,子類方法的權(quán)限必須大于等于父類方法權(quán)限可以實(shí)現(xiàn)繼承。否則,編譯失敗。(舉個(gè)例子,在父類中是public的方法,如果子類中將其降低訪問(wèn)權(quán)限為private,那么子類中重寫以后的方法對(duì)于外部對(duì)象就不可訪問(wèn)了,這個(gè)就破壞了繼承的含義)

    2:覆蓋時(shí),要么都靜態(tài),要么都不靜態(tài)。 (靜態(tài)只能覆蓋靜態(tài),或者被靜態(tài)覆蓋)

    ?

    繼承的一個(gè)弊端:打破了封裝性。對(duì)于一些類,或者類中功能,是需要被繼承,或者復(fù)寫的。

    這時(shí)如何解決問(wèn)題呢?介紹一個(gè)關(guān)鍵字,final

    ?

    final特點(diǎn):(詳細(xì)解釋見(jiàn)前面)

    1:這個(gè)關(guān)鍵字是一個(gè)修飾符,可以修飾類,方法,變量。

    2:被final修飾的類是一個(gè)最終類,不可以被繼承。

    3:被final修飾的方法是一個(gè)最終方法,不可以被覆蓋。

    4:被final修飾的變量是一個(gè)常量,只能賦值一次。

    ?

    抽象類: abstract

    抽象類的特點(diǎn):

    1:抽象方法只能定義在抽象類中,抽象類和抽象方法必須由abstract關(guān)鍵字修飾(可以描述類和方法,不可以描述變量)。

    2:抽象方法只定義方法聲明,并不定義方法實(shí)現(xiàn)。

    3:抽象類不可以被創(chuàng)建對(duì)象(實(shí)例化)。

    4:只有通過(guò)子類繼承抽象類并覆蓋了抽象類中的所有抽象方法后,該子類才可以實(shí)例化。否則,該子類還是一個(gè)抽象類。

    ?

    抽象類的細(xì)節(jié):

    1:抽象類中是否有構(gòu)造函數(shù)?有,用于給子類對(duì)象進(jìn)行初始化。

    2:抽象類中是否可以定義非抽象方法?

    ????可以。其實(shí),抽象類和一般類沒(méi)有太大的區(qū)別,都是在描述事物,只不過(guò)抽象類在描述事物時(shí),有些功能不具體。所以抽象類和一般類在定義上,都是需要定義屬性和行為的。只不過(guò),比一般類多了一個(gè)抽象函數(shù)。而且比一般類少了一個(gè)創(chuàng)建對(duì)象的部分。

    3:抽象關(guān)鍵字abstract和哪些不可以共存?final ,????private , static

    4:抽象類中可不可以不定義抽象方法?可以。抽象方法目的僅僅為了不讓該類創(chuàng)建對(duì)象。

    ?

    ?

    接 口:★★★★★

    1:是用關(guān)鍵字interface定義的。

    2:接口中包含的成員,最常見(jiàn)的有全局常量、抽象方法。

    注意:接口中的成員都有固定的修飾符。

    ????成員變量:public static final

    ????成員方法:public abstract

    interface?Inter{

    ????public static final?int x = 3;

    ????public abstract?void show();

    }

    3:接口中有抽象方法,說(shuō)明接口不可以實(shí)例化接口的子類必須實(shí)現(xiàn)了接口中所有的抽象方法后,該子類才可以實(shí)例化。否則,該子類還是一個(gè)抽象類。

    4:類與類之間存在著繼承關(guān)系,類與接口中間存在的是實(shí)現(xiàn)關(guān)系。

    ????繼承用extends ;實(shí)現(xiàn)用implements ;

    5:接口和類不一樣的地方,就是,接口可以被多實(shí)現(xiàn),這就是多繼承改良后的結(jié)果。java將多繼承機(jī)制通過(guò)多現(xiàn)實(shí)來(lái)體現(xiàn)。

    6:一個(gè)類在繼承另一個(gè)類的同時(shí),還可以實(shí)現(xiàn)多個(gè)接口。所以接口的出現(xiàn)避免了單繼承的局限性。還可以將類進(jìn)行功能的擴(kuò)展。

    7:其實(shí)java中是有多繼承的。接口與接口之間存在著繼承關(guān)系,接口可以多繼承接口

    java類是單繼承的。classB Extends classA

    java接口可以多繼承。Interface3 Extends Interface0, Interface1, interface……

    不允許類多重繼承的主要原因是,如果A同時(shí)繼承B和C,而b和c同時(shí)有一個(gè)D方法,A如何決定該繼承那一個(gè)呢?

    但接口不存在這樣的問(wèn)題,接口全都是抽象方法繼承誰(shuí)都無(wú)所謂,所以接口可以繼承多個(gè)接口。

    ?

    抽象類與接口:

    抽象類:一般用于描述一個(gè)體系單元,將一組共性內(nèi)容進(jìn)行抽取,特點(diǎn):可以在類中定義抽象內(nèi)容讓子類實(shí)現(xiàn),可以定義非抽象內(nèi)容讓子類直接使用。它里面定義的都是一些體系中的基本內(nèi)容

    接口:一般用于定義對(duì)象的擴(kuò)展功能,是在繼承之外還需這個(gè)對(duì)象具備的一些功能。

    ?

    抽象類和接口的共性:都是不斷向上抽取的結(jié)果。

    ?

    抽象類和接口的區(qū)別:

    1:抽象類只能被繼承,而且只能單繼承。

    接口需要被實(shí)現(xiàn),而且可以多實(shí)現(xiàn)。

    2:抽象類中可以定義非抽象方法,子類可以直接繼承使用。

    接口中都是抽象方法,需要子類去實(shí)現(xiàn)。

    3:抽象類使用的是 is a 關(guān)系。

    接口使用的 like a 關(guān)系。

    4:抽象類的成員修飾符可以自定義。

    接口中的成員修飾符是固定的。全都是public的。

    ?

    多 態(tài)★★★★★

    多 態(tài)★★★★★(面向?qū)ο筇卣髦?#xff09;:函數(shù)本身就具備多態(tài)性,某一種事物有不同的具體的體現(xiàn)。

    ?

    體現(xiàn):父類引用或者接口的引用指向了自己的子類對(duì)象。//Animal a = new Cat();父類可以調(diào)用子類中覆寫過(guò)的(父類中有的方法)

    多態(tài)的好處:提高了程序的擴(kuò)展性。繼承的父類或接口一般是類庫(kù)中的東西,(如果要修改某個(gè)方法的具體實(shí)現(xiàn)方式)只有通過(guò)子類去覆寫要改變的某一個(gè)方法,這樣在通過(guò)將父類的應(yīng)用指向子類的實(shí)例去調(diào)用覆寫過(guò)的方法就行了!

    多態(tài)的弊端:當(dāng)父類引用指向子類對(duì)象時(shí),雖然提高了擴(kuò)展性,但是只能訪問(wèn)父類中具備的方法,不可以訪問(wèn)子類中特有的方法。(前期不能使用后期產(chǎn)生的功能,即訪問(wèn)的局限性)

    多態(tài)的前提:

    ????1:必須要有關(guān)系,比如繼承、或者實(shí)現(xiàn)。

    ????2:通常會(huì)有覆蓋操作。

    ?

    如果想用子類對(duì)象的特有方法,如何判斷對(duì)象是哪個(gè)具體的子類類型呢?

    可以可以通過(guò)一個(gè)關(guān)鍵字?instanceof ;//判斷對(duì)象是否實(shí)現(xiàn)了指定的接口或繼承了指定的類

    ?

    格式:<對(duì)象 instanceof 類型> ,判斷一個(gè)對(duì)象是否所屬于指定的類型。

    Student?instanceof?Person = true;//student繼承了person類

    ?

    -------------------------------------------------------------------------------------java.lang.Object

    Object:所有類的直接或者間接父類,Java認(rèn)為所有的對(duì)象都具備一些基本的共性內(nèi)容,這些內(nèi)容可以不斷的向上抽取,最終就抽取到了一個(gè)最頂層的類中的,該類中定義的就是所有對(duì)象都具備的功能。

    ?

    具體方法:

  • boolean?equals(Object obj):用于比較兩個(gè)對(duì)象是否相等,其實(shí)內(nèi)部比較的就是兩個(gè)對(duì)象地址。
  • 2,String?toString():將對(duì)象變成字符串;默認(rèn)返回的格式:類名@哈希值 = getClass().getName() + '@' + Integer.toHexString(hashCode())

    ????為了對(duì)象對(duì)應(yīng)的字符串內(nèi)容有意義,可以通過(guò)復(fù)寫,建立該類對(duì)象自己特有的字符串表現(xiàn)形式。

    ????public String toString(){

    ????????return "person : "+age;

    ????}

    3,Class?getClass():獲取任意對(duì)象運(yùn)行時(shí)的所屬字節(jié)碼文件對(duì)象。

    4,int?hashCode():返回該對(duì)象的哈希碼值。支持此方法是為了提高哈希表的性能。將該對(duì)象的內(nèi)部地址轉(zhuǎn)換成一個(gè)整數(shù)來(lái)實(shí)現(xiàn)的。

    ?

    通常equals,toString,hashCode,在應(yīng)用中都會(huì)被復(fù)寫,建立具體對(duì)象的特有的內(nèi)容。

    -------------------------------------------------------------------------------------

    ?

    內(nèi)部類:如果A類需要直接訪問(wèn)B類中的成員,而B(niǎo)類又需要建立A類的對(duì)象。這時(shí),為了方便設(shè)計(jì)和訪問(wèn),直接將A類定義在B類中。就可以了。A類就稱為內(nèi)部類。內(nèi)部類可以直接訪問(wèn)外部類中的成員。而外部類想要訪問(wèn)內(nèi)部類,必須要建立內(nèi)部類的對(duì)象。

    -----------------------------------------------------

    class Outer{

    ????int num = 4;????

    ????class Inner?{

    ????????void show(){

    ????????????System.out.println("inner show run "+num);

    ????????}

    ????}

    ????public void method(){

    ????????Inner in = new Inner();//創(chuàng)建內(nèi)部類的對(duì)象。

    ????????in.show();//調(diào)用內(nèi)部類的方法。 //內(nèi)部類直接訪問(wèn)外部類成員,用自己的實(shí)例對(duì)象;

    ????}????????????????????????????????????????//外部類訪問(wèn)內(nèi)部類要定義內(nèi)部類的對(duì)象;

    }

    -------------------------------------------------------

    當(dāng)內(nèi)部類定義在外部類中的成員位置上,可以使用一些成員修飾符修飾 private、static。

    1:默認(rèn)修飾符。

    直接訪問(wèn)內(nèi)部類格式:外部類名.內(nèi)部類名 變量名 = 外部類對(duì)象.內(nèi)部類對(duì)象;

    Outer.Inner in = new Outer.new Inner();//這種形式很少用。

    ????但是這種應(yīng)用不多見(jiàn),因?yàn)閮?nèi)部類之所以定義在內(nèi)部就是為了封裝。想要獲取內(nèi)部類對(duì)象通常都通過(guò)外部類的方法來(lái)獲取。這樣可以對(duì)內(nèi)部類對(duì)象進(jìn)行控制。

    2:私有修飾符。

    ????通常內(nèi)部類被封裝,都會(huì)被私有化,因?yàn)榉庋b性不讓其他程序直接訪問(wèn)。

    3:靜態(tài)修飾符。

    ????如果內(nèi)部類被靜態(tài)修飾,相當(dāng)于外部類,會(huì)出現(xiàn)訪問(wèn)局限性,只能訪問(wèn)外部類中的靜態(tài)成員。

    ????注意;如果內(nèi)部類中定義了靜態(tài)成員,那么該內(nèi)部類必須是靜態(tài)的。

    ?

    內(nèi)部類編譯后的文件名為:"外部類名$內(nèi)部類名.java";

    ?

    為什么內(nèi)部類可以直接訪問(wèn)外部類中的成員呢?

    那是因?yàn)閮?nèi)部中都持有一個(gè)外部類的引用。這個(gè)是引用是?外部類名.this

    內(nèi)部類可以定義在外部類中的成員位置上,也可以定義在外部類中的局部位置上。

    當(dāng)內(nèi)部類被定義在局部位置上,只能訪問(wèn)局部中被final修飾的局部變量。

    ?

    匿名內(nèi)部類(對(duì)象):沒(méi)有名字的內(nèi)部類。就是內(nèi)部類的簡(jiǎn)化形式。一般只用一次就可以用這種形式。匿名內(nèi)部類其實(shí)就是一個(gè)匿名子類對(duì)象想要定義匿名內(nèi)部類:需要前提,內(nèi)部類必須繼承一個(gè)類或者實(shí)現(xiàn)接口。

    ?

    匿名內(nèi)部類的格式:new 父類名&接口名(){ 定義子類成員或者覆蓋父類方法 }.方法。

    ?

    匿名內(nèi)部類的使用場(chǎng)景:

    當(dāng)函數(shù)的參數(shù)是接口類型引用時(shí),如果接口中的方法不超過(guò)3個(gè)。可以通過(guò)匿名內(nèi)部類來(lái)完成參數(shù)的傳遞。

    其實(shí)就是在創(chuàng)建匿名內(nèi)部類時(shí),該類中的封裝的方法不要過(guò)多,最好兩個(gè)或者兩個(gè)以內(nèi)。

    --------------------------------------------------------

    //面試

    ????????//1

    ????????new Object(){

    ????????????void show(){

    ????????????????System.out.println("show run");????????????????

    ????????????}

    ????????}.show();????????????????????????????????????//寫法和編譯都沒(méi)問(wèn)題

    ????????//2

    ????????Object obj = new Object(){

    ????????????void show(){

    ????????????????System.out.println("show run");

    ????????????}

    ????????};

    ????????obj.show();????????????????????????????????//寫法正確,編譯會(huì)報(bào)錯(cuò)

    ????????

    ????????1和2的寫法正確嗎?有區(qū)別嗎?說(shuō)出原因。

    ????????寫法是正確,1和2都是在通過(guò)匿名內(nèi)部類建立一個(gè)Object類的子類對(duì)象。

    ????????區(qū)別:

    ????????第一個(gè)可是編譯通過(guò),并運(yùn)行。

    ????????第二個(gè)編譯失敗,因?yàn)槟涿麅?nèi)部類是一個(gè)子類對(duì)象,當(dāng)用Object的obj引用指向時(shí),就被提升為了Object類型,而編譯時(shí)會(huì)檢查Object類中是否有show方法,此時(shí)編譯失敗。

    ?

    ?

    異 常:★★★★

    --java.lang.Throwable:

    Throwable:可拋出的。

    ????|--Error:錯(cuò)誤,一般情況下,不編寫針對(duì)性的代碼進(jìn)行處理,通常是jvm發(fā)生的,需要對(duì)程序進(jìn)行修正。

    ????|--Exception:異常,可以有針對(duì)性的處理方式

    ?

    這個(gè)體系中的所有類和對(duì)象都具備一個(gè)獨(dú)有的特點(diǎn);就是可拋性。

    可拋性的體現(xiàn):就是這個(gè)體系中的類和對(duì)象都可以被throws和throw兩個(gè)關(guān)鍵字所操作。

    ?

    throw與throws區(qū)別:

    throws是用來(lái)聲明一個(gè)方法可能拋出的所有異常信息,而throw則是指拋出的一個(gè)具體的異常類型。此外throws是將異常聲明但是不處理,而是將異常往上傳,誰(shuí)調(diào)用我就交給誰(shuí)處理。

    throw用于拋出異常對(duì)象,后面跟的是異常對(duì)象;throw用在函數(shù)內(nèi)

    throws用于拋出異常類,后面跟的異常類名,可以跟多個(gè),用逗號(hào)隔開(kāi)。throws用在函數(shù)

    ?

    throws格式:方法名(參數(shù))throws 異常類1,異常類2,.....

    throw:就是自己進(jìn)行異常處理,處理的時(shí)候有兩種方式,要么自己捕獲異常(也就是try catch進(jìn)行捕捉),要么聲明拋出一個(gè)異常(就是throws 異常~~)。

    ?

    處理方式有兩種:1、捕捉;2、拋出。

    對(duì)于捕捉:java有針對(duì)性的語(yǔ)句塊進(jìn)行處理。

    try {

    ????需要被檢測(cè)的代碼;

    }

    catch(異常類 變量名){

    ????異常處理代碼;

    }

    fianlly{

    ????一定會(huì)執(zhí)行的代碼;

    }

    ?

    定義異常處理時(shí),什么時(shí)候定義try,什么時(shí)候定義throws呢?

    功能內(nèi)部如果出現(xiàn)異常,如果內(nèi)部可以處理,就用try;

    如果功能內(nèi)部處理不了,就必須聲明出來(lái),讓調(diào)用者處理。使用throws拋出,交給調(diào)用者處理。誰(shuí)調(diào)用了這個(gè)功能誰(shuí)就是調(diào)用者;

    ?

    自定義異常的步驟:

    1:定義一個(gè)子類繼承Exception或RuntimeException,讓該類具備可拋性(既可以使用throw和throws去調(diào)用此類)。

    2:通過(guò)throw 或者throws進(jìn)行操作。

    ?

    異常的轉(zhuǎn)換思想:當(dāng)出現(xiàn)的異常是調(diào)用者處理不了的,就需要將此異常轉(zhuǎn)換為一個(gè)調(diào)用者可以處理的異常拋出。

    ?

    try catch finally的幾種結(jié)合方式:

    1,

    try

    catch

    finally

    ?

    這種情況,如果出現(xiàn)異常,并不處理,但是資源一定關(guān)閉,所以try finally集合只為關(guān)閉資源

    記住:finally很有用,主要用戶關(guān)閉資源。無(wú)論是否發(fā)生異常,資源都必須進(jìn)行關(guān)閉。

    System.exit(0);?//退出jvm,只有這種情況finally不執(zhí)行。

    ?

    注意:

    如果父類或者接口中的方法沒(méi)有拋出過(guò)異常,那么子類是不可以拋出異常的,如果子類的覆蓋的方法中出現(xiàn)了異常,只能try不能throws。

    如果這個(gè)異常子類無(wú)法處理,已經(jīng)影響了子類方法的具體運(yùn)算,這時(shí)可以在子類方法中,通過(guò)throw拋出RuntimeException異常或者其子類,這樣,子類的方法上是不需要throws聲明的。

    ?

    ?

    多線程:★★★★

    返回當(dāng)前線程的名稱:Thread.currentThread().getName()

    線程的名稱是由:Thread-編號(hào)定義的。編號(hào)從0開(kāi)始。

    線程要運(yùn)行的代碼都統(tǒng)一存放在了run方法中。

    ?

    線程要運(yùn)行必須要通過(guò)類中指定的方法開(kāi)啟。start方法。(啟動(dòng)后,就多了一條執(zhí)行路徑)

    start方法:1)、啟動(dòng)了線程;2)、讓jvm調(diào)用了run方法。

    ?

    Thread類中run()和start()方法的區(qū)別:

    start():用start方法來(lái)啟動(dòng)線程,真正實(shí)現(xiàn)了多線程運(yùn)行,這時(shí)無(wú)需等待run方法體代碼執(zhí)行完畢而直接繼續(xù)執(zhí)行下面的代碼。通過(guò)調(diào)用Thread類的start()方法來(lái)啟動(dòng)一個(gè)線程,這時(shí)此線程處于就緒(可運(yùn)行)狀態(tài),并沒(méi)有運(yùn)行,一旦得到cpu時(shí)間片,就開(kāi)始執(zhí)行run()方法,這里方法run()稱為線程體,它包含了要執(zhí)行的這個(gè)線程的內(nèi)容,Run方法運(yùn)行結(jié)束,此線程隨即終止。

    run():run()方法只是類的一個(gè)普通方法而已,如果直接調(diào)用Run方法,程序中依然只有主線程這一個(gè)線程,其程序執(zhí)行路徑還是只有一條,還是要順序執(zhí)行,還是要等待run方法體執(zhí)行完畢后才可繼續(xù)執(zhí)行下面的代碼,這樣就沒(méi)有達(dá)到寫線程的目的。

    總結(jié):start()方法最本質(zhì)的功能是從CPU中申請(qǐng)另一個(gè)線程空間來(lái)執(zhí)行 run()方法中的代碼,它和當(dāng)前的線程是兩條線,在相對(duì)獨(dú)立的線程空間運(yùn)行,也就是說(shuō),如果你直接調(diào)用線程對(duì)象的run()方法,當(dāng)然也會(huì)執(zhí)行,但那是 在當(dāng)前線程中執(zhí)行,run()方法執(zhí)行完成后繼續(xù)執(zhí)行下面的代碼.而調(diào)用start()方法后,run()方法的代碼會(huì)和當(dāng)前線程并發(fā)(單CPU)或并行 (多CPU)執(zhí)行。所以請(qǐng)記住一句話:調(diào)用線程對(duì)象的run方法不會(huì)產(chǎn)生一個(gè)新的線程,雖然可以達(dá)到相同的執(zhí)行結(jié)果,但執(zhí)行過(guò)程和執(zhí)行效率不同

    ?

    創(chuàng)建線程的第一種方式:繼承Thread ,由子類復(fù)寫run方法。

    步驟:

    1,定義類繼承Thread類;

    2,目的是復(fù)寫run方法,將要讓線程運(yùn)行的代碼都存儲(chǔ)到run方法中;

    3,通過(guò)創(chuàng)建Thread類的子類對(duì)象,創(chuàng)建線程對(duì)象;

    4,調(diào)用線程的start方法,開(kāi)啟線程,并執(zhí)行run方法。

    ?

    線程狀態(tài):

    被創(chuàng)建:start()

    運(yùn)行:具備執(zhí)行資格,同時(shí)具備執(zhí)行權(quán);

    凍結(jié):sleep(time),wait()—notify()喚醒;線程釋放了執(zhí)行權(quán),同時(shí)釋放執(zhí)行資格;

    臨時(shí)阻塞狀態(tài):線程具備cpu的執(zhí)行資格,沒(méi)有cpu的執(zhí)行權(quán);

    消亡:stop()

    創(chuàng)建線程的第二種方式:實(shí)現(xiàn)一個(gè)接口Runnable。

    步驟:

    1,定義類實(shí)現(xiàn)Runnable接口。

    2,覆蓋接口中的run方法(用于封裝線程要運(yùn)行的代碼)。

    3,通過(guò)Thread類創(chuàng)建線程對(duì)象;

    4,將實(shí)現(xiàn)了Runnable接口的子類對(duì)象作為實(shí)際參數(shù)傳遞給Thread類中的構(gòu)造函數(shù)。

    為什么要傳遞呢?因?yàn)橐尵€程對(duì)象明確要運(yùn)行的run方法所屬的對(duì)象。

    5,調(diào)用Thread對(duì)象的start方法。開(kāi)啟線程,并運(yùn)行Runnable接口子類中的run方法。

    Ticket t = new Ticket();

    ????????/*

    ????????直接創(chuàng)建Ticket對(duì)象,并不是創(chuàng)建線程對(duì)象。

    ????????因?yàn)閯?chuàng)建對(duì)象只能通過(guò)new Thread類,或者new Thread類的子類才可以。

    ????????所以最終想要?jiǎng)?chuàng)建線程。既然沒(méi)有了Thread類的子類,就只能用Thread類。

    ????????*/

    ????????Thread t1 = new Thread(t);?//創(chuàng)建線程。

    ????????/*

    ????????只要將t作為Thread類的構(gòu)造函數(shù)的實(shí)際參數(shù)傳入即可完成線程對(duì)象和t之間的關(guān)聯(lián)

    ????????為什么要將t傳給Thread類的構(gòu)造函數(shù)呢?其實(shí)就是為了明確線程要運(yùn)行的代碼run方法。

    ????????*/

    ????????t1.start();

    ????????

    為什么要有Runnable接口的出現(xiàn)?

    1:通過(guò)繼承Thread類的方式,可以完成多線程的建立。但是這種方式有一個(gè)局限性,如果一個(gè)類已經(jīng)有了自己的父類,就不可以繼承Thread類,因?yàn)?strong>java單繼承的局限性。

    可是該類中的還有部分代碼需要被多個(gè)線程同時(shí)執(zhí)行。這時(shí)怎么辦呢?

    只有對(duì)該類進(jìn)行額外的功能擴(kuò)展,java就提供了一個(gè)接口Runnable。這個(gè)接口中定義了run方法,其實(shí)run方法的定義就是為了存儲(chǔ)多線程要運(yùn)行的代碼。

    所以,通常創(chuàng)建線程都用第二種方式。

    因?yàn)閷?shí)現(xiàn)Runnable接口可以避免單繼承的局限性。

    ?

    2:其實(shí)是將不同類中需要被多線程執(zhí)行的代碼進(jìn)行抽取。將多線程要運(yùn)行的代碼的位置單獨(dú)定義到接口中。為其他類進(jìn)行功能擴(kuò)展提供了前提。

    所以Thread類在描述線程時(shí),內(nèi)部定義的run方法,也來(lái)自于Runnable接口。

    ?

    實(shí)現(xiàn)Runnable接口可以避免單繼承的局限性。而且,繼承Thread,是可以對(duì)Thread類中的方法,進(jìn)行子類復(fù)寫的。但是不需要做這個(gè)復(fù)寫動(dòng)作的話,只為定義線程代碼存放位置,實(shí)現(xiàn)Runnable接口更方便一些。所以Runnable接口將線程要執(zhí)行的任務(wù)封裝成了對(duì)象

    -------------------------------------------------------

    //面試

    ????????new Thread(new Runnable(){ //匿名

    ????????????public void run(){

    ????????????????System.out.println("runnable run");????

    ????????????}

    ????????})

    ?

    ????????{

    ????????????public void run(){

    ????????????????System.out.println("subthread run");

    ????????????}

    ????????}.start(); //結(jié)果:subthread run

    ---------------------------------------------------------

    synchronized關(guān)鍵字(一)

    一、當(dāng)兩個(gè)并發(fā)線程訪問(wèn)同一個(gè)對(duì)象object中的這個(gè)synchronized(this)同步代碼塊時(shí),一個(gè)時(shí)間內(nèi)只能有一個(gè)線程得到執(zhí)行。另一個(gè)線程必須等待當(dāng)前線程執(zhí)行完這個(gè)代碼塊以后才能執(zhí)行該代碼塊。

    二、然而,當(dāng)一個(gè)線程訪問(wèn)object的一個(gè)synchronized(this)同步代碼塊時(shí),另一個(gè)線程仍然可以訪問(wèn)該object中的非synchronized(this)同步代碼塊。

    三、尤其關(guān)鍵的是,當(dāng)一個(gè)線程訪問(wèn)object的一個(gè)synchronized(this)同步代碼塊時(shí),其他線程對(duì)object中所有其它synchronized(this)同步代碼塊的訪問(wèn)將被阻塞。

    四、第三個(gè)例子同樣適用其它同步代碼塊。也就是說(shuō),當(dāng)一個(gè)線程訪問(wèn)object的一個(gè)synchronized(this)同步代碼塊時(shí),它就獲得了這個(gè)object的對(duì)象鎖。結(jié)果,其它線程對(duì)該object對(duì)象所有同步代碼部分的訪問(wèn)都被暫時(shí)阻塞。

    五、以上規(guī)則對(duì)其它對(duì)象鎖同樣適用.

    ?

    package ths;

    public class Thread1 implements Runnable {

    public void run() {

    synchronized(this) {

    for (int i = 0; i < 5; i++) {

    System.out.println(Thread.currentThread().getName()+"synchronized loop " + i);

    }

    }

    }

    }

    ?

    synchronized關(guān)鍵字(二)

    synchronized 關(guān)鍵字,它包括兩種用法:synchronized 方法和 synchronized 塊。

    1. synchronized 方法:通過(guò)在方法聲明中加入 synchronized關(guān)鍵字來(lái)聲明 synchronized 方法。如:

    public synchronized void accessVal(int newVal);

    synchronized 方法控制對(duì)類成員變量的訪問(wèn):每個(gè)類實(shí)例對(duì)應(yīng)一把鎖,每個(gè) synchronized 方法都必須獲得調(diào)用該方法的類實(shí)例的鎖方能執(zhí)行,否則所屬線程阻塞,方法一旦執(zhí)行,就獨(dú)占該鎖,直到從該方法返回時(shí)才將鎖釋放,此后被阻塞的線程方能獲得該鎖,重新進(jìn)入可執(zhí)行狀態(tài)。這種機(jī)制確保了同一時(shí)刻對(duì)于每一個(gè)類實(shí)例,其所有聲明為 synchronized 的成員函數(shù)中至多只有一個(gè)處于可執(zhí)行狀態(tài)(因?yàn)橹炼嘀挥幸粋€(gè)能夠獲得該類實(shí)例對(duì)應(yīng)的鎖),從而有效避免了類成員變量的訪問(wèn)沖突(只要所有可能訪問(wèn)類成員變量的方法均被聲明為 synchronized)。

    在 Java 中,不光是類實(shí)例,每一個(gè)類也對(duì)應(yīng)一把鎖,這樣我們也可將類的靜態(tài)成員函數(shù)聲明為 synchronized ,以控制其對(duì)類的靜態(tài)成員變量的訪問(wèn)。

    synchronized 方法的缺陷:若將一個(gè)大的方法聲明為synchronized 將會(huì)大大影響效率,典型地,若將線程類的方法 run() 聲明為synchronized ,由于在線程的整個(gè)生命期內(nèi)它一直在運(yùn)行,因此將導(dǎo)致它對(duì)本類任何 synchronized 方法的調(diào)用都永遠(yuǎn)不會(huì)成功。當(dāng)然我們可以通過(guò)將訪問(wèn)類成員變量的代碼放到專門的方法中,將其聲明為 synchronized ,并在主方法中調(diào)用來(lái)解決這一問(wèn)題,但是 Java 為我們提供了更好的解決辦法,那就是 synchronized 塊。

    2. synchronized 塊:通過(guò) synchronized關(guān)鍵字來(lái)聲明synchronized 塊。語(yǔ)法如下:

    synchronized(syncObject) {

    //允許訪問(wèn)控制的代碼

    }

    synchronized 塊是這樣一個(gè)代碼塊,其中的代碼必須獲得對(duì)象 syncObject (如前所述,可以是類實(shí)例或類)的鎖方能執(zhí)行,具體機(jī)制同前所述。由于可以針對(duì)任意代碼塊,且可任意指定上鎖的對(duì)象,故靈活性較高。

    對(duì)synchronized(this)的一些理解

    一、當(dāng)兩個(gè)并發(fā)線程訪問(wèn)同一個(gè)對(duì)象object中的這個(gè)synchronized(this)同步代碼塊時(shí),一個(gè)時(shí)間內(nèi)只能有一個(gè)線程得到執(zhí)行。另一個(gè)線程必須等待當(dāng)前線程執(zhí)行完這個(gè)代碼塊以后才能執(zhí)行該代碼塊。

    二、然而,當(dāng)一個(gè)線程訪問(wèn)object的一個(gè)synchronized(this)同步代碼塊時(shí),另一個(gè)線程仍然可以訪問(wèn)該object中的非synchronized(this)同步代碼塊。

    三、尤其關(guān)鍵的是,當(dāng)一個(gè)線程訪問(wèn)object的一個(gè)synchronized(this)同步代碼塊時(shí),其他線程對(duì)object中所有其它synchronized(this)同步代碼塊的訪問(wèn)將被阻塞。

    四、第三個(gè)例子同樣適用其它同步代碼塊。也就是說(shuō),當(dāng)一個(gè)線程訪問(wèn)object的一個(gè)synchronized(this)同步代碼塊時(shí),它就獲得了這個(gè)object的對(duì)象鎖。結(jié)果,其它線程對(duì)該object對(duì)象所有同步代碼部分的訪問(wèn)都被暫時(shí)阻塞。

    五、以上規(guī)則對(duì)其它對(duì)象鎖同樣適用。

    ?

    解決安全問(wèn)題的原理

    只要將操作共享數(shù)據(jù)的語(yǔ)句在某一時(shí)段讓一個(gè)線程執(zhí)行完,在執(zhí)行過(guò)程中,其他線程不能進(jìn)來(lái)執(zhí)行就可以解決這個(gè)問(wèn)題。

    如何保障共享數(shù)據(jù)的線程安全呢?

    java中提供了一個(gè)解決方式:就是同步代碼塊。

    格式:

    synchronized(對(duì)象) {?//任意對(duì)象都可以。這個(gè)對(duì)象就是共享數(shù)據(jù)。

    ????需要被同步的代碼;

    }

    ---------------------------------------------------------------

    同步:★★★★★

    好處:解決了線程安全問(wèn)題。Synchronized

    弊端:相對(duì)降低性能,因?yàn)榕袛噫i需要消耗資源,產(chǎn)生了死鎖。

    ?

    ?

    同步的第二種表現(xiàn)形式:????????//對(duì)共享資源的方法定義同步

    同步函數(shù):其實(shí)就是將同步關(guān)鍵字定義在函數(shù)上,讓函數(shù)具備了同步性。

    ?

    同步函數(shù)是用的哪個(gè)鎖呢?????????//synchronized(this)用以定義需要進(jìn)行同步的某一部分代碼塊

    通過(guò)驗(yàn)證,函數(shù)都有自己所屬的對(duì)象this,所以同步函數(shù)所使用的鎖就是this鎖。This.方法名

    ?

    當(dāng)同步函數(shù)被static修飾時(shí),這時(shí)的同步用的是哪個(gè)鎖呢?

    靜態(tài)函數(shù)在加載時(shí)所屬于類,這時(shí)有可能還沒(méi)有該類產(chǎn)生的對(duì)象,但是該類的字節(jié)碼文件加載進(jìn)內(nèi)存就已經(jīng)被封裝成了對(duì)象,這個(gè)對(duì)象就是該類的字節(jié)碼文件對(duì)象

    所以靜態(tài)加載時(shí),只有一個(gè)對(duì)象存在,那么靜態(tài)同步函數(shù)就使用的這個(gè)對(duì)象。

    這個(gè)對(duì)象就是?類名.class

    ?

    同步代碼塊和同步函數(shù)的區(qū)別?

    同步代碼塊使用的鎖可以是任意對(duì)象。

    同步函數(shù)使用的鎖是this,靜態(tài)同步函數(shù)的鎖是該類的字節(jié)碼文件對(duì)象

    ?

    在一個(gè)類中只有一個(gè)同步的話,可以使用同步函數(shù)。如果有多同步,必須使用同步代碼塊,來(lái)確定不同的鎖。所以同步代碼塊相對(duì)靈活一些。

    -------------------------------------------------------

    ★考點(diǎn)問(wèn)題:請(qǐng)寫一個(gè)延遲加載的單例模式?寫懶漢式;當(dāng)出現(xiàn)多線程訪問(wèn)時(shí)怎么解決?加同步,解決安全問(wèn)題;效率高嗎?不高;怎樣解決?通過(guò)雙重判斷的形式解決。

    //懶漢式:延遲加載方式。

    當(dāng)多線程訪問(wèn)懶漢式時(shí),因?yàn)閼袧h式的方法內(nèi)對(duì)共性數(shù)據(jù)進(jìn)行多條語(yǔ)句的操作。所以容易出現(xiàn)線程安全問(wèn)題。為了解決,加入同步機(jī)制,解決安全問(wèn)題。但是卻帶來(lái)了效率降低。

    為了效率問(wèn)題,通過(guò)雙重判斷的形式解決。

    class Single{

    ????private static Single s = null;

    ????private Single(){}

    ????public static Single getInstance(){ //鎖是誰(shuí)?字節(jié)碼文件對(duì)象;

    ????????if(s == null){

    ????????????synchronized(Single.class){

    ????????????????if(s == null)

    ????????????????????s = new Single();

    ????????????}

    ????????}

    ????????return s;

    ????}

    }

    ---------------------------------------------------------

    等待喚醒機(jī)制:涉及的方法:

    wait:將同步中的線程處于凍結(jié)狀態(tài)。釋放了執(zhí)行權(quán),釋放了資格。同時(shí)將線程對(duì)象存儲(chǔ)到線程池中。

    notify:喚醒線程池中某一個(gè)等待線程。

    notifyAll:喚醒的是線程池中的所有線程。

    ?

    注意:

    1:這些方法都需要定義在同步中

    2:因?yàn)檫@些方法必須要標(biāo)示所屬的鎖。

    ????你要知道 A鎖上的線程被wait了,那這個(gè)線程就相當(dāng)于處于A鎖的線程池中,只能A鎖的notify喚醒。

    3:這三個(gè)方法都定義在Object類中。為什么操作線程的方法定義在Object類中?

    ????因?yàn)檫@三個(gè)方法都需要定義同步內(nèi),并標(biāo)示所屬的同步鎖,既然被鎖調(diào)用,而鎖又可以是任意對(duì)象,那么能被任意對(duì)象調(diào)用的方法一定定義在Object類中。

    ?

    wait和sleep區(qū)別:?分析這兩個(gè)方法:從執(zhí)行權(quán)和鎖上來(lái)分析:

    wait:可以指定時(shí)間也可以不指定時(shí)間。不指定時(shí)間,只能由對(duì)應(yīng)的notify或者notifyAll來(lái)喚醒。

    sleep:必須指定時(shí)間,時(shí)間到自動(dòng)從凍結(jié)狀態(tài)轉(zhuǎn)成運(yùn)行狀態(tài)(臨時(shí)阻塞狀態(tài))。

    wait:線程會(huì)釋放執(zhí)行權(quán),而且線程會(huì)釋放鎖。

    sleep:線程會(huì)釋放執(zhí)行權(quán),但不是不釋放鎖。

    ?

    線程的停止:通過(guò)stop方法就可以停止線程。但是這個(gè)方式過(guò)時(shí)了。

    停止線程:原理就是:讓線程運(yùn)行的代碼結(jié)束,也就是結(jié)束run方法。

    怎么結(jié)束run方法?一般run方法里肯定定義循環(huán)。所以只要結(jié)束循環(huán)即可。

    第一種方式:定義循環(huán)的結(jié)束標(biāo)記。

    第二種方式:如果線程處于了凍結(jié)狀態(tài),是不可能讀到標(biāo)記的,這時(shí)就需要通過(guò)Thread類中的interrupt方法,將其凍結(jié)狀態(tài)強(qiáng)制清除。讓線程恢復(fù)具備執(zhí)行資格的狀態(tài),讓線程可以讀到標(biāo)記,并結(jié)束。

    ?

    ---------< java.lang.Thread >----------

    interrupt():中斷線程。

    setPriority(int?newPriority):更改線程的優(yōu)先級(jí)。

    getPriority():返回線程的優(yōu)先級(jí)。

    toString():返回該線程的字符串表示形式,包括線程名稱、優(yōu)先級(jí)和線程組。

    Thread.yield():暫停當(dāng)前正在執(zhí)行的線程對(duì)象,并執(zhí)行其他線程。

    setDaemon(true):將該線程標(biāo)記為守護(hù)線程或用戶線程。將該線程標(biāo)記為守護(hù)線程或用戶線程。當(dāng)正在運(yùn)行的線程都是守護(hù)線程時(shí),Java 虛擬機(jī)退出。該方法必須在啟動(dòng)線程前調(diào)用。

    join:臨時(shí)加入一個(gè)線程的時(shí)候可以使用join方法。

    當(dāng)A線程執(zhí)行到了B線程的join方式。A線程處于凍結(jié)狀態(tài),釋放了執(zhí)行權(quán),B開(kāi)始執(zhí)行。A什么時(shí)候執(zhí)行呢?只有當(dāng)B線程運(yùn)行結(jié)束后,A才從凍結(jié)狀態(tài)恢復(fù)運(yùn)行狀態(tài)執(zhí)行。

    ?

    ?

    LOCK的出現(xiàn)替代了同步:lock.lock();………lock.unlock();

    Lock接口:多線程在JDK1.5版本升級(jí)時(shí),推出一個(gè)接口Lock接口。

    解決線程安全問(wèn)題使用同步的形式,(同步代碼塊,要么同步函數(shù))其實(shí)最終使用的都是鎖機(jī)制。

    ?

    到了后期版本,直接將鎖封裝成了對(duì)象。線程進(jìn)入同步就是具備了鎖,執(zhí)行完,離開(kāi)同步,就是釋放了鎖。

    在后期對(duì)鎖的分析過(guò)程中,發(fā)現(xiàn),獲取鎖,或者釋放鎖的動(dòng)作應(yīng)該是鎖這個(gè)事物更清楚。所以將這些動(dòng)作定義在了鎖當(dāng)中,并把鎖定義成對(duì)象。

    ?

    所以同步是隱示的鎖操作,而Lock對(duì)象是顯示的鎖操作,它的出現(xiàn)就替代了同步。

    ?

    在之前的版本中使用Object類中wait、notify、notifyAll的方式來(lái)完成的。那是因?yàn)橥街械逆i是任意對(duì)象,所以操作鎖的等待喚醒的方法都定義在Object類中。

    ?

    而現(xiàn)在鎖是指定對(duì)象Lock。所以查找等待喚醒機(jī)制方式需要通過(guò)Lock接口來(lái)完成。而Lock接口中并沒(méi)有直接操作等待喚醒的方法,而是將這些方式又單獨(dú)封裝到了一個(gè)對(duì)象中。這個(gè)對(duì)象就是Condition,將Object中的三個(gè)方法進(jìn)行單獨(dú)的封裝。并提供了功能一致的方法await()、signal()、signalAll()體現(xiàn)新版本對(duì)象的好處。

    < java.util.concurrent.locks > Condition接口:await()、signal()、signalAll();

    --------------------------------------------------------

    class BoundedBuffer {

    final Lock lock = new ReentrantLock();

    final Condition notFull =?lock.newCondition();

    final Condition notEmpty =?lock.newCondition();

    final Object[] items = new Object[100];

    int putptr, takeptr, count;

    public void put(Object x) throws InterruptedException {

    lock.lock();

    try {

    while (count == items.length)

    notFull.await();

    items[putptr] = x;

    if (++putptr == items.length) putptr = 0;

    ++count;

    notEmpty.signal();

    }

    ????finally {

    lock.unlock();

    }

    }

    public Object take() throws InterruptedException {

    lock.lock();

    try {

    while (count == 0)

    notEmpty.await();

    Object x = items[takeptr];

    if (++takeptr == items.length) takeptr = 0;

    --count;

    notFull.signal();

    return x;

    }

    finally {

    lock.unlock();

    }

    }

    }

    ?

    集合框架

    集合框架:★★★★★,用于存儲(chǔ)數(shù)據(jù)的容器。

    ?

    對(duì)于集合容器,有很多種。因?yàn)槊恳粋€(gè)容器的自身特點(diǎn)不同,其實(shí)原理在于每個(gè)容器的內(nèi)部數(shù)據(jù)結(jié)構(gòu)不同。

    集合容器在不斷向上抽取過(guò)程中。出現(xiàn)了集合體系。

    在使用一個(gè)體系時(shí),原則:參閱頂層內(nèi)容。建立底層對(duì)象。

    ------------------------------------------------------------

    --< java.util >-- List接口:

    List本身是Collection接口的子接口,具備了Collection的所有方法。現(xiàn)在學(xué)習(xí)List體系特有的共性方法,查閱方法發(fā)現(xiàn)List的特有方法都有索引,這是該集合最大的特點(diǎn)。

    ?

    List:有序(元素存入集合的順序和取出的順序一致),元素都有索引。元素可以重復(fù)。

    ????|--ArrayList:底層的數(shù)據(jù)結(jié)構(gòu)是數(shù)組,線程不同步,ArrayList替代了Vector,查詢?cè)氐乃俣确浅?臁?/strong>

    ????|--LinkedList:底層的數(shù)據(jù)結(jié)構(gòu)是鏈表,線程不同步,增刪元素的速度非常快。

    ????|--Vector:底層的數(shù)據(jù)結(jié)構(gòu)就是數(shù)組,線程同步的,Vector無(wú)論查詢和增刪都巨慢。

    ?

    ?

    可變長(zhǎng)度數(shù)組的原理:

    當(dāng)元素超出數(shù)組長(zhǎng)度,會(huì)產(chǎn)生一個(gè)新數(shù)組,將原數(shù)組的數(shù)據(jù)復(fù)制到新數(shù)組中,再將新的元素添加到新數(shù)組中。

    ArrayList:是按照原數(shù)組的50%延長(zhǎng)。構(gòu)造一個(gè)初始容量為?10 的空列表。

    Vector:是按照原數(shù)組的100%延長(zhǎng)。

    ------------------------------------------------------------

    --< java.util >-- Set接口

    數(shù)據(jù)結(jié)構(gòu):數(shù)據(jù)的存儲(chǔ)方式;

    Set接口中的方法和Collection中方法一致的。Set接口取出方式只有一種,迭代器

    ????|--HashSet:底層數(shù)據(jù)結(jié)構(gòu)是哈希表,線程是不同步的無(wú)序,高效;

    ????????HashSet集合保證元素唯一性:通過(guò)元素的hashCode方法,和equals方法完成的。

    ????????當(dāng)元素的hashCode值相同時(shí),才繼續(xù)判斷元素的equals是否為true。

    ????????如果為true,那么視為相同元素,不存。如果為false,那么存儲(chǔ)。

    ????????如果hashCode值不同,那么不判斷equals,從而提高對(duì)象比較的速度。

    |--LinkedHashSet:有序,hashset的子類。

    ????|--TreeSet:對(duì)Set集合中的元素的進(jìn)行指定順序的排序。不同步。TreeSet底層的數(shù)據(jù)結(jié)構(gòu)就是二叉樹(shù)。

    ?

    對(duì)于ArrayList集合,判斷元素是否存在,或者刪元素底層依據(jù)都是equals方法。

    對(duì)于HashSet集合,判斷元素是否存在,或者刪除元素,底層依據(jù)的是hashCode方法和equals方法。

    ?

    ------------------------------------------------------------

    Map集合:

    |--Hashtable:底層是哈希表數(shù)據(jù)結(jié)構(gòu),是線程同步的。不可以存儲(chǔ)null鍵,null值。

    |--HashMap:底層是哈希表數(shù)據(jù)結(jié)構(gòu),是線程不同步的。可以存儲(chǔ)null鍵,null值。替代了Hashtable.

    |--TreeMap:底層是二叉樹(shù)結(jié)構(gòu),可以對(duì)map集合中的鍵進(jìn)行指定順序的排序。

    ?

    Map集合存儲(chǔ)和Collection有著很大不同:

    Collection一次存一個(gè)元素;Map一次存一對(duì)元素。

    Collection是單列集合;Map是雙列集合。

    Map中的存儲(chǔ)的一對(duì)元素:一個(gè)是鍵,一個(gè)是值,鍵與值之間有對(duì)應(yīng)(映射)關(guān)系。

    特點(diǎn):要保證map集合中鍵的唯一性。

    ?

    5,想要獲取map中的所有元素:

    ????原理:map中是沒(méi)有迭代器的,collection具備迭代器,只要將map集合轉(zhuǎn)成Set集合,可以使用迭代器了。之所以轉(zhuǎn)成set,是因?yàn)閙ap集合具備著鍵的唯一性,其實(shí)set集合就來(lái)自于map,set集合底層其實(shí)用的就是map的方法。

    • 把map集合轉(zhuǎn)成set的方法:

    ????Set keySet();

    ????Set entrySet();//取的是鍵和值的映射關(guān)系。

    Entry就是Map接口中的內(nèi)部接口;

    為什么要定義在map內(nèi)部呢?entry是訪問(wèn)鍵值關(guān)系的入口,是map的入口,訪問(wèn)的是map中的鍵值對(duì)。

    ---------------------------------------------------------

    取出map集合中所有元素的方式一:keySet()方法。

    可以將map集合中的鍵都取出存放到set集合中。對(duì)set集合進(jìn)行迭代。迭代完成,再通過(guò)get方法對(duì)獲取到的鍵進(jìn)行值的獲取。

    ????????Set keySet = map.keySet();

    ????????Iterator it = keySet.iterator();

    ????????while(it.hasNext()) {

    ????????????Object key = it.next();

    ????????????Object value = map.get(key);

    ????????????System.out.println(key+":"+value);

    ????????}

    --------------------------------------------------------

    取出map集合中所有元素的方式二:entrySet()方法。

    Set entrySet = map.entrySet();

    ????????Iterator it = entrySet.iterator();

    ????????while(it.hasNext()) {

    ????????????Map.Entry?me = (Map.Entry)it.next();

    ????????????System.out.println(me.getKey()+"::::"+me.getValue());

    ????????}

    --------------------------------------------------------

    ?

    將非同步集合轉(zhuǎn)成同步集合的方法:Collections中的?XXX synchronizedXXX(XXX);

    List synchronizedList(list);

    Map synchronizedMap(map);

    public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {

    return new SynchronizedMap<K,V>(m);

    }

    原理:定義一個(gè)類,將集合所有的方法加同一把鎖后返回。

    List list = Collections.synchronizedList(new ArrayList());

    Map<String,String> synmap = Collections.synchronizedMap(map);

    ?

    Collection 和 Collections的區(qū)別:

    Collections是個(gè)java.util下的類,是針對(duì)集合類的一個(gè)工具類,提供一系列靜態(tài)方法,實(shí)現(xiàn)對(duì)集合的查找、排序、替換、線程安全化(將非同步的集合轉(zhuǎn)換成同步的)等操作。

    Collection是個(gè)java.util下的接口,它是各種集合結(jié)構(gòu)的父接口,繼承于它的接口主要有Set和List,提供了關(guān)于集合的一些操作,如插入、刪除、判斷一個(gè)元素是否其成員、遍歷等。

    -------------------------------------------------------

    自動(dòng)拆裝箱:java中數(shù)據(jù)類型分為兩種 : 基本數(shù)據(jù)類型 引用數(shù)據(jù)類型(對(duì)象)

    在 java程序中所有的數(shù)據(jù)都需要當(dāng)做對(duì)象來(lái)處理,針對(duì)8種基本數(shù)據(jù)類型提供了包裝類,如下:

    int --> Integer

    byte --> Byte

    short --> Short

    long --> Long

    char --> Character

    double --> Double

    float --> Float

    boolean --> Boolean

    ?

    jdk5以前基本數(shù)據(jù)類型和包裝類之間需要互轉(zhuǎn):

    基本---引用 Integer x = new Integer(x);

    引用---基本 int num = x.intValue();

    1)、Integer x = 1; x = x + 1; 經(jīng)歷了什么過(guò)程?裝箱?à?拆箱?à?裝箱

    2)、為了優(yōu)化,虛擬機(jī)為包裝類提供了緩沖池,Integer池的大小 -128~127 一個(gè)字節(jié)的大小

    3)、String池:Java為了優(yōu)化字符串操作 提供了一個(gè)緩沖池;

    ----------------------------------------------------------

    泛型:jdk1.5版本以后出現(xiàn)的一個(gè)安全機(jī)制。表現(xiàn)格式:< >

    好處:

    1:將運(yùn)行時(shí)期的問(wèn)題ClassCastException問(wèn)題轉(zhuǎn)換成了編譯失敗,體現(xiàn)在編譯時(shí)期,程序員就可以解決問(wèn)題。

    2:避免了強(qiáng)制轉(zhuǎn)換的麻煩。

    ?

    泛型中的通配符:可以解決當(dāng)具體類型不確定的時(shí)候,這個(gè)通配符就是???;當(dāng)操作類型時(shí),不需要使用類型的具體功能時(shí),只使用Object類中的功能。那么可以用 ? 通配符來(lái)表未知類型。

    -------------------------------------------------------------------------------------------------------------------------------

    ?

    反射技術(shù)

    反射技術(shù):其實(shí)就是動(dòng)態(tài)加載一個(gè)指定的類,并獲取該類中的所有的內(nèi)容。并將字節(jié)碼文件中的內(nèi)容都封裝成對(duì)象,這樣便于操作這些成員。簡(jiǎn)單說(shuō):反射技術(shù)可以對(duì)一個(gè)類進(jìn)行解剖。

    ?

    反射的好處:大大的增強(qiáng)了程序的擴(kuò)展性。

    ?

    反射的基本步驟:

    1、獲得Class對(duì)象,就是獲取到指定的名稱的字節(jié)碼文件對(duì)象。

    2、實(shí)例化對(duì)象,獲得類的屬性、方法或構(gòu)造函數(shù)。

    3、訪問(wèn)屬性、調(diào)用方法、調(diào)用構(gòu)造函數(shù)創(chuàng)建對(duì)象。

    ?

    獲取這個(gè)Class對(duì)象,有三種方式:

    1:通過(guò)每個(gè)對(duì)象都具備的方法getClass來(lái)獲取。弊端:必須要?jiǎng)?chuàng)建該類對(duì)象,才可以調(diào)用getClass方法。

    2:每一個(gè)數(shù)據(jù)類型(基本數(shù)據(jù)類型和引用數(shù)據(jù)類型)都有一個(gè)靜態(tài)的屬性class。弊端:必須要先明確該類。

    ???? 前兩種方式不利于程序的擴(kuò)展,因?yàn)槎夹枰诔绦蚴褂镁唧w的類來(lái)完成。

    3:使用的Class類中的方法,靜態(tài)的forName方法

    ???? 指定什么類名,就獲取什么類字節(jié)碼文件對(duì)象,這種方式的擴(kuò)展性最強(qiáng),只要將類名的字符串傳入即可。

    // 1. 根據(jù)給定的類名來(lái)獲得 用于類加載

    String classname = "cn.itcast.reflect.Person";// 來(lái)自配置文件

    Class clazz =?Class.forName(classname);// 此對(duì)象代表Person.class

    // 2. 如果拿到了對(duì)象,不知道是什么類型 用于獲得對(duì)象的類型

    Object obj = new Person();

    Class clazz1 = obj.getClass();// 獲得對(duì)象具體的類型

    // 3. 如果是明確地獲得某個(gè)類的Class對(duì)象 主要用于傳參

    Class clazz2 = Person.class;????

    ?

    反射的用法

    1)、需要獲得java類的各個(gè)組成部分,首先需要獲得類的Class對(duì)象,獲得Class對(duì)象的三種方式:

    ????Class.forName(classname)????用于做類加載

    ????obj.getClass()????????????????用于獲得對(duì)象的類型

    ????類名.class???????????? 用于獲得指定的類型,傳參用

    ?

    2)、反射類的成員方法:

    ????Class clazz = Person.class;

    ????Method method = clazz.getMethod(methodName, new Class[]{paramClazz1, paramClazz2});

    ????method.invoke();

    ????

    3)、反射類的構(gòu)造函數(shù):

    ????Constructor con = clazz.getConstructor(new Class[]{paramClazz1, paramClazz2,...})

    ????con.newInstance(params...)

    ?

    4)、反射類的屬性:

    ????Field field = clazz.getField(fieldName);

    ????field.setAccessible(true);

    ????field.setObject(value);

    ?

    獲取了字節(jié)碼文件對(duì)象后,最終都需要?jiǎng)?chuàng)建指定類的對(duì)象:

    創(chuàng)建對(duì)象的兩種方式(其實(shí)就是對(duì)象在進(jìn)行實(shí)例化時(shí)的初始化方式):

    1,調(diào)用空參數(shù)的構(gòu)造函數(shù):使用了Class類中的newInstance()方法。

    2,調(diào)用帶參數(shù)的構(gòu)造函數(shù):先要獲取指定參數(shù)列表的構(gòu)造函數(shù)對(duì)象,然后通過(guò)該構(gòu)造函數(shù)的對(duì)象的newInstance(實(shí)際參數(shù))?進(jìn)行對(duì)象的初始化。

    ?

    綜上所述,第二種方式,必須要先明確具體的構(gòu)造函數(shù)的參數(shù)類型,不便于擴(kuò)展。所以一般情況下,被反射的類,內(nèi)部通常都會(huì)提供一個(gè)公有的空參數(shù)的構(gòu)造函數(shù)。

    ------------------------------------------------------

    ????// 如何生成獲取到字節(jié)碼文件對(duì)象的實(shí)例對(duì)象。

    ????????Class clazz = Class.forName("cn.itcast.bean.Person");//類加載

    //?直接獲得指定的類型

    ????????clazz = Person.class;

    ????????//?根據(jù)對(duì)象獲得類型

    ????????Object obj =?new?Person("zhangsan", 19);

    ????????clazz = obj.getClass();

    ?

    ????????Object obj = clazz.newInstance();//該實(shí)例化對(duì)象的方法調(diào)用就是指定類中的空參數(shù)構(gòu)造函數(shù),給創(chuàng)建對(duì)象進(jìn)行初始化。當(dāng)指定類中沒(méi)有空參數(shù)構(gòu)造函數(shù)時(shí),該如何創(chuàng)建該類對(duì)象呢?請(qǐng)看method_2();

    ????public static void method_2() throws Exception {

    ????????Class clazz = Class.forName("cn.itcast.bean.Person");

    ????????//既然類中沒(méi)有空參數(shù)的構(gòu)造函數(shù),那么只有獲取指定參數(shù)的構(gòu)造函數(shù),用該函數(shù)來(lái)進(jìn)行實(shí)例化。

    ????????//獲取一個(gè)帶參數(shù)的構(gòu)造器。

    ????????Constructor constructor = clazz.getConstructor(String.class,int.class);

    ????????//想要對(duì)對(duì)象進(jìn)行初始化,使用構(gòu)造器的方法newInstance();

    ????????Object obj = constructor.newInstance("zhagnsan",30);

    ????????//獲取所有構(gòu)造器。

    ????????Constructor[] constructors = clazz.getConstructors();//只包含公共的

    ????????constructors = clazz.getDeclaredConstructors();//包含私有的

    ????????for(Constructor con : constructors) {

    ????????????System.out.println(con);

    ????????}

    ????}

    ------------------------------------------------------

    反射指定類中的方法:

    ????//獲取類中所有的方法。

    ????public static void method_1() throws Exception {

    ????????Class clazz = Class.forName("cn.itcast.bean.Person");

    ????????Method[] methods = clazz.getMethods();//獲取的是該類中的公有方法和父類中的公有方法。

    ????????methods = clazz.getDeclaredMethods();//獲取本類中的方法,包含私有方法。

    ????????for(Method method : methods) {

    ????????????System.out.println(method);

    ????????}

    ????}

    ????//獲取指定方法;

    ????public static void method_2() throws Exception {

    ????????Class clazz = Class.forName("cn.itcast.bean.Person");

    ????????//獲取指定名稱的方法。

    ????????Method method = clazz.getMethod("show", int.class,String.class);

    ????????//想要運(yùn)行指定方法,當(dāng)然是方法對(duì)象最清楚,為了讓方法運(yùn)行,調(diào)用方法對(duì)象的invoke方法即可,但是方法運(yùn)行必須要明確所屬的對(duì)象和具體的實(shí)際參數(shù)。

    ????????Object obj = clazz.newInstance();

    ????????method.invoke(obj, 39,"hehehe");//執(zhí)行一個(gè)方法

    ????}

    ????//想要運(yùn)行私有方法。

    ????public static void method_3() throws Exception {

    ????????Class clazz = Class.forName("cn.itcast.bean.Person");

    ????????//想要獲取私有方法。必須用getDeclearMethod();

    ????????Method method = clazz.getDeclaredMethod("method", null);

    ????????// 私有方法不能直接訪問(wèn),因?yàn)闄?quán)限不夠。非要訪問(wèn),可以通過(guò)暴力的方式。

    ????????method.setAccessible(true);//一般很少用,因?yàn)樗接芯褪请[藏起來(lái),所以盡量不要訪問(wèn)。

    ????}

    ????//反射靜態(tài)方法。

    ????public static void method_4() throws Exception {

    ????????Class clazz = Class.forName("cn.itcast.bean.Person");

    ????????Method method = clazz.getMethod("function",null);

    ????????method.invoke(null,null);

    ????}

    轉(zhuǎn)載于:https://www.cnblogs.com/404NOTFoundNEO/p/9066788.html

    總結(jié)

    以上是生活随笔為你收集整理的【转】Java基础知识整理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 精品天堂| 亚洲精品18p | 久久性爱视频网站 | 一区二区三区在线视频播放 | 色婷婷视频 | 自拍偷拍20p | 国产白拍| 91福利社在线观看 | 精品久久久久一区二区国产 | 公侵犯人妻一区二区三区 | 欧美xxxx18 | 欧美巨大乳 | 天堂无乱码 | www.毛片| 国产三级精品三级在线观看 | 好吊日免费视频 | 懂色av一区二区夜夜嗨 | 久久久久久久97 | 色婷婷国产精品综合在线观看 | 久久免费黄色 | 欧美经典一区 | 狠狠干夜夜操 | 久久婷婷国产麻豆91天堂 | 国产精品111 | 日韩免费观看一区二区三区 | 国产又粗又黄又爽又硬 | 黄色一区二区三区四区 | 嫩草影院黄 | 欧美涩涩视频 | 国产又爽又黄免费软件 | 天天舔天天操天天干 | 日本美女性生活视频 | 日韩精品一区中文字幕 | 青草视频在线播放 | 艳妇臀荡乳欲伦交换在线看 | 国产精品成人久久 | 无码国产69精品久久久久同性 | 农村偷人一级超爽毛片 | 亚洲中文一区二区三区 | 亚洲永久免费精品 | 日批免费在线观看 | 毛片网站在线免费观看 | 欧美一级视频在线观看 | 人妻 日韩 欧美 综合 制服 | 91麻豆精品在线观看 | 午夜欧美精品久久久久久久 | 777777av| 国产香蕉视频在线 | 91tv在线观看 | 一区二区在线视频免费观看 | 精品久久久久久一区二区里番 | 精品在线视频观看 | 国内精品偷拍视频 | 亚洲精品在线网站 | 毛片网站在线免费观看 | 欧美不卡高清 | 99久久精品国产成人一区二区 | 黄色片久久 | 男人午夜视频 | 精品国产乱码久久久久久郑州公司 | 午夜777| 亚洲av片一区二区三区 | 国产精品人人人人 | 国产一区二区三区四区五区在线 | 午夜香蕉视频 | 超碰在线观看99 | 成年人性生活免费视频 | 精品国产人妻一区二区三区 | 久久久久久无码精品大片 | 韩国三级丰满少妇高潮 | h片在线观看免费 | 欧美50p| 日本视频在线播放 | 四季av一区二区三区免费观看 | 男人天堂免费视频 | 人人草人人搞 | 成品短视频泡芙 | 女女同性女同一区二区三区按摩 | 中国丰满老妇xxxxx交性 | 很嫩很紧直喷白浆h | 亚洲区欧美区 | 日本精品视频网站 | 69超碰| 草草久久久 | www.五月婷婷| 插我舔内射18免费视频 | 国产中文字幕三区 | 青青草日本 | 一区二区内射 | 欧美 日韩 国产一区 | 欧美激情成人 | 非洲黑人狂躁日本妞 | 影音先锋丝袜美腿 | 久久综合第一页 | 国产三级av片 | 四虎视频国产精品免费 | avtt在线观看| 黄色污网站在线观看 | 黄色免费在线视频 |