Java核心技术(1)
一、Java反射机制
1.1、反射的机制
1、反射机制的作用:
- 反编译:.class-->.java
- 通过反射机制访问java对象的属性,方法,构造方法等;
2、反射机制的优点与缺点
为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念:
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中,它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
3、应用场景:
- l 反射机制是很多Java框架的基石
在Java类里面解析xml或properties里面的内容,得到一个字符串,然后用反射机制,根据这个字符串获得某个类的Class实例,这样就可以动态配置一些东西,不用每一
次都要在代码里面去new或者做其他的事情,以后要改的话直接改配置文件,代码维护起来就很方便了。
- l 当你做一个软件可以安装插件的功能,你连插件的类型名称都不知道,你怎么实例化这个对象呢?因为程序是支持插件的(第三方的),在开发的时候并不知道。所以无法在代码中 New出来 ,但反射可以,通过反射,动态加载程序集,然后读出类,检查标记之后再实例化对象,就可以获得正确的类实例。
- l 在编码阶段不知道那个类名,要在运行期从配置文件读取类名, 这时候就没有办法硬编码new ClassName(),而必须用到反射才能创建这个对象.反射的目的就是为了扩展未知的应用。当你不知道要创建什么类型的对象时,使用在运行时提供类的完整路径的方式来生成类的实例时, 例如:
在struts中对messageResources引用的生成中,使用到工厂方法的模式,对于他所要使用的工厂,他采用的是factoryClass参数来生成工厂,之后使用这个工厂的实例来生成messageResources对象。 这其中就使用到了使用reflect产生类的实例。
当对象的方法只有在运行时才知道那些方法被调用,那些方法不用调用时,且方法遵循一定的规律生成,而且方法很对,比如100个。1.2、Java类加载器与反射包
1.2.1、java类加载器
1、Java 3中类加载器
- l 引导类加载器(Bootstrap ClassLoader )它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader。
- l 扩展类加载器(Extension ClassLoader )它用来加载 Java 的扩展库,一般对应的是jre\lib\ext目录中的类
- l 系统类加载器(system class loader) 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器,一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。
2、应用实例
//类加载器加载类的用法
ClassLoader loader= ClassLoader.getSystemClassLoader();
Class<User> classUser=(Class<User>) loader.loadClass("com.data.User");
User user=classUser.newInstance();
//用Class加载类
Class<?> cl=Class.forName("com.data.User");
User user=(User) cl.newInstance();
3、ServiceLoader的用法
ServiceLoader通常用来动态加载实现同一个接口的若干类,配置文件通常在src/META-INF/services下的配置文件。如图:
ClassLoader loader=Thread.currentThread().getContextClassLoader();
ServiceLoader<Person> serviceLoader=ServiceLoader.load(Person.class, loader);
Iterator<Person> interator=serviceLoader.iterator();
while(interator.hasNext()){
Person p=interator.next();
p.print();
}
1.2.2、Java反射包
1、java.lang.reflect反射包中主要包含以下几类:
java.lang.reflect.Constructor;
java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
2、反射包应用示例
1)获取构造方法及参数java.lang.reflect.Constructor
@Test
public void testConstructor() throws ClassNotFoundException{
Class<?> user = Class.forName("com.data.User");
Constructor<?> cons[] = user.getConstructors();//获取一个类中所有的构造方法
for (int i = 0; i < cons.length; i++) {
Class<?> p[]=cons[i].getParameterTypes();//获取构造方法的参数列表:参数类型
System.out.print("构造方法: ");
int mo=cons[i].getModifiers(); //获取构造方法的修饰符:public private protected
System.out.print(Modifier.toString(mo)+" ");
System.out.print(cons[i].getName());
System.out.print("(");
for(int j=0;j<p.length;++j){
System.out.print(p[j].getName()+" arg"+i);
if(j<p.length-1){
System.out.print(",");
}
}
System.out.println("){}");
}
}
2)获取类的方法及其类型
@Test
public void testMethod() throws ClassNotFoundException{
Class<?> user = Class.forName("com.data.User");
Method method[]=user.getMethods();//获取类中包含的方法(不包含构造方法)
for(int i=0;i<method.length;++i){
Class<?> returnType=method[i].getReturnType();//获取方法的返回类型
Class<?> para[]=method[i].getParameterTypes();//获取方法的参数类型
int temp=method[i].getModifiers();//获取方法的修饰符
System.out.print(Modifier.toString(temp)+" ");
System.out.print(returnType.getName()+" ");
System.out.print(method[i].getName()+" ");
System.out.print("(");
for(int j=0;j<para.length;++j){
System.out.print(para[j].getName()+" "+"arg"+j);
if(j<para.length-1){
System.out.print(",");
}
}
Class<?> exce[]=method[i].getExceptionTypes();//获取方法的异常类型
if(exce.length>0){
System.out.print(") throws ");
for(int k=0;k<exce.length;++k){
System.out.print(exce[k].getName()+" ");
if(k<exce.length-1){
System.out.print(",");
}
}
}else{
System.out.print(")");
}
System.out.println();
}
}
输出结果:
public java.lang.String getName ()
public void setName (java.lang.String arg0)
public void print ()
public void setAge (int arg0)
public int getAge ()
public final void wait (long arg0,int arg1) throws java.lang.InterruptedException
public final native void wait (long arg0) throws java.lang.InterruptedException
public final void wait () throws java.lang.InterruptedException
public boolean equals (java.lang.Object arg0)
public java.lang.String toString ()
public native int hashCode ()
public final native java.lang.Class getClass ()
public final native void notify ()
public final native void notifyAll ()
3)获取类的成员变量
@Test
publicvoid testField() throws ClassNotFoundException{
Class<?>user = Class.forName("com.data.User");
Field[]field = user.getDeclaredFields();
for (int i = 0; i < field.length; i++) {
// 权限修饰符
int mo = field[i].getModifiers();
String priv = Modifier.toString(mo);
// 属性类型
Class<?> type =field[i].getType();
System.out.println(priv + " " + type.getName() + " "
+ field[i].getName() + ";");
}
}
4) invoke
Class<?> user = Class.forName("com.data.User");
Method method =user.getMethod("setAge",int.class);
User u=(User) user.newInstance();
method.invoke(u, 11);
u.print();
执行invoke时,相当于执行u.setAge(11)方法