Java高新技术(二)之类加载机制和反射
2012-12-08 22:08
465 查看
-------android培训、java培训、期待与您交流! ----------
a)
在运行时判断任意一个对象所属的类
b)
在运行时构造一个类的对象
c)
在运行时判断任意一个类所具有的成员变量和方法
d)
在运行时调用任意一个对象的方法
在jdk中,主要由以下类来实现java反射机制,这些类位于java.lang.reflect包中
1.
Class类:代表一个类
在java当中,无论生成某个类的多少个对象,这些对象都会对应于同一个Class对象
即一个类对应于一个Class对象。
2.
Field:代表类的成员变量(成员变量也称为类的属性)。
3.
Method类:代表类的方法
4.
Constructor:代表类的构造方法
5.
Array类:提供了动态创建数组,以及访问数组的元素的静态方法
Class对象
Class是所有类的对象。它是怎么获取的呢。
获取某个类或某个对象所对应的Class对象常用的有三种方式
a) 使用Class类的静态方法forName,例如Class.forName(“java.lang.String”);
b) 使用类.Class语法.例如:String.class;
c) 使用对象(object)的getClass()的方法。例如String
s=“aa”;Class<?>cla=s.getClass();
这三种所获得的一个类的Class字节码都是一样的
九个预定义对象:
基本的 Java
类型(boolean、byte、char、short、int、long、float和
double)和关键字 void也表示为 Class对象,他们都是使用Class类的isPrimitive()方法判断
比如:Integer.Type返回的是int.而Integer.class返回的是Integer所对应的Class对象
我们要是判断数组类型的Class实例对象,使用的是isArray()方法。
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void
我们看看如下代码演示:
publicclass ClassDemo {
publicstaticvoid main(String[] args)throws
Exception{
//Class对象的字节码判断
String str="Hello";
Class c1=str.getClass();
Class c2=String.class;
Class c3=Class.forName("java.lang.String");
System.out.println("c1==c2:"+(c1==c2));//true
System.out.println("c1==c3:"+(c1==c3));//ture
//基本类型的判定
System.out.println(c1.isPrimitive());//true
System.out.println(int.class.isPrimitive());//true
System.out.println(int.class==Integer.class);//false
System.out.println(int.class==Integer.TYPE);//true
System.out.println(int[].class.isPrimitive());//false
System.out.println(int[].class.isArray());//true
}
}
Constructor类
Constructor就是构造方法的反射
构造方法
我们通过Class对象的一些方法来获得Constructor的构造方法
获得所有的构造方法:
Constructor<?>[]getDeclaredConstructors()
获得publie所有构造方法
Constructor<?>[]getConstructors()
获得某一个构造方法
Constructor<T>getConstructor(Class<?>... parameterTypes)
创建实例对象两种方式:
a) 先获得Class对象,然后通过该Class对象的newInstance()直接生成即可,例如:
Class<?> classType=String.class;
Object obj=classType.newInctance();
b) 先获得Class对象,然后通过该对象获得对应的Constructor对象,再通过该Constructor对象的newInctance()方法生成,例如:
Class<?> classType()=Cunstomer.class;
Constructor cons=classtype.getConstructor(new Class[]{});
Object obj=cons.newInstance(new Object[]{});
若想通过类的的带参数的构造方法生成对象,只能使用下面这一种方式:
Class<?> classType()=Cunstomer.class;
Constructor cons=classtype.getConstructor(newClass[]{String.class,int.class});
Object obj=cons.newInstance(new Object[]{“hello”,3});
比如:
普通方式:
StringBuffer sb=new StringBuffer(newStringBuffer(“abc”));
反射方式:
String str=(String)Constructor.newInstance(newStringBuffer(“abc”));
Field类
Field类都是成员变量的反射
构造方法都是通过Class对象获取的
构造方法:
获得指定的无需访问权限的Field:
Field getDeclaredField(String name)
获得所有的Field
Field[] getFields()
获得publie
的某个Field
Field getField(String name)
Field类的常用方法
a) Object get(Object obj):返回指定对象上此Field表示的字段的值
b) void setAccessible(boolean flag):将此对象的 accessible标志设置为指示的布尔值。
比如如下代码所示:
importjava.lang.reflect.Constructor;
import java.lang.reflect.Field;
publicclass FieldClass {
publicstaticvoid main(String[] args)throws
Exception {
FieldDemo fd=new FieldDemo(3,5);
//取出FieldDemo的x值
Field fieldx=FieldDemo.class.getField("x");
Object objx=fieldx.get(fd);
//取出FieldDemo的y值
Field fieldy=FieldDemo.class.getDeclaredField("y");
//由于y是private修饰的,所以暴力反射成可取的值
fieldy.setAccessible(true);
Object objy=fieldy.get(fd);
System.out.println("x=="+objx+",y=="+objy);
}
}
class FieldDemo{
publicintx;
privateinty;//private修饰的field
FieldDemo(int x,int y){
this.x=x;
this.y=y;
}
}
Method类
Method是成员方法的反射
构造方法都是通过Class对象获取的
构造方法:
获得所有的方法:
Method[] getDeclaredMethods()
获得无限制的指定方法
Method getDeclaredMethod(String name,Class<?>... parameterTypes)
获得所有public方法
Method[] getMethods()
获得指定public方法
Method getMethod(String name,Class<?>... parameterTypes)
Method的常用方法
调用一个类的指定的方法
Object invoke(Object obj, Object... args)
如果是调用时指定类的静态方法,那么Object invoke (null,Object….args)
我们代码演示下:
import java.lang.reflect.Method;
publicclass MethodTest {
publicstaticvoid main(String[] args)throws
Exception {
String str="Hello";
//指定String类的charAt方法
Method charAtMethod=String.class.getMethod("charAt",int.class);
System.out.println(charAtMethod.invoke(str, 4));
//指定String类的subString方法
Method subMethod=String.class.getMethod("substring",int.class,int.class);
System.out.println(subMethod.invoke(str, 1,3));
//获得此类的所有方法
Method[] allMethod=String.class.getDeclaredMethods();
for (Method me:allMethod){
System.out.println(me);
}
}
}
Array类
Array类就是数组的反射
Array的常用方法是:
a)
static Object get(Object array, int index) :返回指定数组对象中索引组件的值。
b)
static int getLength(Object array):以
c)
static Object newInstance(Class<?> componentType, int length):创建一个具有指定的组件类型和长度的新数组。
d)
static void set(Object array, int index, Object value):将指定数组对象中索引组件的值设置为指定的新值。
如下面代码演示
import java.lang.reflect.Array;
publicclass ArrayDemo {
publicstaticvoid main(String[] args) {
int[] a ={1,2,3,4,5};
Class clazz=a.getClass();
if (clazz.isArray()){
int len=Array.getLength(a);//获得数组的长度
for(int i=0;i<len;i++){
System.out.println(Array.get(a, i));
}
}
}
}
反射的框架应用
反射是经常用在框架上的,当我们需要某个类时,可在配置文件里使用键值对来指定我们需要的引用的类。比如我们新建一个文件名称是config.properties,里面写上classname=java.util.ArrayList.注意这里值不要用双引号。那么我们使用反射来实现一个小小的框架。代码演示如下:
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.*;
publicclass FrameDemo {
publicstaticvoid main(String[] args)throws
Exception {
//关联系统中次配置文件
InputStreamin=new FileInputStream("config.properties");
Properties pro=new Properties();
pro.load(in);//加载此配置文件
//获得此配置文件中key对应的我们要取的对象
String className=pro.getProperty("classname");
//将此对象使用反射来获得实例
Collection coll=(Collection) Class.forName(className).newInstance();
coll.add(new Point(3, 3));
coll.add(new Point(5, 5));
coll.add(new Point(3, 3));
System.out.println(coll);
}
}
class Point{
intx;
inty;
public Point(int x,int
y) {
this.x=x;
this.y=y;
}
@Override
public String toString() {
return"x=="+x+",y=="+y;
}
}
我们在加载配置文件的时候(上面红色部分替换掉)建议使用这行代码,以后在开发时有用
InputStream in=
FieldDemo.class.getResourceAsStream("config.properties");
Javabean属性是根据方法名来的,主要是用于传递数据信息
第一种抽取Javabean方法:
Javabean包下有个类是PropertyDescriptor,它描述 Java Bean通过一对存储器方法导出的一个属性
常用的方法:
a)
构造方法:PropertyDescriptor(StringpropertyName, Class<?> beanClass):传入一个成员值,并传入类是javaBean的对象
b)
Method getReadMethod() :获得JavaBean的get方法
c)
Method getWriteMethod() :获得javabean的set方法
代码演示如下:
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
publicclass JavaBeanDemo {
publicstaticvoid main(String[] args)throws
Exception {
Point p=new Point(3, 5);
String propertyName="x";
PropertyDescriptor pd=new PropertyDescriptor(propertyName,Point.class);
//获得get方法
Method meGetX= pd.getReadMethod();
//调用get方法
Object retVal=meGetX.invoke(p);
System.out.println(retVal);
Object value=7;
//获得set方法
Method meSetY=pd.getWriteMethod();
//调用set方法并传值
meSetY.invoke(p, value);
System.out.println(meGetX.invoke(p));
}
}
//javabean类
class Point{
privateintx;
privateinty;
public Point(int x,int
y) {
this.x=x;
this.y=y;
}
publicint getX() {
returnx;
}
publicvoid setX(int
x) {
this.x = x;
}
publicint getY() {
returny;
}
publicvoid setY(int
y) {
this.y = y;
}
}
第二种抽取JavaBean的方法:
第二种我们使用内省器(Introspector)来抽取出BeanInfo的方法
Instrospector有个静态的方法是getBeanInfo(ClassbeanClass),向这个方法传递一个javaBeanClass对象,获得一个BeanInfo对象,可以通过这个对象的方法获得PropertyDescriptor,然后通过它来操作Bean的方法。BeanInfo可以操作属性,方法,和事件
比如我们对上面进行第二种写法的过程,类Point我们借用上面的。
public class JavaBeanDemo {
publicstatic void main(String[] args) throws Exception {
Pointp = new Point(3, 5);
StringpropertyName = "x";
//第一步:通过内省器来获得BeanInfo
BeanInfobean = Introspector.getBeanInfo(Point.class);
//第二步:BeanInfo对象获得后可以对方法,属性,事件操作。
//这里我们通过它的方法getPropertyDescriptors()来获得PropertyDescriptor数组
PropertyDescriptor[]pd = bean.getPropertyDescriptors();
//遍历PropertyDescrptor数组,并通过它的方法来对bean进行操作
for(PropertyDescriptor pds : pd) {
Class<?>clazz = pds.getPropertyType();
if(clazz == null)
continue;
System.out.println("Propertytype:" + clazz.getName());
System.out.println("Propertyname:" + pds.getName());
//判断所获得的变量名是否是x
if(pds.getName().equals(propertyName)) {
MethodgetXMethod = pds.getReadMethod();
Objectretval = getXMethod.invoke(p);
System.out.println(retval);
break;
}
}
}
}
第三种抽取JavaBean方法:
使用的Apache的开源BeanUtils工具包的jar包,来操作Bean。而且我们还要下载一个logging包,否则会报错,在BeanUtils中,JavaBeam类必须是public。否则会抛出NoSuchMethodException。
在Beanutils包有两种抽取Javabean的方法:
a) 第一种:BeanUtils类
b) 第二种:ProperUtils类
它们都有两个方法:分别是
a)
获得set方法,setProperty(bean,name,value);
b)
获得get方法:getProperty(bean,name);
代码演示如下:
注:依然引用上面的Point类
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
publicclass JavaBeanDemo {
publicstaticvoid main(String[] args)throws
Exception {
Point p = new Point(3, 5);
String propertyName ="y";
System.out.println("----------BeanUtils----------");
System.out.println("x=="+BeanUtils.getProperty(p,"x"));
BeanUtils.setProperty(p,"x",9);
System.out.println("x=="+p.getX());
System.out.println("----------Properutils-----------");
System.out.println("y=="+PropertyUtils.getProperty(p,"y"));
PropertyUtils.setProperty(p,"y", 3);
System.out.println("y=="+p.getY());
}
}
系统默认三种类加载器:
a) BootStrap classLoader:JRE/lib/rt.jar,根类加载器
它被称为引导类加载器,它负责加载java的核心类,它不是ClassLoader的子类,是jvm自身实现的,即不是java实现的。
b) ExitClassLoader(Extension ClassLoader):,扩展类加载器
它负责加载JRE/lib/exit/下面的jar包的类,这样可以为java扩展核心类以外的类。
c) AppClassLoader(System classLoader):classpath指定的所有jar包或目录。系统类加载器
它负责JVM启动时加载来自java命令的的classPath环境变量所指定的jar包和类
d) 指定特殊的目录:这里放置的是我们自定义加载器,用户类加载器
这上面三个类是继承关系的,Bootstrap是顶类,AppClassLoader继承ExitClassLoader
这里的继承关系是类加载器实例之间的关系,不是传统的意义。
这里涉及到一个委托机制:
类加载器从AppClassLoader开始即发起者,如果找不到指定的类,就交给父类ExitClassLoader,如果父类没找到就交给顶类Bootstrap,如果找到就可以进行加载,如果还是找不到,就往回返,返回到发起者就会停止报错。所以通常情况下AppClassLoader下的子类是不会被加载到的,除非我们可以自定义加载器
我们代码演示下JVM类的类加载器
import java.io.*;
import java.net.*;
import java.util.*;
class ClassLoaderProTest
{
publicstatic void main(String[] args) throws Exception
{
ClassLoadersystemLoader=ClassLoader.getSystemClassLoader();
System.out.println("获取系统加载器:"+systemLoader);
//获取系统类加载器的加载路径
Enumeration<URL>emu=systemLoader.getResources("");
while(emu.hasMoreElements())
{
System.out.println(emu.nextElement());
}
ClassLoaderparentLoader=systemLoader.getParent();
System.out.println("获得此加载器的父类扩展类:"+parentLoader);
System.out.println("扩展类加载器的加载路径:"+System.getProperty("java.ext.dirs"));
System.out.println("扩展类");
}
}
从以上代码可以看出它们分别加载的路径是什么?扩展类的加载路径是JRE/lib/exit/
系统加载器加载的路径是程序运行的当前路径。
类加载机制:
1) 全盘负责:当一个加载器加载某个类的时候,这个类所引用的或依赖其他的class也将由此加载器加载,除非特别显式其他加载器来加载
2) 父类委托:加载一个类时,试图让父类(parent)先加载该class,只有在父类无法加载该类时,才尝试从自己的加载路径来加载。
3) 缓存机制:它将会保证所有被加载的Class都被缓存,当程序需要使用某个类时,先在缓存中查找该类,如果该类不存在该Class对象,系统才会读取二进制数据,将其转换成Class对象,存入缓存中。这也就是为什么修改了程序还要执行编译命令的原因。
自定义加载器
自定义加载器必须继承ClassLoader,是为了覆盖findclass,得到class文件来转换成字节码,
这种转换的方法是defineClass()。
反射
反射(Reflection)的功能:a)
在运行时判断任意一个对象所属的类
b)
在运行时构造一个类的对象
c)
在运行时判断任意一个类所具有的成员变量和方法
d)
在运行时调用任意一个对象的方法
在jdk中,主要由以下类来实现java反射机制,这些类位于java.lang.reflect包中
1.
Class类:代表一个类
在java当中,无论生成某个类的多少个对象,这些对象都会对应于同一个Class对象
即一个类对应于一个Class对象。
2.
Field:代表类的成员变量(成员变量也称为类的属性)。
3.
Method类:代表类的方法
4.
Constructor:代表类的构造方法
5.
Array类:提供了动态创建数组,以及访问数组的元素的静态方法
Class对象
Class是所有类的对象。它是怎么获取的呢。
获取某个类或某个对象所对应的Class对象常用的有三种方式
a) 使用Class类的静态方法forName,例如Class.forName(“java.lang.String”);
b) 使用类.Class语法.例如:String.class;
c) 使用对象(object)的getClass()的方法。例如String
s=“aa”;Class<?>cla=s.getClass();
这三种所获得的一个类的Class字节码都是一样的
九个预定义对象:
基本的 Java
类型(boolean、byte、char、short、int、long、float和
double)和关键字 void也表示为 Class对象,他们都是使用Class类的isPrimitive()方法判断
比如:Integer.Type返回的是int.而Integer.class返回的是Integer所对应的Class对象
我们要是判断数组类型的Class实例对象,使用的是isArray()方法。
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void
我们看看如下代码演示:
publicclass ClassDemo {
publicstaticvoid main(String[] args)throws
Exception{
//Class对象的字节码判断
String str="Hello";
Class c1=str.getClass();
Class c2=String.class;
Class c3=Class.forName("java.lang.String");
System.out.println("c1==c2:"+(c1==c2));//true
System.out.println("c1==c3:"+(c1==c3));//ture
//基本类型的判定
System.out.println(c1.isPrimitive());//true
System.out.println(int.class.isPrimitive());//true
System.out.println(int.class==Integer.class);//false
System.out.println(int.class==Integer.TYPE);//true
System.out.println(int[].class.isPrimitive());//false
System.out.println(int[].class.isArray());//true
}
}
Constructor类
Constructor就是构造方法的反射
构造方法
我们通过Class对象的一些方法来获得Constructor的构造方法
获得所有的构造方法:
Constructor<?>[]getDeclaredConstructors()
获得publie所有构造方法
Constructor<?>[]getConstructors()
获得某一个构造方法
Constructor<T>getConstructor(Class<?>... parameterTypes)
创建实例对象两种方式:
a) 先获得Class对象,然后通过该Class对象的newInstance()直接生成即可,例如:
Class<?> classType=String.class;
Object obj=classType.newInctance();
b) 先获得Class对象,然后通过该对象获得对应的Constructor对象,再通过该Constructor对象的newInctance()方法生成,例如:
Class<?> classType()=Cunstomer.class;
Constructor cons=classtype.getConstructor(new Class[]{});
Object obj=cons.newInstance(new Object[]{});
若想通过类的的带参数的构造方法生成对象,只能使用下面这一种方式:
Class<?> classType()=Cunstomer.class;
Constructor cons=classtype.getConstructor(newClass[]{String.class,int.class});
Object obj=cons.newInstance(new Object[]{“hello”,3});
比如:
普通方式:
StringBuffer sb=new StringBuffer(newStringBuffer(“abc”));
反射方式:
String str=(String)Constructor.newInstance(newStringBuffer(“abc”));
Field类
Field类都是成员变量的反射
构造方法都是通过Class对象获取的
构造方法:
获得指定的无需访问权限的Field:
Field getDeclaredField(String name)
获得所有的Field
Field[] getFields()
获得publie
的某个Field
Field getField(String name)
Field类的常用方法
a) Object get(Object obj):返回指定对象上此Field表示的字段的值
b) void setAccessible(boolean flag):将此对象的 accessible标志设置为指示的布尔值。
比如如下代码所示:
importjava.lang.reflect.Constructor;
import java.lang.reflect.Field;
publicclass FieldClass {
publicstaticvoid main(String[] args)throws
Exception {
FieldDemo fd=new FieldDemo(3,5);
//取出FieldDemo的x值
Field fieldx=FieldDemo.class.getField("x");
Object objx=fieldx.get(fd);
//取出FieldDemo的y值
Field fieldy=FieldDemo.class.getDeclaredField("y");
//由于y是private修饰的,所以暴力反射成可取的值
fieldy.setAccessible(true);
Object objy=fieldy.get(fd);
System.out.println("x=="+objx+",y=="+objy);
}
}
class FieldDemo{
publicintx;
privateinty;//private修饰的field
FieldDemo(int x,int y){
this.x=x;
this.y=y;
}
}
Method类
Method是成员方法的反射
构造方法都是通过Class对象获取的
构造方法:
获得所有的方法:
Method[] getDeclaredMethods()
获得无限制的指定方法
Method getDeclaredMethod(String name,Class<?>... parameterTypes)
获得所有public方法
Method[] getMethods()
获得指定public方法
Method getMethod(String name,Class<?>... parameterTypes)
Method的常用方法
调用一个类的指定的方法
Object invoke(Object obj, Object... args)
如果是调用时指定类的静态方法,那么Object invoke (null,Object….args)
我们代码演示下:
import java.lang.reflect.Method;
publicclass MethodTest {
publicstaticvoid main(String[] args)throws
Exception {
String str="Hello";
//指定String类的charAt方法
Method charAtMethod=String.class.getMethod("charAt",int.class);
System.out.println(charAtMethod.invoke(str, 4));
//指定String类的subString方法
Method subMethod=String.class.getMethod("substring",int.class,int.class);
System.out.println(subMethod.invoke(str, 1,3));
//获得此类的所有方法
Method[] allMethod=String.class.getDeclaredMethods();
for (Method me:allMethod){
System.out.println(me);
}
}
}
Array类
Array类就是数组的反射
Array的常用方法是:
a)
static Object get(Object array, int index) :返回指定数组对象中索引组件的值。
b)
static int getLength(Object array):以
int形式返回指定数组对象的长度。
c)
static Object newInstance(Class<?> componentType, int length):创建一个具有指定的组件类型和长度的新数组。
d)
static void set(Object array, int index, Object value):将指定数组对象中索引组件的值设置为指定的新值。
如下面代码演示
import java.lang.reflect.Array;
publicclass ArrayDemo {
publicstaticvoid main(String[] args) {
int[] a ={1,2,3,4,5};
Class clazz=a.getClass();
if (clazz.isArray()){
int len=Array.getLength(a);//获得数组的长度
for(int i=0;i<len;i++){
System.out.println(Array.get(a, i));
}
}
}
}
反射的框架应用
反射是经常用在框架上的,当我们需要某个类时,可在配置文件里使用键值对来指定我们需要的引用的类。比如我们新建一个文件名称是config.properties,里面写上classname=java.util.ArrayList.注意这里值不要用双引号。那么我们使用反射来实现一个小小的框架。代码演示如下:
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.*;
publicclass FrameDemo {
publicstaticvoid main(String[] args)throws
Exception {
//关联系统中次配置文件
InputStreamin=new FileInputStream("config.properties");
Properties pro=new Properties();
pro.load(in);//加载此配置文件
//获得此配置文件中key对应的我们要取的对象
String className=pro.getProperty("classname");
//将此对象使用反射来获得实例
Collection coll=(Collection) Class.forName(className).newInstance();
coll.add(new Point(3, 3));
coll.add(new Point(5, 5));
coll.add(new Point(3, 3));
System.out.println(coll);
}
}
class Point{
intx;
inty;
public Point(int x,int
y) {
this.x=x;
this.y=y;
}
@Override
public String toString() {
return"x=="+x+",y=="+y;
}
}
我们在加载配置文件的时候(上面红色部分替换掉)建议使用这行代码,以后在开发时有用
InputStream in=
FieldDemo.class.getResourceAsStream("config.properties");
JavaBean
想要对JavaBean操作就是内省IntroSpector,javaBean是特殊的Java类。Javabean属性是根据方法名来的,主要是用于传递数据信息
第一种抽取Javabean方法:
Javabean包下有个类是PropertyDescriptor,它描述 Java Bean通过一对存储器方法导出的一个属性
常用的方法:
a)
构造方法:PropertyDescriptor(StringpropertyName, Class<?> beanClass):传入一个成员值,并传入类是javaBean的对象
b)
Method getReadMethod() :获得JavaBean的get方法
c)
Method getWriteMethod() :获得javabean的set方法
代码演示如下:
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
publicclass JavaBeanDemo {
publicstaticvoid main(String[] args)throws
Exception {
Point p=new Point(3, 5);
String propertyName="x";
PropertyDescriptor pd=new PropertyDescriptor(propertyName,Point.class);
//获得get方法
Method meGetX= pd.getReadMethod();
//调用get方法
Object retVal=meGetX.invoke(p);
System.out.println(retVal);
Object value=7;
//获得set方法
Method meSetY=pd.getWriteMethod();
//调用set方法并传值
meSetY.invoke(p, value);
System.out.println(meGetX.invoke(p));
}
}
//javabean类
class Point{
privateintx;
privateinty;
public Point(int x,int
y) {
this.x=x;
this.y=y;
}
publicint getX() {
returnx;
}
publicvoid setX(int
x) {
this.x = x;
}
publicint getY() {
returny;
}
publicvoid setY(int
y) {
this.y = y;
}
}
第二种抽取JavaBean的方法:
第二种我们使用内省器(Introspector)来抽取出BeanInfo的方法
Instrospector有个静态的方法是getBeanInfo(ClassbeanClass),向这个方法传递一个javaBeanClass对象,获得一个BeanInfo对象,可以通过这个对象的方法获得PropertyDescriptor,然后通过它来操作Bean的方法。BeanInfo可以操作属性,方法,和事件
比如我们对上面进行第二种写法的过程,类Point我们借用上面的。
public class JavaBeanDemo {
publicstatic void main(String[] args) throws Exception {
Pointp = new Point(3, 5);
StringpropertyName = "x";
//第一步:通过内省器来获得BeanInfo
BeanInfobean = Introspector.getBeanInfo(Point.class);
//第二步:BeanInfo对象获得后可以对方法,属性,事件操作。
//这里我们通过它的方法getPropertyDescriptors()来获得PropertyDescriptor数组
PropertyDescriptor[]pd = bean.getPropertyDescriptors();
//遍历PropertyDescrptor数组,并通过它的方法来对bean进行操作
for(PropertyDescriptor pds : pd) {
Class<?>clazz = pds.getPropertyType();
if(clazz == null)
continue;
System.out.println("Propertytype:" + clazz.getName());
System.out.println("Propertyname:" + pds.getName());
//判断所获得的变量名是否是x
if(pds.getName().equals(propertyName)) {
MethodgetXMethod = pds.getReadMethod();
Objectretval = getXMethod.invoke(p);
System.out.println(retval);
break;
}
}
}
}
第三种抽取JavaBean方法:
使用的Apache的开源BeanUtils工具包的jar包,来操作Bean。而且我们还要下载一个logging包,否则会报错,在BeanUtils中,JavaBeam类必须是public。否则会抛出NoSuchMethodException。
在Beanutils包有两种抽取Javabean的方法:
a) 第一种:BeanUtils类
b) 第二种:ProperUtils类
它们都有两个方法:分别是
a)
获得set方法,setProperty(bean,name,value);
b)
获得get方法:getProperty(bean,name);
代码演示如下:
注:依然引用上面的Point类
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
publicclass JavaBeanDemo {
publicstaticvoid main(String[] args)throws
Exception {
Point p = new Point(3, 5);
String propertyName ="y";
System.out.println("----------BeanUtils----------");
System.out.println("x=="+BeanUtils.getProperty(p,"x"));
BeanUtils.setProperty(p,"x",9);
System.out.println("x=="+p.getX());
System.out.println("----------Properutils-----------");
System.out.println("y=="+PropertyUtils.getProperty(p,"y"));
PropertyUtils.setProperty(p,"y", 3);
System.out.println("y=="+p.getY());
}
}
类加载机制剖析
系统加载器系统默认三种类加载器:
a) BootStrap classLoader:JRE/lib/rt.jar,根类加载器
它被称为引导类加载器,它负责加载java的核心类,它不是ClassLoader的子类,是jvm自身实现的,即不是java实现的。
b) ExitClassLoader(Extension ClassLoader):,扩展类加载器
它负责加载JRE/lib/exit/下面的jar包的类,这样可以为java扩展核心类以外的类。
c) AppClassLoader(System classLoader):classpath指定的所有jar包或目录。系统类加载器
它负责JVM启动时加载来自java命令的的classPath环境变量所指定的jar包和类
d) 指定特殊的目录:这里放置的是我们自定义加载器,用户类加载器
这上面三个类是继承关系的,Bootstrap是顶类,AppClassLoader继承ExitClassLoader
这里的继承关系是类加载器实例之间的关系,不是传统的意义。
这里涉及到一个委托机制:
类加载器从AppClassLoader开始即发起者,如果找不到指定的类,就交给父类ExitClassLoader,如果父类没找到就交给顶类Bootstrap,如果找到就可以进行加载,如果还是找不到,就往回返,返回到发起者就会停止报错。所以通常情况下AppClassLoader下的子类是不会被加载到的,除非我们可以自定义加载器
我们代码演示下JVM类的类加载器
import java.io.*;
import java.net.*;
import java.util.*;
class ClassLoaderProTest
{
publicstatic void main(String[] args) throws Exception
{
ClassLoadersystemLoader=ClassLoader.getSystemClassLoader();
System.out.println("获取系统加载器:"+systemLoader);
//获取系统类加载器的加载路径
Enumeration<URL>emu=systemLoader.getResources("");
while(emu.hasMoreElements())
{
System.out.println(emu.nextElement());
}
ClassLoaderparentLoader=systemLoader.getParent();
System.out.println("获得此加载器的父类扩展类:"+parentLoader);
System.out.println("扩展类加载器的加载路径:"+System.getProperty("java.ext.dirs"));
System.out.println("扩展类");
}
}
从以上代码可以看出它们分别加载的路径是什么?扩展类的加载路径是JRE/lib/exit/
系统加载器加载的路径是程序运行的当前路径。
类加载机制:
1) 全盘负责:当一个加载器加载某个类的时候,这个类所引用的或依赖其他的class也将由此加载器加载,除非特别显式其他加载器来加载
2) 父类委托:加载一个类时,试图让父类(parent)先加载该class,只有在父类无法加载该类时,才尝试从自己的加载路径来加载。
3) 缓存机制:它将会保证所有被加载的Class都被缓存,当程序需要使用某个类时,先在缓存中查找该类,如果该类不存在该Class对象,系统才会读取二进制数据,将其转换成Class对象,存入缓存中。这也就是为什么修改了程序还要执行编译命令的原因。
自定义加载器
自定义加载器必须继承ClassLoader,是为了覆盖findclass,得到class文件来转换成字节码,
这种转换的方法是defineClass()。
相关文章推荐
- Java高新技术【4】 反射机制 及 Java类加载原理及类加载器
- 黑马程序员--反射机制和类加载器--java学习日记12(高新技术)
- Java高新技术【4】 反射机制 及 Java类加载原理及类加载器
- JAVA之类加载机制与反射(二)
- JAVA之类加载机制与反射(一)
- Java学习之类加载全过程_JVM内存分析_反射机制核心原理_常量池理解
- JAVA之类加载机制与反射(三)
- Java基础之类加载机制及反射
- 初学Java的类加载与反射机制(一)
- 深入理解Java:类加载机制及反射
- Java——类加载和反射机制
- 深入理解Java:类加载机制及反射
- 深入理解Java:类加载机制及反射
- java通过反射机制加载类方法和实例方法
- 深入理解Java:类加载机制及反射
- Java中类加载机制和反射技术
- Java-类加载器、反射机制
- JAVA 与 MyCat(5) 类的加载 Java内省/反射机制 注解Annotation 详解
- Java之类加载机制
- Java中类加载机制及反射