1,由內省引出的 javaBean講解
內省→IntroSpector(檢查,視察,瞭解內部的細節)→對JavaBean操作→是一個特殊的java類,方法的名稱符合某種約定的規則的java類。
這種java類中的方法用於訪問私有的字段,且方法名符合某種命名規則。
從方法得到屬性-->如果第二個字母是小寫,則把第一個字符變成小寫的
gettime--time setTime---time getCPU--CPU
總之,一個類被當做javaBean使用時,javaBean的屬性是根據方法名推斷出來的,它根本看不到java類內部的成員變量。
一個符合javaBean特點的類可以當做普通類一樣使用,但把它當做javaBean用肯定需要帶來一些額外的好處,我們纔會去了解和應用javaBean
javaEE開發中,經常用到javaBean。很多環境就要求按JavaBean方式進行操作
如果要在兩個模塊之間傳遞多個信息,可以將這些信息封裝到一個JavaBean中,這種JavaBean的實例對象通常稱爲值對象(Value Object,簡稱VO)。
jdk中提供了一些api,這套內省就稱爲內省。
內省的綜合案例。package com.itcast.zhang;
public class ReflectPoint {
private int x;// 私有成員變量
public int y;// 共有成員變量
// 共有成員變量str1;str2;str3;
public String str1 = "ball";
public String str2 = "baseketball";
public String str3 = "itcast";
/**
* 得到x
*
* @return
*/
public int getX() {
return x;
}
/**
* 設置x
*
* @param x
*/
public void setX(int x) {
this.x = x;
}
/*
* 得到y
*/
public int getY() {
return y;
}
/**
* 設置y
*
* @param y
*/
public void setY(int y) {
this.y = y;
}
/**
* 構造方法
*
* @param x
* @param y
*/
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
/**
* 重寫hashCode方法
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
/**
* 重寫equas方法
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ReflectPoint other = (ReflectPoint) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
/**
* 重寫toString方法
*/
@Override
public String toString() {
return str1 + ":" + str2 + ":" + str3;
}
}
1 package com.itcast.zhang; 3 import java.beans.IntrospectionException; 4 import java.beans.PropertyDescriptor; 5 import java.lang.reflect.InvocationTargetException; 6 import java.lang.reflect.Method; 7 8 public class IntroSpectorTest { 9 10 /** 11 * @param args 12 * @throws IntrospectionException 13 * @throws InvocationTargetException 14 * @throws IllegalAccessException 15 * @throws IllegalArgumentException 16 */ 17 public static void main(String[] args) throws IntrospectionException, 18 IllegalArgumentException, IllegalAccessException, 19 InvocationTargetException { 20 // TODO Auto-generated method stub 21 ReflectPoint pt1 = new ReflectPoint(3, 4);//實例對象 22 String propertyName = "x";//屬性名 23 PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1 24 .getClass());//屬性描述符,看做javaBean 25 Method methodGetx = pd.getReadMethod();//得到讀的方法 26 Object retVal = methodGetx.invoke(pt1);//調用,讀方法沒有參數 27 System.out.println(retVal); 28 Method methodSetx = pd.getWriteMethod();//得到設置方法 29 methodSetx.invoke(pt1, 7);//對象調用 30 System.out.println(pt1.getX());//原來方式進行輸出輸出 31 } 32 33 }
採用遍歷BeanInfo的所有屬性方式來查找和設置某個RefectPoint對象的x屬性。在程序中把一個類當做JavaBean來看,就是調用IntroSpectro.getBeanInfo方法,得到的BeanInfo對象封裝了把這個類當做JavaBean的結果信息。但是這種方法寫起來比較麻煩,知道有這種方法就好。
package com.itcast.zhang;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class IntroSpectorTest {
/**
* @param args
* @throws IntrospectionException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
public static void main(String[] args) throws IntrospectionException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
// TODO Auto-generated method stub
ReflectPoint pt1 = new ReflectPoint(3, 4);
String propertyName = "x";
Object retVal = getProperty(pt1, propertyName);
System.out.println(retVal);
Object value = 7;
setProperties(pt1, propertyName, value);
System.out.println(pt1.getX());
}
/**
* 設置屬性名的值
*
* @param pt1
* @param propertyName
* @param value
* @throws IntrospectionException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
private static void setProperties(Object pt1, String propertyName,
Object value) throws IntrospectionException,
IllegalAccessException, InvocationTargetException {
// new 一個PropertyDescription
// (屬性描述符)類的對象方法,裏面有兩個參數,第一個是屬性名,第二個是對象的字節碼對文件,把某一個類當做javaBean來看可以操作這個類的屬性
PropertyDescriptor pd2 = new PropertyDescriptor(propertyName, pt1
.getClass());
Method methodSetx = pd2.getWriteMethod();// 得到寫的方法。
methodSetx.invoke(pt1, value);// 調用 傳入value
}
/**
* 得到屬性名
*
* @param pt1
* 對象
* @param propertyName屬性名
* @return
* @throws IntrospectionException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
private static Object getProperty(Object pt1, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1
.getClass());
Method methodGetx = pd.getReadMethod();
Object retVal = methodGetx.invoke(pt1);
// 麻煩的方式 這中方式用的不太多,只是爲了提高編碼能力而寫
// 採用遍歷BeanInfo的多有屬性方式來查找和設置某個RefectPoint對象的x屬性。在程序中,
// 把一個類當做JavaBean開看,就是調用了IntroSpector.getBeanInfo方法,得到BeanInfo對象封裝了把這個類當作javaBean看的結果信息
/*
* BeanInfo beaninfo = Introspector.getBeanInfo(pt1.getClass());
* PropertyDescriptor[] pds = beaninfo.getPropertyDescriptors(); Object
* retVal = null; for (PropertyDescriptor pd : pds) { if
* (pd.getName().equals(propertyName)) { Method methodGetx =
* pd.getReadMethod(); retVal = methodGetx.invoke(pt1); break; } }
*/
return retVal;
}
}
package com.itcast.zhang;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) throws Exception,
NoSuchMethodException {
//定義一個集合
ArrayList<String> collection1 = new ArrayList<String>();
collection1.add("abc");
//collection1.add(1);這裏編譯錯誤,只能添加固定的類型
//根據反射 得到構造函數的對象,這裏通過泛型也可以避免強制類型轉換
Constructor<String> constructor1 = String.class.getConstructor(StringBuffer.class);
//這裏也避免了類型轉換的苦惱
String str2 = constructor1.newInstance(new StringBuffer("abc"));
System.out.println(str2.charAt(2));
}
}
package com.itcast.zhang;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) { // 已經參數化的類型。
//定義兩個集合
ArrayList<String> collection1 = new ArrayList<String>();
ArrayList<Integer> collection2 = new ArrayList<Integer>();
//通過比較兩個對象的字節碼,打印是true;
System.out.println(collection1.getClass() == collection2.getClass());
}
}
泛型是提供給java編譯器使用的,可以限定集合中的輸入類型,讓編譯器擋住源程序中的非法輸入,編譯器編譯類型說明的集合時會去掉“類型”信息,使程序運行效率不受影響,對於參數化的泛型類型,getClass()方法的返回值和原始類型完全一樣。由於編譯生成的字節碼會去掉泛型的類型信息,只要能跳過編譯器,就可以往某個泛型集合中加入其它類型的數據,例如,用反射得到集合,再調用add()方法即可。
1 import java.lang.reflect.InvocationTargetException; 2 import java.util.ArrayList; 3 4 5 public class Test2 { 6 public static void main(String[] args) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { 7 //已經參數化的類型。 8 ArrayList<String> collection1=new ArrayList<String>(); 9 ArrayList<Integer> collection2=new ArrayList<Integer>(); 10 System.out.println(collection1.getClass()==collection2.getClass()); 11 // 編譯錯誤 collection2.add("abc"); 12 collection2.getClass().getMethod("add",Object.class).invoke(collection2, "abc");//用反射得到集合,再調用add()方法即可跳過編譯階段 13 System.out.println(collection2.get(0));//打印看結果 14 } 15 }
打印 abc --泛型是給編譯器看的
泛型的術語:
整個稱爲ArrayList<E>泛型類型
ArrayList<Integer>稱爲參數化的類型。
ArrayList<Integer>中的Integer稱爲類型參數的實例或實際類型參數
ArrayList<Integer>中的<>念着type of
ArrayList稱爲原始類型。
參數化類型與原始類型的兼容性:
參數化類型可以引用一個原始類型的對象,編譯器報告警告,例如,
Collection<String> c=new Vector();
原始類型可以引用一個參數化類型的對象,編譯器報告警告
Collection c=new Vector<String>();
參數化類型不考慮繼承關係:
Vector<String> =new Vector<Object>();//錯誤
在創建數組實例時,數組的元素不能使用參數化的類型,例如,下面語句有錯誤:
Vector<Integer> vectorList[]=new Vector<Integeer>[10];
泛型的通配符擴展應用
1 import java.lang.reflect.InvocationTargetException; 2 import java.util.ArrayList; 3 import java.util.Collection; 4 5 public class Test2 { 6 public static void main(String[] args) throws IllegalArgumentException, 7 SecurityException, IllegalAccessException, 8 InvocationTargetException, NoSuchMethodException { 9 // 已經參數化的類型。 10 ArrayList<String> collection1 = new ArrayList<String>(); 11 ArrayList<Integer> collection2 = new ArrayList<Integer>(); 12 System.out.println(collection1.getClass() == collection2.getClass()); 13 // 編譯錯誤 collection2.add("abc"); 14 collection2.getClass().getMethod("add", Object.class).invoke( 15 collection2, "abc"); 16 System.out.println(collection2.get(0)); 17 printCollection(collection2); 18 } 19 20 /** 21 * ?表示任意類型,編譯器不會報錯 22 * 23 * @param collection 24 */ 25 public static void printCollection(Collection<?> collection) { 26 // 編譯錯誤。 27 // ?可以作爲引用變量引用別的類型,但是不能調用與參數有關係的方法 28 // collection.add("abc"); 29 collection.size();// 這個方法可以調用,與參數類型無關。 30 for (Object obj : collection) { 31 System.out.println(obj); 32 } 33 // 總結:使用?通配符可以引用其他各種參數化的類型, 34 // ?通配符定義的變量主要作用是引用,可以調用與參數化無關的方法,不能調用與參數化有關的方法。 35 36 } 37 }
通配符的限定
限定通配符的上邊界:
正確:Vector<?extends Number> x=new Vector<Integer>();--必須是Number以及是Number的子類
錯誤:Vector<?extends Number> x=new Vector<String>();
限定通配符的下邊界:
正確:Vector<?super Integer> x=new Vector<Number>();必須是Integer的父類,或者Integer
錯誤:Vector<?super Integer> x=new Vector<Byte>();平級的,所以錯誤。
泛型集合類的綜合案例
1 import java.util.HashMap; 2 import java.util.Map; 3 import java.util.Set; 4 5 public class Test3 { 6 public static void main(String[] args) { 7 HashMap<String, Integer> maps = new HashMap<String, Integer>();//定義一個map集合,鍵是String類型,值是Integer類型 8 maps.put("xxx", 23);//添加 9 maps.put("yyy", 22); 10 maps.put("zz", 13); 11 Set<Map.Entry<String, Integer>> enrtyset = maps.entrySet();//Map.Entry<String,Integer>是一個對,包括鍵值 12 for (Map.Entry<String, Integer> entry : enrtyset) {//遍歷打印輸出 13 System.out.println(entry.getKey() + ":" + entry.getValue()); 14 } 15 } 16 }
定義泛型的類型。
如果類的實例對象中的多處都要用到同意個泛型參數,即這些地方引用的泛型類型要保持同一個實際類型時,這時候就要採用泛型類型的方式進行定義,也就是類級別的泛型,語法格式如下:
public class Generic<T>{
pirvate T field;
public void save(T obj){};
public T getByid(int id){}
}
通過反射獲得泛型的實際類型參數
1 import java.lang.reflect.Method; 2 import java.lang.reflect.ParameterizedType; 3 import java.lang.reflect.Type; 4 import java.util.Date; 5 import java.util.Vector; 6 7 /** 8 * 通過反射獲得泛型的實際類型參數 9 * 10 * @author Administrator 11 * 12 */ 13 public class Test4 { 14 public static void main(String[] args) throws Exception, 15 NoSuchMethodException { 16 Method applyMethod = Test4.class.getMethod("applyVector", Vector.class); 17 Type[] type = applyMethod.getGenericParameterTypes();// 得到參數類型的數組 18 ParameterizedType ptype = (ParameterizedType) type[0];// ParameterizedType 19 // 是Type的子類 20 System.out.println(ptype.getRawType());// 得到原始類型 打印Vector 21 System.out.println(ptype.getActualTypeArguments()[0]);// 打印Date 22 } 23 //測試方法 24 public static void applyVector(Vector<Date> v1) { 25 26 } 27 }
類加載器
用到一個類,jvm首先也把這個類的字節碼,加載到內存中來進行處理,通常這個字節碼的原始信息放在硬盤上ClassPath指定的目錄下
java虛擬機中可以安裝多個類加載器,系統默認三個類加載器,每個類負責加載特定位置的類:
BootStrap,ExtClassLoader,AppClassLoader
類加載器本身也是Java類,因爲其他是Java類的類加載器本身也要被類加載器加載,顯然必須有第一個類加載器不是java類,這正是BootStrap(不需要被加載嵌套在jvm內核中的)
java虛擬機中的所有類裝載器採用具有父子關係的樹形結構進行組織,在實例化每個類裝載器對象時,需要爲其指定一個父級類裝載器對象或者默認採用系統類裝載器爲其父級類加載。
1 public class ClassLoaderTest { 2 public static void main(String[] args) { 3 // 打印 sun.misc.Launcher$AppClassLoader 4 System.out.println(ClassLoaderTest.class.getClassLoader().getClass() 5 .getName()); 6 7 // 報錯 空指針異常 8 // System.out.println(System.class.getClassLoader().getClass().getName()); 9 System.out.println(System.class.getClassLoader());// 打印null 由 10 // BootStrap加載 11 ClassLoader loader = ClassLoaderTest.class.getClassLoader();//得到一個類的加載器 12 while (loader != null) { 13 System.out.println(loader.getClass().getName());//輸出類加載的名字 14 loader = loader.getParent();//得到父級加載器 15 } 16 System.out.println(loader); 17 } 18 }
類加載器之間的父子關係和管轄範圍圖
類加載器的委託機制
當java虛擬機要加載一個類時,到底派出哪個類加載器去加載呢?
首先當前線程的類加載器去加載線程中的第一個類。
如果類A中引用了類B,java虛擬機將使用加載類A的類裝載器來加載類B
每個類加載器加載類時,又先委託給其上級類加載器。
編寫自己的類加載器
1,必須繼承一個抽象類ClassLoader
2,複寫findClass
代理
代理設計 :一個操作的接口有兩個子類,其中一個是真實主題實現類,另外一個是代理實現類。代理實現類要完成比真實主題實現類更多的內容,而且
本身還需要處理一些與業務有關的程序代碼
要爲已存在的多個具有相同的接口的目標類的各個方法增加一些系統功能,例如,異常處理,日誌,計算方法的運行時間,事物處理,等等。import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
import java.util.Collection;
/**
* 創建動態類及查看其方法列表
*
* @author Administrator
*
*/
public class Test1 {
public static void main(String[] args) {
Class clazzProxy1 = Proxy.getProxyClass(Collection.class
.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());// 打印 $Proxy0
System.out.println("begin constructo list");
// 有什麼樣的構造 方法
Constructor[] constructors = clazzProxy1.getConstructors();
for (Constructor constructor : constructors) {
// System.out.println(constructor.getName());
String name = constructor.getName();
StringBuilder sb = new StringBuilder(name);// 單線程StrinbBuilder
sb.append('(');
Class[] classParams = constructor.getParameterTypes();
for (Class clazzParam : classParams) {
sb.append(clazzParam.getName()).append(',');
}
if (classParams != null && classParams.length != 0) {
sb.deleteCharAt(sb.length() - 1);
sb.append(')');
System.out.println(sb.toString());
}
}
}
}
創建動態類的實例對象
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
/**
* 創建動態類及查看其方法列表
*
* @author Administrator
*
*/
public class Test1 {
public static void main(String[] args) throws Exception,
InstantiationException, IllegalAccessException,
InvocationTargetException {
Class clazzProxy1 = Proxy.getProxyClass(Collection.class
.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());// 打印 $Proxy0
System.out.println("begin constructo list");
// 有什麼樣的構造 方法
Constructor[] constructors = clazzProxy1.getConstructors();
for (Constructor constructor : constructors) {
// System.out.println(constructor.getName());
String name = constructor.getName();
StringBuilder sb = new StringBuilder(name);// 單線程StrinbBuilder
sb.append('(');
Class[] classParams = constructor.getParameterTypes();
for (Class clazzParam : classParams) {
sb.append(clazzParam.getName()).append(',');
}
if (classParams != null && classParams.length != 0) {
sb.deleteCharAt(sb.length() - 1);
sb.append(')');
System.out.println(sb.toString());
}
}
Constructor constructor1 = clazzProxy1
.getConstructor(InvocationHandler.class);
class MyInvocationHander1 implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
}
Collection proxy1 = (Collection) constructor1
.newInstance(new MyInvocationHander1());
System.out.println(proxy1);// 打印null;但是對象不是null;
proxy1.clear();
}
}
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
/**
* 創建動態類及查看其方法列表
*
* @author Administrator
*
*/
public class Test1 {
public static void main(String[] args) throws Exception,
InstantiationException, IllegalAccessException,
InvocationTargetException {
Class clazzProxy1 = Proxy.getProxyClass(Collection.class
.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());// 打印 $Proxy0
System.out.println("begin constructo list");
// 有什麼樣的構造 方法
Constructor[] constructors = clazzProxy1.getConstructors();
for (Constructor constructor : constructors) {
// System.out.println(constructor.getName());
String name = constructor.getName();
StringBuilder sb = new StringBuilder(name);// 單線程StrinbBuilder
sb.append('(');
Class[] classParams = constructor.getParameterTypes();
for (Class clazzParam : classParams) {
sb.append(clazzParam.getName()).append(',');
}
if (classParams != null && classParams.length != 0) {
sb.deleteCharAt(sb.length() - 1);
sb.append(')');
System.out.println(sb.toString());
}
}
/* Constructor constructor1 = clazzProxy1
.getConstructor(InvocationHandler.class);
class MyInvocationHander1 implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
}
Collection proxy1 = (Collection) constructor1
.newInstance(new MyInvocationHander1());
System.out.println(proxy1);// 打印null;但是對象不是null;
proxy1.clear();*/
//第二種方式
Constructor constructor1 = clazzProxy1
.getConstructor(InvocationHandler.class);
Collection proxy2=(Collection)constructor1.newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
});
}
}
讓jvm創建動態類及其實例對象,需要給他提供哪些信息?
Proxy
提供用於創建動態代理類和實例的靜態方法,它還是由這些方法創建的所有動態代理類的超類。
import java.lang.reflect.InvocationHandler ;
import java.lang.reflect.Proxy ;
import java.lang.reflect.Method ;
interface Subject{
public String say(String name,int age) ; // 定義抽象方法say
}
class RealSubject implements Subject{ // 實現接口
public String say(String name,int age){
return "姓名:" + name + ",年齡:" + age ;
}
};
class MyInvocationHandler implements InvocationHandler{
private Object obj ;
public Object bind(Object obj){
this.obj = obj ; // 真實主題類 代理的對象
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this) ;
}
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
Object temp = method.invoke(this.obj,args) ; // 調用方法
return temp ;
}
};
public class DynaProxyDemo{
public static void main(String args[]){
Subject sub = (Subject)new MyInvocationHandler().bind(new RealSubject()) ;
String info = sub.say("周珂珂",30) ;
System.out.println(info) ;
}
};