1、java語法基礎java
一、finalc++
關於final的問題我曾經被問到兩次,因此首先說一下這個東西。編程
應用於變量,表示該變量一旦被賦值則不能夠改變,可是有一個特殊的:StringBuffer,看下面一個例子設計模式
final StringBuffer sb=new StringBuffer("123");數組
這樣寫 sb=new StringBuffer("");會報錯,可是sb.append("111");不會報錯。安全
final是指引用變量不能變,但變量的內容是不能夠改變的。StringBuffer 只是有這樣一個方法能夠改變它的內容而已。數據結構
應用於方法,表示該方法不能夠被重寫覆蓋。多線程
應用與類,表示該類不能夠被繼承。app
二、關於private,public,protected,friendly異步
能夠用一個表格說明他們的權限和訪問範圍,當修飾元素沒有修飾符時默認是friendly
- 表示不支持 √ 表示支持
修飾符 | 當前類 | 同一包 | 子孫類 | 其餘包 |
public | √ | √ | √ | √ |
protected | √ | √ | √ | - |
friendly | √ | √ | - | - |
private | √ | - | - | - |
三、基本數據類型
byte、int、short、double、float、long、double、boolean
級別從低到高爲:byte,char,short(這三個平級)-->int-->float-->long-->double
由低級到高級系統會自動轉換,由高級到低級須要強制轉換。
四、運算符
a++ 和++a區別
二者都表示a+1可是前者表示先進行運算,而後給a+1,後者表示先a+1,再參加運算,例如:a=2;b=a++;能夠理解爲b=a,a=a+1;b=++a;能夠理解爲a=a+1,b=a;一樣a--和--a相似。
& 和 &&(| 和||)區別
首先二者都表示與運算符,兩邊條件均爲true時結果才爲true,其餘狀況均爲false;
&&有短路功能,例如a&&b,當a爲false時,就不會執行b;可是a&b無論a爲true或者false,b都會執行。
& 還能夠看成位運算符,兩邊表達式不是boolean類型時,表示按位與操做。
有一個關於位運算的題:請編程實現計算1234變成二進制之後包含多少1。
通常思路就是先經過Integer.toBinaryString(int i)方法轉換成二進制,而後遍歷裏面1的個數。
這裏說一下不一樣進制之間的轉換方法:
十進制轉成十六進制:
Integer.toHexString(int i)
十進制轉成八進制
Integer.toOctalString(int i)
十進制轉成二進制
Integer.toBinaryString(int i)
十六進制轉成十進制
Integer.valueOf("FFFF",16).toString()
八進制轉成十進制
Integer.valueOf("876",8).toString()
二進制轉十進制
Integer.valueOf("0101",2).toString()
其實經過位運算能夠實現更快的方法。
public static void main(String[] args) { int c=0; int t=1234; while (t>0) { t=t&(t-1); c++; } System.out.print(c); }
說明一下,t&(t-1)實際上是 t 的二進制進行移位運算,0&1=0,1&0=0,1&1=1。
說道移位運算還有一個:請用最有效率的方法計算出2乘以8的結果。
2<<3 一個數左移幾位就至關於這個數乘以2的幾回方,2*八、等價於2左移3位
五、Override和Overload的區別(重寫和重載區別)。
重載是指同一個類中能夠存在多個命名相同的方法,可是各個方法的參數個數或類型必須不一樣,而且不能夠經過改變方法的返回值來表示兩個方法的不通。
重寫是指子類能夠與父類的方法名稱參數相同,等於徹底把父類的方法覆蓋了。可是對於異常,子類的方法必須比父類拋出更少的異常或者是父類異常的子異常。
六、java內存
java內存大概分爲5塊:寄存器,本地方法區,方法區,堆,棧。
棧:主要用來存儲局部變量,當運算完成所在趨於結束,內存將被釋放。
堆:存儲數組和對象。
七、成員變量和局部變量區別
成員變量在類裏面定義,只在類裏面有效;局部變量存在方法中定義,只在方法所在的大括號有效。
成員變量存在於堆內存中;局部變量存在與棧內存中。
八、this 和 super
this 一般用來表示對象自己,super訪問父類被子類隱藏的變量或覆蓋的方法。
若是一個類繼承自父類,那麼子類的super()方法即對父類的初始化。當類中有兩個同名變量,一個屬於類(類的成員變量),而另外一個屬於某個特定的方法(方法中的局部變量),使用this區分紅員變量和局部變量。
調用super()必須寫在子類構造方法的第一行,不然編譯不經過。每一個子類構造方法的第一條語句,都是隱含地調用super(),若是父類沒有這種形式的構造函數,那麼在編譯的時候就會報錯。
super()和this()相似,區別是,super從子類中調用父類的構造方法,this()在同一類內調用其它方法。
super的本質是java的一個關鍵字,this的本質是一個指向本對象的指針。
九、單例模式
保證一個類在內存中的對象中惟一性。
步驟:一、私有化構造函數。二、建立一個靜態的私有的本類對象。三、提供一個對外調用的方法。
單例模式的建立有兩種:懶漢式,餓漢式
首先來看下懶漢式:
public class Single { public static Single single; private Single(){ } public static Single getInstance(){ if (single==null) { single=new Single(); } return single; } }
能夠看出當須要Single的時候,隨時用隨時new,這樣之後就不用實例了,再看下餓漢式:
public class Single { public static Single singleInstance=new Single(); private Single(){ } public static Single getInstance(){ return single; } }
比較推薦餓漢式,由於他不用考慮線程安全問題,懶漢模式下若是有兩個線程同時訪問,第一個線程走到if後尚未執行new,第二個線程也會判斷爲Null,從新建立一個實例,這樣就建立了兩個。固然有一種方法能夠解決這個問題那就是synchronized,看一下代碼:
public class Single { public static Single single; private Single(){ } public synchronized static Single getInstance(){ if (single==null) { single=new Single(); } return single; } }
固然這樣是能夠的,實現了同步鎖,可是其實還能夠進行優化,這樣每次調用getInstance()都會受同步鎖的影響,效率會下降。其實只要保證new的時候同步就能夠了,這種方法叫雙重鎖定(Double-Check Locking)有興趣的能夠查一下,先看代碼:
public class Single { public static Single single; private Single(){ } public static Single getInstance(){ if(sing==null){ synchronized (Single.class){ if (single==null) { single=new Single(); } } } return single; } }
10、abstract
抽象類的特色:
1:抽象方法只能定義在抽象類中,抽象類和抽象方法必須由abstract關鍵字修飾(能夠描述類和方法,不能夠描述變量)。
2:抽象方法只定義方法聲明,並不定義方法實現。
3:抽象類不能夠被建立對象(實例化)。
4:只有經過子類繼承抽象類並覆蓋了抽象類中的全部抽象方法後,該子類才能夠實例化。不然,該子類仍是一個抽象類。
十一、String、StringBuffer、StringBuilder區別
因爲String類是final修飾的,因此string對象是不可變的,當前它也就是線程安全的。
StringBuffer和StringBuilder都是繼承AbstractStringBuilder類,他們都是可變的。
因爲StringBuffer對方法或者調用的方法加了同步鎖,StringBuilder沒有加,因此StringBuilder是非線程安全的,StringBuffer是線程安全的。
在不kao慮多線程的狀況下,StringBuilder效率要高於StringBuffer。
十二、==和equals區別
==表示兩個對象在內存中存儲的值相等,而equals是兩個對象的內容相等。
好比:String a=new String("123");String =new String("123");
若是用a==b的話返回false,而a.equals(b)返回true,a和b的內容是相等的,可是a、b是不通的兩個對象,他們的首地址是不同的,因此a==b返回false。
1三、JAVA集合類
有時候會有這樣的題:請說出幾個JAVA經常使用的集合類,他們都有什麼區別?
集合你們並不陌生,經常使用的什麼ArrayList、map等,下面來介紹一下JAVA的集合類。
總的來講總共分爲兩大部分一個是Collection接口,一個是Map接口。
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
│├AbstractSet
│├HashSet
│└TreeSet
Map
├Hashtable
├HashMap
└WeakHashMap
先說下Collection,由Collection又派生出兩個接口:List和set,二者最大的區別就是list容許有重複元素,set不容許有重複元素;List是有序的,而set除了TreeSet之外,都是無序的。
給定一個字符串(長度不會超過500,必定會有重複的字符),編程返回字符串內第一個重複的字符。例如:「tyuioqiwyss」,返回值:i 。
public static char getFirstRepeat(String str){ HashSet<Object> hs=new HashSet<>(); //定義一個hashset char[] m=str.toCharArray();//將字符串放進一個char數組 for (int i = 0; i < m.length; i++) { boolean b=hs.add(m[i]);//遍歷數組元素放進hashset if (!b) { //因爲hashset不容許有重複元素,因此當有重複元素被添加的時候就會返回false return m[i]; } } return 0; }
List下面又有ArrayList、LinkedList、Vector和stack,先說下ArrayList、LinkedList的區別:一、ArrayList是基於動態數組的數據結構,對於查找訪問操做效率較高;LinkedList是基於鏈表的數據結構,對於元素的增長刪除效率較高。二者都是非同步的。Vector和stack固然就是同步的了,stack繼承自Vector,實現了一個後進先出的堆棧。
Set接口是不容許插入重複元素的。
Map的元素是用key,value的形式存儲的,能夠存入相同的value可是key要保證惟一。
1四、Math
關於math有幾個經常使用的方法。
Math.ceil():向上取整 Math.ceil(11.5)=12 Math.ceil(-11.5)=-11
Math.floor():向下取整 Math.floor(11.5)=11 Math.floor(-11.5)=-12
Math.round():四捨五入 Math.round(11.5)=12 Math.round(-11.5)=-11 Math.round(-11.6)=-12
1五、關於異或運算
給定兩個Int參數,編程返回兩個參數二進制數有多少位不一樣。
異或運算是這樣的:兩位相同則爲0,不一樣則爲1。0000^0011=0011 1001^1100=0101
因此先把給定的兩個參數作異或運算,獲得的值在判斷他的二進制裏面有多少1即有多少個不一樣的位。
public static int Sample(int m,int n) { int s=m^n; //異或運算 int count=0;//統計1的個數 while (s>0) { s=s&(s-1);//進行與運算,相似移位運算 0&0=0 0&1=0 1&1=1 1&0=0 count++; } return count; }
1六、面向對象的特色,說說對他們的理解。
封裝:可使程序實現「高內聚,低耦合」,對象是封裝的最基本單位。
繼承:提升軟件的可重用性和可擴展性
抽象:把某些具備相同特徵的事物抽象成一個具體的類,只關心咱們須要的地方
多態:增長軟件的靈活性和可擴展性
1七、列舉常見的異常及可能產生緣由,異常解決方法?
NullPointerException 空指針異常 簡單地說就是調用了未經初始化的對象或者是不存在的對象,好比調用了未初始化對象的方法
ArrayIndexOutOfBoundsException 數組越界 調用的數組長度與實際數組長度不一致,好比一個數組有3個元素,獲取第四個元素時就會出現這個異常,因此最好先查看一下數組長度。
NumberFormatException 數字強轉異常 常見於把一個字符串轉爲Int 類型是,Intenger.parseInt("123#")就會拋出異常。
ClassCastException 數據類型轉換異常 如用戶在輸入日期的時候只輸入月、日信息,而沒有年份的信息。此時應用程序在進行數據類型轉換的時候,就會出現異常。
IllegalArgumentException 方法的參數錯誤 好比g.setColor(int red,int green,int blue)這個方法中的三個值,若是有超過255的也會出現這個異常,所以一旦發現這個異常,咱們要作的,就是趕忙去檢查一下方法調用中的參數傳遞是否是出現了錯誤。
異常的處理一般咱們使用try catch來處理可能出現的異常,固然咱們應該是捕獲這個異常來處理。下面是有關異常處理的幾個關鍵字:
throws 捕獲並向外拋出異常
throw 拋出異常
try catch 內部捕獲異常並作自定義處理
finally 不管是否有異常都會被處理的語句
1八、線程相關
1)實現一個線程
兩種方法:繼承thread和實現Runnable接口
2)sleep() wait()區別
sleep()是thread類的一個方法,他須要指定一個時間告訴線程暫停指定時間,時間到了繼續執行,暫停期間依然佔用CPU;wait()是Object類的一個方法,不須要指定時間,想恢復執行的話須要調用notify或者notifyAll方法,暫停期間不會佔用CPU資源。
3)同步和異步
若是數據須要在線程間共享,一個線程在讀取數據,另外一個線程在插入數據,這個時候就須要保證同步讀取。若是一個線程須要調用的方法須要執行很長時間,但其餘線程又不須要該線程的數據返回時應該用異步。
4)啓動一個線程是調用start()方法,run()方法是線程進入執行狀態所執行的方法。
1九、輸入輸出流
JAVA的輸入輸出流有兩種 字節流和字符流。字節流繼承InputOutStream、OutputStream,字符流繼承自InputOutStreamReader、OutputStreamReader。字節流主要操做對象是byte,字符流主要操做對象是字符或者字符串。
字節流在操做的時候自己是不會用到緩衝區(內存)的,是與文件自己直接操做的,而字符流在操做的時候是使用到緩衝區的
字節流在操做文件時,即便不關閉資源(close方法),文件也能輸出,可是若是字符流不使用close方法的話,則不會輸出任何內容,說明字符流用的是緩衝區,而且可使用flush方法強制進行刷新緩衝區,這時才能在不close的狀況下輸出內容。
20、內存溢出和內存泄漏(主要針對Android中的狀況進行分析)
內存溢出:應用使用的內存大於機器的最大內存。
內存泄漏:cursor使用完了沒有關閉;Bitmap沒有回收;構造Adapter時,沒有使用 convertView
2一、抽象類和接口的區別
一、抽象類能夠有成員變量,接口裏通常沒有。若是有的話默認必須是static final類型的。
二、一個類能夠實現多個接口但只能繼承一個抽象類
三、抽象類裏面能夠有非抽象的方法,接口裏面的方法都是抽象的,也就是實現他的類裏面必須實現他的方法。
四、抽象類中的抽象方法的訪問類型能夠是public、protected或者包訪問類型。而接口中的抽象方法只能是public abstract類型,接口的方法前面能夠不加修飾符,默認就是public abstract類型。
2二、java中靜態屬性、靜態代碼塊、非靜態屬性、非靜態代碼塊、構造函數在new的時候執行順序是怎樣的?
對於沒有繼承其餘類的執行順序是這樣的:
靜態屬性--靜態代碼塊--非靜態屬性--非靜態代碼塊--構造函數
若是繼承了其餘類:
父類的公共靜態屬性和靜態代碼塊--自身的靜態屬性和靜態代碼塊--父類的非靜態屬性和非靜態代碼塊--父類的構造函數--自身的非靜態屬性和非靜態代碼塊--自身的構造函數
2三、什麼是編譯型語言,什麼是解釋型語言?JAVA屬於哪種?
編譯型語言是指程序在執行前須要有一個單獨的編譯過程,將程序翻譯成機器語言,之後執行這個程序的時候,就不用再進行翻譯了。
解釋型語言是指是每次在運行的時候將程序翻譯成機器語言,因此運行速度相對於編譯型語言要慢。
C/C++ 等都是編譯型語言,而Java,C#,腳本語言等都是解釋型語言。
雖然Java程序在運行以前也有一個編譯過程,可是並非將程序編譯成機器語言,而是將它編譯成字節碼(能夠理解爲一箇中間語言)。
在運行的時候,由JVM將字節碼再翻譯成機器語言。
2四、經常使用的設計模式有哪些?
單例模式、工廠模式、觀察者設計模式、適配器模式等。
2五、synchronized修飾靜態方法和非靜態方法的區別
synchronized在靜態方法上表示調用前要得到類的鎖,而在非靜態方法上表示調用此方法前要得到對象的鎖。
public class StaticSynDemo { private static String a="test"; //等同於方法print2 public synchronized void print1(String b){ //調用前要取得StaticSynDemo實例化後對象的鎖 System.out.println(b+a); } public void print2(String b){ synchronized (this) {//取得StaticSynDemo實例化後對象的鎖 System.out.println(b+a); } } //等同於方法print4 public synchronized static void print3(String b){//調用前要取得StaticSynDemo.class類的鎖 System.out.println(b+a); } public static void print4(String b){ synchronized (StaticSynDemo.class) { //取得StaticSynDemo.class類的鎖 System.out.println(b+a); } } }