本文目錄一覽:
- 1、Java編程中,你經常遇到的異常有哪些?場景如何?
- 2、Java中位運算符的具體應用是什麼,在實際編程中有什麼作用
- 3、JAVA編程中常見的錯誤有哪些
- 4、線程在java編程中的作用
- 5、java編程中,常提到的反射代碼指的是什麼?
Java編程中,你經常遇到的異常有哪些?場景如何?
在Java程序設計中,異常是經常遇到的問題。我個人是做軟件開發的,自然會遇到不少異常,我這裡總結了自己開發中經常遇到的幾種異常和異常爆發的場景:
第一種是算術異常。一般發生的場景是當兩數相除,被除數為零時會引發這種錯誤,這是比較常見的一種錯誤;
第二種是輸入不匹配異常,一般發生在本來要你輸入整數,結果你卻輸入了字符,所以兩種數據類型不一致而導致發生異常,這也是經常發生的;
第三種是空指針異常,這一般是由於沒有給對象賦值而導致對象出現空值而導致異常的發生,這種是隱含型錯誤,一般是由於開發者自己的失誤而導致的;
第四種是數組越界異常,主要是由於數組本身的大小和要取的值超出了數組的範圍而出現的錯誤;
第五種是數據類型轉換異常,主要是兩種不同類型的數據之間進行轉換時而出現的錯誤,所以做轉換時一定要非常的小心。
以上這五種,只是在工作中見得比較多的幾種基礎異常。異常引發的原因有很多,使用不同的技術,採用不同的手段都會出現異常情況。
當異常發生時,一定要仔細分析異常發生的原因是什麼,該如何解決等等。如果出了錯,自己不會解決,那就很麻煩了。
不好人總是抱怨異常不好解決,其實是因為他們根本沒有很好的異常處理經驗,只有不斷總結,才會有相應的排錯經驗。
Java中位運算符的具體應用是什麼,在實際編程中有什麼作用
位邏輯運算符有“與”(AND)、“或”(OR)、“異或(XOR)”、“非(NOT)”,分別用“”、“|”、“^”、“~”表示。
下面的例子說明了位邏輯運算符:
//
Demonstrate
the
bitwise
logical
operators.
class
BitLogic
{
public
static
void
main(String
args[])
{
String
binary[]
=
{
“0000”,
“0001”,
“0010”,
“0011”,
“0100”,
“0101”,
“0110”,
“0111”,
“1000”,
“1001”,
“1010”,
“1011”,
“1100”,
“1101”,
“1110”,
“1111”
};
int
a
=
3;
//
+
2
+
1
or
0011
in
binary
int
b
=
6;
//
4
+
2
+
or
0110
in
binary
int
c
=
a
|
b;
int
d
=
a
b;
int
e
=
a
^
b;
int
f
=
(~a
b)
|
(a
~b);
int
g
=
~a
0x0f;
System.out.println(“
a
=
“
+
binary[a]);
System.out.println(“
b
=
“
+
binary[b]);
System.out.println(“
a|b
=
“
+
binary[c]);
System.out.println(“
ab
=
“
+
binary[d]);
System.out.println(“
a^b
=
“
+
binary[e]);
System.out.println(“~ab|a~b
=
“
+
binary[f]);
System.out.println(“
~a
=
“
+
binary[g]);
}
}
在本例中,變量a與b對應位的組合代表了二進制數所有的
4
種組合模式:0-0,0-1,1-0,和1-1。“|”運算符和“”運算符分別對變量a與b各個對應位的運算得到了變量c和變量d的值。對變量e和f的賦值說明了“^”運算符的功能。字符串數組binary代表了0到15對應的二進制的值。在本例中,數組各元素的排列順序顯示了變量對應值的二進制代碼。數組之所以這樣構造是因為變量的值n對應的二進制代碼可以被正確的存儲在數組對應元素binary[n]中。例如變量a的值為3,則它的二進制代碼對應地存儲在數組元素binary[3]中。~a的值與數字0x0f
(對應二進制為0000
1111)進行按位與運算的目的是減小~a的值,保證變量g的結果小於16。因此該程序的運行結果可以用數組binary對應的元素來表示。
JAVA編程中常見的錯誤有哪些
錯誤就是error,它不同於異常。有時候程序不發生異常是不會出問題的,但有錯誤一定有問題。
常見的錯誤:編寫錯誤,語句錯誤—這兩個編譯器會提醒,也就是常用的eclipse;
邏輯錯誤,這個要看你自己的邏輯思維了。
潛在錯誤,也就是編寫語句邏輯都沒有問題,但jvm檢測有問題,就需要你自己找了,通常潛在錯誤都有邏輯問題。
線程在java編程中的作用
線程在java編程中的作用可以實現多個任務同時進行。java創建線程的方式最常用的有兩種。
1、第一種是創建Thread子類的一個實例並重寫run方法,run方法會在調用start()方法之後被執行。例子如下:
public class MyThread extends Thread {
public void run(){
System.out.println(“MyThread running”);
}
}
MyThread myThread = new MyThread();
myTread.start();
2、第二種編寫線程執行代碼的方式是新建一個實現了java.lang.Runnable接口的類的實例,實例中的方法可以被線程調用。下面給出例子:
public class MyRunnable implements Runnable {
public void run(){
System.out.println(“MyRunnable running”);
}
}
Thread thread = new Thread(new MyRunnable());
thread.start();
java編程中,常提到的反射代碼指的是什麼?
反射的概念是由Smith在1982年首次提出的,主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力。這一概念的提出很快引發了計算機科學領域關於應用反射性的研究。它首先被程序語言的設計領域所採用,並在Lisp和面向對象方面取得了成績。其中LEAD/LEAD++ 、OpenC++ 、MetaXa和OpenJava等就是基於反射機制的語言。最近,反射機制也被應用到了視窗系統、操作系統和文件系統中。
反射本身並不是一個新概念,它可能會使我們聯想到光學中的反射概念,儘管計算機科學賦予了反射概念新的含義,但是,從現象上來說,它們確實有某些相通之處,這些有助於我們的理解。在計算機科學領域,反射是指一類應用,它們能夠自描述和自控制。也就是說,這類應用通過採用某種機制來實現對自己行為的描述(self-representation)和監測(examination),並能根據自身行為的狀態和結果,調整或修改應用所描述行為的狀態和相關的語義。可以看出,同一般的反射概念相比,計算機科學領域的反射不單單指反射本身,還包括對反射結果所採取的措施。所有採用反射機制的系統(即反射系統)都希望使系統的實現更開放。可以說,實現了反射機制的系統都具有開放性,但具有開放性的系統並不一定採用了反射機制,開放性是反射系統的必要條件。一般來說,反射系統除了滿足開放性條件外還必須滿足原因連接(Causally-connected)。所謂原因連接是指對反射系統自描述的改變能夠立即反映到系統底層的實際狀態和行為上的情況,反之亦然。開放性和原因連接是反射系統的兩大基本要素。13700863760
Java中,反射是一種強大的工具。它使您能夠創建靈活的代碼,這些代碼可以在運行時裝配,無需在組件之間進行源代表鏈接。反射允許我們在編寫與執行時,使我們的程序代碼能夠接入裝載到JVM中的類的內部信息,而不是源代碼中選定的類協作的代碼。這使反射成為構建靈活的應用的主要工具。但需注意的是:如果使用不當,反射的成本很高。
二、Java中的類反射:
Reflection 是 Java 程序開發語言的特徵之一,它允許運行中的 Java 程序對自身進行檢查,或者說“自審”,並能直接操作程序的內部屬性。Java 的這一能力在實際應用中也許用得不是很多,但是在其它的程序設計語言中根本就不存在這一特性。例如,Pascal、C 或者 C++ 中就沒有辦法在程序中獲得函數定義相關的信息。
1.檢測類:
1.1 reflection的工作機制
考慮下面這個簡單的例子,讓我們看看 reflection 是如何工作的。
import java.lang.reflect.*;
public class DumpMethods {
public static void main(String args[]) {
try {
Class c = Class.forName(args[0]);
Method m[] = c.getDeclaredMethods();
for (int i = 0; i m.length; i++)
System.out.println(m[i].toString());
} catch (Throwable e) {
System.err.println(e);
}
}
}
按如下語句執行:
java DumpMethods java.util.Stack
它的結果輸出為:
public java.lang.Object java.util.Stack.push(java.lang.Object)
public synchronized java.lang.Object java.util.Stack.pop()
public synchronized java.lang.Object java.util.Stack.peek()
public boolean java.util.Stack.empty()
public synchronized int java.util.Stack.search(java.lang.Object)
這樣就列出了java.util.Stack 類的各方法名以及它們的限制符和返回類型。
這個程序使用 Class.forName 載入指定的類,然後調用 getDeclaredMethods 來獲取這個類中定義了的方法列表。java.lang.reflect.Methods 是用來描述某個類中單個方法的一個類。
1.2 Java類反射中的主要方法
對於以下三類組件中的任何一類來說 — 構造函數、字段和方法 — java.lang.Class 提供四種獨立的反射調用,以不同的方式來獲得信息。調用都遵循一種標準格式。以下是用於查找構造函數的一組反射調用:
l Constructor getConstructor(Class[] params) — 獲得使用特殊的參數類型的公共構造函數,
l Constructor[] getConstructors() — 獲得類的所有公共構造函數
l Constructor getDeclaredConstructor(Class[] params) — 獲得使用特定參數類型的構造函數(與接入級別無關)
l Constructor[] getDeclaredConstructors() — 獲得類的所有構造函數(與接入級別無關)
獲得字段信息的Class 反射調用不同於那些用於接入構造函數的調用,在參數類型數組中使用了字段名:
l Field getField(String name) — 獲得命名的公共字段
l Field[] getFields() — 獲得類的所有公共字段
l Field getDeclaredField(String name) — 獲得類聲明的命名的字段
l Field[] getDeclaredFields() — 獲得類聲明的所有字段
用於獲得方法信息函數:
l Method getMethod(String name, Class[] params) — 使用特定的參數類型,獲得命名的公共方法
l Method[] getMethods() — 獲得類的所有公共方法
l Method getDeclaredMethod(String name, Class[] params) — 使用特寫的參數類型,獲得類聲明的命名的方法
l Method[] getDeclaredMethods() — 獲得類聲明的所有方法
1.3開始使用 Reflection:
用於 reflection 的類,如 Method,可以在 java.lang.relfect 包中找到。使用這些類的時候必須要遵循三個步驟:第一步是獲得你想操作的類的 java.lang.Class 對象。在運行中的 Java 程序中,用 java.lang.Class 類來描述類和接口等。
下面就是獲得一個 Class 對象的方法之一:
Class c = Class.forName(“java.lang.String”);
這條語句得到一個 String 類的類對象。還有另一種方法,如下面的語句:
Class c = int.class;
或者
Class c = Integer.TYPE;
它們可獲得基本類型的類信息。其中後一種方法中訪問的是基本類型的封裝類 (如 Integer) 中預先定義好的 TYPE 字段。
第二步是調用諸如 getDeclaredMethods 的方法,以取得該類中定義的所有方法的列表。
一旦取得這個信息,就可以進行第三步了——使用 reflection API 來操作這些信息,如下面這段代碼:
Class c = Class.forName(“java.lang.String”);
Method m[] = c.getDeclaredMethods();
System.out.println(m[0].toString());
它將以文本方式打印出 String 中定義的第一個方法的原型。
2.處理對象:
如果要作一個開發工具像debugger之類的,你必須能發現filed values,以下是三個步驟:
a.創建一個Class對象
b.通過getField 創建一個Field對象
c.調用Field.getXXX(Object)方法(XXX是Int,Float等,如果是對象就省略;Object是指實例).
例如:
import java.lang.reflect.*;
import java.awt.*;
class SampleGet {
public static void main(String[] args) {
Rectangle r = new Rectangle(100, 325);
printHeight(r);
}
static void printHeight(Rectangle r) {
Field heightField;
Integer heightValue;
Class c = r.getClass();
try {
heightField = c.getField(“height”);
heightValue = (Integer) heightField.get(r);
System.out.println(“Height: ” + heightValue.toString());
} catch (NoSuchFieldException e) {
System.out.println(e);
} catch (SecurityException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
}
}
}
三、安全性和反射:
在處理反射時安全性是一個較複雜的問題。反射經常由框架型代碼使用,由於這一點,我們可能希望框架能夠全面接入代碼,無需考慮常規的接入限制。但是,在其它情況下,不受控制的接入會帶來嚴重的安全性風險,例如當代碼在不值得信任的代碼共享的環境中運行時。
由於這些互相矛盾的需求,Java編程語言定義一種多級別方法來處理反射的安全性。基本模式是對反射實施與應用於源代碼接入相同的限制:
n 從任意位置到類公共組件的接入
n 類自身外部無任何到私有組件的接入
n 受保護和打包(缺省接入)組件的有限接入
不過至少有些時候,圍繞這些限制還有一種簡單的方法。我們可以在我們所寫的類中,擴展一個普通的基本類java.lang.reflect.AccessibleObject 類。這個類定義了一種setAccessible方法,使我們能夠啟動或關閉對這些類中其中一個類的實例的接入檢測。唯一的問題在於如果使用了安全性管理器,它將檢測正在關閉接入檢測的代碼是否許可了這樣做。如果未許可,安全性管理器拋出一個例外。
下面是一段程序,在TwoString 類的一個實例上使用反射來顯示安全性正在運行:
public class ReflectSecurity {
public static void main(String[] args) {
try {
TwoString ts = new TwoString(“a”, “b”);
Field field = clas.getDeclaredField(“m_s1”);
// field.setAccessible(true);
System.out.println(“Retrieved value is ” +
field.get(inst));
} catch (Exception ex) {
ex.printStackTrace(System.out);
}
}
}
如果我們編譯這一程序時,不使用任何特定參數直接從命令行運行,它將在field .get(inst)調用中拋出一個IllegalAccessException異常。如果我們不注釋field.setAccessible(true)代碼行,那麼重新編譯並重新運行該代碼,它將編譯成功。最後,如果我們在命令行添加了JVM參數-Djava.security.manager以實現安全性管理器,它仍然將不能通過編譯,除非我們定義了ReflectSecurity類的許可權限。
四、反射性能:
反射是一種強大的工具,但也存在一些不足。一個主要的缺點是對性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什麼並且它滿足我們的要求。這類操作總是慢於只直接執行相同的操作。
下面的程序是字段接入性能測試的一個例子,包括基本的測試方法。每種方法測試字段接入的一種形式 — accessSame 與同一對象的成員字段協作,accessOther 使用可直接接入的另一對象的字段,accessReflection 使用可通過反射接入的另一對象的字段。在每種情況下,方法執行相同的計算 — 循環中簡單的加/乘順序。
程序如下:
public int accessSame(int loops) {
m_value = 0;
for (int index = 0; index loops; index++) {
m_value = (m_value + ADDITIVE_VALUE) *
MULTIPLIER_VALUE;
}
return m_value;
}
public int accessReference(int loops) {
TimingClass timing = new TimingClass();
for (int index = 0; index loops; index++) {
timing.m_value = (timing.m_value + ADDITIVE_VALUE) *
MULTIPLIER_VALUE;
}
return timing.m_value;
}
public int accessReflection(int loops) throws Exception {
TimingClass timing = new TimingClass();
try {
Field field = TimingClass.class.
getDeclaredField(“m_value”);
for (int index = 0; index loops; index++) {
int value = (field.getInt(timing) +
ADDITIVE_VALUE) * MULTIPLIER_VALUE;
field.setInt(timing, value);
}
return timing.m_value;
} catch (Exception ex) {
System.out.println(“Error using reflection”);
throw ex;
}
}
在上面的例子中,測試程序重複調用每種方法,使用一個大循環數,從而平均多次調用的時間衡量結果。平均值中不包括每種方法第一次調用的時間,因此初始化時間不是結果中的一個因素。下面的圖清楚的向我們展示了每種方法字段接入的時間:
圖 1:字段接入時間 :
我們可以看出:在前兩副圖中(Sun JVM),使用反射的執行時間超過使用直接接入的1000倍以上。通過比較,IBM JVM可能稍好一些,但反射方法仍舊需要比其它方法長700倍以上的時間。任何JVM上其它兩種方法之間時間方面無任何顯著差異,但IBM JVM幾乎比Sun JVM快一倍。最有可能的是這種差異反映了Sun Hot Spot JVM的專業優化,它在簡單基準方面表現得很糟糕。反射性能是Sun開發1.4 JVM時關注的一個方面,它在反射方法調用結果中顯示。在這類操作的性能方面,Sun 1.4.1 JVM顯示了比1.3.1版本很大的改進。
如果為為創建使用反射的對象編寫了類似的計時測試程序,我們會發現這種情況下的差異不象字段和方法調用情況下那麼顯著。使用newInstance()調用創建一個簡單的java.lang.Object實例耗用的時間大約是在Sun 1.3.1 JVM上使用new Object()的12倍,是在IBM 1.4.0 JVM的四倍,只是Sun 1.4.1 JVM上的兩部。使用Array.newInstance(type, size)創建一個數組耗用的時間是任何測試的JVM上使用new type[size]的兩倍,隨着數組大小的增加,差異逐步縮小。
結束語:
Java語言反射提供一種動態鏈接程序組件的多功能方法。它允許程序創建和控制任何類的對象(根據安全性限制),無需提前硬編碼目標類。這些特性使得反射特別適用於創建以非常普通的方式與對象協作的庫。例如,反射經常在持續存儲對象為數據庫、XML或其它外部格式的框架中使用。Java reflection 非常有用,它使類和數據結構能按名稱動態檢索相關信息,並允許在運行着的程序中操作這些信息。Java 的這一特性非常強大,並且是其它一些常用語言,如 C、C++、Fortran 或者 Pascal 等都不具備的。
但反射有兩個缺點。第一個是性能問題。用於字段和方法接入時反射要遠慢於直接代碼。性能問題的程度取決於程序中是如何使用反射的。如果它作為程序運行中相對很少涉及的部分,緩慢的性能將不會是一個問題。即使測試中最壞情況下的計時圖顯示的反射操作只耗用幾微秒。僅反射在性能關鍵的應用的核心邏輯中使用時性能問題才變得至關重要。
許多應用中更嚴重的一個缺點是使用反射會模糊程序內部實際要發生的事情。程序人員希望在源代碼中看到程序的邏輯,反射等繞過了源代碼的技術會帶來維護問題。反射代碼比相應的直接代碼更複雜,正如性能比較的代碼實例中看到的一樣。解決這些問題的最佳方案是保守地使用反射——僅在它可以真正增加靈活性的地方——記錄其在目標類中的使用。
利用反射實現類的動態加載
Bromon原創 請尊重版權
最近在成都寫一個移動增值項目,俺負責後台server端。功能很簡單,手機用戶通過GPRS打開Socket與服務器連接,我則根據用戶傳過來的數據做出響應。做過類似項目的兄弟一定都知道,首先需要定義一個類似於MSNP的通訊協議,不過今天的話題是如何把這個系統設計得具有高度的擴展性。由於這個項目本身沒有進行過較為完善的客戶溝通和需求分析,所以以後肯定會有很多功能上的擴展,通訊協議肯定會越來越龐大,而我作為一個不那麼勤快的人,當然不想以後再去修改寫好的程序,所以這個項目是實踐面向對象設計的好機會。
首先定義一個接口來隔離類:
package org.bromon.reflect;
public interface Operator
{
public java.util.List act(java.util.List params)
}
根據設計模式的原理,我們可以為不同的功能編寫不同的類,每個類都繼承Operator接口,客戶端只需要針對Operator接口編程就可以避免很多麻煩。比如這個類:
package org.bromon.reflect.*;
public class Success implements Operator
{
public java.util.List act(java.util.List params)
{
List result=new ArrayList();
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/286015.html