總結源於海子博客http://www.cnblogs.com/dolphin0520/html
一、在class文件中有一部分來存儲編譯期間生成的字面常量以及符號引用,這部分叫作class文件常量池,在運行期間對應着方法區的運行時常量池。java
(1)String str1 = "hello world";和String str2= "hello world";都在編譯期間生成了字面常量和符號引用,運行期間字面常量"hello world"被存儲在運行時常量池(固然只保存了一份)。經過這種方式來將String對象跟引用綁定的話,JVM執行引擎會先在運行時常量池查找是否存在相同的字面常量,若是存在,則直接將引用指向已經存在的字面常量; 不然在運行時常量池開闢一個空間來存儲該字面常量,並將引用指向該字面常量。git
(2)String str = new String("hello world")經過new關鍵字來生成對象是在堆區進行的,而在堆區進行對象生成的過程是不會去檢測該對象是否已經存在的。所以經過new來建立對象,建立出的必定是不一樣的對象,即便字符串的內容是相同的。該段代碼執行過程和類的加載過程是有區別的。在類加載的過程當中,確實在運行時常量池中建立了一個"hello world"對象,而在代碼執行過程當中確實只建立了一個String對象,即在堆上建立了"hello world"對象。github
(3)String str = new String("hello"); str+="java";這段代碼涉及(非建立)5個對象,首先,「hello」在堆和常量池各一個;其次,「java」在常量池有一個;最後,「helloJava」在堆和常量池各一個。第一次出現字符串直接量時會在池中建立一個新的,以後出現就不會建立了,而是直接把引用指向第一次建立的對象。但對於new出來的對象,不管怎樣賦值,new一次在運行期建立一次(在堆中),不會考慮以前是否已經已存在相同的。並且,字符串是不可追加的,因此每次使用鏈接符號其實至關於先產生一個常量,而後再賦給引用,原來指向的串就成垃圾被回收了。算法
(4)String str1="java";//指向字符串常量池 String str2="blog";//指向字符串常量池 String s = str1+str2; +運算符會在堆中創建起兩個String對象,這兩個對象的值分別是「java」,"blog",也就是說從字符串常量池中複製這兩個值,而後在堆中建立兩個對象。而後再創建對象s,而後將「javablog」的堆地址賦給s. 這句話共建立了3個String對象。json
二、Integer a = 1; Integer b = 2; Integer c = 3; Integer d = 3;
api
Integer e = 321; Integer f = 321; Long g = 3L; Long h = 2L;數組
System.out.println(c==d);//true緩存
System.out.println(e==f);//falseiphone
System.out.println(c==(a+b));//true
System.out.println(c.equals(a+b));//true
System.out.println(g==(a+b));//true
System.out.println(g.equals(a+b));//false
System.out.println(g.equals(a+h));//true
當 "=="運算符的兩個操做數都是 包裝器類型的引用,則是比較指向的是不是同一個對象,而若是其中有一個操做數是表達式(即包含算術運算)
則比較的是數值
(即會觸發自動拆箱的過程)。另外,對於包裝器類型,equals方法並不會進行類型轉換。java中基本類型的包裝類的大部分都實現了常量池技術,這些類是Byte, Short, Integer, Long, Character, Boolean, 另外兩種浮點數類型(Float、Double)的包裝類則沒有實現。另外Byte, Short, Integer, Long, Character這5種整型的包裝類也只在大於等於-128而且小於等於127時才使用常量池,也即對象不負責建立和管理大於127的這些類的對象。
mvn install:install-file //mvn 命令
-Dfile=sojson-demo.jar //要添加的包
-DgroupId=com.sojson //pom文件對應的groupId
-DartifactId=com.sojson.demo //pom文件對應得artifactId
-Dversion=1.0 //添加包的版本
-Dpackaging=jar
public ∨ ∨ ∨ ∨
protect ∨ ∨ ∨ ×
default ∨ ∨ × ×
private ∨ × × ×
(10)update ft_airport set ft_airport.airport_name=REPLACE(airport_name,'機場','');
(11)Java8 時間日期api https://lw900925.github.io/java/java8-newtime-api.html
(12)分佈式與集羣的區別 http://blog.csdn.net/javaloveiphone/article/details/52368291
(13)kafka http://blog.csdn.net/tangdong3415/article/details/53432166
(14)Windows環境下的監控工具
jvisualvm.exe在JDK安裝目錄下的bin目錄下面,雙擊便可打開。
MemoryAnalyzer.exe。
(15)this表明當前對象。
static是不容許用來修飾局部變量。
static final用來修飾成員變量和成員方法,可簡單理解爲「全局常量」! 對於變量,表示一旦給值就不可修改,而且經過類名能夠訪問。對於方法,表示不可覆蓋,而且能夠經過類名直接訪問。
public class Test { Person person = new Person("Test"); static{ System.out.println("test static"); } public Test() { System.out.println("test constructor"); } public static void main(String[] args) { new MyClass(); } } class Person{ static{ System.out.println("person static"); } public Person(String str) { System.out.println("person "+str); } } class MyClass extends Test { Person person = new Person("MyClass"); static{ System.out.println("myclass static"); } public MyClass() { System.out.println("myclass constructor"); } }
結果爲:
test static myclass static person static person Test test constructor person MyClass myclass constructor
在執行開始,先要尋找到main方法,由於main方法是程序的入口,可是在執行main方法以前,必須先加載Test類,所以會執行Test類中的static塊。(注意:若是main方法在MyClass類中,則先會加載其父類Test,執行Test類中的static塊,再加載MyClass類,執行MyClass類中的static代碼塊)接着執行new MyClass(),而MyClass類尚未被加載,所以須要加載MyClass類。在加載MyClass類的時候,發現MyClass類繼承自Test類,可是因爲Test類已經被加載了,因此只須要加載MyClass類,那麼就會執行MyClass類的中的static塊。在加載完以後,就經過構造器來生成對象。而在生成對象的時候,必須先初始化父類的成員變量,所以會執行Test中的Person person = new Person(),而Person類尚未被加載過,所以會先加載Person類並執行Person類中的static塊,接着執行父類的構造器,完成了父類的初始化,而後就來初始化自身了,所以會接着執行MyClass中的Person person = new Person(),最後執行MyClass的構造器。
第一點,全部的類都會優先加載基類
第二點,靜態成員的初始化優先
第三點,成員初始化後,纔會執行構造方法
第四點,靜態成員的初始化與靜態塊的執行,發生在類加載的時候。
第五點,類對象的建立以及靜態塊的訪問,都會觸發類的加載。
五、對於子類能夠繼承的父類成員變量,若是在子類中出現了同名稱的成員變量,則會發生隱藏現象,即子類的成員變量會屏蔽掉父類的同名成員變量。若是要在子類中訪問父類中同名成員變量,須要使用super關鍵字來進行引用。對於子類能夠繼承的父類成員方法,若是在子類中出現了同名稱的成員方法,則稱爲覆蓋,即子類的成員方法會覆蓋掉父類的同名成員方法。若是要在子類中訪問父類中同名成員方法,須要使用super關鍵字來進行引用。注意:隱藏和覆蓋是不一樣的。隱藏是針對成員變量和靜態方法的,而覆蓋是針對普通方法的。
public class Test { public static void main(String[] args) { Shape shape = new Circle(); System.out.println(shape.name); //隱藏了子類 shape.printType(); //被子類覆蓋 shape.printName(); //隱藏了子類 } } class Shape { public String name = "shape"; public Shape(){ System.out.println("shape constructor"); } public void printType() { System.out.println("this is shape"); } public static void printName() { System.out.println("shape"); } } class Circle extends Shape { public String name = "circle"; public Circle() { System.out.println("circle constructor"); } public void printType() { System.out.println("this is circle"); } public static void printName() { System.out.println("circle"); } }
結果爲:
shape constructor circle constructor shape this is circle shape
六、接口與抽象類
抽象類:[ public ] abstract class ClassName {
1)抽象方法必須爲public或者protected(由於若是爲private,則不能被子類繼承,子類便沒法實現該方法),缺省狀況下默認爲public。
2)抽象類不能用來建立對象;
3)若是一個類繼承於一個抽象類,則子類必須實現父類的抽象方法。若是子類沒有實現父類的抽象方法,則必須將子類也定義爲爲abstract類。
在其餘方面,抽象類和普通的類並無區別。
接口:[ public ] interface InterfaceName {
[ public static final ] String MSG = "hello",//全局常量
[ public abstract ] void print();//抽象方法
}
2)方法會被隱式地指定爲public abstract方法
語法層面區別:
1)抽象類能夠提供成員方法的實現細節,而接口中只能存在public abstract 方法;
2)抽象類中的成員變量能夠是各類類型的,而接口中的成員變量只能是public static final類型的;
3)接口中不能含有靜態代碼塊以及靜態方法,而抽象類能夠有靜態代碼塊和靜態方法;
4)一個類只能繼承一個抽象類,而一個類卻能夠實現多個接口。
設計層面上的區別:
1)抽象類是對一種事物的抽象,即對類抽象,而接口是對行爲的抽象。抽象類是對整個類總體進行抽象,包括屬性、行爲,可是接口倒是對類局部(行爲)進行抽象。若是一個類繼承了某個抽象類,則子類一定是抽象類的種類,而接口實現則是有沒有、具有不具有的關係,好比鳥是否能飛(或者是否具有飛行這個特色),能飛行則能夠實現這個接口,不能飛行就不實現這個接口。
2)設計層面不一樣,抽象類做爲不少子類的父類,它是一種模板式設計。而接口是一種行爲規範,它是一種輻射式設計。對於抽象類,若是須要添加新的方法,能夠直接在抽象類中添加具體的實現,子類能夠不進行變動;而對於接口則不行,若是接口進行了變動,則全部實現這個接口的類都必須進行相應的改動。
七、建立成員內部類對象的通常方式
public class Test { public static void main(String[] args) { //第一種方式: Outter outter = new Outter(); Outter.Inner inner = outter.new Inner(); //必須經過Outter對象來建立 //第二種方式: Outter.Inner inner1 = outter.getInnerInstance(); } } class Outter { private Inner inner = null; public Outter() { } public Inner getInnerInstance() { if(inner == null) inner = new Inner(); return inner; } class Inner { public Inner() { } } }
八、線程建立到消亡的狀態
九、Lock和synchronized的選擇
總結來講,Lock和synchronized有如下幾點不一樣:
1)Lock是一個接口,而synchronized是Java中的關鍵字,synchronized是內置的語言實現;
2)synchronized在發生異常時,會自動釋放線程佔有的鎖,所以不會致使死鎖現象發生;而Lock在發生異常時,若是沒有主動經過unLock()去釋放鎖,則極可能形成死鎖現象,所以使用Lock時須要在finally塊中釋放鎖;
3)Lock可讓等待鎖的線程響應中斷,而synchronized卻不行,使用synchronized時,等待的線程會一直等待下去,不可以響應中斷;
4)經過Lock能夠知道有沒有成功獲取鎖,而synchronized卻沒法辦到。
5)Lock能夠提升多個線程進行讀操做的效率。
在性能上來講,若是競爭資源不激烈,二者的性能是差很少的,而當競爭資源很是激烈時(即有大量線程同時競爭),此時Lock的性能要遠遠優於synchronized。因此說,在具體使用時要根據適當狀況選擇。
十、nio讀寫文件
public static void main(String[] args) throws IOException { FileInputStream in = new FileInputStream("D:\\bbb.txt"); FileOutputStream on = new FileOutputStream("D:\\aaa.txt"); //爲該文件輸入流生成惟一的文件通道 FileChannel FileChannel channel = in.getChannel(); FileChannel fileChannel = on.getChannel(); //開闢一個長度爲1024的字節緩衝區 ByteBuffer buffer = ByteBuffer.allocate(1024); while(true){ //clear方法重設緩衝區,能夠讀新內容到buffer裏 buffer.clear(); if (channel.read(buffer) == -1) { break; } System.out.println(new String(buffer.array(),"GBK")); //flip方法讓緩衝區的數據輸出到新的通道里面 buffer.flip(); fileChannel.write(buffer); } }
十一、return、continue、break
public static void main(String[] args) { for (int i = 0; i < 6; i++) { if (i==4) { return;//0 1 2 3 知足return條件後該循環體以及循環後的方法不往下執行 // break;//0 1 2 3 111 知足break條件後該循環終止,但循環後的方法仍往下執行 // continue;//0 1 2 3 5 111 僅知足continue條件的項不執行,循環體以及循環後的方法仍執行 } System.out.println(i); } System.out.println(111); }
十二、簡單工廠模式
工廠方法模式
抽象工廠模式
http://www.cnblogs.com/java-my-life/archive/2012/03/28/2418836.html
在什麼狀況下應當使用抽象工廠模式
(1)一個系統不該當依賴於產品類實例如何被建立、組合和表達的細節,這對於全部形態的工廠模式都是重要的。
(2)這個系統的產品有多於一個的產品族,而系統只消費其中某一族的產品。
(3)同屬於同一個產品族的產品是在一塊兒使用的,這一約束必須在系統的設計中體現出來。(好比:Intel主板必須使用Intel CPU、Intel芯片組)
(4)系統提供一個產品類的庫,全部的產品以一樣的接口出現,從而使客戶端不依賴於實現。
1三、成員變量與局部變量的區別:
一:在方法中聲明的變量,即該變量是局部變量,每當程序調用方法時,系統都會爲該方法創建一個方法棧,其所在方法中聲明的變量就放在方法棧中,當方法結束系統會釋放方法棧,其對應在該方法中聲明的變量隨着棧的銷燬而結束,這就局部變量只能在方法中有效的緣由。在方法中聲明的變量能夠是基本類型的變量,也能夠是引用類型的變量。
(1)當聲明是基本類型的變量的時,其變量名及值(變量名及值是兩個概念)是放在JAVA虛擬機棧中
(2)當聲明的是引用變量時,所聲明的變量(該變量其實是在方法中存儲的是內存地址值)是放在JAVA虛擬機的棧中,該變量所指向的對象是放在堆類存中的。
二:在類中聲明的變量是成員變量,也叫全局變量,放在堆中的(由於全局變量不會隨着某個方法執行結束而銷燬)。一樣在類中聲明的變量便可是基本類型的變量 也但是引用類型的變量
(1)當聲明的是基本類型的變量其變量名及其值放在堆內存中的
(2)引用類型時,其聲明的變量仍然會存儲一個內存地址值,該內存地址值指向所引用的對象。引用變量名和對應的對象仍然存儲在相應的堆中
(1)定義的位置不一樣
成員變量定義在類中,在整個類中均可以被訪問。
局部變量只定義在局部範圍內,如:函數內,語句內等。
(2)在內存中的位置不一樣
成員變量存在於對象所在的堆內存中。
局部變量存在於棧內存中。
(3)生命週期不一樣
成員變量隨着對象的創建而創建,隨着對象的消失而消失。
局部變量隨着方法的運行而出現,隨着方法的彈棧而消失。
(4)初始化不一樣
成員變量無論程序有沒有顯式的進行初始化,加載時Java虛擬機都會先自動給它初始化爲默認值。
局部變量聲明以後,Java虛擬機就不會自動給它初始化爲默認值,所以局部變量的使用必須先通過顯式的初始化。
1四、靜態變量與成員變量的區別:
(1)所屬範圍不一樣
靜態變量所屬於類,成員變量所屬於對象。
靜態變量也稱爲:類變量 成員變量也稱爲:實例變量。
(2)調用不一樣
靜態變量能夠被對象和類名調用(通常用類名調用)。
成員變量只能被對象調用。
(3)加載時期不一樣
靜態變量隨着類的加載而加載。
成員變量隨着對象的加載而加載。
(4)內存的存儲區域不一樣
靜態變量存儲在方法區。
成員變量存儲在堆內存。
1五、摘錄於http://www.cnblogs.com/xiaoxi/p/6428432.html
http://www.cnblogs.com/xiaoxi/p/6473480.html
(1)從Set集合元素不可重複性看hashCode()的做用
Set裏面的元素是不能夠重複的,那麼如何作到?Set是根據equals()方法來判斷兩個元素是否相等的。比方說Set裏面已經有1000個元素了,那麼第1001個元素進來的時候,最多可能調用1000次equals方法,若是equals方法寫得複雜,對比的東西特別多,那麼效率會大大下降。使用HashCode就不同了,比方說HashSet,底層是基於HashMap實現的,先經過HashCode取一個模,這樣一會兒就固定到某個位置了,若是這個位置上沒有元素,那麼就能夠確定HashSet中一定沒有和新添加的元素equals的元素,就能夠直接存放了,都不須要比較;HashCode相等,再equals比較,沒有相同的元素就存,有相同的元素就不存。若是原來的Set裏面有相同的元素,只要HashCode的生成方式定義得好(不重複),無論Set裏面原來有多少元素,只須要執行一次的equals就能夠了。這樣一來,實際調用equals方法的次數大大下降,提升了效率。
hashCode() 的做用是獲取哈希碼,也稱爲散列碼;它其實是返回一個int整數。這個哈希碼的做用是肯定該對象在哈希表中的索引位置。hashCode在上面扮演的角色爲尋域(尋找某個對象在集合中區域位置)。hashCode能夠將集合分紅若干個區域,每一個對象均可以計算出他們的hash碼,能夠將hash碼分組,每一個分組對應着某個存儲區域,根據一個對象的hash碼就能夠肯定該對象所存儲區域,這樣就大大減小查詢匹配元素的數量,提升了查詢效率。
每一個Java類都包含hashCode() 函數。可是,僅僅當建立某個「類的散列表」(Java集合中本質是散列表的類,如HashMap,Hashtable,HashSet)時,該類的hashCode() 纔有用(做用是:肯定該類的每個對象在散列表中的位置);其它狀況下(例如,建立類的單個對象,或者建立類的對象數組等等),類的hashCode() 沒有做用。
也就是說:hashCode() 在散列表中才有用,在其它狀況下沒用。在散列表中hashCode() 的做用是獲取對象的散列碼,進而肯定該對象在散列表中的位置。
(2)equals()的做用
equals() 的做用是 用來判斷兩個對象是否相等(即,是不是同一個對象)。
public boolean equals(Object obj) { return (this == obj); }
既然Object.java中定義了equals()方法,這就意味着全部的Java類都實現了equals()方法,全部的類均可以經過equals()去比較兩個對象是否相等。 可是,咱們已經說過,使用默認的「equals()」方法,等價於「==」方法。所以,咱們一般會重寫equals()方法:若兩個對象的內容相等,則equals()方法返回true;不然,返回fasle。
下面根據「類是否覆蓋equals()方法」,將它分爲2類。
(01) 若某個類沒有覆蓋equals()方法,當它的經過equals()比較兩個對象時,其實是比較兩個對象是否是同一個對象。這時,等價於經過「==」去比較這兩個對象。
(02) 咱們能夠覆蓋類的equals()方法,來讓equals()經過其它方式比較兩個對象是否相等。一般的作法是:若兩個對象的內容相等,則equals()方法返回true;不然,返回fasle。
(3)hashCode()與equals()總結
1)hashCode的存在主要是用於查找的快捷性,如Hashtable,HashMap等,hashCode是用來在散列存儲結構中肯定對象的存儲地址的;
2)若是兩個對象相同,就是適用於equals(java.lang.Object) 方法,那麼這兩個對象的hashCode必定要相同;
3)若是對象的equals方法被重寫,那麼對象的hashCode也儘可能重寫,而且產生hashCode使用的對象,必定要和equals方法中使用的一致,不然就會違反上面提到的第2點;
4)兩個對象的hashCode相同,並不必定表示兩個對象就相同,也就是不必定適用於equals(java.lang.Object) 方法,只可以說明這兩個對象在散列存儲結構中,如Hashtable,他們「存放在同一個籃子裏」。
hashCode是用於查找使用的,而equals是用於比較兩個對象的是否相等的。
例如內存中有這樣的位置
0 1 2 3 4 5 6 7
而我有個類,這個類有個字段叫ID,我要把這個類存放在以上8個位置之一,若是不用hashcode而任意存放,那麼當查找時就須要到這八個位置裏挨個去找,或者用二分法一類的算法。 但若是用hashcode那就會使效率提升不少。 咱們這個類中有個字段叫ID,那麼咱們就定義咱們的hashcode爲ID%8,而後把咱們的類存放在取得得餘數那個位置。好比咱們的ID爲9,9除8的餘數爲1,那麼咱們就把該類存在1這個位置,若是ID是13,求得的餘數是5,那麼咱們就把該類放在5這個位置。這樣,之後在查找該類時就能夠經過ID 除 8求餘數直接找到存放的位置了。 可是若是兩個類有相同的hashcode怎麼辦那(咱們假設上面的類的ID不是惟一的),例如9除以8和17除以8的餘數都是1,那麼這是否是合法的,回答是:能夠這樣。那麼如何判斷呢?在這個時候就須要定義 equals了。 也就是說,咱們先經過 hashcode來判斷兩個類是否存放某個籃子裏,但這個籃子裏可能有不少類,那麼咱們就須要再經過 equals 來在這個籃子裏找到咱們要的類。
爲何必需要重寫hashcode方法,其實簡單的說就是爲了保證同一個對象,保證在equals相同的狀況下hashcode值一定相同,若是重寫了equals而未重寫hashcode方法,可能就會出現兩個沒有關係的對象equals相同的(由於equal都是根據對象的特徵進行重寫的),但hashcode確實不相同的。