java动态与静态加载类(二)

1. 简介反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods; 反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。通过JAVA的反射机制,可以获得程序内部或第三方JAR包的CLASS,METHOD,属性,参数等信息。

2.JAVA动态加载类和静态加载类的区别

   它们俩本质的区别在于静态加载的类的源程序在编译时期加载(必须存在),而动态加载的类在编译时期可以缺席(源程序不必存在)。

3. JAVA动态加载类和静态加载类的方式

1 ).程序在编译时执行,在执行过程中加载所有可能执行到的程序。在这种加载方式下,只要加载中一个方法出错,程序就不能运行。我们一般写程序默认的是静态加载;new创建对象的方式称作为静态加载。

2).动态加载(类唯一字节码对象); 程序在运行时调用相应方法,即使其他方法是错误的,程序依旧会执行。通过动态加载可以让程序的可延长性大大提升,对以后的维护和扩展有重要意义。

Class c1=Class.forName("XXX");

Class c2= XXX.class;  

XXX u1=new XXX();  Class c3=u1.getClass(); 

使用当前类的ClassLoader  

ClassLoader  clo1 =this.getClass.getClassLoader(); 

Class c3=clo1.loadClass("XXX"); 

 使用当前线程的ClassLoader 

ClassLoader  clo2 =Thread.currentThread().getContextClassLoader();             

 Class c4=clo2.loadClass("XXX"); 

使 用系统ClassLoader,即系统的入口点所使用的ClassLoader,(注意,system ClassLoader与根 ClassLoader并不一样。JVM下system ClassLoader通常为App ClassLoader)   

ClassLoader  clo3=ClassLoader.getSystemClassLoader();  

 Class c5=clo3.loadClass("XXX"); 

4.举两个实际例子说明:

1)例一

public interface IUser {

}

package reflect;

public class User implements IUser{

   private String  name; 

    private int  id; 

    /**

     * @return the name

     */ 

    public String getName() { 

        return name; 

    } 

    /**

     * @param name the name to set

     */ 

    public void setName(String name) {

        this.name = name;

    } 

    /**

     * @return the id

     */ 

    public int getId() { 

        return id; 

    } 

    /**

     * @param id the id to set

     */ 

    public void setId(int id) { 

        this.id = id; 

    } 

}

public static void main (String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{

      Class c1=Class.forName("reflect.User");//每个类对应一个字节码实体对象

      Class c2=User.class; //每个类对应一个字节码实体对象

      User u1=new User();//构造器实例化一个对象

        Class c3=u1.getClass();//该对象对应的字节码实体对象

      Object o1=c1.newInstance();//该类反射出的实例

        Object o2=c2.newInstance();//该类反射出的实例

        System.out.print(o1==o2);//false

        System.out.print(c3==c1);//true

        System.out.print(c1==c2);//true

        ClassLoader clo=Thread.currentThread().getContextClassLoader();

        ClassLoader clos=ClassLoader.getSystemClassLoader(); 

        Class c4=clo.loadClass("reflect.User");

        Class c5=clo.loadClass("reflect.User");

        System.out.println(c5==c1);//true

        System.out.print(c4==c1);//true

        //利用反射获取一个类的属性

        Field[] fs = c1.getDeclaredFields(); 

        for(Field field:fs){   

            System.out.println("获得属性的修饰符,例如public,static等等 >>"+Modifier.toString(field.getModifiers())); 

            System.out.println("属性的类型的名字 >>"+field.getType()); 

            System.out.println("属性的名字 >>"+field.getName()); 

        } 

       

        Method[] ms = c1.getDeclaredMethods(); 

        for(Method field:ms){

System.out.println("获得方法的修饰符,例如public,static等等 >>"+Modifier.toString(field.getModifiers())); 

            System.out.println("方法的参数个数 >>"+field.getParameterTypes().length); 

            System.out.println("方法的名字 >>"+field.getName()); 

        }

        System.out.println("c1的父类>>"+c1.getSuperclass());  //c1的父类>>class java.lang.Object

        Class[] cs=c1.getInterfaces();

        for(Class field:cs){

            System.out.println("接口的名字 >>"+field.getName());  //接口的名字 >>reflect.IUser

        }

       

        Method method=c1.getDeclaredMethod("setName", String.class);

        method.invoke(o1, "guolzlijing");

        Method method2=c1.getDeclaredMethod("getName", null);

        System.out.println(method2.invoke(o1, null));//guolzlijing

       

      }

2)解释关键字:

方法关键字

getDeclaredMethods()
获取所有的方法(不包括继承类)

getDeclaredMethod方法第一个参数指定一个需要调用的方法名称
第二个参数是需要调用方法的参数类型列表,是参数类型!如无参数可以指定null。
参数必须和方法中一样int和Integer,double和Double被视为不同的类型。

反射中getMethods getDeclaredMethods 的区别

public Method[] getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。
public Method[] getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

当然也包括它所实现接口的方法。

getReturnType()
获得方法的反回类型

getParameterTypes()
获得方法的传入参数类型

getDeclaredMethod("方法名",参数类型.class,……)
获得特定的方法

构造方法关键字

getDeclaredConstructors()
获取所有的构造方法(不包括继承类)

getDeclaredConstructor(参数类型.class,……)
获取特定的构造方法

父类和父接口
getSuperclass()
获取某类的父类
getInterfaces()
获取某类实现的接口

Invoke

一个方法可以生成多个Method对象,但只有一个root对象,主要用于持有一个MethodAccessor对象,这个对象也可以认为一个方法只有一个,相当于是static的,因为Method的invoke是交给MethodAccessor执行的。

可以看到Method.invoke()实际上并不是自己实现的反射调用逻辑,而是委托给sun.reflect.MethodAccessor来处理。 
每个实际的Java方法只有一个对应的Method对象作为root。这个root是不会暴露给用户的,而是每次在通过反射获取Method对象时新创建Method对象把root包装起来再给用户。
在第一次调用一个实际Java方法对应得Method对象的invoke()方法之前,实现调用逻辑的MethodAccessor对象还没创建;
等第一次调用时才新创建MethodAccessor并更新给root,然后调用MethodAccessor.invoke()真正完成反射调用。

AVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

3)例子二:

public interface RunBetter {

   public void startPro();

}

public class Word implements RunBetter{

@Override

public void startPro() {

// TODO Auto-generated method stub

System.out.println("Word Test!");

}

}

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {

      //静态加载。编译时加载,编译时就需要加载全部可能使用到的的类,一个类出错,其他类的功能都不能得到执行  如下注释将编译不通过

      /*if("Word".equals(args[0])){

      Word Word = new Word();

      System.out.println("Word");

      }

      if("Excel".equals(args[0])){

      Excel excel = new Excel();

      System.out.println("Excel");

      }

      }*/

     

      Class c1 = Class.forName(GetProperties.use_classLoador());//配置文件中读取具体实现类

      //在这个代码中我们通过获得类类型newInstance。然后再执行startPro中的方法。

      //为什么不将RunBetter rb = (RunBetter)c1.newInstance();写成 MainLoad rb = (MainLoad)c1.newInstance(); ???

      //不利于拓展,如果有多个实现类都执行startPro方法,这样每加一个类都需要改动源代码程序;接口的形式,只需要 关注接口不关注具体实现类是哪一个;也是多态性

      RunBetter rb = (RunBetter)c1.newInstance();

      rb.startPro();

     

      }

4)例子三:

public interface Attribute {
    abstract void belongNature();
}

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {

        Scanner sc=new Scanner(System.in);

        System.out.println("请输入人群,获取属性……");

        while(true){

            String action=sc.nextLine();

            if("exit".equals(action)){

                return;

            }

            if(action.length()>0){

              runClassLoader(action); 

            }

        }

    }

   static void run(String action){

      switch (action) {

     case "Student":

         Student student=new Student();

         student.belongNature();

          break;

     case "Teacher":

         Teacher teacher=new Teacher();

         teacher.belongNature();

          break;

      default:

          break;

      }

  }

  

static void runClassLoader(String action) throws ClassNotFoundException, InstantiationException, IllegalAccessException{

         switch (action) {

        case "Student":

           Class class1=Class.forName(GetProperties.use_classLoador("class_student"));

           Attribute attribute=(Attribute)class1.newInstance();

           attribute.belongNature();

            break;

        case "Teacher":

            Class class2=Class.forName(GetProperties.use_classLoador("class_teacher"));

            Teacher attribute2=(Teacher)class2.newInstance();

            attribute2.belongNature();

             break;

         default:

             break;

         }

     }

猜你喜欢

转载自my.oschina.net/u/1054538/blog/1626390
今日推荐