Java是一門面向對象的高級編程語言,不只吸取了C++語言的各類優勢,好比繼承了C++語言面嚮對象的技術核心。還摒棄了C++裏難以理解的多繼承、指針等概念,,同時也增長了垃圾回收機制,釋放掉不被使用的內存空間,解決了管理內存空間的煩惱。java
所以Java語言具備功能強大和簡單易用兩個特徵。Java語言做爲靜態面向對象編程語言的表明,極好地實現了面向對象理論,容許程序員以優雅的思惟方式進行復雜的編程 。程序員
Java 語言是一種分佈式的面嚮對象語言,具備面向對象、平臺無關性、簡單性、解釋執行、多線程、安全性等不少特色,下面針對這些特色進行逐一介紹。web
1. 面向對象面試
Java 是一種面向對象的語言,它對對象中的類、對象、繼承、封裝、多態、接口、包等均有很好的支持。爲了簡單起見,Java 只支持類之間的單繼承,可是可使用接口來實現多繼承。使用 Java 語言開發程序,須要採用面向對象的思想設計程序和編寫代碼。編程
2. 平臺無關性數組
平臺無關性的具體表如今於,Java 是「一次編寫,處處運行(Write Once,Run any Where)」的語言,所以採用 Java 語言編寫的程序具備很好的可移植性,而保證這一點的正是 Java 的虛擬機機制。在引入虛擬機以後,Java 語言在不一樣的平臺上運行不須要從新編譯。tomcat
Java 語言使用 Java 虛擬機機制屏蔽了具體平臺的相關信息,使得 Java 語言編譯的程序只需生成虛擬機上的目標代碼,就能夠在多種平臺上不加修改地運行。安全
3. 簡單性網絡
Java 語言的語法與 C 語言和 C++ 語言很相近,使得不少程序員學起來很容易。對 Java 來講,它捨棄了不少 C++ 中難以理解的特性,如操做符的重載和多繼承等,並且 Java 語言不使用指針,加入了垃圾回收機制,解決了程序員須要管理內存的問題,使編程變得更加簡單。多線程
4. 解釋執行
Java 程序在 Java 平臺運行時會被編譯成字節碼文件,而後能夠在有 Java 環境的操做系統上運行。在運行文件時,Java 的解釋器對這些字節碼進行解釋執行,執行過程當中須要加入的類在鏈接階段被載入到運行環境中。
5. 多線程
Java 語言是多線程的,這也是 Java 語言的一大特性,它必須由 Thread 類和它的子類來建立。Java 支持多個線程同時執行,並提供多線程之間的同步機制。任何一個線程都有本身的 run() 方法,要執行的方法就寫在 run() 方法體內。
6. 分佈式
Java 語言支持 Internet 應用的開發,在 Java 的基本應用編程接口中就有一個網絡應用編程接口,它提供了網絡應用編程的類庫,包括 URL、URLConnection、Socket 等。Java 的 RIM 機制也是開發分佈式應用的重要手段。
7. 健壯性
Java 的強類型機制、異常處理、垃圾回收機制等都是 Java 健壯性的重要保證。對指針的丟棄是 Java 的一大進步。另外,Java 的異常機制也是健壯性的一大致現。
8. 高性能
Java 的高性能主要是相對其餘高級腳本語言來講的,隨着 JIT(Just in Time)的發展,Java 的運行速度也愈來愈高。
9. 安全性
Java 一般被用在網絡環境中,爲此,Java 提供了一個安全機制以防止惡意代碼的攻擊。除了 Java 語言具備許多的安全特性之外,Java 還對經過網絡下載的類增長一個安全防範機制,分配不一樣的名字空間以防替代本地的同名類,幷包含安全管理機制。
Java 語言的衆多特性使其在衆多的編程語言中佔有較大的市場份額,Java 語言對對象的支持和強大的 API 使得編程工做變得更加容易和快捷,大大下降了程序的開發成本。Java 的「一次編寫,處處執行」正是它吸引衆多商家和編程人員的一大優點。
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
1. JDK
JDK(Java SE Development Kit),Java標準的開發包,提供了編譯、運行Java程序所須要的各類工具和資源,包括了Java編譯器、Java運行時環境、以及經常使用的Java類庫等。
2. JRE
JRE(Java Runtime Environment),Java運行時環境,用於解釋執行Java的字節碼文件。普通用戶只須要安裝JRE來運行Java程序便可,而做爲一名程序員必須安裝JDK,來編譯、調試程序。
3. JVM
JVM(Java Virtual Mechinal),Java虛擬機,是JRE的一部分。它是整個Java實現跨平臺的核心,負責解釋執行字節碼文件,是可運行Java字節碼文件的虛擬計算機。全部平臺上的JVM向編譯器提供相同的接口,而編譯器只須要面向虛擬機,生成虛擬機能識別的代碼,而後由虛擬機來解釋執行。
當使用Java編譯器編譯Java程序時,生成的是與平臺無關的字節碼,這些字節碼只面向JVM。也就是說JVM是運行Java字節碼的虛擬機。
不一樣平臺的JVM是不一樣的,可是他們都提供了相同的接口。JVM是Java程序跨平臺的關鍵部分,只要爲不一樣平臺實現了相同的虛擬機,編譯後的Java字節碼就能夠在該平臺上運行。
爲何要採用字節碼:
在 Java 中,JVM 能夠理解的代碼就叫作字節碼
(即Java源代碼通過虛擬機編譯器編譯後擴展名爲.class
的文件),它不面向任何特定的處理器,只面向虛擬機。Java 語言經過字節碼的方式,在必定程度上解決了傳統解釋型語言執行效率低的問題,同時又保留了解釋型語言可移植的特色。因此 Java 程序運行時比較高效,並且,因爲字節碼並不針對一種特定的機器,所以,Java 程序無須從新編譯即可在多種不一樣操做系統的計算機上運行。
什麼是跨平臺:
所謂跨平臺性,是指java語言編寫的程序,一次編譯後,能夠在多個系統平臺上運行。
實現原理:Java程序是經過java虛擬機在系統平臺上運行的,只要該系統能夠安裝相應的java虛擬機,該系統就能夠運行java程序。
Java 程序從源代碼到運行須要三步:
4. 總結
Java中有 8 種基本數據類型,分別爲:
byte:
short:
int:
long:
float:
double:
char:
boolean:
這八種基本類型都有對應的包裝類分別爲:Byte、Short、Integer、Long、Float、Double、Character、Boolean
類型名稱 | 字節、位數 | 最小值 | 最大值 | 默認值 | 例子 |
---|---|---|---|---|---|
byte字節 | 1字節,8位 | -128(-2^7) | 127(2^7-1) | 0 | byte a = 100,byte b = -50 |
short短整型 | 2字節,16位 | -32768(-2^15) | 32767(2^15 - 1) | 0 | short s = 1000,short r = -20000 |
int整形 | 4字節,32位 | -2,147,483,648(-2^31) | 2,147,483,647(2^31 - 1) | 0 | int a = 100000, int b = -200000 |
lang長整型 | 8字節,64位 | -9,223,372,036,854,775,808(-2^63) | 9,223,372,036,854,775,807(2^63 -1) | 0L | long a = 100000L,Long b = -200000L |
double雙精度 | 8字節,64位 | double類型一樣不能表示精確的值,如貨幣 | 0.0d | double d1 = 123.4 | |
float單精度 | 4字節,32位 | 在儲存大型浮點數組的時候可節省內存空間 | 不一樣統計精準的貨幣值 | 0.0f | float f1 = 234.5f |
char字符 | 2字節,16位 | \u0000(即爲0) | \uffff(即爲65,535) | 能夠儲存任何字符 | char letter = 'A'; |
boolean布爾 | 返回true和false兩個值 | 這種類型只做爲一種標誌來記錄 true/false 狀況; | 只有兩個取值:true 和 false; | false | boolean one = true |
引用數據類型分3種:類,接口,數組;
簡單來講,只要不是基本數據類型.都是引用數據類型。 那他們有什麼不一樣呢?
一、從概念方面來講
1,基本數據類型:變量名指向具體的數值
2,引用數據類型:變量名不是指向具體的數值,而是指向存數據的內存地址,.也及時hash值
二、從內存的構建方面來講(內存中,有堆內存和棧內存二者)
1,基本數據類型:被建立時,在棧內存中會被劃分出必定的內存,並將數值存儲在該內存中.
2,引用數據類型:被建立時,首先會在棧內存中分配一塊空間,而後在堆內存中也會分配一塊具體的空間用來存儲數據的具體信息,即hash值,而後由棧中引用指向堆中的對象地址.
舉個例子
//基本數據類型做爲方法參數被調用 public class Main{ public static void main(String[] args){ //基本數據類型 int i = 1; int j = 1; double d = 1.2; //引用數據類型 String str = "Hello"; String str1= "Hello"; } }
由上圖可知,基本數據類型中會存在兩個相同的1,而引用型類型就不會存在相同的數據。
假如"hello"的引用地址是xxxxx1,聲明str變量並其賦值"hello"實際上就是讓str變量引用了"hello"的內存地址,這個內存地址就存儲在堆內存中,是不會改變的,當再次聲明變量str1也是賦值爲"hello"時,此時就會在堆內存中查詢是否有"hello"這個地址,若是堆內存中已經存在這個地址了,就不會再次建立了,而是讓str1變量也指向xxxxx1這個地址,若是沒有的話,就會從新建立一個地址給str1變量。
1,基本數據類型:判斷數據是否相等,用==和!=判斷。
2,引用數據類型:判斷數據是否相等,用equals()方法,==和!=是比較數值的。而equals()方法是比較內存地址的。
補充:數據類型選擇的原則
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
什麼是自動裝箱拆箱?
從下面的代碼中就能夠看到裝箱和拆箱的過程
//自動裝箱 Integer total = 99; //自定拆箱 int totalprim = total;
裝箱就是自動將基本數據類型轉換爲包裝器類型;拆箱就是自動將包裝器類型轉換爲基本數據類型。
在Java SE5以前,自動裝箱要這樣寫:Integer i =
new` `Integer(
10``);
對於Java的自動裝箱和拆箱,咱們看看源碼編譯後的class文件,其實裝箱調用包裝類的valueOf方法,拆箱調用的是Integer.Value方法,下面就是變編譯後的代碼:
常見面試一:
這段代碼輸出什麼?
public class Main { public static void main(String[] args) { Integer i1 = 100; Integer i2 = 100; Integer i3 = 200; Integer i4 = 200; System.out.println(i1==i2); System.out.println(i3==i4); } }
答案是:
true false
爲何會出現這樣的結果?輸出結果代表i1和i2指向的是同一個對象,而i3和i4指向的是不一樣的對象。此時只需一看源碼便知究竟,下面這段代碼是Integer的valueOf方法的具體實現:
public static Integer valueOf(int i) { if(i >= -128 && i <= IntegerCache.high) return IntegerCache.cache[i + 128]; else return new Integer(i); }
private static class IntegerCache { static final int high; static final Integer cache[]; static { final int low = -128; // high value may be configured by property int h = 127; if (integerCacheHighPropValue != null) { // Use Long.decode here to avoid invoking methods that // require Integer's autoboxing cache to be initialized int i = Long.decode(integerCacheHighPropValue).intValue(); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - -low); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} }
從這2段代碼能夠看出,在經過valueOf方法建立Integer對象的時候,若是數值在[-128,127]之間,便返回指向IntegerCache.cache中已經存在的對象的引用;不然建立一個新的Integer對象。
上面的代碼中i1和i2的數值爲100,所以會直接從cache中取已經存在的對象,因此i1和i2指向的是同一個對象,而i3和i4則是分別指向不一樣的對象。
常見面試二:
public class Main { public static void main(String[] args) { Double i1 = 100.0; Double i2 = 100.0; Double i3 = 200.0; Double i4 = 200.0; System.out.println(i1==i2); System.out.println(i3==i4); } }
輸出結果爲:
false false
緣由很簡單,在某個範圍內的整型數值的個數是有限的,而浮點數卻不是。
讓基本數據類型也具備對象的特徵
基本類型 | 包裝器類型 |
---|---|
boolean | Boolean |
char | Character |
int | Integer |
byte | Byte |
short | Short |
long | Long |
float | Float |
double | Double |
爲了讓基本類型也具備對象的特徵,就出現了包裝類型(如咱們在使用集合類型Collection時就必定要使用包裝類型而非基本類型)由於容器都是裝object的,這是就須要這些基本類型的包裝器類了。
自動裝箱:new Integer(6);
,底層調用:Integer.valueOf(6)
自動拆箱: int i = new Integer(6);
,底層調用i.intValue();
方法實現。
Integer i = 6; Integer j = 6; System.out.println(i==j);
答案在下面這段代碼中找:
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
兩者的區別:
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
+=
操做符會進行隱式自動類型轉換,此處a+=b隱式的將加操做的結果類型強制轉換爲持有結果的類型,而a=a+b則不會自動進行類型轉換.如:
byte a = 127; byte b = 127; b = a + b; // 報編譯錯誤:cannot convert from int to byte b += a;
如下代碼是否有錯,有的話怎麼改?
short s1= 1; s1 = s1 + 1;
有錯誤.short類型在進行運算時會自動提高爲int類型,也就是說s1+1
的運算結果是int類型,而s1是short類型,此時編譯器會報錯.
正確寫法:
short s1= 1; s1 += 1;
+=
操做符會對右邊的表達式結果強轉匹配左邊的數據類型,因此沒錯.
咱們能夠作強制轉換,可是 Java 中 int 是 32 位的,而 byte 是 8 位的,因此,若是強制轉化,int 類型的高 24 位將會被丟棄,由於byte 類型的範圍是從 -128 到 127
咱們平常的工做中都使用開發工具(IntelliJ IDEA 或 Eclipse 等)能夠很方便的調試程序,或者是經過打包工具把項目打包成 jar 包或者 war 包,放入 Tomcat 等 Web 容器中就能夠正常運行了,但你有沒有想過 Java 程序內部是如何執行的?其實不管是在開發工具中運行仍是在 Tomcat 中運行,Java 程序的執行流程基本都是相同的,它的執行流程以下:
final做爲Java中的關鍵字能夠用於三個地方。用於修飾類、類屬性和類方法。
特徵:凡是引用final關鍵字的地方皆不可修改!
(1)修飾類:表示該類不能被繼承;
(2)修飾方法:表示方法不能被重寫;
(3)修飾變量:表示變量只能一次賦值之後值不能被修改(常量)。
final也是不少面試喜歡問的地方,但我以爲這個問題很無聊,一般能回答下如下5點就不錯了:
除此以外,編譯器對final域要遵照的兩個重排序規則更好:
在構造函數內對一個final域的寫入,與隨後把這個被構造對象的引用賦值給一個引用變量,這兩個操做之間不能重排序 初次讀一個包含final域的對象的引用,與隨後初次讀這個final域,這兩個操做之間不能重排序.
全部的人都知道static關鍵字這兩個基本的用法:靜態變量和靜態方法.也就是被static所修飾的變量/方法都屬於類的靜態資源,類實例所共享.
除了靜態變量和靜態方法以外,static也用於靜態塊,多用於初始化操做:
public calss PreCache{ static{ //執行相關操做 } }
此外static也多用於修飾內部類,此時稱之爲靜態內部類.
最後一種用法就是靜態導包,即import static
.import static是在JDK 1.5以後引入的新特性,能夠用來指定導入某個類中的靜態資源,而且不須要使用類名,能夠直接使用資源名,好比:
import static java.lang.Math.*; public class Test{ public static void main(String[] args){ //System.out.println(Math.sin(20));傳統作法 System.out.println(sin(20)); } }
關鍵詞 | 修飾物 | 影響 |
---|---|---|
final | 變量 | 分配到常量池中,程序不可改變其值 |
final | 方法 | 子類中將不能被重寫 |
final | 類 | 不能被繼承 |
static | 變量 | 分配在內存堆上,引用都會指向這一個地址而不會從新分配內存 |
static | 方法塊 | 虛擬機優先加載 |
static | 類 | 能夠直接經過類來調用而不須要new |
爲了網絡進行傳輸或者持久化
什麼是序列化
將對象的狀態信息轉換爲能夠存儲或傳輸的形式的過程
除了實現Serializable接口還有什麼序列化方式
咱們有時候將一個java對象變成字節流的形式傳出去或者從一個字節流中恢復成一個java對象,例如,要將java對象存儲到硬盤或者傳送給網絡上的其餘計算機,這個過程咱們能夠本身寫代碼去把一個java對象變成某個格式的字節流再傳輸。
可是,jre自己就提供了這種支持,咱們能夠調用OutputStream
的writeObject
方法來作,若是要讓java幫咱們作,要被傳輸的對象必須實現serializable
接口,這樣,javac編譯時就會進行特殊處理,編譯的類才能夠被writeObject
方法操做,這就是所謂的序列化。須要被序列化的類必須實現Serializable
接口,該接口是一個mini接口,其中沒有須要實現方法,implements Serializable只是爲了標註該對象是可被序列化的。
例如,在web開發中,若是對象被保存在了Session中,tomcat在重啓時要把Session對象序列化到硬盤,這個對象就必須實現Serializable接口。若是對象要通過分佈式系統進行網絡傳輸,被傳輸的對象就必須實現Serializable接口。
內部類的定義
將一個類定義在另外一個類裏面或者一個方法裏面,這樣的類稱爲內部類。
內部類的做用:
一、成員內部類 成員內部類能夠無條件訪問外部類的全部成員屬性和成員方法(包括private成員和靜態成員)。 當成員內部類擁有和外部類同名的成員變量或者方法時,會發生隱藏現象,即默認狀況下訪問的是成員內部類的成員。
二、局部內部類 局部內部類是定義在一個方法或者一個做用域裏面的類,它和成員內部類的區別在於局部內部類的訪問僅限於方法內或者該做用域內。
三、匿名內部類 匿名內部類就是沒有名字的內部類
四、靜態內部類 指被聲明爲static的內部類,他能夠不依賴內部類而實例,而一般的內部類須要實例化外部類,從而實例化。靜態內部類不能夠有與外部類有相同的類名。不能訪問外部類的普通成員變量,可是能夠訪問靜態成員變量和靜態方法(包括私有類型) 一個 靜態內部類去掉static 就是成員內部類,他能夠自由的引用外部類的屬性和方法,不管是靜態仍是非靜態。可是不能夠有靜態屬性和方法
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...
Java可拋出(Throwable)的結構分爲三種類型:被檢查的異常(CheckedException),運行時異常(RuntimeException),錯誤(Error)。
一、運行時異常
定義:RuntimeException及其子類都被稱爲運行時異常。
特色:Java編譯器不會檢查它。也就是說,當程序中可能出現這類異常時,假若既"沒有經過throws聲明拋出它",也"沒有用try-catch語句捕獲它",仍是會編譯經過。例如,除數爲零時產生的ArithmeticException異常,數組越界時產生的IndexOutOfBoundsException異常,fail-fast機制產生的ConcurrentModificationException異常(java.util包下面的全部的集合類都是快速失敗的,「快速失敗」也就是fail-fast,它是Java集合的一種錯誤檢測機制。當多個線程對集合進行結構上的改變的操做時,有可能會產生fail-fast機制。記住是有可能,而不是必定。例如:假設存在兩個線程(線程一、線程2),線程1經過Iterator在遍歷集合A中的元素,在某個時候線程2修改了集合A的結構(是結構上面的修改,而不是簡單的修改集合元素的內容),那麼這個時候程序就會拋出 ConcurrentModificationException 異常,從而產生fail-fast機制,這個錯叫併發修改異常。Fail-safe,java.util.concurrent包下面的全部的類都是安全失敗的,在遍歷過程當中,若是已經遍歷的數組上的內容變化了,迭代器不會拋出ConcurrentModificationException異常。若是未遍歷的數組上的內容發生了變化,則有可能反映到迭代過程當中。這就是ConcurrentHashMap迭代器弱一致的表現。ConcurrentHashMap的弱一致性主要是爲了提高效率,是一致性與效率之間的一種權衡。要成爲強一致性,就獲得處使用鎖,甚至是全局鎖,這就與Hashtable和同步的HashMap同樣了。)等,都屬於運行時異常。
常見的五種運行時異常:
ClassCastException
(類轉換異常)IndexOutOfBoundsException
(數組越界)NullPointerException
(空指針異常)ArrayStoreException
(數據存儲異常,操做數組是類型不一致)BufferOverflowException
二、被檢查異常
定義:Exception類自己,以及Exception的子類中除了"運行時異常"以外的其它子類都屬於被檢查異常。
特色 : Java編譯器會檢查它。 此類異常,要麼經過throws進行聲明拋出,要麼經過try-catch進行捕獲處理,不然不能經過編譯。例如,CloneNotSupportedException就屬於被檢查異常。
當經過clone()接口去克隆一個對象,而該對象對應的類沒有實現Cloneable接口,就會拋出CloneNotSupportedException異常。被檢查異常一般都是能夠恢復的。 如:
IOException
FileNotFoundException
SQLException
被檢查的異常適用於那些不是因程序引發的錯誤狀況,好比:讀取文件時文件不存在引起的FileNotFoundException
。然而,不被檢查的異常一般都是因爲糟糕的編程引發的,好比:在對象引用時沒有確保對象非空而引發的NullPointerException
。
三、錯誤
定義 : Error類及其子類。
特色 : 和運行時異常同樣,編譯器也不會對錯誤進行檢查。
當資源不足、約束失敗、或是其它程序沒法繼續運行的條件發生時,就產生錯誤。程序自己沒法修復這些錯誤的。例如,VirtualMachineError就屬於錯誤。出現這種錯誤會致使程序終止運行。OutOfMemoryError、ThreadDeath。
Java虛擬機規範規定JVM的內存分爲了好幾塊,好比堆,棧,程序計數器,方法區等
24W字Java面試手冊下載地址: https://shimo.im/docs/Wyj8QRp...