# 題記
JDK,Java Development Kit。
我們必須先認識到,JDK只是,僅僅是一套Java基礎類庫而已,是Sun公司開發的基礎類庫,僅此而已,JDK本身和我們自行書寫總結的類庫,從技術含量來說,還是在一個層級上,它們都是需要被編譯成字節碼,在JRE中運行的,JDK編譯后的結果就是jre/lib下的rt.jar,我們學習使用它的目的是加深對Java的理解,提高我們的Java編碼水平。
本系列所有文章基于的JDK版本都是1.7.16。
源碼下載地址:[https://jdk7.java.net/source.html](https://jdk7.java.net/source.html)
# 本節內容
在本節中,簡析java.lang包所包含的基礎類庫,當我們新寫一個class時,這個package里面的class都是被默認導入的,所以我們不用寫import java.lang.Integer這樣的代碼,我們依然使用Integer這個類,當然,如果你顯示寫了import java.lang.Integer也沒有問題,不過,何必多此一舉呢
# Object
默認所有的類都繼承自Object,Object沒有Property,只有Method,其方法大都是native方法(也就是用其他更高效語言,一般是c實現好了的),
Object沒有實現clone(),實現了hashCode(),哈希就是對象實例化后在堆內存的地址,用“==”比較兩個對象,實際就是比較的內存地址是否是一個,也就是hashCode()是否相等,
默認情況下,對象的equals()方法和==符號是一樣的,都是比較內存地址,但是有些對象重寫了equals()方法,比如String,使其達到比較內容是否相同的效果
另外兩個方法wait()和notify()是和多線程編程相關的,多線程里面synchronized實際就是加鎖,默認是用this當鎖,當然也可以用任何對象當鎖,wait()上鎖,線程阻塞,notify()開鎖,收到這個通知的線程運行。以下代碼示例:
~~~
class Test implements Runnable
{
private String name;
private Object prev;
private Object self;
public Test(String name,Object prev,Object self)
{
this.name=name;
this.prev = prev;
this.self = self;
}
@Override
public void run()
{
int count = 2;
while(count>0)
{
synchronized(prev)
{
synchronized(self)
{
System.out.println(name+":"+count);
count--;
self.notify(); //self解鎖
}
try
{
prev.wait(); //prev上鎖
} catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws Exception
{
Object a = new Object();
Object b = new Object();
Object c = new Object();
Test ta = new Test("A",c,a);
Test tb = new Test("B",a,b);
Test tc = new Test("C",b,c);
new Thread(ta).start();
Thread.sleep(10);
new Thread(tb).start();
Thread.sleep(10);
new Thread(tc).start();
}
}
~~~
以上代碼將順序輸出:A:2、B:2、C:2、A:1、B:1、C:1 。
Object類占用內存大小計算:[http://m.blog.csdn.net/blog/aaa1117a8w5s6d/8254922](http://m.blog.csdn.net/blog/aaa1117a8w5s6d/8254922)
Java如何實現Swap功能:[http://segmentfault.com/q/1010000000332606](http://segmentfault.com/q/1010000000332606)
# 構造函數和內部類
構造函數不能繼承,是默認調用的,如果不顯示用super指明的話,默然是調用的父類中沒有參數的構造函數。
~~~
class P {
public P() {System.out.println("P");}
public P(String name) {System.out.println("P" + name);}
}
class S extends P {
public S(String name) {
super("pname"); //不過不指定的話,默認是調用的父類的沒有參數的構造函數
System.out.println("name");
}
}
~~~
關于內部類,在應用編程中較少用到,但是JDK源碼中大量使用,比如Map.Entry,ConcurrentHashMap,ReentrantLock等,enum本身也會被編譯成static final修飾的內部類。
關于內部類的更多內容,可以參閱這篇文章:[http://android.blog.51cto.com/268543/384844/](http://android.blog.51cto.com/268543/384844/)
# Class和反射類
Java程序在運行時每個類都會對應一個Class對象,可以從Class對象中得到與類相關的信息,Class對象存儲在方法區(又名Non-Heap,永久代),當我們運行Java程序時,如果加載的jar包非常多,大于指定的永久代內存大小時,則會報出PermGen錯誤,就是Class對象的總計大小,超過永久代內存的緣故。
Class類非常有用,在我們做類型轉換時經常用到,比如以前用Thrift框架時,經常需要在Model類型的對象:Thrift對象和Java對象之間進行轉換,需要手工書寫大量模式化代碼,于是,就寫了個對象轉換的工具,在Thrift對象和Java對象的Property名字一致的情況下,可以使用這個工具直接轉換,其中大量使用了Class里面的方法和java.lang.reflect包的內容。
關于Calss類,方法眾多,不詳述。下面附上這個Thrift工具的代碼。
~~~
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Thrift前綴的對象和不含Thrift前綴的對象相互轉換.
* 參考:
* http://blog.csdn.net/it___ladeng/article/details/7026524
* http://www.cnblogs.com/jqyp/archive/2012/03/29/2423112.html
* http://www.cnblogs.com/bingoidea/archive/2009/06/21/1507889.html
* http://java.ccidnet.com/art/3539/20070924/1222147_1.html
* http://blog.csdn.net/justinavril/article/details/2873664
*/
public class ThriftUtil {
public static final Integer THRIFT_PORT = 9177;
/**
* Thrift生成的類的實例和項目原來的類的實例相關轉換并賦值
* 1.類的屬性的名字必須完全相同
* 2.當前支持的類型僅包括:byte,short,int,long,double,String,Date,List
* 3.如果有Specified列,則此列為true才賦值,否則,不為NULL就賦值
* @param sourceObject
* @param targetClass
* @param toThrift:true代表把JavaObject轉換成ThriftObject,false代表把ThriftObject轉換成JavaObject,ThriftObject中含有Specified列
* @return
*/
public static Object convert(Object sourceObject,Class<?> targetClass,Boolean toThrift)
{
if(sourceObject==null)
{
return null;
}
//對于簡單類型,不進行轉換,直接返回
if(sourceObject.getClass().getName().startsWith("java.lang"))
{
return sourceObject;
}
Class<?> sourceClass = sourceObject.getClass();
Field[] sourceFields = sourceClass.getDeclaredFields();
Object targetObject = null;
try {
targetObject = targetClass.newInstance();
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
};
if(targetObject==null)
{
return null;
}
for(Field sourceField:sourceFields)
{
try {
//轉換時過濾掉Thrift框架自動生成的對象
if(sourceField.getType().getName().startsWith("org.apache.thrift")
||sourceField.getName().substring(0,2).equals("__")
||("schemes,metaDataMap,serialVersionUID".indexOf(sourceField.getName())!=-1)
||(sourceField.getName().indexOf("_Fields")!=-1)
||(sourceField.getName().indexOf("Specified")!=-1)
)
{
continue;
}
//處理以DotNet敏感字符命名的屬性,比如operator
String sourceFieldName = sourceField.getName();
if(sourceFieldName.equals("operator"))
{
sourceFieldName = "_operator";
} else {
if(sourceFieldName.equals("_operator"))
{
sourceFieldName = "operator";
}
}
//找出目標對象中同名的屬性
Field targetField = targetClass.getDeclaredField(sourceFieldName);
sourceField.setAccessible(true);
targetField.setAccessible(true);
String sourceFieldSimpleName = sourceField.getType().getSimpleName().toLowerCase().replace("integer", "int");
String targetFieldSimpleName = targetField.getType().getSimpleName().toLowerCase().replace("integer", "int");
//如果兩個對象同名的屬性的類型完全一致:Boolean,String,以及5種數字類型:byte,short,int,long,double,以及List
if(targetFieldSimpleName.equals(sourceFieldSimpleName))
{
//對于簡單類型,直接賦值
if("boolean,string,byte,short,int,long,double".indexOf(sourceFieldSimpleName)!=-1)
{
Object o = sourceField.get(sourceObject);
if(o != null)
{
targetField.set(targetObject, o);
//處理Specified列,或者根據Specified列對數值對象賦NULL值
try
{
if(toThrift)
{
Field targetSpecifiedField = targetClass.getDeclaredField(sourceFieldName+"Specified");
if(targetSpecifiedField != null)
{
targetSpecifiedField.setAccessible(true);
targetSpecifiedField.set(targetObject, true);
}
} else {
Field sourceSpecifiedField = sourceClass.getDeclaredField(sourceFieldName+"Specified");
if(sourceSpecifiedField != null
&& "B,S,B,I,L,D".indexOf(targetField.getType().getSimpleName().substring(0,1))!=-1
)
{
sourceSpecifiedField.setAccessible(true);
if(sourceSpecifiedField.getBoolean(sourceObject)==false)
{
targetField.set(targetObject, null);
}
}
}
} catch (NoSuchFieldException e) {
//吃掉NoSuchFieldException,達到效果:如果Specified列不存在,則所有的列都賦值
}
}
continue;
}
//對于List
if(sourceFieldSimpleName.equals("list"))
{
@SuppressWarnings("unchecked")
List<Object> sourceSubObjs = (ArrayList<Object>)sourceField.get(sourceObject);
@SuppressWarnings("unchecked")
List<Object> targetSubObjs = (ArrayList<Object>)targetField.get(targetObject);
//關鍵的地方,如果是List類型,得到其Generic的類型
Type targetType = targetField.getGenericType();
//如果是泛型參數的類型
if(targetType instanceof ParameterizedType)
{
ParameterizedType pt = (ParameterizedType) targetType;
//得到泛型里的class類型對象。
Class<?> c = (Class<?>)pt.getActualTypeArguments()[0];
if(sourceSubObjs!=null)
{
if(targetSubObjs==null)
{
targetSubObjs = new ArrayList<Object>();
}
for(Object obj:sourceSubObjs)
{
targetSubObjs.add(convert(obj,c,toThrift));
}
targetField.set(targetObject, targetSubObjs);
}
}
continue;
}
}
//轉換成Thrift自動生成的類:Thrift沒有日期類型,我們統一要求日期格式化成yyyy-MM-dd HH:mm:ss形式
if(toThrift)
{
if(sourceFieldSimpleName.equals("date")&&targetFieldSimpleName.equals("string"))
{
Date d = (Date)sourceField.get(sourceObject);
if(d!=null)
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
targetField.set(targetObject,sdf.format(d));
}
continue;
}
} else {
if(sourceFieldSimpleName.equals("string")&&targetFieldSimpleName.equals("date"))
{
String s = (String)sourceField.get(sourceObject);
if(s!=null)
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
targetField.set(targetObject,sdf.parse(s));
}
continue;
}
}
//對于其他自定義對象
targetField.set(targetObject, convert(sourceField.get(sourceObject),targetField.getType(),toThrift));
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
return targetObject;
}
}
~~~
### ClassLoader
類裝載器是用來把類(class)裝載進JVM的,JVM規范定義了兩種類型的類裝載器:啟動內裝載器 (bootstrap) 和用戶自定義裝載器 (user-defined class loader) 。
JVM在運行時會產生三個ClassLoader:Bootstrap ClassLoader、Extension ClassLoader和App ClassLoader.。
Bootstrap是用C++編寫的,我們在Java中看不到它,是null,是JVM自帶的類裝載器,用來裝載核心類庫,如java.lang.*等。
AppClassLoader 的 Parent 是ExtClassLoader ,而 ExtClassLoader 的 Parent 為 Bootstrap ClassLoader 。?
Java 提供了抽象類 ClassLoader ,所有用戶自定義類裝載器都實例化自 ClassLoader 的子類。?
System Class Loader 是一個特殊的用戶自定義類裝載器,由 JVM 的實現者提供,在編程者不特別指定裝載器的情況下默認裝載用戶類 ,系統類裝載器可以通過ClassLoader.getSystemClassLoader() 方法得到。
**代碼演示如下:**
~~~
class ClassLoaderTest {
public static void main(String[] args) throws Exception{
Class c;
ClassLoader cl;
cl = ClassLoader.getSystemClassLoader();
System.out.println(cl);
while(cl != null) {
cl = cl.getParent();
System.out.println(cl);
}
c = Class.forName("java.lang.Object");
cl = c.getClassLoader();
System.out.println("java.lang.Object's loader is " + cl);
c = Class.forName("ClassLoaderTest");
cl = c.getClassLoader();
System.out.println("ClassLoaderTest's loader is " + cl);
}
}
~~~
# 八種基本數據類型
| 類類型 | 原生類型(primitive) | 代表意義 |
|-----|-----|-----|
| Boolean | boolean | 布爾 |
| Character | char | 單個Unicode字符,占用兩個字節,例如'a','中',范圍0-65535 |
| Byte | byte | 8位有符號整型 |
| Short | short | 16位有符號整型 |
| Integer | int | 32位有符號整型 |
| Long | long | 64位有符號整型 |
| Float | float | 單精度浮點 |
| Double | double | 雙精度浮點 |
了解到數據類型,就要了解一點編碼(數字在計算機中的01編碼)的知識,計算機是用01表示所有類型的,第一位是符號位,0+1-,java中得整型都是有符號的。
對于數字,定義了原碼、反碼和補碼。
正數的原碼、反碼和補碼都是一樣的,負數的反碼是除符號位之外,所有位取反,補碼是反碼+1,以Byte類型為例:
能表示的數字范圍是-128~127,總計256個數,對于0~127,表示為:0000000~01111111,即0~2^7-1,對于負數,-128~-1,表示如下:
-127~-1,其原碼分別為11111111~10000001,換算成補碼是10000001~11111111,然后10000000代表-128,-128只有補碼,沒有原碼和反碼。
**補碼的設計目的:**
使符號位能與有效值部分一起參加運算,從而簡化運算規則。補碼機器數中的符號位,并不是強加上去的,是數據本身的自然組成部分,可以正常地參與運算。
使減法運算轉換為加法運算,進一步簡化計算機中運算器的線路設計。
反碼是原碼與補碼轉換的一個中間過渡,使用較少。
所有這些轉換都是在計算機的最底層進行的,而在我們使用的匯編、c等其他高級語言中使用的都是原碼。
除此之外,JDK原碼還經常使用>>、>>>運算符,>>是有符號移位,高位補符號位,右移;>>>是無符號移為,高位補0,右移。
關于數據類型的內存存儲,如下描述一下:
原生類型,比如int i = 3,不論是變量,還是值,都是存儲在棧中的;
類類型,比如Integer i = 300,則變量是存儲在棧中,對象是存儲在堆中的一個對象,既然Integer是這樣,那么Integer a = 300,Integer b = 300,請問 a == b,是否成立?
答案是:不成立的,因為兩個對象的內存地址不同了;
既然這樣,那么Integer a = 1,Integer b = 1,請問a == b,是否成立?
答案是:成立的,這其實是Java的一個坑,我們可以看Integer對于int進行封箱操作的源碼,如下:
~~~
public static Integer valueOf(int i) {
if(i >= -128 && i<= IntegerCache.high)
return IntegerCache.cache[i+128];
else
return new Integer(i);
}
~~~
由此可見,對于128之內的數字,是進行了Cache存儲的 ,所以在堆中的內存地址是一樣的,所以成立。
在編程中,可以對于數字前面加0x表示16進制數,加0表示8進制數,默認是10進制數;在數字的后面增加L表示long類型,默認是整型;對于浮點數,在后面增加F表示float類型,模式是double型。
對于類型轉換,比如int i=(int)1.5,會直接把小數后面的部分去掉,對于數學函數Math.round()、Math.ceil()、Math.floor(),可以把數字想象成0為水平線,負數在水平線下,正數在水平線上,ceil是轉換成天花板,floor是轉換成地板,round()是四舍五入,等于+0.5之后求floor。
# String
String a = "abc",String b = "abc",a == b是成立的,這是String的編譯時優化,對于字符串常量,在內存中只存一份(JDK6是存儲在“方法區”的“運行時常量區”,JDK7是存儲在堆中);
我們對于String進一步分析:
String a = "a" + "b" + "c",String b = "abc",a == b依然是成立的,原理同上;
String t = "a",String a = t + "b" + "c",String b = "abc",則a == b是不成立的,因為對于變量,編譯器無法進行編譯時優化;但是a.intern() == b是成立的,因為當調用intern()方法時,是到運行時常量池中找值相對的對象,找到了b,所以a.intern() == b。
final String t = "a",String a = t + "b" + "c",String b = "abc",則a == b是成立的,因為final是不可以重新賦值的,編譯器可以進行編譯時優化;
對于String s = a + b這樣的操作,每次操作,都會在堆中開辟一塊內存空間,所以對于頻繁大量的字符操作,性能低,所以對于大量字符操作,推薦使用的StringBuffer和StringBuilder,其中StringBuffer是線程安全的,StringBuilder是1.5版本新加的,是非線程安全的。
### 實現36進制加法,及字符串替換代碼演示
~~~
public class RadixAndReplace {
public static void main(String[] args) {
//1.36進制加法(不允許使用字符串整體轉換為10進制再相加的辦法,所以只能按位加)
System.out.println(add("ZZ","ZZZ"));
System.out.println(add("3A","2"));
//2.替換字符串(考慮替換之后符合要求的情況,只用一次循環)
System.out.println(replace("acbd"));
System.out.println(replace("abcd"));
}
//36進制加法
public static String add(String s1,String s2) {
int l1 = s1.length(),l2 = s2.length();
int maxLength = l1 > l2 ? l1 : l2;
int carrybit = 0; //進位
StringBuilder sb = new StringBuilder();
for(int i = 0 ; i < maxLength ; i++) {
int r1 = i < l1 ? convertToNumber(s1.charAt(s1.length()-1-i)) : 0;
int r2 = i < l2 ? convertToNumber(s2.charAt(s2.length()-1-i)) : 0;
String r = convertToString(r1 + r2 + carrybit);
carrybit = r.length() == 2 ? 1 : 0;
sb.append(r.charAt(r.length()-1));
}
if(carrybit == 1) {
sb.append("1");
}
return sb.reverse().toString();
}
//把字符(A-Z代表10-36,a-z代表37-72)
private static int convertToNumber(char ch)
{
int num = 0;
if(ch >= 'A' && ch <= 'Z')
num = ch - 'A' + 10;
else if(ch >= 'a' && ch <= 'z')
num = ch - 'a' + 36;
else
num = ch - '0';
return num;
}
//轉換數字為36進制的字符串表示
//A的ASCII碼是65,a的ASCII碼是97
private static String convertToString(int n) {
if(n >= 0 && n <= 9) {
return String.valueOf(n);
}
if(n >= 10 && n <= 35) {
return String.valueOf((char)(n-10+65));
}
if(n >= 36 && n <= 71) {
return "1" + convertToString(n-36);
}
return "0";
}
//替換字符串“ac”,“b”,考慮b在ac中間的情況
public static String replace(String str) {
StringBuilder sb = new StringBuilder();
Boolean flag = false; //連續判斷標志位
for(int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if(c == 'b') continue;
if(c == 'a') {
flag = true;
continue;
}
if(c == 'c' && flag) {
flag = false;
continue;
}
if(flag) {
sb.append('a').append(c);
} else {
sb.append(c);
}
}
return sb.toString();
}
}
~~~
# 異常和錯誤
Exception和Error都繼承自Throwable對象,Exception分為兩類,RuntimeException(運行時異常,unchecked)和一般異常(checked),Error是比較嚴重的錯誤,也是unchecked。
簡單地講,checked是必須用try/catch 或者throw處理的,可以在執行過程中恢復的,比如java.io.FileNotFoundException;而unchecked異常則是不需要try/catch處理的,比如java.lang.NullPointerException。
在比較流行的語言中,Java是唯一支持checked異常,要求我們必須進行處理的語言,這有利有弊。
關于異常類、錯誤類,在JDK中定義了很多,用來描述我們的代碼可能遇到的各種類型的錯誤,這里不一一整理描述。
### UnsupportedOperationException
舉個例子,如下:
在其他語言(比如C#),如果一個類中,某些方法還沒有完成,但是需要提供一個名字給別人調用,我們可以先對這個方法加行代碼throw new Exception("xxx");
剛用Java時,我們可能也想只是給一行代碼throw new Exception,這是不合理的,因為:對于非RuntimeException,必須try/catch,或者在方法名后面增加throws Exception(這導致調用這個方法的地方都要try/catch,或者throws,是不合理的);所以,對于這個功能,我們正確的做法是:throws new UnsupportedOperationException("xxx"),這個是運行時異常,unchecked。
# Runtime
java.lang包里有很多運行時環境相關的類,可以查看運行時環境的各種信息,比如內存、鎖、安全、垃圾回收等等。見過如下鉤子代碼,在JVM關閉時,執行一些不好在程序計算過程中進行的資源釋放工作,如下:
~~~
public class MongoHook {
static void addCloseHook(){
Runtime.getRuntime().addShutdownHook( new Thread(){
@Override
public void run() {
MongoDBConn.destoryAllForHook() ;
}
}) ;
}
}
~~~
關于這個推出鉤子,實際是java.lang包種的以下3個類配合完成的:Runtime、Shutdown、ApplicationShutdownHooks。
# 多線程
Thread、Runnable、ThreadLocal等,關于多線程的更多知識,可以[參閱](http://blog.csdn.net/puma_dong/article/details/37597261)。
# 接口
Clonable:生命式接口
Comparable:對象比較,泛型類
Appendable:
CharSequence:統一的字符串只讀接口,共有4個方法,length()、charAt()、subSequence()、toString()。
Readable:
Iterable:迭代器
# 注解類
主要在java.lang.annotation包中,注解類用@interface來進行定義,注解類的作用范圍可以是方法、屬性、包等,作用失效可以是Source、Runtime、Class。
比如Override就是一個注解類,用來標記實現接口中定義的類,其源碼如下;
~~~
package java.lang;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
~~~
注解本身不做任何事情,只是像xml文件一樣起到配置作用。注解代表的是某種業務意義,spring中@Resource注解簡單解析:首先解析類的所有屬性,判斷屬性上面是否存在這個注解,如果存在這個注解,再根據搜索規則來取得這個bean,然后通過反射注入。
**注解有如下規則:**
1)所有的注解類都隱式繼承于 java.lang.annotation.Annotation,注解不允許顯式繼承于其他的接口。
2)注解不能直接干擾程序代碼的運行,無論增加或刪除注解,代碼都能夠正常運行。Java語言解釋器會忽略這些注解,而由第三方工具負責對注解進行處理。
3)注解的成員以無入參、無拋出異常的方式聲明;可以通過default為成員指定一個默認值;成員類型是受限的,合法的類型包括primitive及其封裝類、String、Class、enums、注解類型,以及上述類型的數組類型;注解類可以沒有成員,沒有成員的注解稱為標識注解,解釋程序以標識注解存在與否進行相應的處理。
代碼示例1:
~~~
package com.cl.search.utils;
import java.lang.annotation.*;
import java.lang.reflect.*;
public class MyAnnotationTest {
public static void main(String[] args) {
Test test = Container.getBean();
test.loginTest();
}
}
@Documented
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface AnnotationTest {
public String nation() default "";
}
interface IUser {
public void login();
}
class ChineseUserImpl implements IUser {
@Override
public void login() {
System.err.println("用戶登錄!");
}
}
class EnglishUserImpl implements IUser {
@Override
public void login() {
System.err.println("User Login!");
}
}
@AnnotationTest
class Test {
private IUser userdao;
public IUser getUserdao() {
return userdao;
}
@AnnotationTest(nation = "EnglishUserImpl")
public void setUserdao(IUser userdao) {
this.userdao = userdao;
}
public void loginTest() {
userdao.login();
}
}
class Container {
public static Test getBean() {
Test test = new Test();
if (Test.class.isAnnotationPresent(AnnotationTest.class)) {
Method[] methods = Test.class.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
if (method.isAnnotationPresent(AnnotationTest.class)) {
AnnotationTest annotest = method.getAnnotation(AnnotationTest.class);
System.out.println("AnnotationTest(field=" + method.getName()
+ ",nation=" + annotest.nation() + ")");
IUser userdao;
try {
userdao = (IUser) Class.forName("com.cl.search.utils." + annotest.nation()).newInstance();
test.setUserdao(userdao);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
} else {
System.out.println("沒有注解標記!");
}
return test;
}
}
~~~
# java.lang.ref包
java.lang.ref 是 Java 類庫中比較特殊的一個包,它提供了與 Java 垃圾回收器密切相關的引用類。這篇IBM工程師寫的文章很好:[深入探討 java.lang.ref 包](http://www.ibm.com/developerworks/cn/java/j-lo-langref/)。
# java.lang.AutoCloseable接口
在Java7中,引入了一個新特性try-with-resource,即在try中的代碼,其資源會自動釋放,不用手工執行資源釋放操作。
要求跟在try后面的資源必須實現AutoCloseable接口,否則會報變異錯誤,代碼示例如下:
~~~
class CustomResource implements AutoCloseable
{
@Override
public void close() throws Exception {
System.out.println("進行資源釋放操作!");
}
public static void main(String[] args) throws Exception {
try(CustomResource r = new CustomResource()) {
System.out.println("使用資源!");
}
}
}
~~~
- 前言
- Java之旅--如何從草根成為技術專家
- 《深入理解Java虛擬機》學習筆記
- 《Spring3.X企業應用開發實戰》學習筆記--IoC和AOP
- 《Tomcat權威指南》第二版學習筆記
- Java之旅--多線程進階
- Java之旅--Web.xml解析
- 《Spring3.X企業應用開發實戰》學習筆記--DAO和事務
- 《Spring3.X企業應用開發實戰》學習筆記--SpringMVC
- Java之旅--定時任務(Timer、Quartz、Spring、LinuxCron)
- Spring實用功能--Profile、WebService、緩存、消息、ORM
- JDK框架簡析--java.lang包中的基礎類庫、基礎數據類型
- JDK框架簡析--java.util包中的工具類庫
- JDK框架簡析--java.io包中的輸入輸出類庫
- Java之旅--通訊
- Java之旅--XML/JSON
- Java之旅--Linux&amp;java進階(看清操作系統層面的事)
- Java之旅--硬件和Java并發(神之本源)
- Java之旅--設計模式
- jetty