反射

基础

  • JAVA反射机制是在运行状态中,对于任意一个类,都能够得到这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.
  • 概括一下: 反射就是让你可以通过名称来得到对象(类,属性,方法)的技术。
  • 例如我们可以通过类名来生成一个类的实例 ; 知道了方法名,就可以调用这个方法 ; 知道了属性名就可以访问这个属性的值。
  • class文件首先被ClassLoader将其Load到CodeSegment
  • CodeSegment中的一个个class文件就是那个java.lang.Class类的对象
  • Load类文件后运行环境找到main函数开始执行
  • 动态加载机制,会在这个class运行过程中有更多的class被Load到内存中
  • ClassLoader并非一次性加载,用到时再加载

TestReflection

TestDynamicLoading.java

  • 这里解释是针对下一段代码
  • 代码区右键 -> Run as -> Run Configurations -> 切换到Arguments标签 -> 在VM arguments: 中输入:-verbose:class 意思是详细的输出Class运行过程,可以观察类的具体加载过程
  • VM arguments是java虚拟机运行时命令行上可以指定的参数
  • console中输出的第一行意思是[open] jre中的lib文件夹下的rt.jar包
  • 后面第一个[Loaded] 的是java.lang.Object类
  • 往下拉好长看到[Loaded A from file:/D:/share/JavaProjects/TestReflection/bin/]
  • 中间会有自己要输出的那行话,在紧接着[Loaded B from file:……]
  • [Loaded A from file:/C:/Users/Administrator/Desktop/TestMVC/Test/bin/]
  • *****************
  • [Loaded B from file:/C:/Users/Administrator/Desktop/TestMVC/Test/bin/]
  • static 语句块本身就是在Load完成之后调用,就调用一次,dynamic语句块内次new新的对象都会执行
public class TestDynamicLoading {
    public static void main(String[] args) {
        new A();
        System.out.println("***************************");
        new B();//如果先加载A后加载B,即动态加载,中间会打印横线

        new C();
        new C();//静态语句块只执行一次

        new D();
        new D();//动态语句块执行两次,每次new一个对象就被调用一次
    }
}
class A {
}
class B {
}
class C {
    static {
        System.out.println("cccccccccccccccccccccccc");
    }
}
class D {
    {// 动带语句块 
        System.out.println("dddddddddddddddddddddddddd");
    } // 和下面的几句话没有区别
// D() {
// System.out.println("dddddddddddddddddddddddddd");
// }
}

TestJDKClassLoader.java

  • 对下一段代码的解释
  • JDK中的ClassLoader有很多,非常多
  • 默认有bootstrap class loader 最顶层的loader,负责专门管理一些最核心的class,最早启动的,一般用c语言或汇编写的,其他的loader都是用java写的,并且bootstrap class loader可以Load其他的Loader,那最核心的jar包,这个loader没有名字,不让动
  • extension class loader 负责JDK的扩展类,在JDK/jre/lib/ext中的类,进去文件夹后 -> 用压缩文件打开查看jar包中的文件 -> 记下路径 -> 用syso输出getClassLoader().
  • application class loader 用来Load自己定义的类
  • 每个class loader中都会有只想父亲loader的引用,利用getParent()方法可以得到上一级的class loader,最高层的是bootstrap class loader,他们不是继承关系,是含有上一级的引用的对象,它们之间是从最高级开始向下加载的过程
  • 当一个classloader加载一个class是会首先问加载这个classloader的classloader是否加载了要加载的类,这样自己写的java.lang.String类就永远不会被加载,防止有破坏性的语句
  • .class是获得Class类对象要加载的
public class TestJDKClassLoader {
    public static void main(String[] args) {
         System.out.println(String.class.getClassLoader());// 输出ClassLoader的名字
         //打印出来是空值,就是最上层的Loader//null
//         System.out.println(com.sun.nio.zipfs.ZipCoder.class.getClassLoader().getClass().getName());
         System.out.println(TestDynamicLoading.class.getClassLoader());//sun.misc.Launcher$AppClassLoader@15b57dcb
         System.out.println(TestDynamicLoading.class.getClassLoader().getClass().getName());//sun.misc.Launcher$AppClassLoader
         System.out.println(ClassLoader.getSystemClassLoader());//sun.misc.Launcher$AppClassLoader@15b57dcb
         System.out.println();

         ClassLoader c = TestJDKClassLoader.class.getClassLoader();//拿到当前装在这个类的classloader
         System.out.println(c);//sun.misc.Launcher$AppClassLoader@15b57dcb
         System.out.println(c.getClass().getName());
         while(c != null) {
             c = c.getParent();
             System.out.println(c);
             System.out.println(c.getClass().getName());
         }
         System.out.println();//输出是:
//         sun.misc.Launcher$AppClassLoader@4e77b794
//         sun.misc.Launcher$AppClassLoader
//         sun.misc.Launcher$ExtClassLoader@15b57dcb
//         sun.misc.Launcher$ExtClassLoader
//         null

//         testthis();这样写是错的
         new TestJDKClassLoader().testthis();
    }
    public void testthis() {
        System.out.println(this.getClass());//输出//class TestJDKClassLoader
        System.out.println(this.getClass().getName());//TestJDKClassLoader
    }
}

TestReflection.java 得到类名,方法,属性,返回值,参数

  • 对下一段代码的解释
  • 在classloader看来,多有的xxx.class都是java.lang.Class的对象
  • 再深层的看,类里面的方法和方法的参数也是对象,类的属性也是对象,都是
  • JDK中有java.lang.reflect.Field和java.lang.reflect.Method来分别代表
import java.lang.reflect.Method;
//从test.properties中读取class的名字,然后生成它的一个对象
//test.properties中的内容是//class=T//
public class TestReflection {
    public static void main(String[] args) throws Exception{
        String str = "T";//简化了,直接读出来了
        Class c = Class.forName(str);//返回值是Class的对象,把名字叫"T"的类装载到内存 ,是Class的一个静态方法
        Object o = c.newInstance();//new出类c的一个对象
        System.out.println();
        Method[] methods = c.getMethods();//把方法的信息都放在了methods的数组里
        for(Method m : methods) {
// System.out.println(m.getName());
            if(m.getName().equals("mm")) {
                m.invoke(o);//让对象o调用方法m,对方法进行调用,方法调用需要对象,是newinstance出来的对象
                //可变参数的方法针对方法参数多的情况
            }
            if(m.getName().equals("m1")) {
                m.invoke(o, 1, 2);
                for(Class paraType : m.getParameterTypes()) {
                    System.out.println(paraType.getName());
                }//得到参数类型
                m.getParameterTypes();
            }
            if(m.getName().equals("getS")) {
                Class returnType = m.getReturnType();
                System.out.println(returnType);
            }//得到参数返回值
        }
    }
}
class T {
    static {//静态语句块验证类是否加载进了内存,验证Class.forName(str);
        System.out.println("T loaded");
    }
    public T() {//验证c.newInstance();
        System.out.println("T constructed");
    }
    int i;
    String s;
    public void m1(int i, int j) {
        this.i = i + j;
        System.out.println(i);
    }
    public void mm() {
        System.out.println("m invoked");
    }
    public String getS() {
        return s;
    }
}

一些其他的知识点

TestGetClassObject.java

public class TestGetClassObject {
    public static void main(String[] args) {
        // 1、获取类对应的Class对象
        // 运用(已知对象)getClass():Object类中的方法,每个类都拥有此方法。
        String str = new String();
        Class strClass = str.getClass();
        System.out.println(strClass);// 输出//class java.lang.String
        System.out.println(strClass.getName());//输出//java.lang.String
        System.out.println("");
        // 运用(已知子类的class)
        // Class.getSuperclass():Class类中的方法,返回该Class的父类的Class;运用(已知类全名):Class.forName()
        // 静态方法运用(已知类): 类名.class

        // 2.通过一个对象获得完整的包名和类名
        Demo demo = new Demo();
        System.out.println(demo.getClass().getName());// 返回//包名.Demo//因为default包,所以没有包名
        System.out.println(" ");

        // 3.实例化Class类对象
        Class<?> demo1 = null;
        Class<?> demo2 = null;
        Class<?> demo3 = null;
        try {
            // 一般尽量采用这种形式
            demo1 = Class.forName("Demo");
        } catch (Exception e) {
            e.printStackTrace();
        }
// demo2 = new Demo();//这样是错的
        demo2 = new Demo().getClass();
        demo3 = Demo.class;

        System.out.println("类名称 " + demo1.getName());
        System.out.println("类 " + demo1);
        System.out.println("类名称 " + demo2.getName());
        System.out.println("类名称 " + demo3.getName());
// 输出
// 类名称 Demo
// 类 class Demo
// 类名称 Demo
// 类名称 Demo
    }
}
class Demo {
}

你可能感兴趣的:(反射)