一)抽象類:使用格式爲:public abstract class A{}html
一、在抽象類中的方法能夠定義抽象方法,也能夠是具體的成員方法,不能是(static)類方法。java
public void get(){ System.out.println("ok")};面試
public abstract void geta(String abc);//ok編程
public static abstract void geta(String abc);//錯誤設計模式
二、在抽象類中屬性能夠是成員屬性,也能夠是類屬性。安全
private String name;//ok
private static String age;//ok多線程
三、在抽象類中有構造方法,默認是無參(沒有參數列表)的,也能夠有參數的構造方法,可是不能用來實例化對象(不能使用new去建立對象)。併發
四、抽象類是用來充當父類,給子類去繼承與發展的,當子類繼承抽象類時,方法須要定義訪問限定符,並且子類必須重寫全部的抽象方法,且子類不能減少可見範圍(訪問限定符的設定不能減少)。jvm
五、一個類只能繼承一個抽象類。ide
繼承的方法以下:public class B extends A{}
二)接口
使用格式爲:public interface C{}
一、在接口中的方法只能定義抽象方法,不能有方法體,定義時默認爲public abstract,能夠省略。接口中的方法默認是public,也只能是public。
eg: [public abstract] void I; ----無返回值
[public abstract] int J; ----有返回值
二、接口中屬性的定義時固定的:
public static final 數據類型 變量名 =初始值;
eg: public static final int a =0;
public static final String aa =null;
三、接口中不能有構造方法,更加不能建立對象。
四、接口也是用來充當父類的,給子類去實現與擴展的,當子類實現接口時,必須重寫接口中全部的方法。且子類不能減少可見範圍(訪問限定符的設置不能減少)。
五、一個類能夠實現多個接口。
public class E inmplements C,D{}
一個類能夠先繼承一個類,再實現多個接口
public class F extends E implements C,D{}
一)計算機編程中classpath和path的用處和區別
通常它們在何時使用
用java來舉例,咱們想要運行java文件,好比咱們安裝jdk的時候,咱們須要將bin指定到path,這樣才行,當咱們運行jar包時,須要把jar包放在當前路徑,或者classpath下,才能夠運行成功,那麼大家有沒有想過爲何要這樣作,他們兩者的區別是什麼?
path,classpath配置好以後有什麼用?
path配置好以後,讓java jdk\bin目錄下的工具,能夠在任意目錄下運行,緣由是,將該工具所在目錄告訴了系統,當使用該工具時,由系統幫咱們去找指定的目錄。
若是沒有定義環境變量classpath,java啓動jvm後,會在當前目錄下查找要運行的類文件,若是指定了classpath,那麼會在指定的目錄下查找要運行的類文件。還會在當前目錄找嗎?兩種狀況:第一種,若是classpath的值結尾處有分號,在具體路徑中沒有找到運行的類,會默認在當前目錄再找一次。第二種,若是classpath的值結果出沒有分號,在具體的路徑中沒有找到運行的類,不會再當前目錄找。經常使用:通常不指定分號,若是沒有在指定目錄下找到要運行的類文件,就報錯,這樣能夠調試程序。
3.path配置方式
永久配置方式:JAVA_HOME=%安裝路徑%\Java\jdk 和path=%JAVA_HOME%\bin搭配配置
臨時配置方式:set path=%path%;C:\Program Files\Java\jdk\bin
4.classpath如何配置
永久配置方式:classpath=.;c:\;e:\
臨時配置方式:set classpath=.;c:\;e:\
單例模式是一種經常使用的軟件設計模式。在它的核心結構中只包含一個被稱爲單例的特殊類。經過單例模式能夠保證系統中一個類只有一個實例。
今天咱們不談單例模式的用途,只說一說若是在面試的時候面試官讓你敲一段代碼實現單例模式的狀況下怎樣寫出讓面試官眼前一亮的單例代碼。由於筆者學的是Java,因此接下來的實例將用Java語言編寫。
說到單例模式,第一個想到的是該類中有一個初始化爲null的自身引用,且被private修飾符修飾,其它類不得直接訪問。除此以外,單例模式的類還須要有private的構造方法,這一點不難理解,若是構造方法是public的,那麼類外部能夠直接調用該類的構造方法,如此一來便不具有單例的特性。那麼怎麼獲取該類惟一的實例呢?這就須要一個公有的獲取器,該方法返回值類型是單例模式類,返回的結果天然是該類中惟一的實例。思路有了,咱們即可以實現最簡單的單例模式類:
不得不說,這樣的作法確實達到了單例模式的要求,正常狀況下系統中只有一個Singleton的對象。可是若是存在併發的狀況呢?兩個用戶同時訪問該類的獲取器,此時假設Singleton對象還未被實例化,那麼系統將會兩次調用構造方法,這樣一來系統中就會存在兩個Singleton類的實例。說明這種方式的單例沒有考慮到併發狀況,說明面試者只是粗略的瞭解單例模式,並無加以深刻思考,想讓面試官滿意?
Java相較於C++而言我的認爲編程的難易度上來講要容易不少。在考慮線程同步時一個synchronized關鍵字便能解決普通加鎖問題。synchronized關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,可以保證在同一時刻最多隻有一個線程執行該段代碼。也就是說當兩個線程同時訪問類中synchronized方法或代碼塊時,只能有一個線程執行其代碼,另外一個只能等待當前線程調用結束後才能訪問。這下子單例的實現就so easy了!只要對代碼稍加改動便可:
這樣的寫法面試官會以爲你這個面試者在思考問題的時候比較全面,考慮到併發的狀況,相較以前的方式面試官會以爲:少年,頗有前途哦!
然而光是讓面試官看好是不夠的,咱們要讓他欣賞,經過單例這樣的小問題便能拿到offer。也就是說第二種實現方式是能夠進行優化的。如何優化呢?咱們看到,當前系統中每次調用獲取方法時便會進行加鎖,而加鎖須要的時間即是咱們能夠進行優化的地方。如今我所想的是咱們只須要在第一次調用時加一次鎖日後便不再不須要加鎖了,這樣一來便省下了每次調用加鎖的時間,雖然計算機執行加鎖的時間很短但長此以往也是至關長的一段時間。
那麼怎麼實現呢?這須要引入另外一個關鍵字volatile。volatile修飾的話就能夠確保instance = new Singleton();對應的指令不會重排序(JVM當發現代碼執行順序變化但結果不變時可能會改變執行順序來提高自身性能。好坑。。。),也是線程安全的。
在java線程併發處理中,有一個關鍵字volatile的使用目前存在很大的混淆,覺得使用這個關鍵字,在進行多線程併發處理的時候就能夠萬事大吉。
Java語言是支持多線程的,爲了解決線程併發的問題,在語言內部引入了 同步塊 和 volatile 關鍵字機制。
synchronized
同步塊你們都比較熟悉,經過 synchronized 關鍵字來實現,全部加上synchronized 和 塊語句,在多線程訪問的時候,同一時刻只能有一個線程可以用
synchronized 修飾的方法 或者 代碼塊。
volatile
用volatile修飾的變量,線程在每次使用變量的時候,都會讀取變量修改後的最新值。volatile很容易被誤用,用來進行原子性操做。
下面看一個例子,咱們實現一個計數器,每次線程啓動的時候,會調用計數器inc方法,對計數器進行加一
|
1 |
|
在 java 垃圾回收整理一文中,描述了jvm運行時刻內存的分配。其中有一個內存區域是jvm虛擬機棧,每個線程運行時都有一個線程棧, 線程棧保存了線程運行時候變量值信息。當線程訪問某一個對象時候值的時候,首先經過對象的引用找到對應在堆內存的變量的值,而後把堆內存 變量的具體值load到線程本地內存中,創建一個變量副本,以後線程就再也不和對象在堆內存變量值有任何關係,而是直接修改副本變量的值, 在修改完以後的某一個時刻(線程退出以前),自動把線程變量副本的值回寫到對象在堆中變量。這樣在堆中的對象的值就產生變化了。下面一幅圖 描述這寫交互 read and load 從主存複製變量到當前工做內存 其中use and assign 能夠屢次出現 可是這一些操做並非原子性,也就是 在read load以後,若是主內存count變量發生修改以後,線程工做內存中的值因爲已經加載,不會產生對應的變化,因此計算出來的結果會和預期不同 對於volatile修飾的變量,jvm虛擬機只是保證從主內存加載到線程工做內存的值是最新的 例如假如線程1,線程2 在進行read,load 操做中,發現主內存中count的值都是5,那麼都會加載這個最新的值 在線程1堆count進行修改以後,會write到主內存中,主內存中的count變量就會變爲6 線程2因爲已經進行read,load操做,在進行運算以後,也會更新主內存count的變量值爲6 致使兩個線程及時用volatile關鍵字修改以後,仍是會存在併發的狀況。 對於值引用來講,多線程操做的是變量的副本,操做完後刷新到主存中。而對於地址引用,多線程是經過地址操做的是同一個變量。volatitle關鍵字告訴編譯器,直接去經過地址操做變量,而不是變量的副本 |