1. 程式人生 > >java面試題技術面試問題彙總(陸續補充)

java面試題技術面試問題彙總(陸續補充)

1.堆,棧,方法區的區別?
堆區
①存放的都是物件,每個物件都包含著一個與之相對應的class的資訊,class的目的是得到一些操作指令
②jvm中只有一個堆區,被所有執行緒共享,堆區不存放基本型別和物件引用,只存放物件本身。
棧區
①每個執行緒包含一個棧區,棧中只儲存基礎資料型別的物件和自定義物件的引用(不是物件),物件都存放在堆區中。
②每個棧中的資料(原始型別和物件引用)都是私有的,其他棧中不能訪問
方法區
①又叫靜態區,跟堆一樣,被所有的執行緒共享。方法區包含所有的class和static變數。
②方法區中包含的都是在整個程式中永遠唯一的元素,如class,static變數

2.建立一個類的幾種方法? 四種方法.
①使用new關鍵字
②使用Class類的newInstance方法
③使用clone方法
④使用反序列化

3,序列化和反序列化的概念? 讀取和寫入一個序列化的類.

① :概念
序列化:指把記憶體中的java物件資料,通過某種方式吧物件儲存到磁碟檔案中或者傳遞給其他網路節點(在網路上傳輸)。通俗來說就是將資料結構或者物件轉換成二進位制串的過程。
反序列化:把磁碟檔案中的物件資料或者把網路節點上的物件資料,恢復成java物件模型的過程。通俗點說就是講序列化過程生成的二進位制串轉換成資料結構或者物件的過程。

② .為什麼要使用序列化?


I、 在分散式系統中,物件是在網路上傳輸,就得把物件資料轉換成二進位制形式,需要共享的資料的javabean物件,這就需要使用序列化

③ 序列化的過程:
I、 需要序列化的物件的類,必須實現序列化介面:java.lang.Serializable,大多數類都實現了該介面,比如string、integer。
II、 在java中使用物件流來完成序列化和反序列化
ObjectoutputStream 通過writeObject做序列化
ObjectInputStream 通過readObject做反序列化

具體方法在https://blog.csdn.net/nb7474/article/details/79644777

第七題

4.現有employee 表,表中有 員工編號(id) 員工年齡(age) 員工工資(salary) 員工部門(deptid), 按要求用一條SQL語句完成
①查出各個部門高於部門平均工資的員工名單
Select ta.* from employee ta,
(select deptia,avg(salary) avgsal from employee group by deptid) tb
Where ta.deptid=tb.deptid and ta.salary>tb.avgsal

②列出各個部門中工資高於本部門的平均工資的員工數和部門號,並按部門號排序
Select ta.deptid,count(*) as ‘人數’ from employee ta,
(select deptid,avg(salary) avgsal from employee group by deptid) tb
Where ta.deptid=tb.deptid and ta.salary>tb.avgsal group by ta.deptid order by ta.deptid

③ 求每個部門工資不小於6000的人員的平均值
Select avg(salary) as ‘平均值’,deptid from employee where salary>=6000 GROUP BY dept_id

④ 各部門在各年齡段的平均工資
Select deptid
Sum(case when age<20 then salary else 0 end )/sum (case when age < 20 then 1 else 0 end) as “20歲以下平均工資”,
Sum (case when age >= 20 ande age <40 then salary else 0 end)/sum(case when age >=20 and age<40 then 1 else 0 end) as “20至40歲平均工資”,
From employee
Group by deptid

5.abstract和native方法的區別?

Native本地方法,這種方法和抽象方法類似,只有方法宣告沒有方法實現,但是與抽象方法不同的是,它吧具體具體實現移交給了本地系統的函式庫,沒有通過虛擬機器,可以說是java與其它語言通訊的一種機制。
Abstract是抽象的,指的是方法只有宣告沒有實現,他的實現要方式宣告該類的子類中實現。
抽象方法都是不可以與private、static、final和native一起使用的,因為抽象方法都是要子類來實現的。

Abstract與介面的區別:https://blog.csdn.net/jackzhouyu/article/details/52699682

6, 類載入的生命週期?
首先我們所說的類載入指的是類的生命週期中載入、連線、初始化三個階段。
① 載入:查詢並載入類的二進位制資料。找到要載入的類並把類的資訊載入到jvm的方法區中,然後再堆區例項化畫一個java.lang.class物件,作為方法區中這個類的資訊的入口。
常用的類的載入方式有兩種:
I、 根據類的全路徑名找到相應的class檔案,從class檔案中讀取檔案內容。
II、 另一種是從jar檔案中讀取。

② 連線:一般會跟載入階段和初始化階段交叉進行,主要做一些載入後的驗證工作,和一些初始化前的準備工作,分為:

I、驗證:保證載入的類能夠被jvm所執行

II、準備:為類的靜態變數分配記憶體並設預設的初值。基本型別(int、long、short、char、byte、boolean、float、double)的預設值為0,引用型別的預設值為null,常量的預設值為設定的值,如final static int a=100,則初值就是100。

III、 解析:把常量池中的符號引用轉換為直接引用,在這階段,jvm會將所有的類或介面名、欄位名、方法名轉換為具體的記憶體地址。比如我們要在記憶體中找一個show方法,在解析階段,jvm會把show這個名字轉換為指向方法區的一塊記憶體地址,比如c1716,通過c1716可以找到這show這個方法。Show就是符號引用,c1617就是直接引用。

③ 初始化:如果一個類被直接引用,就會觸發類的初始化。在java中,直接引用的情況有:

I、 new關鍵字例項化物件、讀取或設定類的靜態變數、呼叫類的靜態方法

II、 通過反射方式執行以上三種行為。

III、 初始化子類的時候,會觸發父類的初始化

IV、 作為程式入口直接執行,即直接呼叫main方法
除了以上四種情況,其他使用類的方式叫被動引用,不會觸發類的初始化。

7, arrayList的擴容方式?

首先擴容機制:當向ArrayList中新增元素的時候,ArrayList如果要滿足新元素的儲存超過ArrayList儲存新元素前的儲存能力,ArrayList會增強自身的儲存能力,以達到儲存新元素的要求。

ArrayList通過內部維護的陣列物件進行資料儲存。
以jdl1.7舉例
① :分析ArrayList的add(e)方法

public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!!
 elementData[size++] = e; return true; }

通過ensureCapacityInternal()方法確保當前ArrayList維護的陣列具有儲存新元素的能力,經過處理後將元素儲存在陣列elementData的尾部。elementData是ArrayList真正用於儲存元素的陣列。

② :分析ensureCapacityInternal方法

private void ensureCapacityInternal(int paramInt)
  {
    if (elementData == EMPTY_ELEMENTDATA) {
      paramInt = Math.max(10, paramInt);
    }
    ensureExplicitCapacity(paramInt);
  }

ensureCapacityInternal判斷ArrayList預設的元素儲存資料是否為空,為空則設定最小要求的儲存能力為10和傳遞過來需要儲存的元素個數之間的最大值,然後呼叫ensureExplicitCapacity方法實現這種最低要求的儲存能力。

③:分析ensureExplicitCapacity方法:

private void ensureExplicitCapacity(int paramInt)
  {
    modCount += 1;
    if (paramInt - elementData.length > 0) {
      grow(paramInt);
    }
  }

④:分析grow方法:

private void grow(int paramInt)
  {
    int i = elementData.length;
    int j = i + (i >> 1);
    if (j - paramInt < 0) {
      j = paramInt;
    }
    if (j - 2147483639 > 0) {
      j = hugeCapacity(paramInt);
    }
    elementData = Arrays.copyOf(elementData, j);
  }

執行擴容操作的時候會設定新的儲存能力為原來的1.5倍,如果擴容之後還是不能滿足需求,會執行hugeCapacity()方法獲取ArrayList能允許的最大值。

⑤:分析hugeCapacity()方法:

private static int hugeCapacity(int paramInt)
  {
    if (paramInt < 0) {
      throw new OutOfMemoryError();
    }
    return paramInt > 2147483639 ? Integer.MAX_VALUE : 2147483639;
  }

在確定ArrayList擴容後最新的可儲存元素的個數時,呼叫elementData = Arrays.copyOf(elementData, j);實現最終的擴容。

8, spring事務的優點?

在以往的jdbcTemplate中事務提交成功,異常處理是通過try/catch實現的。
Hibernate中事務管理是通過sessionFactory建立和維護session來完成。

在spring中集成了transactionTemplate,封裝了所有對事物處理的功能,包括異常時事務回滾,操作成功時資料提交等複雜業務功能。對sessionFactory配置也進行了整合,都是有spring容器來管理,大大減少了程式設計師的程式碼量。避免了每次對資料操作都要獲取session例項來啟動事務、提交、回滾事務還有複雜的try/catch。使開發業務邏輯更清晰、降低了程式的耦合性使我們可以在不同的應用中將各個切面結合起來使用提高了程式碼重用度。

9, getParameter和getAttribute的區別?

① getAttribute表示從request範圍取得設定的屬性,必須要先setAttribute設定屬性。設定與取得的都是Object物件型別getParameter表示接收引數,引數為頁面提交的引數,包括:表單提交的引數、URL重寫(就是xxx?id=1)傳的引數,沒有setParameter的方法,接收的引數型別是string

② request.getParameter方法傳遞的資料,會從web客戶端傳到web伺服器端,代表HTTP請求的資料getAttribute傳遞的資料只會存在於web容器內部,在具有轉發關係的web元件之間共享。返回的是request範圍內存在的物件

③ getParameter取得的是通過容器的實現來取得通過類似post,get等方式傳入的資料,getAttribute只在web容器內部流轉,僅僅是請求處理階段

10, onload()和ready()的區別?

$(document).ready()和window.onload在表面上看都是頁面載入時候我們就去執行一個函式或動作,但是有幾個基本的區別:

① 執行時間:window.onload必須等到頁面內包括圖片的所有元素載入完畢後才能執行。$(document).ready()是dom結構繪製完畢後就執行,不必等到載入完畢

② 編寫個數不同:window.onload不能同時編寫多個,如果有多個window.onload方法,只能執行一個。$(document).ready()可以同時編寫多個,並且都能得到執行

③ 簡化寫法:
window.onload沒有簡化寫法 (document).ready(function()) (function(){})需要注意的一點: 由於在$(document).ready()方法內註冊的時間,只要DOM就緒就會被執行,因此可能此時元素的關聯檔案未下載完。例如與圖片有關的html下載完畢,並且已經解析為DOM樹了,但很有可能圖片還未載入完畢,所以例如圖片的高度和寬度這樣的屬性此時不一定生效。要解決這種問題,可以使用JQuery中另一個關於頁面載入的方法-load()。Load方法會在元素的onload時間中繫結一個處理函式,如果處理函式繫結給window物件,則會在所有內容載入完畢後觸發,如果繫結在元素上,則會在元素的內載入完畢後觸發。

$(window).load(function(){ } ) 等價於js中的window.onload=funciton(){ }

11、 SpringMVC 怎麼新增過濾使得避免空指標?
這個最後才知道可以在javabean上設定註解設定這個欄位不能為空.

12, 如何通過反射去呼叫一個類的私有方法?
這個是需要setAccessible()方法來抑制Java訪問許可權的檢查的, 詳見:https://blog.csdn.net/nb7474/article/details/79679629

13, 你對Spirng的理解?
Spring相對於ejb來說是一個輕量級的DI和AOP容器框架
在spring中的主要核心有兩點:

① 控制反轉(IOC)

控制反轉意思就是物件的建立不通過手動new,而是把物件的建立權交給Spring來完成。接著便是依賴注入(DI),在容器例項化物件的時候主動將他的依賴物件注入給呼叫物件。
Spring的IOC有三種注入方式:I、根據屬性注入,也叫set方法注入
II、根據構造方法進行注入
III、根據註解進行注入,bean多的情況下,前兩種方法會過於臃腫

② 面向切面程式設計(AOP)

給目標物件的目標方法新增一些額外的功能,將業務中必須的卻又與核心業務無關的功能(如許可權、日誌、事務等功能)獨立出去,定義到切面中。好處就是層級清晰便於拓展維護。
比如:每對資料庫進行一次操作,都要生成一條體質,如果對資料庫的操作有很多類,那麼每一類都要寫關於日誌的方法。如果用aop,那麼可以寫一個方法,在這個方法中有關於資料庫操作的方法,每呼叫一次這個方法,就加上生成日誌的操作。
Spring的優點:解決系統程式碼耦合度過高的問題,易於維護。

14.List和Array的區別?

①相似之處:
I、都可以表示一組同類型的物件
II、都可以用下標進行索引
②不同之處:
I、陣列可以存任何型別的元素,list不可以存基本資料型別的元素,必須要包裝。(Java集合如Map、Set、List等所有集合只能存放引用型別資料,實際存放的只是物件的引用,想把基本資料型別存入集合中,直接存就可以了,系統會自動將其裝箱成封裝類,然後加入到集合當中)
II、陣列容量固定不可改變;List 容量可動態增長。
III、陣列效率高; List 由於要維護額外內容,效率相對低一些。

容量固定時優先使用陣列,容納型別更多,更高效。
在容量不確定的情景下, List 更有優勢。