一、Eclipse的使用 (myeclipse 10)java
(1)工做空間(workspace)、工程(project)程序員
(2)在eclipse下Java程序的編寫和運行,及java運行環境的配置。編程
(3)快捷鍵的配置,經常使用快捷鍵:bootstrap
內容提示:Alt + / 設計模式
快速修復:Ctrl + 1api
導包:Ctrl + shift + O數組
格式化代碼塊:ctrl + shift + F安全
向前向後:Alt + 方向鍵網絡
添加註釋 Ctrl+Shift+/session
除去註釋 Ctrl+Shift+\
(4)程序的調試和運行
F5(跳入) F6(跳過) F7(跳出)
Junit
(5)查看方法說明:F2
重置透視圖
更改成大寫 Ctrl+Shift+X
更改成小寫 Ctrl+Shift+Y
複製行 Ctrl+Alt+向下鍵(有些不能用) -------------- > win7 下更改 快捷鍵 (屏幕分辨率---> 高級設置---> ...)
查看源代碼
1、ctrl+T
2、ctrl+shift+T
測試用例
assert 類 api
二、JDK 5.0 新特性 1.0
JDK5中新增了不少新的java特性,利用這些新語法能夠幫助開發人員編寫出更加高效、清晰,安全的代碼。
(1)靜態導入
(2)自動裝箱/拆箱
(3)加強for循環
(4)可變參數
(5)枚舉
(6)泛型
(7)元數據
三、靜態導入
(1)JDK 1.5 增長的靜態導入語法用於導入類的某個靜態屬性或方法。使用靜態導入能夠簡化程序對類靜態屬性和方法的調用。
(2)語法:
Import static 包名.類名.靜態屬性|靜態方法|*
(3)例如:
import static java.lang.System.out
import static java.lang.Math.*
4、自動裝箱/拆箱
(1)JDK5.0的語法容許開發人員把一個基本數據類型直接賦給對應的包裝類變量, 或者賦給 Object 類型的變量,這個過程稱之爲自動裝箱。
(2)自動拆箱與自動裝箱與之相反,即把包裝類對象直接賦給一個對應的基本類型變量。
(3)典型應用:
List list = new ArrayList();
list.add(1);
int j = (Integer)list.get(0);
5、加強for循環
(1)引入加強for循環的緣由:在JDK5之前的版本中,遍歷數組或集合中的元素,需先得到數組的長度或集合的迭代器,比較麻煩!
(2)所以JDK5中定義了一種新的語法——加強for循環,以簡化此類操做。加強for循環只能用在數組、或實現Iterator接口的集合類上
(3)語法格式:
for(變量類型 變量 :需迭代的數組或集合){
}
例子:
int arr[] = new int[5];
for(int num : arr){
num = 1;
}
System.out.println(arr[0]);
六、可變參數
(1)測試JDK中具備可變參數的類Arrays.asList()方法。分別傳多個參、傳數組,傳數組又傳參的狀況。
注意:傳入基本數據類型數組的問題。
(2)從JDK 5開始, Java 容許爲方法定義長度可變的參數。語法:
public void foo(int … args){
}
(3)注意事項:
調用可變參數的方法時, 編譯器將自動建立一個數組保存傳遞給方法的可變參數,所以,程序員能夠在方法體中以數組的形式訪問可變參數
可變參數只能處於參數列表的最後, 因此一個方法最多隻能有一個長度可變的參數
7、枚舉類
(1)爲何須要枚舉?
一些方法在運行時,它須要的數據不能是任意的,而必須是必定範圍內的值,此類問題在JDK5之前採用自定義帶有枚舉功能的類解決,Java5之後能夠直接使用枚舉予以解決。
(2)JDK 5新增的 enum 關鍵字用於定義一個枚舉類。
(3)枚舉類具備以下特性:
1、枚舉類也是一種特殊形式的Java類。
2、枚舉類中聲明的每個枚舉值表明枚舉類的一個實例對象。
3、與java中的普通類同樣,在聲明枚舉類時,也能夠聲明屬性、方法和構造函數,但枚舉類的構造函數必須爲私有的(這點不難理解)。
4、枚舉類也能夠實現接口、或繼承抽象類。
5、JDK5中擴展了swith語句,它除了能夠接收int, byte, char, short外,還能夠接收一個枚舉類型。
若枚舉類只有一個枚舉值,則能夠看成單態設計模式使用。
練習:請編寫一個關於星期幾的枚舉WeekDay,要求:
枚舉值:Mon,Tue,Wed,Thu,Fri,Sat,Sun
該枚舉要有一個方法,調用該方法返回中文格式的星期。
(3)Java中聲明的枚舉類,均是java.lang.Enum類的孩子,它繼承了Enum類的全部方法。經常使用方法:
name()
ordinal()
valueof(Class enumClass, String name)
values() 此方法雖然在JDK文檔中查找不到,但每一個枚舉類都具備該方法,它遍歷枚舉類的全部枚舉值很是方便。
八、反射
(1)什麼是反射?
反射就是把Java類中的各類成分映射成一個個的java對象(加載類,解剖出類的各個組成部分)。例如,一個類有:成員變量,方法,構造方法,包等等信息,利用反射技術能夠對一個類進行解剖,把各個組成部分映射成一個個對象。
(2)反射用在哪裏?
(3)學習反射應該掌握些什麼?
9、Class類
(1)Class類用於表示.class文件,畫圖演示一個對象的建立過程。
(2)如何獲得某個class文件對應的class對象。
類名.class,
對象.getClass()
Class.forName(「類名」)
(3)數組類型的Class實例對象
Class.isArray()
(4)總之,只要是在源程序中出現的類型,都有各自的Class實例對象,例如,int,void…
10、Constructor類
(1)Constructor類的實例對象表明類的一個構造方法。
(2)獲得某個類全部的構造方法,例:
Constructor [] constructors= Class.forName("java.lang.String").getConstructors();
(3)獲得某一個構造方法,例:
Constructor constructor = Class.forName(「java.lang.String」).getConstructor(StringBuffer.class);
(4)利用構造方法建立實例對象:
String str = (String)constructor.newInstance(「abc」);
(5)Class類的newInstance()方法也可建立類的實例,其內部工做原理是先得無參的構造方法,再用構造方法建立實例對象。
String obj =(String)Class.forName("java.lang.String").newInstance();
(6)String obj =(String)Class.forName(「java.lang.String」).newInstance(); 這個也是 爲何 你們在學 基礎班的時候 , 老師跟你說 若是你的 一個類定義了一個有參的構造函數,那麼還須要在定義一個無參的構造函數.
11、Field類
(1)Field類表明某個類中的一個成員變量
(2)問題:獲得的Field對象是對應到類上面的成員變量,仍是對應到對象上的成員變量?類只有一個,而該類的實例對象有多個,若是是與對象關聯,哪關聯的是哪一個對象呢?因此字段fieldX 表明的是x的定義,而不是具體的x變量。(注意訪問權限的問題)
(3)示例代碼:
ReflectPoint point = new ReflectPoint(1,7);
Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");
System.out.println(y.get(point));
//Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");
Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");
x.setAccessible(true);
System.out.println(x.get(point));
12、Method類
(1)Method類表明某個類中的一個成員方法
(2)獲得類中的某一個方法:
例子: Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
(3)調用方法:
一般方式:System.out.println(str.charAt(1));
反射方式: System.out.println(charAt.invoke(str, 1));
若是傳遞給Method對象的invoke()方法的第一個參數爲null,這有着什麼樣的意義呢?說明該Method對象對應的是一個靜態方法!
(4)jdk1.4和jdk1.5的invoke方法的區別:
Jdk1.5:public Object invoke(Object obj,Object... args)
Jdk1.4:public Object invoke(Object obj,Object[] args),即按jdk1.4的語法,須要將一個數組做爲參數傳遞給invoke方法時,數組中的每一個元素分別對應被調用方法中的一個參數,因此,調用charAt方法的代碼也能夠用Jdk1.4改寫爲 charAt.invoke(「str」, new Object[]{1})形式。
13、用反射方式執行某個類中的main方法
(1)目標:
寫一個程序,這個程序可以根據用戶提供的類名,去執行該類中的main方法。用普通方式調完後,你們要明白爲何要用反射方式去調啊?
(2)問題:
啓動Java程序的main方法的參數是一個字符串數組,即public static void main(String[] args),經過反射方式來調用這個main方法時,如何爲invoke方法傳遞參數呢?按jdk1.5的語法,整個數組是一個參數,而按jdk1.4的語法,數組中的每一個元素對應一個參數,當把一個字符串數組做爲參數傳遞給invoke方法時,javac會到底按照哪一種語法進行處理呢?jdk1.5確定要兼容jdk1.4的語法,會按jdk1.4的語法進行處理,即把數組打散成爲若干個單獨的參數。因此,在給main方法傳遞參數時,不能使用代碼mainMethod.invoke(null,new String[]{「xxx」}),javac只把它看成jdk1.4的語法進行理解,而不把它看成jdk1.5的語法解釋,所以會出現參數類型不對的問題。
(3)解決辦法:
mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
mainMethod.invoke(null,(Object)new String[]{"xxx"}); ,編譯器會做特殊處理,編譯時不把參數看成數組看待,也就不會數組打散成若干個參數了
1四、內省(Introspector) — JavaBean
(1)什麼是JavaBean和屬性的讀寫方法?
(2)訪問JavaBean屬性的兩種方式:
直接調用bean的setXXX或getXXX方法。
經過內省技術訪問(java.beans包提供了內省的API),內省技術訪問也提供了兩種方式。
經過PropertyDescriptor類操做Bean的屬性
經過Introspector類得到Bean對象的 BeanInfo,而後經過 BeanInfo 來獲取屬性的描述器( PropertyDescriptor ),經過這個屬性描述器就能夠獲取某個屬性對應的 getter/setter 方法,而後經過反射機制來調用這些方法。
1五、內省—beanutils工具包
(1)Apache組織開發了一套用於操做JavaBean的API,這套API考慮到了不少實際開發中的應用場景,所以在實際開發中不少程序員使用這套API操做JavaBean,以簡化程序代碼的編寫。
(2)Beanutils工具包的經常使用類:
BeanUtils
PropertyUtils
ConvertUtils.regsiter(Converter convert, Class clazz)
自定義轉換器
16、泛型(Generic)—泛形的做用
(1)JDK5之前,對象保存到集合中就會失去其特性,取出時一般要程序員手工進行類型的強制轉換,這樣不可避免就會引起程序的一些安全性問題。例如:
(2)ArrayList list = new ArrayList();
list.add("abc");
Integer num = (Integer) list.get(0); //運行時會出錯,但編碼時發現不了
list.add(new Random());
list.add(new ArrayList());
for(int i=0;i<list.size();i++){
(?)list.get(i); //此處取出來的對象應轉換成什麼類型
}
(3)JDK5中的泛形容許程序員在編寫集合代碼時,就限制集合的處理類型,從而把原來程序運行時可能發生問題,轉變爲編譯時的問題,以此提升程序的可讀性和穩定性(尤爲在大型程序中更爲突出)。
(4)注意:泛型是提供給javac編譯器使用的,它用於限定集合的輸入類型,讓編譯器在源代碼級別上,即擋住向集合中插入非法數據。但編譯器編譯完帶有泛形的java程序後,生成的class文件中將再也不帶有泛形信息,以此使程序運行效率不受到影響,這個過程稱之爲「擦除」。
(5)泛形的基本術語,以ArrayList<E>爲例:<>念着typeof
ArrayList<E>中的E稱爲類型參數變量
ArrayList<Integer>中的Integer稱爲實際類型參數
整個稱爲ArrayList<E>泛型類型
整個ArrayList<Integer>稱爲參數化的類型ParameterizedType
17、泛型典型應用
(1)使用迭代器迭代泛形集合中的元素。
(2)使用加強for循環迭代泛形集合中的元素。
(3)存取HashMap中的元素。
(4)使用泛形時的幾個常見問題:
使用泛形時,泛形類型須爲引用類型,不能是基本數據類型
ArrayList<String> list = new ArrayList<Object>();
ArrayList<Object> list = new ArrayList<String>();
ArrayList<String> list = new ArrayList ();// 兼容老程序
ArrayList list = new ArrayList<String>();
18、自定義泛形——泛型方法
(1)Java程序中的普通方法、構造方法和靜態方法中均可以使用泛型。方法使用泛形前,必須對泛形進行聲明,語法:<T> ,T能夠是任意字母,但一般必需要大寫。<T>一般需放在方法的返回值聲明以前。例如:
public static <T> void doxx(T t);
(2)練習:
編寫一個泛形方法,實現指定位置數組元素的交換。
編寫一個泛形方法,接收一個任意數組,並顛倒數組中的全部元素。
(3)注意:
只有對象類型才能做爲泛型方法的實際參數。
在泛型中能夠同時有多個類型,例如:
public static <K,V> V getValue(K key) { return map.get(key);}
/點到任意數組中的指定位置上的兩個元素
//[1,2,3] 0 2 [3,2,1]
public static <T> void m1(T[] t,int index1,int index2){
//緩衝區
T temp = t[index1];
t[index1] = t[index2];
t[index2] = temp;
}
//顛倒任意數組中的元素順序
//[1,2,3] [3,2,1]
public static <T> void reverse(T[] t){
int startIndex = 0;
int endIndex = t.length -1;
while(startIndex<endIndex){
T temp = t[startIndex];
t[startIndex] = t[endIndex];
t[endIndex] = temp;
startIndex++;
endIndex--;
}
}
package com.itheima.base;
//把泛型定義在了類上面。可是隻對實例方法有效
public class Demo2<T> {
//<T>泛型的定義,後面的T就是使用了
//必須先定義才能使用。定義的語法就是<T>(字符隨便),可是必須放在返回值的前面
public T findOne(){
return null;
}
public void get(Class<T> clazz){
}
//靜態方法老是須要單獨定義泛型類型
public static <T> void get1(Class<T> clazz){
}
}
19、自定義泛形——泛型類和反射泛形
(1)若是一個類多處都要用到同一個泛型,這時能夠把泛形定義在類上(即類級別的泛型),語法格式以下:
public class GenericDao<T> {
private T field1;
public void save(T obj){}
public T getId(int id){}
}
(2)注意,靜態方法不能使用類定義的泛形,而應單獨定義泛形。
(3)泛形的典型應用:BaseDao和反射泛型
package com.itheima.dao;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import org.hibernate.Session;
public class BaseDao<T> implements Dao<T> {
private Session session;
private Class clazz;
// public void setClazz(Class clazz) {//注入
// this.clazz = clazz;
// }
public BaseDao(){//注入
//給clazz賦值,知道具體子類的操做對象究竟是什麼類型的
Class cz = this.getClass();//當前實例對象
//System.out.println(cz.getName());
//獲得參數化的類型
ParameterizedType type = (ParameterizedType)cz.getGenericSuperclass();// BaseDao<Book> BaseDao<Product>
clazz = (Class)type.getActualTypeArguments()[0];//獲得第一個實際的泛型參數類型
}
public void add(T t) {
session.save(t);
}
public void update(T t) {
session.update(t);
}
public void delete(Serializable id) {
T t = findOne(id);
session.delete(t);
}
public T findOne(Serializable id) {
return (T)session.get(clazz, id);
}
}
package com.itheima.dao;
public class Book {
}
package com.itheima.dao;
public interface BookDao extends Dao<Book>{
}
package com.itheima.dao;
public class BookDaoImpl extends BaseDao<Book> implements BookDao {
}
package com.itheima.dao;
public class Client {
public static void main(String[] args) {
//ProductDao pDao = new ProductDaoImpl();
BookDao bDao = new BookDaoImpl();
}
}
package com.itheima.dao;
import java.io.Serializable;
public interface Dao<T> {
/**
* 執行添加實體的功能
* @param t
*/
void add(T t);
/**
* 更新記錄
* @param t
*/
void update(T t);
/**
* 按照主鍵刪除記錄
* @param id
*/
void delete(Serializable id);
/**
* 按照主鍵查詢一條記錄
* @param id
* @return
*/
T findOne(Serializable id);
}
package com.itheima.dao;
public class Product {
}
package com.itheima.dao;
import java.util.List;
//操做產品的dao
public interface ProductDao extends Dao<Product> {
//根據條件進行查詢
List<Product> findByCondition(String where);
}
package com.itheima.dao;
import java.util.List;
public class ProductDaoImpl extends BaseDao<Product> implements ProductDao {
//public ProductDaoImpl(){
//super(Product.class);
//}
public List<Product> findByCondition(String where) {
return null;
}
}
20、泛型的高級應用——通配符
(1)定義一個方法,接收一個集合,並打印出集合中的全部元素,以下所示:
void print (Collection<String> c) {
for (String e : c) {
System.out.println(e);
}
}
(2)問題:該方法只能打印保存了String對象的集合,不能打印其它集合。通配符用於解決此類問題,方法的定義可改寫爲以下形式:
void print (Collection<?> c) {//Collection<?>(發音爲:"collection of unknown")
for (Object e : c) {
System.out.println(e);
}
}
(3)此種形式下須要注意的是:因爲print方法c參數的類型爲Collection<?>,即表示一種不肯定的類型,所以在方法體內不能調用與類型相關的方法,例如add()方法。
(4)總結:使用?通配符主要用於引用對象,使用了?通配符,就只能調對象與類型無關的方法,不能調用對象與類型有關的方法。
import java.util.ArrayList;
import java.util.Collection;
public class Demo3 {
public static void main(String[] args) {
m1(new ArrayList<String>());
}
//泛型通配符
public static void m1(Collection<?> collection){
// collection.add(1);//使用通配符,因爲泛型的類型不肯定,所以方法內部不能調用與泛型有關的方法
for(Object o:collection)
System.out.println(o);
}
}
21、泛型的高級應用——有限制的通配符
(1)限定通配符的上邊界:
正確:Vector<? extends Number> x = new Vector<Integer>();
錯誤:Vector<? extends Number> x = new Vector<String>();
(2)限定通配符的下邊界:
正確:Vector<? super Integer> x = new Vector<Number>();
錯誤:Vector<? super Integer> x = new Vector<Byte>();
22、Annotation(註解) 概述
(1)從 JDK 5.0 開始, Java 增長了對元數據(MetaData) 的支持, 也就是 Annotation(註解)。
(2)什麼是Annotation,以及註解的做用?三個基本的 Annotation:
@Override: 限定重寫父類方法, 該註解只能用於方法
@Deprecated: 用於表示某個程序元素(類, 方法等)已過期
@SuppressWarnings: 抑制編譯器警告.
package com.itheima.annotation;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Demo1 {
@SuppressWarnings({"all"})
public static void main(String[] args) {
Date d = new Date();
System.out.println(d.toLocaleString());
List list = new ArrayList();
int i = 10;
mm();
}
@Override
public String toString() {
return super.toString();
}
@Deprecated
public static void mm(){
}
}
(3)Annotation 其實就是代碼裏的特殊標記, 它用於替代配置文件,也就是說,傳統方式經過配置文件告訴類如何運行,有了註解技術後,開發人員能夠經過註解告訴類如何運行。在Java技術裏註解的典型應用是:能夠經過反射技術去獲得類裏面的註解,以決定怎麼去運行類。
(4)掌握註解技術的要點:
如何定義註解
如何反射註解,並根據反射的註解信息,決定如何去運行類
2三、自定義 Annotation
(1)定義新的 Annotation 類型使用 @interface 關鍵字
(2)聲明註解的屬性
註解屬性的做用:原來寫在配置文件中的信息,能夠經過註解的屬性進行描述。
Annotation 的屬性聲明方式:String name();
屬性默認值聲明方式:String name() default 「xxx」;
特殊屬性value:若是註解中有一個名稱value的屬性,那麼使用註解時能夠省略value=部分,如@MyAnnotation(「xxx")
特殊屬性value[];
package com.itheima.annotation;
//都是Annotation子類
public @interface MyAnnotation1 {
String name();
int age();
String gender() default "male";
MyAnnotation2[] initParam();
}
package com.itheima.annotation;
public @interface MyAnnotation2 {
String paramName() default "";
String paramValue() default "";
}
package com.itheima.annotation;
public @interface MyAnnotation3 {
String value();
String name();
}
package com.itheima.annotation;
public @interface MyAnnotation4 {
String[] value();
}
package com.itheima.annotation;
public class MyAnnotationTest {
@MyAnnotation1(name = "shit", age = 18, gender = "female", initParam = {
@MyAnnotation2(paramName = "a", paramValue = "b"),
@MyAnnotation2(paramName = "x", paramValue = "y") })
//@MyAnnotation3(value="abc")
@MyAnnotation3(value="abc",name="xxx")//abc就是value屬性賦值
@MyAnnotation4({"abc","def"})
public void m1() {
}
}
24、JDK 的元 Annotation
(1)元 Annotation指修飾Annotation的Annotation。JDK中定義了以下元Annotation:
(2)@Retention: 只能用於修飾一個 Annotation 定義, 用於指定該 Annotation 能夠保留的域, @Rentention 包含一個 RetentionPolicy 類型的成員變量, 經過這個變量指定域。
RetentionPolicy.CLASS: 編譯器將把註解記錄在 class 文件中. 當運行 Java 程序時, JVM 不會保留註解. 這是默認值
RetentionPolicy.RUNTIME:編譯器將把註釋記錄在 class 文件中. 當運行 Java 程序時, JVM 會保留註解. 程序能夠經過反射獲取該註釋
RetentionPolicy.SOURCE: 編譯器直接丟棄這種策略的註釋
(3)@Target:指定註解用於修飾類的哪一個成員. @Target 包含了一個名爲 value,類型爲ElementType的成員變量。
(4)@Documented: 用於指定被該元 Annotation 修飾的 Annotation 類將被 javadoc 工具提取成文檔.
(5)@Inherited: 被它修飾的 Annotation 將具備繼承性.若是某個類使用了被 @Inherited 修飾的 Annotation, 則其子類將自動具備該註解
package com.itheima.annotation.app1;
public class UserDaoImplTest {
private UserDaoImpl dao = new UserDaoImpl();
/**
* 測試添加操做
*/
@MyTest
public void testAddUser() {
dao.addUser();
}
@MyTest
public void testDelUser() {
dao.delUser();
}
}
package com.itheima.annotation.app1;
public class UserDaoImpl {
public void addUser(){
System.out.println("addUser");
}
public void delUser(){
System.out.println("delUser");
}
}
package com.itheima.annotation.app1;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface MyTest {
}
public class MyTestRunner {
public static void main(String[] args) throws Exception {
runTest(UserDaoImplTest.class);
}
/**
* 執行測試
* @param clazz測試類的的字節碼
* @throws Exception
*/
public static void runTest(Class clazz) throws Exception{
//只有@MyTest註解的方法纔是測試方法
//獲得測試類中的全部方法 Tips:Class Method Field Constructor都實現了AnnotatedElement接口
Method ms[] = clazz.getMethods();
//遍歷:看看誰的上面有@MyTest
for(Method m:ms){
//誰有就執行誰
boolean b = m.isAnnotationPresent(MyTest.class);
if(b)
m.invoke(clazz.newInstance(), null);
}
}
}
package com.itheima.annotation.app2;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Limit {
float value();
}
package com.itheima.annotation.app2;
public class Client {
public static void main(String[] args) throws Exception {
Account a = new Account(1000000);
a.drawMoney(3000);
}
}
package com.itheima.annotation.app2;
import java.lang.reflect.Method;
public class Account {
private float amount;//餘額
public Account(float amount){//開戶
this.amount = amount;
}
//取款
@Limit(4000)
public void drawMoney(float money) throws Exception{
//先判斷餘額足嗎
if(money>amount)
throw new RuntimeException("餘額不足");
//用傳統方式
//ResourceBundle rb = ResourceBundle.getBundle("com.itheima.annotation.app2.cfg");
//String sLimit = rb.getString("limit");
//用註冊方式
Class clazz = Account.class;
Method m = clazz.getMethod("drawMoney", float.class);//獲得取款這個方法
Limit limitAnno = m.getAnnotation(Limit.class);//獲得方法上的Limit註解
float limit = limitAnno.value();//取屬性的值
//判斷一次取款是否超限:2K 3K
//float limit = Float.parseFloat(sLimit);
if(money>limit)
throw new RuntimeException("一次取款不能超過"+limit);
amount = amount-money;
System.out.println("您本次取款:"+money+",餘額是:"+amount);
}
}
2五、提取 Annotation 信息
(1)JDK 5.0 在 java.lang.reflect 包下新增了 AnnotationElement 接口, 該接口表明程序中能夠接受註釋的程序元素
(2)當一個 Annotation 類型被定義爲運行時 Annotation 後, 該註釋纔是運行時可見, 當 class 文件被載入時保存在 class 文件中的 Annotation 纔會被虛擬機讀取
(3)程序能夠調用 AnnotationElement 對象的以下方法來訪問 Annotation 信息
2六、動態代理
(1)明確兩個概念:
代理對象存在的價值:主要用於攔截對真實業務對象的訪問。
代理對象有什麼方法?
(2)如今要生成某一個對象的代理對象,這個代理對象一般也要編寫一個類來生成,因此首先要編寫用於生成代理對象的類。
(3)如何編寫生成代理對象的類,兩個要素:
代理誰
如何生成代理對象
(4)代理誰?
設計一個類變量,以及一個構造函數,記住代理類 代理哪一個對象。
(5)如何生成代理對象?
設計一個方法生成代理對象(在方法內編寫代碼生成代理對象是此處編程的難點)
(6)Java提供了一個Proxy類,調用它的newInstance方法能夠生成某個對象的代理對象,使用該方法生成代理對象時,須要三個參數:
1.生成代理對象使用哪一個類裝載器
2.生成哪一個對象的代理對象,經過接口指定
3.生成的代理對象的方法裏幹什麼事,由開發人員編寫handler接口的實現來指定。
(7)初學者必須理解,或不理解必須記住的2件事情:
Proxy類負責建立代理對象時,若是指定了handler(處理器),那麼無論用戶調用代理對象的什麼方法,該方法都是調用處理器的invoke方法。
因爲invoke方法被調用須要三個參數:代理對象、方法、方法的參數,所以無論代理對象哪一個方法調用處理器的invoke方法,都必須把本身所在的對象、本身(調用invoke方法的方法)、方法的參數傳遞進來。
package com.itheima.proxy;
public class SpringBrother implements Human {
public void sing(float money) {
System.out.println("拿到"+money+"錢,開唱");
}
public void dance(float money) {
System.out.println("拿到"+money+"錢,開跳");
}
public void eat() {
System.out.println("吃飯");
}
}
package com.itheima.proxy;
public interface Human {
void sing(float money);
void dance(float money);
void eat();
}
package com.itheima.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
final Human h = new SpringBrother();
//動態獲得代理人
/**
* loader:代理人使用的類加載器。與被代理人h使用的是同樣的
* interfaces:代理人要實現的接口。與被代理人h所實現的接口是同樣的
* InvocationHandler h:策略設計模式。具體該怎麼代理?
*/
Human proxyHuman = (Human)Proxy.newProxyInstance(h.getClass().getClassLoader(), h.getClass().getInterfaces(), new InvocationHandler() {
//具體怎麼代理:具體代理策略
/**
* 調用被代理人的任何方法都會執行該方法
* proxy:代理對象的引用
* method:當前執行的是什麼方法
* args:當前執行的方法須要的參數
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// System.out.println("被代理了");
if("sing".equals(method.getName())){
//判斷出場費
float money = (Float)args[0];
if(money>=10000){
return method.invoke(h, money/2);
}
return null;
}else if("dance".equals(method.getName())){
//判斷出場費
float money = (Float)args[0];
if(money>=20000){
return method.invoke(h, money/2);
}
return null;
}else{
return method.invoke(h, args);
}
}
});
proxyHuman.sing(20000);
proxyHuman.dance(30000);
proxyHuman.eat();
}
}
2七、動態代理應用
(1)在動態代理技術裏,因爲無論用戶調用代理對象的什麼方法,都是調用開發人員編寫的處理器的invoke方法(這至關於invoke方法攔截到了代理對象的方法調用)。
(2)而且,開發人員經過invoke方法的參數,還能夠在攔截的同時,知道用戶調用的是什麼方法,所以利用這兩個特性,就能夠實現一些特殊需求,例如:攔截用戶的訪問請求,以檢查用戶是否有訪問權限、動態爲某個對象添加額外的功能。
28、類加載器
(1)類加載器負責將 .class 文件(可能在磁盤上, 也可能在網絡上) 加載到內存中, 併爲之生成對應的 java.lang.Class 對象
(2)當 JVM 啓動時,會造成由三個類加載器組成的初始類加載器層次結構:
2九、bootstrap classloader
(1)bootstrap classloader:引導(也稱爲原始)類加載器,它負責加載Java的核心類。這個加載器的是很是特殊的,它實際上不是 java.lang.ClassLoader的子類,而是由JVM自身實現的。能夠經過執行如下代碼來得到bootstrap classloader加載了那些核心類庫:
由於JVM在啓動的時候就自動加載它們,因此不須要在系統屬性CLASSPATH中指定這些類庫
30、extension classloader
extension classloader -擴展類加載器,它負責加載JRE的擴展目錄(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系統屬性指定的)中的JAR包。這爲引入除Java核心類之外的新功能提供了一個標準機制。由於默認的擴展目錄對全部從同一個JRE中啓動的JVM都是通用的,因此放入這個目錄的 JAR類包對全部的JVM和system classloader都是可見的。
3一、system classloader
(1)system classloader - 系統(也稱爲應用)類加載器,它負責在JVM被啓動時,加載來自在命令java中的-classpath或者java.class.path系統屬性或者 CLASSPATH操做系統屬性所指定的JAR類包和類路徑。
(2)能夠經過靜態方法ClassLoader.getSystemClassLoader()找到該類加載器。若是沒有特別指定,則用戶自定義的任何類加載器都將該類加載器做爲它的父加載器。
32、全盤負責委託機制 :父類委託機制
(1)classloader 加載類用的是全盤負責委託機制。
(2)全盤負責:便是當一個classloader加載一個Class的時候,這個Class所依賴的和引用的其它Class一般也由這個classloader負責載入。
(3)委託機制:先讓parent(父)類加載器 尋找,只有在parent找不到的時候才從本身的類路徑中去尋找。
(4)類加載還採用了cache機制:若是 cache中保存了這個Class就直接返回它,若是沒有才從文件中讀取和轉換成Class,並存入cache,這就是爲何修改了Class可是必須從新啓動JVM才能生效,而且類只加載一次的緣由。