對象被多個用戶共用仍要編譯嗎
A. 一個關於java的問題,如果成員屬性i 被static修飾,i屬性被多個對象共用共用的話,static屬性i 在內存中
靜態是屬於類的,比如你使用不同的對象操縱相同的非靜態函數,其參數或者操作結果是分開的,也就是你說的不同的內存地址,而如果是靜態函數,那就是相同的,也就是說,靜態的東西是類下面所有的對象共有的,好像地球是靜態的,是屬於人類這個類的,而類中的每一個對象「人」對地球做一個什麼事情,其他的對象也同時會得到反饋,而電腦不是靜態的,每個人都有一部,你家的電腦壞了,別人家的沒事
屬性也是一樣
B. 目標被多個用戶共用,仍然編寫嗎
你說的這個被大家調用的對象他始終都是同一內存地址,所謂多線程,其實還是一個單線程,只是幾個線程方法的級別一樣高,所以執行一會這個再執行一會其它線程。就好像有一碗粥,三個人分,單線程的情況下可能第一個人都給吃完了,二三個人沒有的吃了,如果多線程的話,一人一口,輪著吃,大家都有吃到的機會了。但是粥始終是那一碗粥。
線程的生命周期java基礎的書上都有寫。
不知道我說的你能明白不。
哦,對,你說的這個一個對象被多個線程調用,如果線程做了休眠或者其它的處理,還可能還存在死鎖的問題。出現無法執行的現象
C. java對象調用靜態方法為什麼會增加編譯成本
不管是靜態方法還是非靜態方法,都需要調用後執行,也就是聲明的時候只是在棧內存中存了一個引用,堆內存中並沒有分配存儲空間,執行的時候才載入到堆內存中...
其執行的次序和在類里聲明的次序無關,區別是靜態方法是「class.method"方式執行,非靜態方法是"object.method"方式執行,即後者需要創建一個對象。
所以就有一個問題,對象是執行的時候才真正載入到內存中去,但是非靜態方法執行後,若不會再使用則會被垃圾回收器回收,釋放內存
而靜態方法載入且只載入一次,所有對象都共用這獨一份,因此會一直放在內存中,消耗內存資源...
D. Java創建對象是在編譯時還是在運行時
運行期。編譯好的java程序(即.class文件)需要運行在JVM中。程序,無論代碼還是數據,都需要存儲在內存中。JVM為java程序提供並管理所需要的內存空間。JVM內存分為"堆"、"棧"、"方法區"三個區域,分別用於存儲不同數據。首先JVM會檢查創建這個對象的類是否是一個以前從沒有見過的類型,如果不是,JVM將為其分配內存,如果是,java虛擬機將調用具體的ClassLoader找到對應的.class文件,並將這個文件的內容讀到內存中去。
1)堆:
1.1)用於存儲所有new出來的對象(包括成員變數)。
1.2)垃圾:沒有任何引用所指向的對象。
垃圾回收器(GC)不定時到內存中清掃垃圾,
並不一定一發現垃圾就立刻回收,
回收過程是透明的(看不到的),
通過調用System.gc()可以建議虛擬機盡快調度GC來回收。
1.3)內存泄漏:不再使用的內存沒有被及時的回收。
建議:不再使用的對象,及時將引用設置為null。
1.4)成員變數的生命周期:
創建對象時存儲在堆中,對象被回收時一並被回收。
2)棧:
2.1)用於存儲正在調用的方法中的所有局部變數(包括參數)
2.2)JVM會為每一個正在調用的方法分配一塊對應的棧幀,
棧幀中存儲方法中的局部變數(包括參數),
方法調用結束時,棧幀被清除,局部變數一並被清除。
2.3)局部變數的生命周期:
調用方法時存在棧中,方法結束時與棧幀一並被清除。
3)方法區:
3.1)用於存儲.class位元組碼文件(包括方法)。
3.2)方法只有一份,通過this來區分具體的對象。
既然對象在堆中創建,因此Java創建對象是在運行時,而不是編譯時。
E. C++這里構造函數帶有形參,建立對象沒有給出初始值,但編譯器沒有提示出錯,為什麼
不會的。
c++類的構造函數詳解
一、構造函數是干什麼的
classCounter
{
public:
//類Counter的構造函數
//特點:以類名作為函數名,無返回類型
Counter()
{
m_value=0;
}
private:
//數據成員
intm_value;
}
該類對象被創建時,編譯系統對象分配內存空間,並自動調用該構造函數->由構造函數完成成員的初始化工作
eg:Counterc1;
編譯系統為對象c1的每個數據成員(m_value)分配內存空間,並調用構造函數Counter()自動地初始化對象c1的m_value值設置為0
故:
構造函數的作用:初始化對象的數據成員。
二、構造函數的種類
classComplex
{
private:
doublem_real;
doublem_imag;
public:
//無參數構造函數
//如果創建一個類你沒有寫任何構造函數,則系統會自動生成默認的無參構造函數,函數為空,什麼都不做
//只要你寫了一個下面的某一種構造函數,系統就不會再自動生成這樣一個默認的構造函數,如果希望有一個這樣的無參構造函數,則需要自己顯示地寫出來
Complex(void)
{
m_real=0.0;
m_imag=0.0;
}
//一般構造函數(也稱重載構造函數)
//一般構造函數可以有各種參數形式,一個類可以有多個一般構造函數,前提是參數的個數或者類型不同(基於c++的重載函數原理)
//例如:你還可以寫一個Complex(intnum)的構造函數出來
//創建對象時根據傳入的參數不同調用不同的構造函數
Complex(doublereal,doubleimag)
{
m_real=real;
m_imag=imag;
}
//復制構造函數(也稱為拷貝構造函數)
//復制構造函數參數為類對象本身的引用,用於根據一個已存在的對象復制出一個新的該類的對象,一般在函數中會將已存在對象的數據成員的值復制一份到新創建的對象中
//若沒有顯示的寫復制構造函數,則系統會默認創建一個復制構造函數,但當類中有指針成員時,由系統默認創建該復制構造函數會存在風險,具體原因請查詢有關「淺拷貝」、「深拷貝」的文章論述
Complex(constComplex&c)
{
//將對象c中的數據成員值復制過來
m_real=c.m_real;
m_img=c.m_img;
}
//類型轉換構造函數,根據一個指定的類型的對象創建一個本類的對象
//例如:下面將根據一個double類型的對象創建了一個Complex對象
Complex::Complex(doubler)
{
m_real=r;
m_imag=0.0;
}
//等號運算符重載
//注意,這個類似復制構造函數,將=右邊的本類對象的值復制給等號左邊的對象,它不屬於構造函數,等號左右兩邊的對象必須已經被創建
//若沒有顯示的寫=運算符重載,則系統也會創建一個默認的=運算符重載,只做一些基本的拷貝工作
Complex&operator=(constComplex&rhs)
{
//首先檢測等號右邊的是否就是左邊的對象本,若是本對象本身,則直接返回
if(this==&rhs)
{
return*this;
}
//復制等號右邊的成員到左邊的對象中
this->m_real=rhs.m_real;
this->m_imag=rhs.m_imag;
//把等號左邊的對象再次傳出
//目的是為了支持連等eg:a=b=c系統首先運行b=c
//然後運行a=(b=c的返回值,這里應該是復制c值後的b對象)
return*this;
}
};
下面使用上面定義的類對象來說明各個構造函數的用法:
voidmain()
{
//調用了無參構造函數,數據成員初值被賦為0.0
Complexc1,c2;
//調用一般構造函數,數據成員初值被賦為指定值
Complexc3(1.0,2.5);
//也可以使用下面的形式
Complexc3=Complex(1.0,2.5);
//把c3的數據成員的值賦值給c1
//由於c1已經事先被創建,故此處不會調用任何構造函數
//只會調用=號運算符重載函數
c1=c3;
//調用類型轉換構造函數
//系統首先調用類型轉換構造函數,將5.2創建為一個本類的臨時對象,然後調用等號運算符重載,將該臨時對象賦值給c1
c2=5.2;
//調用拷貝構造函數(有下面兩種調用方式)
Complexc5(c2);
Complexc4=c2;//注意和=運算符重載區分,這里等號左邊的對象不是事先已經創建,故需要調用拷貝構造函數,參數為c2
}
F. 用戶管理系統 - 用戶許可權設計(RBAC模型)
許可權管控可以通俗的理解為權力限制,即不同的人由於擁有不同權力,他所看到的、能使用的可能不一樣。對應到一個應用系統,其實就是一個用戶可能擁有不同的數據許可權(看到的)和操作許可權(使用的)。
Access Control List,ACL是最早的、最基本的一種訪問控制機制,是基於客體進行控制的模型,在其他模型中也有ACL的身影。為了解決相同許可權的用戶挨個配置的問題,後來也採用了用戶組的方式。
原理:每一個客體都有一個列表,列表中記錄的是哪些主體可以對這個客體做哪些行為,非常簡單。
例如:當用戶A要對一篇文章進行編輯時,ACL會先檢查一下文章編輯功能的控制列表中有沒有用戶A,有就可以編輯,無則不能編輯。再例如:不同等級的會員在產品中可使用的功能范圍不同。
缺點:當主體的數量較多時,配置和維護工作就會成本大、易出錯。
Discretionary Access Control,DAC是ACL的一種拓展。
原理:在ACL模型的基礎上,允許主體可以將自己擁有的許可權自主地授予其他主體,所以許可權可以任意傳遞。
例如:常見於文件系統,linux,UNIX、WindowsNT版本的操作系統都提供DAC的支持。
缺點:對許可權控制比較分散,例如無法簡單地將一組文件設置統一的許可權開放給指定的一群用戶。主體的許可權太大,無意間就可能泄露信息。
Mandatory Access Control,MAC模型中主要的是雙向驗證機制。常見於機密機構或者其他等級觀念強烈的行業,如軍用和市政安全領域的軟體。
原理:主體有一個許可權標識,客體也有一個許可權標識,而主體能否對該客體進行操作取決於雙方的許可權標識的關系。
例如:將軍分為上將>中將>少將,軍事文件保密等級分為絕密>機密>秘密,規定不同軍銜僅能訪問不同保密等級的文件,如少將只能訪問秘密文件;當某一賬號訪問某一文件時,系統會驗證賬號的軍銜,也驗證文件的保密等級,當軍銜和保密等級相對應時才可以訪問。
缺點:控制太嚴格,實現工作量大,缺乏靈活性。
(Attribute-Based Access Control),能很好地解決RBAC的缺點,在新增資源時容易維護。
原理:通過動態計算一個或一組屬性是否滿足某種機制來授權,是一種很靈活的許可權模型,可以按需實現不同顆粒度的許可權控制。
屬性通常有四類:
例如:早上9:00 11:00期間A、B兩個部門一起以考生的身份考試,下午14:00 17:00期間A、B兩個部門相互閱卷。
缺點:規則復雜,不易看出主體與客體之間的關系,實現非常難,現在應用的很少。
RBAC的核心在於用戶只和角色關聯,而角色代表對了許可權,是一系列許可權的集合。
RBAC三要素:
在RBAC中,許可權與角色相關聯,用戶通過成為適當角色的成員而得到這些角色的許可權。角色是為了完成各種工作而創造,用戶則依據它的責任和資格來被指派相應的角色,用戶可以很容易地從一個角色被指派到另一個角色。角色可依新的需求和系統的合並而賦予新的許可權,而許可權也可根據需要而從某角色中回收。角色與角色的關系同樣也存在繼承關系防止越權。
RBAC模型可以分為:RBAC 0、RBAC 1、RBAC 2、RBAC 3 四個階段,一般公司使用RBAC0的模型就可以。另外,RBAC 0相當於底層邏輯,後三者都是在RBAC 0模型上的拔高。
我先簡單介紹下這四個RBAC模型:
RBAC 0模型: 用戶和角色、角色和許可權多對多關系。
簡單來說就是一個用戶擁有多個角色,一個角色可以被多個用戶擁有,這是用戶和角色的多對多關系;同樣的,角色和許可權也是如此。
RBAC 0模型如下圖:沒有畫太多線,但是已經能夠看出多對多關系。
RBAC 1模型: 相對於RBAC 0模型,增加了角色分級的邏輯,類似於樹形結構,下一節點繼承上一節點的所有許可權,如role1根節點下有role1.1和role1.2兩個子節點。
角色分級的邏輯可以有效的規范角色創建(主要得益於許可權繼承邏輯),我之前做過BD工具(類CRM),BD之間就有分級(經理、主管、專員),如果採用RBAC 0模型做許可權系統,我可能需要為經理、主管、專員分別創建一個角色(角色之間許可權無繼承性),極有可能出現一個問題,由於許可權配置錯誤,主管擁有經理都沒有許可權。
而RBAC 1模型就很好解決了這個問題,創建完經理角色並配置好許可權後,主管角色的許可權繼承經理角色的許可權,並且支持針對性刪減主管許可權。
RBAC 1模型如下圖:多對多關系仍舊沒有改變,只增加角色分級邏輯。
[圖片上傳中...(-95cc0-1640060170347-0)]
RBAC 2模型: 基於RBAC 0模型,對角色增加了更多約束條件。
如角色互斥,比較經典的案例是財務系統中出納不得兼管稽核,那麼在賦予財務系統操作人員角色時,同一個操作員不能同時擁有出納和稽核兩個角色。
如角色數量限制,例如:一個角色專門為公司CEO創建的,最後發現公司有10個人擁有CEO角色,一個公司有10個CEO?
這就是對角色數量的限制,它指的是有多少用戶能擁有這個角色。
RBAC 2 模型主要是為了增加角色賦予的限制條件,這也符合許可權系統的目標:權責明確,系統使用安全、保密。
RBAC 3模型: 同樣是基於RBAC0模型,但是綜合了RBAC 1和RBAC 2的所有特點。這里就不在多描述,讀者返回去看RBAC 1和RBAC 2模型的描述即可。
RBAC 許可權模型由三大部分構成,即用戶管理、角色管理、許可權管理。用戶管理按照企業架構或業務線架構來劃分,這些結構本身比較清晰,擴展性和可讀性都非常好。角色管理一定要在深入理解業務邏輯後再來設計,一般使用各部門真實的角色作為基礎,再根據業務邏輯進行擴展。許可權管理是前兩種管理的再加固,做太細容易太碎片,做太粗又不夠安全,這里我們需要根據經驗和實際情況來設計。
用戶管理中的用戶,是企業里每一位員工,他們本身就有自己的組織架構,我們可以直接使用企業部門架構或者業務線架構來作為線索,構建用戶管理系統。
需要特殊注意:
實際業務中的組織架構可能與企業部門架構、業務線架構不同,需要考慮數據共享機制,一般的做法為授權某個人、某個角色組共享某個組織層級的某個對象組數據。
在設計系統角色時,我們應該深入理解公司架構、業務架構後,再根據需求設計角色及角色內的等級。一般角色相對於用戶來說是固定不變的,每個角色都有自己明確的許可權和限制,這些許可權在系統設計之處就確定了,之後也輕易不會再變動。
(1)自動獲得基礎角色
當員工入職到某部門時,該名員工的賬號應該自動被加入該部門對應的基礎角色中,並擁有對應的基礎許可權。這種操作是為了保證系統安全的前提下,減少了管理員大量手動操作。使新入職員工能快速使用系統,提高工作效率。
(2)臨時角色與失效時間
公司業務有時需要外援來支持,他們並不屬於公司員工,也只是在某個時段在公司做支持。此時我們需要設置臨時角色,來應對這種可能跨多部門協作的臨時員工。
如果公司安全級別較高,此類賬號默認有固定失效時間,到達失效時間需再次審核才能重新開啟。避免臨時賬號因為流程不完善,遺忘在系統中,引起安全隱患。
(3)虛擬角色
部門角色中的等級,可以授權同等級的員工擁有相同的許可權,但某些員工因工作原因,需要調用角色等級之外的許可權,相同等級不同員工需要使用的許可權還不相同。這種超出角色等級又合理的許可權授予,我們可以設置虛擬角色。這一虛擬角色可集成這一工作所需的所有許可權,然後將它賦予具體的員工即可。這樣即不用調整組織架構和對應的角色,也可以滿足工作中特殊情況的許可權需求。
(4)黑白名單
白名單:某些用戶自身不擁有某部門的頂級角色,但處於業務需求,需要給他角色外的高級許可權,那麼我們可以設計限制范圍的白名單,將需要的用戶添加進去即可。在安全流程中,我們僅需要對白名單設計安全流程,即可審核在白名單中的特殊用戶,做到監控擁有特殊許可權的用戶,減少安全隱患。
黑名單:比較常見的黑名單場景是某些犯了錯誤的員工,雖然在職,但已經不能給他們任何公司許可權了。這種既不能取消角色關聯,也不能完全停用賬號的情況,可以設置黑名單,讓此類用戶可以登錄賬號,查看基本信息,但大多數關鍵許可權已經被黑名單限制。
許可權管理一般從三個方面來做限制。頁面/菜單許可權,操作許可權,數據許可權。
(1)頁面/菜單許可權
對於沒有許可權操作的用戶,直接隱藏對應的頁面入口或菜單選項。這種方法簡單快捷直接,對於一些安全不太敏感的許可權,使用這種方式非常高效。
(2)操作許可權
操作許可權通常是指對同一組數據,不同的用戶是否可以增刪改查。對某些用戶來說是只讀瀏覽數據,對某些用戶來說是可編輯的數據。
(3)數據許可權
對於安全需求高的許可權管理,僅從前端限制隱藏菜單,隱藏編輯按鈕是不夠的,還需要在數介面上做限制。如果用戶試圖通過非法手段編輯不屬於自己許可權下的數據,伺服器端會識別、記錄並限制訪問。
數據許可權如何管控
數據許可權可以分為行許可權和列許可權。行許可權控制:看多少條數據。列許可權控制:看一條數據的多少個欄位
簡單系統中可以通過組織架構來管控行許可權,按照角色來配置列許可權,但是遇到復雜情況,組織架構是承載不了復雜行許可權管控,角色也更不能承載列的特殊化展示。
目前行業的做法是提供行列級數據權規則配置,把規則當成類似許可權點配置賦予某個角色或者某個用戶。
網易有數做法:
https://youdata.163.com/index/manual/o/6System_management/data_role.html
1.超級管理員
超級管理員是用來啟動系統,配置系統的賬號。這個賬號應該在配置好系統,創建管理員之後被隱藏起來。超級管理員賬號擁有系統中全部許可權,可穿梭查看各部門數據,如果使用不恰當,是系統管理的安全隱患。
2.互斥角色如何處理
當用戶已經有用的角色和即將添加的角色互相互斥時,應該在添加新角色時,提示管理員因角色互斥的原因,無法進行新角色添加。如需添加,要先撤銷掉前一個角色,再添加新角色。
3.用戶管理許可權系統設計一定要簡單清晰
在設計許可權系統之處,一定要理清思路,一切從簡,能不增加的多餘角色和許可權邏輯,就一定不要增加。因為隨著公司業務的擴大,許可權和角色也會隨之增多,如果初期設計思路不嚴謹,那麼許可權系統會隨著業務的擴大而無限混亂下去,此時再來整理許可權,已經太晚了。所以初期設計就一定要條理清晰,簡單明了,能避免後續非常多不必要的麻煩。
4.無權提示頁
有時員工 A 會直接給員工 B 分享他當下正在操作的頁面,但有可能員工 B 無權查看。此時我們應該在這里考慮添加「無權提示頁」,避免粗暴的 404 頁面讓員工 B 以為是系統出錯了。
G. 請問高手!
EJB
中科永聯高級技術培訓中心(www.itise.com)
EJB (Enterprise JavaBean)是J2EE的一部分,定義了一個用於開發基於組件的企業多重應用程序的標准。其特點包括網路服務支持和核心開發工具(SDK)。
在J2EE里,Enterprise Java Beans(EJB)稱為Java 企業柄,是Java的核心代碼,分為整體柄和片段柄和消息柄三個部分,其中的消息柄將在以後再作討論。現在我們來看看什麼是整體柄和片段柄。
整體柄是一種對象: 標准Java對象由創建它的程序創建,當程序終止時,對象也隨之丟失,這就意味著當再次運行些程序時,將無法找到先前創建的柄,而整體柄會一直存在著直到它被刪除。 一個程序可以創建一個整體柄,並且這個程序可以在被保存後隨時停止和重啟。整體柄將會依然存在。重啟後,程序可以找到與之相對應的整體柄,並且會繼續使用這個整體柄。
EJB實際上是SUN的J2EE中的一套規范,並且規定了一系列的API用來實現把EJB概念轉換成EJB產品.EJB是BEANS,BEANS是什麼概念,那就是得有一個容納她,讓她可勁造騰的地方,就是得有容器.EJB必須生存在EJB容器中.這個容器可是功能強大之極!她首先要包裝你BEAN,EJB的客戶程序實際上從來就不和你編寫的EJB直接打交道,他們之間是通過HOME/REMOTE介面來發生關系的.它負責你的BEAN的所有的吃喝拉薩睡,比如BEAN的持續化,安全性,事務管理...
一.什麼是 EJB?
一個技術規范:EJB 從技術上而言不是一種"產品"
EJB 是一種標准描述了構建應用組件要解決的:
可擴展 (Scalable)
分布式 (Distributed)
事務處理 (Transactional)
數據存儲 (Persistent)
安全性 (Secure)
二.Sun 對 EJB 的期望
提供一個標準的分布的、基於 OO 的組件架構
屏蔽復雜的系統級功能需求
Write once, run anywhere
與非 Java 應用之間的互操作能力
兼容 CORBA 標准
三.為什麼選擇 EJB?
EJB 伺服器完成"繁雜"的工作:應用開發人員關注於業務邏輯的實現而不是底層的實現機制(類似於 4GL 語言設計的目標)
支持事務處理
多個業務操作同時成功,或全部失敗
可以通過在代碼外的描述來定義事務處理級別
可擴展性
EJB 可以根據您應用的增長而擴展
EJB 伺服器往往還提供了負載均衡和
安全性:由 EJB 伺服器提供資源的訪問許可權控制
四.EJB 架構
為了滿足架構的目標,規范中描述了
伺服器 (Server)
容器 (Container)
類 (Class) 和實例 (Instance)
Home 和 Remote 介面
客戶端 (Client)
五. 簡化的編程模型
關注於業務邏輯實現:EJB 負責生命周期 (lifecycle), 數據存儲 (persistence), 事務處理語義 (transactional semantic), 安全(security), ...
通用的編程模型:各種服務的高層 API
Java 是其編程語言
1.EJB 特點
由一個 EJB 容器在運行時創建和管理 EJB
在部署 EJB 時定製其運行方式
由 EJB 容器和伺服器來協調客戶端的訪問
可以部署到任何兼容的 EJB 容器中
客戶端對 EJB 的視圖是由 Bean 開發人員決定的
2.EJB 伺服器
管理 EJB 容器 (它管理 Bean)
提供對操作系統服務的存取
提供 Java 相關的服務,尤其是
通過 JNDI 訪問命名空間
基於 OTS 的事務處理服務
3.EJB 容器
管理 Bean 生命周期:將 EJB 伺服器提供的服務傳遞給 Bean
生成代碼來實現對 Bean 的存取訪問
強制事務處理的限制
創建、初始化和回收 Bean
管理持久數據的存儲
對客戶端而言 EJB 容器是透明的
4.在一個 EJB 伺服器中的容器
目前容器通常是由 EJB 伺服器本身提供的
在 EJB 1.0 或 1.1 規范中沒有定義容器-到-伺服器的介面
各廠商可以根據他們的見解來實現伺服器和容器的各自責任
5.容器提供服務: 數據存儲
容器決定何時載入/儲存狀態
Container-Managed Persistence(容器管理存儲/CMP)
容器負責存儲您的 Bean
容器生成必要的類和代碼
Bean-Managed Persistence(Bean 管理存儲/BMP)
Bean 開發人員提供存儲代碼
開發人員決定 如何存儲, 容器仍然決定 何時進行
6.容器提供服務: 事務處理
可以由容器代理來實現
容器將得到業務邏輯方法的事務處理需求
容器提供事務控制代碼
也可以由程序員通過代碼實現
7.容器提供服務: 其它服務
其它服務包括
命名 (Naming)
安全 (Security)
線程管理 (Thread management)
這些服務由容器代理完成將減少應用開發人員的負擔
8.分布式對象運算
遠程對象被作為本地對象來處理:傳遞信息的方式不變,但開銷更大
Enterprise JavaBeans 永遠運行在伺服器上:對 Bean 的訪問永遠是遠程調用
9.Stub 和 Skeleton
由 EJB 生成:
"Stub" 對要傳遞出去的信息編碼
"Tie/Skel" 將接受到的信息解碼並傳遞給目標對象
10.分類: Enterprise JavaBeans
+---Entity Beans--CMP/BMP
Ejb--|
+---Session Beans--Stateful/Stateless
會話 Bean (Session Bean):根據 EJB 規范,一個會話 Bean 是:
代表單個客戶端來執行
可以參與到事務處理中
不直接代表共享於資料庫中的數據,但它能訪問和更新這些數據
相對而言是短暫存在的
當 EJB 容器失效後就不存在---客戶端需要重新建立一個信新的會話對象來繼續運算
實體 Bean (Entity Bean):根據 EJB 規范,一個實體 Bean 是:
提供在資料庫中數據的對象視圖
允許被多個用戶共享存取訪問
可以是長期存在 (只要它存在於資料庫中)
實體 Bean, 它的主鍵對象, 以及它的遠程引用將能跨 EJB 容器的宕機而存在
11.EJB 類和實例
構建 EJB 應用包括來自三方的代碼
開發人員編寫的代碼
由 EJB API 定義的類和介面
由容器自動生成的代碼
開發人員編寫的代碼包括
Bean 類 (定義了業務邏輯)
Home 介面 (如何查找或創建 bean)
Remote 介面 (如何存取 bean)
其它組件,根據 bean 實際要求
12.EJB Home 介面
每個 bean 有一個
用於:創建新的 bean 實例、查找現存的 bean (只能是實體 bean)
Remote 介面:定義 bean 的公共介面---只有在 Remote 介面中定義的方法才能被客戶端訪問
EJB 客戶端
可以為 servlet, JSP, 應用程序或其它 bean
通過 JNDI 來查找 EJB home 介面,步驟為:
創建一個 JNDI Context (initial context)
使用 JNDI Context 來查找 bean home 介面
使用 bean home 介面來創建/查找 bean 實例
使用 bean 實例完成業務操作
實際的存取 (對 EJB) 是通過容器生成的類來完成
EJB 架構
客戶端對 bean 訪問永遠不是直接的
EJBObject (tie) 是由容器自身提供的:用來幫助管理 bean 的生命周期
EJB 中的角色
EJB 伺服器供應商: 開發並銷售 EJB 伺服器
EJB 容器供應商: 開發並銷售 EJB 容器
Enterprise bean 開發人員: 開發並銷售 EJB
應用組裝人員: 將不同的 EJB 搭建成應用
六、EJB的體系結構
目前,EJB最新的標準是2.1,EJB3.0規范正在討論中,預計將於明年推出。EJB2.1定義了三種企業Bean,分別是會話Bean(Session Bean),實體Bean(Entity Bean)和消息驅動Bean(MessageDriven Bean)。
Session Bean用於實現業務邏輯,它可以是有狀態的,也可以是無狀態的。每當客戶端請求時,容器就會選擇一個Session Bean來為客戶端服務。Session Bean可以直接訪問資料庫,但更多時候,它會通過Entity Bean實現數據訪問。
Entity Bean是域模型對象,用於實現O/R映射,負責將資料庫中的表記錄映射為內存中的Entity對象,事實上,創建一個Entity Bean對象相當於新建一條記錄,刪除一個Entity Bean會同時從資料庫中刪除對應記錄,修改一個Entity Bean時,容器會自動將Entity Bean的狀態和資料庫同步。
MessageDriven Bean是EJB2.0中引入的新的企業Bean,它基於JMS消息,只能接收客戶端發送的JMS消息然後處理。MDB實際上是一個非同步的無狀態Session Bean,客戶端調用MDB後無需等待,立刻返回,MDB將非同步處理客戶請求。這適合於需要非同步處理請求的場合,比如訂單處理,這樣就能避免客戶端長時間的等待一個方法調用直到返回結果。
調用一個EJB組件要比調用一個JavaBean麻煩些,由於EJB組件可以分布在多台伺服器上,因此必須首先獲得遠程或本地Home介面,然後使用Home介面創建EJB之後就可以調用EJB的方法了。
七、EJB設計模式
常見EJB設計模式
SESsion Facade pattern
通常項目中,客戶端往往需要頻繁的對伺服器端數據進行操作。當採用實體EJB作為數據的抽象層時,如果直接讓客戶端程序與實體EJB交互,會產生實現一個業務需求便需要大量的EJB屬性操作(如下圖1)。這直接導致如下問題:網路負載大(遠程客戶端時)、並發性能低、客戶端與伺服器端關聯度大、可重用性和可維護性差、性能
因此有必要在客戶端與實體EJB層間加入Session EJB層,在Sessino EJB中實現商業邏輯並封裝對實體EJB的操作。(如下圖2)
圖1:客戶端直接與實體EJB交互
圖2:通過SessionEJB層實現
Session Facade模式的好處是:降低了網路負載,SessionEjb可以調用實體EJB的本地介面;將商業邏輯與商業數據隔離;維護與開發方便;顯著提高性能。
Session Facade模式因其簡單使用,是目前使用很廣的模式。但具體應用過程中應注意:避免將所有的操作封裝到一個很大的SessionEJB內;伺服器端數據結構應由實體EJB實現,除非特例否則避免直接的資料庫操作;SessionEjb內某些系統通用操作的代碼容易重復(比如許可權檢查等,解決辦法是將系統通用服務封裝在Java Class內)。
MesSAge Facade Pattern
很多時候,一次RequeST需要操作多個EJB又不需要得到即時返回。對這種非同步調用,通常應用Message Fa?ade Pattern.
這種時候,如採用Session Fa?ade Pattern存在如下問題:
1. 客戶端等待返回的時間過長。一個SessionEjb的實例在完成客戶請求過程中中涉及到的每一次對其他實體Ejb的調用過程中都會被鎖定直到得到實體EJB返回信息後才能進行下一步操作。這樣造成客戶不必要的等待,並很容易因時間導致整個事務失敗。
2. 系統可靠性和容錯性低。如果需要調用不同系統或伺服器上或多個異構數據源的多個EJB時,任何一個環節出錯,均導致客戶請求失敗。
以Message-Driven Bean為基礎的Message Facade Pattern則可以解決上述非同步請求需求。具體架構見下圖3
圖3:使用Message Facade Pattern
Message Facade Pattern的不足之處在於:
1. Message-Driven Bean沒有返回值。這樣通知客戶執行結果只能依賴於EmAIl或人工等其他手段。
2. Message-Driven Bean執行過程中無法將捕獲的異常直接返回給客戶端,即無法使客戶端直接直到錯誤信息。
3. Message-Driven Bean通過接收Message響應客戶請求,對Message內容的合法性(比如對象的類型等)依賴與客戶端.容易產生運行時錯誤。
Message Facade Pattern經常與Session Facade Pattern在同一個項目里共同使用。
EJB Command Pattern
Session Facade Pattern中將商業邏輯實現封裝在Session EJB中,這種做法帶來諸多益處之外也帶來如下問題:
1. 由於業務經常的變化,導致經常需要更新Session EJB代碼。
2. 客戶端代碼不得不包含大量EJB相關的API,不利於後期項目維護。
3. 項目開發測試需要經常的EJB重部署過程。
引起上述問題的重要根結就是Session EJB本身重量級組件,其開發測試部署工作量較大,開發周期較長。以上不足可以通過EJB Command Pattern克服。
EJB Command Pattern中將商業邏輯實現封裝在普通的Java ClASs(稱之為Command Bean)中。該模式的具體實現有很多種,通常的框架都包括三部分:
1. Command Bean.由應用開發者寫的具體實現某商業操作的Java Class.主要包含getXXX(),setXXX(),exECute()方法。
2. Client-Side Routing Logic.由多個Class組成,用於將請求轉發至Command Sever,這個過程對客戶是透明的。這部分代碼可以跨項目使用。路由規則中可以考慮用XML技術。
3. Remote Command Server.實際執行商業操作請求。通常可以用Session EJB層實現。
整個框架見下圖4:
圖4:Command的基本框架
EJB Command Pattern具有如下好處:
1. 適應與需要快速開發環境。因Command Bean是輕量級的Java Class,其編譯和調試比較方便。
2. 將表現層與商業實現層隔離,同時將客戶端代碼與EJB層隔離。
3. 將客戶端代碼開發與伺服器端代碼開發相對清晰。早期可以創建空的Command Bean方便客戶端代碼調試。
EJB Command Pattern的弱處在於:
1. Command Bean中對事務的控制不如Session EJB中。
2. Command Bean是無狀態的。
3. 無法將異常直接返回給客戶。
4. 在大項目中,由於商業邏輯復雜,常導致大數量的Command Bean存在.
5. 作為Command Server的Session EJB打包時必須包含Command Bean以致存在維護上的不便。
EJB Command Pattern的一個實際實現可以參考IBM's Command framework.
Data Transfer object Factory
基於EJB的J2EE項目,經常需要在客戶端與伺服器端傳輸大量數據。數據的組織形式常用的是DTO(Data Transfer Object,伺服器端數據對象的抽象)。但因為客戶端表現層經常是變化的,所需要伺服器端數據也變動頻繁,換句話說,DTO的數量和屬性經常要更改。因此如何以及在何處生成和維護DTO便是需要考慮的問題。
一種解決方案是直接在Entity EJB中直接處理,即在Entity EJB的Bean類中加入getXXXDTO()、setXXXDTO()等。但這樣做導致EJB與DTO層緊緊綁定。一旦DTO更改,與該DTO相關的EJB即需要重編譯打包。EJB層與客戶端層相關聯不僅使維護困難而且導致EJB的重用性大大降低。
更好的解決方案是利用Data Transfer Object Factory封裝對DTO的操作邏輯(如下圖6)。
圖6:DTO Factory示例
DTO Factory具體實現方式通常有兩種:
1. 普通Java Class實現,用於Session Facade Pattern使用DTO環境下。
2. Stateless Session EJB實現,用於非EJB客戶端使用DTO環境下(見圖7)。
圖7:SessionEJB實現DTOFactory
DTO Factory帶來如下好處:
1. 使Entity EJB的重用成為可能。由於不含DTO處理邏輯,Entity EJB功能單一化,只作為數據源。不通客戶端通過各自的DTO Factory可以從同一個Entity EJB得到各自所需的個性化數據(自定義DTO)。
2. 提高可維護性和性能。
3. 可以根據在DTO Factory層生成很復雜的DTO結構,諸如繼承、關聯關系等,而對客戶端提供一個透明、細化的數據介面。
使用DTO Factory時需要注意的是:不需為每個Entity EJB定義一個Factory。可以為一系列相關的Entity EJB創建一個Factory,或者只創建一個Factory。
Generic Attribute Access
使用Entity EJB作為商業數據層時,我們首先需要從資料庫載入數據,創建對應的Entity EJB實例,之後對內存中Entity EJB實例的屬性進行相應操作。對屬性的操作比較直接的做法是:直接調用Entity EJB的getXXX()/setXXX(),通常利用EJB2.0的本地介面;通過DTO Factory生成DTO。但這兩種做法都存在如下問題:
1. 當Entity EJB的屬性特別多時候,以上做法會帶來復雜羅嗦的代碼,使EJB變的龐大無比。
2. 使Entity EJB的客戶端(比如Session EJB)和Entity EJB的介面緊密關聯。Entity EJB屬性的增刪都需要更改客戶端代碼,給項目開發和維護帶來不便。
事實上可以利用更通用的方式訪問Entity EJB的屬性,即定義Generic Attribute Access Interface。見下圖8:
圖8:Generic Attribute Access Interface示例
Generic Attribute Access Interface由Entity EJB的本地或遠程介面實現,並利用Hash Maps傳輸數據。實現方式常見如下:
1. BMP類型實體EJB可以在Bean類中定義包含所有屬性的私有成員變數HashMap。
2. CMP類型實體EJB可以在Bean類中可以適用Java Reflection API實現。
3. 建立一個父類,在不同的情況下定義子類重載父類方法。
使用Generic Attribute Access Interface需要在客戶端與伺服器端對屬性以及對應的關鍵字建立統一的命名習慣。常見的做法如下:
1. 建立並保持良好的文檔記錄和命名約定。
2. 在實體EJB的實現類中定義靜態成員映射屬性。
3. 創建共享靜態類,通過成員變數映射實體EJB屬性。
4. 通過JNDI在伺服器端保存屬性映射關系。
Generic Attribute Access Interface的運用帶來一下益處:
1. 介面實現後對不通實體EJB都適用。
2. 對屬性較多實體EJB能精簡代碼,並更具維護性。
3. 使運行中動態增刪實體EJB屬性成為可能。
Generic Attribute Access Interface的缺點在於:
1. 訪問EJB屬性時增加了額外的操作。需要通過關鍵字映射屬性,最後還需進行類型轉換。
2. 需要建立客戶端與伺服器端的命名約定。
3. 因為通過HashMap操作時候需要進行類型轉換,容易產生運行時類型不匹配異常。
Business Interface
EJB規范要求Bean實現類必須實現所有在遠程(或本地)介面中定義的所有方法,同時不允許Bean實現類直接繼承遠程(或本地)介面。這就導致編譯時候很容易產生兩者不一致的問題,即遠程(或本地)介面中定義的某方法為在Bean實現類中被實現等錯誤。為避免上訴錯誤,可以利用應用伺服器廠商所提供的工具。但也可以應用EJB的設計架構來實現:定義商業介面。
Business Interface即創建自定義商業介面,在介面中定義所有EJB提供的商業方法,並讓Bean實現類和遠程(或本地)介面都實現該商業介面。其繼承關系見下圖9:
圖9:商業介面的使用
Business Interface是個普通的Java Class。依賴於使用本地介面與遠程介面的不通,Business Interface的定義略有不同:應用與遠程介面時,在介面中的方法需要拋出java.rmi.RemoteException;而應用與本地介面時候則不需要作任何特別處理。
應用Business Interface時候必須注意一點:EJB規范不允許直接EJB的實例將對自己的引用(this對象)返回給客戶端,否則編譯時候即報錯。但使用Business Interface後,編譯時候無法檢查出有無將this對象返回給客戶端。這一點需要程序員自己保證。
三. 內部數據轉換策略
Data Transfer Object
基於EJB的J2EE多層架構應用中,經常涉及的一個問題就是如何在各層之間傳遞批量數據,比如客戶端對伺服器端數據的批量讀寫操作等。比如需要得到實體EJB的屬性,直接的方法是多次調用不通的屬性,如下圖10:
圖10:低效的數據傳遞方式
但這種方法容易導致許多問題,比如性能以及代碼的復雜度等,更有效的辦法是在一個調用中得到所有需要的屬性。所以可以引入Data Transfer Object來封裝所需要的屬性,並在客戶與伺服器端通過傳遞該對象一次實現對數據的操作。如下圖11:
圖11:通過DTO傳遞數據
DTO為普通的Java Class,通常是伺服器端數據的快照。由於網路傳輸的需要,DTO應該實現java.io.Serializable介面。
DTO的設計有兩種模型:Domain DTO以及Custom DTO。
Domain DTO僅僅實現對伺服器數據的拷貝,通常與實體EJB為一對一的關系(也存在為多個相關聯的實體EJB對應一個Domain DTO)。Domain DTO通常除用於讀取更改實體EJB屬性外也可用於創建實體EJB時候。實體EJB與Domain DTO對應關系如下圖12:
圖12:Account EJB 與 Account DomainDTO
Domain DTO的應用除了DTO所具有的一般優點外,還有別的益處:
1. 開發迅速。因為一旦實體EJB設計好後,很容易轉換得到Domain DTO。
2. 可以利用Domain DTO的setXXX()方法在客戶端進行屬性有效性效驗。
Domain DTO的缺點有:
1. 客戶端綁定了伺服器端數據模型,不利於維護。
2. 不夠靈活,無法處理客戶端的多樣化數據要求。對一個數百個屬性的實體EJB請求一個屬性時候卻返回一個包含所有屬性值的Domain DTO明顯是笨重的實現。
3. 導致代碼的重復。
4. Domain DTO中如果嵌套包含了別的Domain DTO時,一旦需伺服器端數據的更改而需要重定義Domain DTO模型時候異常困難。
Custom DTO則可以克服上述的一些缺點。Customer DTO僅僅封裝用戶感興趣的伺服器數據集即可以根據客戶端需求創建Customer DTO。這樣作的優點是靈活高效;缺點是大項目中可能導致大量的Customer DTO存在。
通常Domain DTO可以用於數據的更新與創建;Customer DTO可以用於客戶用於表現層的數據讀取。兩者可以相輔相成。而且使用DTO一般與DTO Factory同時使用。
Domain Transfer Hash Map
DTO的使用往往缺乏通用性。不通的用戶案例需要創建不同的DTO。當項目很復雜時,從維護性考慮需要更好的數據傳輸的實現方式。
Domain Transfer Hash Map即利用HashMap作為客戶所需數據集的封裝。好處是:
1. 良好的維護性。
2. 較大的通用性。不同的客戶端可以使用相同的數據傳遞方式。
缺點是:
1. 需要維護客戶端與伺服器端在屬性及其對應關鍵字的映射關系。
2. 當需要使用基本類型的數據時候,因為Hash Map的限制必須將基本類型先轉換成對象。
3. 使用得到的數據時,需要進行類型強制轉換。
Data Transfer RowSet
當需要處理直接的JDBC調用得到的結果集時,顯然用DTO/Hash Map已經不合適,因為需要對大量數據進行類型轉換等額外操作是很費資源和不必要的,而且最終用戶常需要以表格式樣顯示數據。
所以對二維表式數據,更好的處理方式是利用Data Transfer RowSet。Data Transfer RowSet通過將ResultSet直接轉換為RowSet傳遞給客戶端。
在Session EJB中使用RowSet的一段示例代碼如下圖13:
圖13:使用RowSet
使用RowSet的好處很多:
1. 介面通用於各樣的資料庫查詢操作。
2. 當需要表格式數據顯示時,因為直接從ResultSet得到,所以不需要額外的數據類型轉換。
缺點是:
1. 資料庫結構暴露給客戶端。
2. 不符合面向對象設計思想。
3. 依賴於SQL。
Data Transfer RowSet通常用於只讀式數據的顯示操作,經常和JDBC for Reading Pattern連用。
四.事務和數據持久機制
JDBC for Reading Pattern
基於EJB的J2EE應用中,通過EJB對資料庫的操作可以有兩種方式:實體EJB或者Session EJB中直接利用JDBC訪問。
客戶很多時候取出資料庫中數據並以表格方式顯示。這種情形如果使用實體EJB會導致如下問題:
1. 引用伺服器端頻繁的資料庫查詢和載入操作。因為載入N個實體EJB總需要進行一次find()操作N次數據載入。
2. 如果使用Remote介面,引起頻繁的額外網路操作。
3. 對關聯關系比較復雜的資料庫表結構,很難直接通過Entity EJB表現。
因此建議在只需對資料庫表數據進行只讀訪問時候,應該採用JDBC for Reading Pattern,即通過JDBC直接訪問資料庫。除了避免上述使用實體EJB的缺點還帶來一下好處:
1. 充分利用資料庫能力,比如資料庫的緩存機制。
2. 減少了對事務控制的資源。
3. 利用自定義SQL可以按需要比較靈活的讀取數據。
4. 只需要一次數據查詢,減少了資料庫操作。
缺點是:
1. 於J2EE應用的面向對象設計相違背。
2. 因為Session EJB代碼中包含了自定義SQL,維護性差。
3. Session EJB中不得不包含JDBC的API,並且需要了解資料庫結構。
部屬人員: 使用相應工具在運行環境下配置 EJB
系統管理員: 監視運行時情況
H. c語言既可以編譯執行又可以解釋執行嗎 編譯執行怎麼解釋 解釋執行又怎麼解釋
C 語言程序僅可以解釋執行。
解釋程序是將源程序(如BASIC)作為輸入,解釋一句後就提交計算機執行一句,並不形成目標程序。編譯程序是把高級語言(如FORTRAN、COBOL、Pascal、C等)源程序作為輸入,進行翻譯轉換,產生出機器語言的目標程序,然後再讓計算機執行這個目標程序,得到計算結果。
相對於編譯性語言,其優點是可移植性好,只要有解釋器環境,程序就可以在不同的操作系統上運行。
缺點是代碼需要有專門的解釋器,在程序運行時,除要給用戶程序本身分配內存空間外,解釋器也佔用系統資源,所以其運行速度較慢。另外,也很難達到像C、C++那樣操作系統底層操作的目的。
解釋型語言常用於,一是對運行速度要求不高(如一些網頁腳本等)的場合,二是對跨平台(操作系統的兼容性)有要求的場合。
(8)對象被多個用戶共用仍要編譯嗎擴展閱讀
1、Python和Java語言,專門有一個解釋器能夠直接執行Python程序,每個語句都是執行的時候才翻譯。
2、Python代碼在運行前,會先編譯成中間代碼,每個 .py 文件將被換轉成pyc 文件,pyc 就是一種位元組碼文件,它是與平台無關的中間代碼。不管放在 Windows 還是 Linux 平台都可以執行,運行時將由虛擬機逐行把位元組碼翻譯成目標代碼。
I. 如何解決java.lang.NoClassDefFoundError
NoClassDefFoundError錯誤發生的原因
NoClassDefFoundError錯誤的發生,是因為Java虛擬機在編譯時能找到合適的類,而在運行時不能找到合適的類導致的錯誤。例如在運行時我們想調用某個類的方法或者訪問這個類的靜態成員的時候,發現這個類不可用,此時Java虛擬機就會拋出NoClassDefFoundError錯誤。與ClassNotFoundException的不同在於,這個錯誤發生只在運行時需要載入對應的類不成功,而不是編譯時發生。很多Java開發者很容易在這里把這兩個錯誤搞混。
簡單總結就是,NoClassDefFoundError發生在編譯時對應的類可用,而運行時在Java的classpath路徑中,對應的類不可用導致的錯誤。發生NoClassDefFoundError錯誤時,你能看到如下的錯誤日誌:
Exception in thread "main" java.lang.NoClassDefFoundError
錯誤的信息很明顯地指明main線程無法找到指定的類,而這個main線程可能時主線程或者其他子線程。如果是主線程發生錯誤,程序將崩潰或停止,而如果是子線程,則子線程停止,其他線程繼續運行。
NoClassDefFoundError和ClassNotFoundException區別
我們經常被java.lang.ClassNotFoundException和java.lang.NoClassDefFoundError這兩個錯誤迷惑不清,盡管他們都與Java classpath有關,但是他們完全不同。NoClassDefFoundError發生在JVM在動態運行時,根據你提供的類名,在classpath中找到對應的類進行載入,但當它找不到這個類時,就發生了java.lang.NoClassDefFoundError的錯誤,而ClassNotFoundException是在編譯的時候在classpath中找不到對應的類而發生的錯誤。ClassNotFoundException比NoClassDefFoundError容易解決,是因為在編譯時我們就知道錯誤發生,並且完全是由於環境的問題導致。而如果你在J2EE的環境下工作,並且得到NoClassDefFoundError的異常,而且對應的錯誤的類是確實存在的,這說明這個類對於類載入器來說,可能是不可見的。
怎麼解決NoClassDefFoundError錯誤
根據前文,很明顯NoClassDefFoundError的錯誤是因為在運行時類載入器在classpath下找不到需要載入的類,所以我們需要把對應的類載入到classpath中,或者檢查為什麼類在classpath中是不可用的,這個發生可能的原因如下:
對應的Class在java的classpath中不可用
你可能用jar命令運行你的程序,但類並沒有在jar文件的manifest文件中的classpath屬性中定義
可能程序的啟動腳本覆蓋了原來的classpath環境變數
因為NoClassDefFoundError是java.lang.LinkageError的一個子類,所以可能由於程序依賴的原生的類庫不可用而導致
檢查日誌文件中是否有java.lang.ExceptionInInitializerError這樣的錯誤,NoClassDefFoundError有可能是由於靜態初始化失敗導致的
如果你工作在J2EE的環境,有多個不同的類載入器,也可能導致NoClassDefFoundError
下面我們看一些當發生NoClassDefFoundError時,我們該如何解決的樣例。
NoClassDefFoundError解決示例
當發生由於缺少jar文件,或者jar文件沒有添加到classpath,或者jar的文件名發生變更會導致java.lang.NoClassDefFoundError的錯誤。
當類不在classpath中時,這種情況很難確切的知道,但如果在程序中列印出System.getproperty(「java.classpath」),可以得到程序實際運行的classpath
運行時明確指定你認為程序能正常運行的 -classpath 參數,如果增加之後程序能正常運行,說明原來程序的classpath被其他人覆蓋了。
NoClassDefFoundError也可能由於類的靜態初始化模塊錯誤導致,當你的類執行一些靜態初始化模塊操作,如果初始化模塊拋出異常,哪些依賴這個類的其他類會拋出NoClassDefFoundError的錯誤。如果你查看程序日誌,會發現一些java.lang.ExceptionInInitializerError的錯誤日誌,ExceptionInInitializerError的錯誤會導致java.lang.NoClassDefFoundError: Could not initialize class,如下面的代碼示例:
/**
* Java program to demonstrate how failure of static initialization subsequently cause
* java.lang.NoClassDefFoundError in Java.
* @author Javin Paul
*/
public class {
public static void main(String args[]){
List<User> users = new ArrayList<User>(2);
for(int i=0; i<2; i++){
try{
users.add(new User(String.valueOf(i))); //will throw NoClassDefFoundError
}catch(Throwable t){
t.printStackTrace();
}
}
}
}
class User{
private static String USER_ID = getUserId();
public User(String id){
this.USER_ID = id;
}
private static String getUserId() {
throw new RuntimeException("UserId Not found");
}
}
Output
java.lang.ExceptionInInitializerError
at testing..main(.java:23)
Caused by: java.lang.RuntimeException: UserId Not found
at testing.User.getUserId(.java:41)
at testing.User.<clinit>(.java:35)
... 1 more
java.lang.NoClassDefFoundError: Could not initialize class testing.User
at testing..main(.java:23)
Read more: http://javarevisited.blogspot.com/2011/06/noclassdeffounderror-exception-in.html#ixzz3dqtbvHDy
由於NoClassDefFoundError是LinkageError的子類,而LinkageError的錯誤在依賴其他的類時會發生,所以如果你的程序依賴原生的類庫和需要的dll不存在時,有可能出現java.lang.NoClassDefFoundError。這種錯誤也可能拋出java.lang.UnsatisfiedLinkError: no dll in java.library.path Exception Java這樣的異常。解決的辦法是把依賴的類庫和dll跟你的jar包放在一起。
如果你使用Ant構建腳本來生成jar文件和manifest文件,要確保Ant腳本獲取的是正確的classpath值寫入到manifest.mf文件
Jar文件的許可權問題也可能導致NoClassDefFoundError,如果你的程序運行在像linux這樣多用戶的操作系統種,你需要把你應用相關的資源文件,如Jar文件,類庫文件,配置文件的許可權單獨分配給程序所屬用戶組,如果你使用了多個用戶不同程序共享的jar包時,很容易出現許可權問題。比如其他用戶應用所屬許可權的jar包你的程序沒有許可權訪問,會導致java.lang.NoClassDefFoundError的錯誤。
基於XML配置的程序也可能導致NoClassDefFoundError的錯誤。比如大多數Java的框架像Spring,Struts使用xml配置獲取對應的bean信息,如果你輸入了錯誤的名稱,程序可能會載入其他錯誤的類而導致NoClassDefFoundError異常。我們在使用Spring MVC框架或者Apache Struts框架,在部署War文件或者EAR文件時就經常會出現Exception in thread 「main」 java.lang.NoClassDefFoundError。
在有多個ClassLoader的J2EE的環境中,很容易出現NoClassDefFoundError的錯誤。由於J2EE沒有指明標準的類載入器,使用的類載入器依賴與不同的容器像Tomcat、WebLogic,WebSphere載入J2EE的不同組件如War包或者EJB-JAR包。關於類載入器的相關知識可以參考這篇文章類載入器的工作原理。
總結來說,類載入器基於三個機制:委託、可見性和單一性,委託機制是指將載入一個類的請求交給父類載入器,如果這個父類載入器不能夠找到或者載入這個類,那麼再載入它。可見性的原理是子類的載入器可以看見所有的父類載入器載入的類,而父類載入器看不到子類載入器載入的類。單一性原理是指僅載入一個類一次,這是由委託機制確保子類載入器不會再次載入父類載入器載入過的類。現在假設一個User類在WAR文件和EJB-JAR文件都存在,並且被WAR ClassLoader載入,而WAR ClassLoader是載入EJB-JAR ClassLoader的子ClassLoader。當EJB-JAR中代碼引用這個User類時,載入EJB-JAR所有class的Classloader找不到這個類,因為這個類已經被EJB-JAR classloader的子載入器WAR classloader載入。
這會導致的結果就是對User類出現NoClassDefFoundError異常,而如果在兩個JAR包中這個User類都存在,如果你使用equals方法比較兩個類的對象時,會出現ClassCastException的異常,因為兩個不同類載入器載入的類無法進行比較。
有時候會出現Exception in thread 「main」 java.lang.NoClassDefFoundError: com/sun/tools/javac/Main 這樣的錯誤,這個錯誤說明你的Classpath, PATH 或者 JAVA_HOME沒有安裝配置正確或者JDK的安裝不正確。這個問題的解決辦法時重新安裝你的JDK。
Java在執行linking操作的時候,也可能導致NoClassDefFoundError。例如在前面的腳本中,如果在編譯完成之後,我們刪除User的編譯文件,再運行程序,這個時候你就會直接得到NoClassDefFoundError,而錯誤的消息只列印出User類的名稱。
java.lang.NoClassDefFoundError: testing/User
at testing..main(.java:23)
現在我們知道要怎樣去面對NoClassDefFoundError異常並解決它了。
J. 在c語言中「可執行程序」是什麼意思
C語言中的可執行程序就是將用文本信息表示的程序翻譯成計算機認識的二進制代碼串。
首先,我們先用C語言把源代碼寫好,然後交給C語言編譯器。C語言編譯器內部分為前端和後端。
(1)編譯器前端
前端負責將C語言代碼進行詞法和語法上的解析,然後可以生成中間代碼。
中間代碼這部分不是必須的,但是它能夠為程序的跨平台移植帶來諸多好處。比如,同樣的一份C語言源代碼在一台計算機上編譯完之後,生成一套中間代碼。
然後針對不同的目標平台(比如要將這一套代碼分別編譯成 ARM 處理器的二進制機器碼、MIPS 處理器的二進制機器碼以及 x86 處理器的二進制機器碼),只需要編寫相應目標平台的編譯器後端即可。
所以,這么做就可以把編譯器的前端與後端剝離開來(這在軟體工程上又可稱為解耦合),不同處理器廠商可以針對自家的處理器特性,對中間代碼生成到目標二進制代碼的過程再度進行優化。
(2)編譯器後端
接下來,由C語言編譯器後端生成源文件相應的目標文件。
目標文件在 Windows 系統上往往是.obj文件,而在 Unix/Linux 系統上往往是.o文件,C語言的源文件在所有平台上都統一用.c文件表示。
(3)鏈接器
最後,對於各個獨立的目標文件,通過連接器將它們合並成一個最終可執行文件。
(10)對象被多個用戶共用仍要編譯嗎擴展閱讀:
起初,C語言沒有官方標准。1978年由美國電話電報公司(AT&T)貝爾實驗室正式發表了C語言。布萊恩·柯林漢(Brian Kernighan) 和 丹尼斯·里奇(Dennis Ritchie) 出版了一本書,名叫《The C Programming Language》。
這本書被 C語言開發者們稱為K&R,很多年來被當作 C語言的非正式的標准說明。人們稱這個版本的 C語言為K&R C。
K&R C主要介紹了以下特色:
結構體(struct)類型
長整數(long int)類型
無符號整數(unsigned int)類型
把運算符=+和=-改為+=和-=。因為=+和=-會使得編譯器不知道使用者要處理i = -10還是i =- 10,使得處理上產生混淆。
即使在後來ANSI C標准被提出的許多年後,K&R C仍然是許多編譯器的最 准要求,許多老舊的編譯器仍然運行K&R C的標准。
1970到80年代,C語言被廣泛應用,從大型主機到小型微機,也衍生了C語言的很多不同版本。
1983年,美國國家標准協會(ANSI)成立了一個委員會X3J11,來制定 C語言標准。
1989年,美國國家標准協會(ANSI)通過了C語言標准,被稱為ANSI X3.159-1989 "Programming Language C"。因為這個標準是1989年通過的,所以一般簡稱C89標准。有些人也簡稱ANSI C,因為這個標準是美國國家標准協會(ANSI)發布的。
1990年,國際標准化組織(ISO)和國際電工委員會(IEC)把C89標準定為C語言的國際標准,命名為ISO/IEC 9899:1990 - Programming languages -- C 。因為此標準是在1990年發布的,所以有些人把簡稱作C90標准。不過大多數人依然稱之為C89標准,因為此標准與ANSI C89標准完全等同。
1994年,國際標准化組織(ISO)和國際電工委員會(IEC)發布了C89標准修訂版,名叫ISO/IEC 9899:1990/Cor 1:1994 ,有些人簡稱為C94標准。
1995年,國際標准化組織(ISO)和國際電工委員會(IEC)再次發布了C89標准修訂版,名叫ISO/IEC 9899:1990/Amd 1:1995 - C Integrity ,有些人簡稱為C95標准。
C99標准
1999年1月,國際標准化組織(ISO)和國際電工委員會(IEC)發布了C語言的新標准,名叫ISO/IEC 9899:1999 - Programming languages -- C ,簡稱C99標准。這是C語言的第二個官方標准。
參考資料:網路-c語言