reflection_reflections - CSDN
精华内容
参与话题
  • Reflection是Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性。例如,使用它能获得 Java 类中各成员的名称并显示出来。 Java 的这一...
    Reflection是Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性。例如,使用它能获得 Java 类中各成员的名称并显示出来。
    Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。

      JavaBean 是 reflection 的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过 reflection 动态的载入并取得 Java 组件(类) 的属性。

    1. 一个简单的例子

      考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。


    import java.lang.reflect.*;
    public class DumpMethods {
    public static void main(String args[]) {
    try {
    Class c = Class.forName(args[0]);
    Method m[] = c.getDeclaredMethods();
    for (int i = 0; i < m.length; i++)
    System.out.println(m[i].toString());
    } catch (Throwable e) {
    System.err.println(e);
    }
    }
    }


      按如下语句执行:

    java DumpMethods java.util.Stack


      它的结果输出为:

    public java.lang.Object java.util.Stack.push(java.lang.Object)

    public synchronized java.lang.Object java.util.Stack.pop()

    public synchronized java.lang.Object java.util.Stack.peek()

    public boolean java.util.Stack.empty()

    public synchronized int java.util.Stack.search(java.lang.Object)


      这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。

      这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。


    2.开始使用 Reflection

      用于 reflection 的类,如 Method,可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤:第一步是获得你想操作的类的 java.lang.Class 对象。在运行中的 Java 程序中,用 java.lang.Class 类来描述类和接口等。
    下面就是获得一个 Class 对象的方法之一:

    Class c = Class.forName("java.lang.String");


      这条语句得到一个 String 类的类对象。还有另一种方法,如下面的语句:

    Class c = int.class;


      或者

    Class c = Integer.TYPE;


      它们可获得基本类型的类信息。其中后一种方法中访问的是基本类型的封装类 (如 Integer) 中预先定义好的 TYPE 字段。

      第二步是调用诸如 getDeclaredMethods 的方法,以取得该类中定义的所有方法的列表。

      一旦取得这个信息,就可以进行第三步了——使用 reflection API 来操作这些信息,如下面这段代码:

    Class c = Class.forName("java.lang.String");

    Method m[] = c.getDeclaredMethods();

    System.out.println(m[0].toString());


      它将以文本方式打印出 String 中定义的第一个方法的原型。

      在下面的例子中,这三个步骤将为使用 reflection 处理特殊应用程序提供例证。

    模拟 instanceof 操作符

      得到类信息之后,通常下一个步骤就是解决关于 Class 对象的一些基本的问题。例如,Class.isInstance 方法可以用于模拟 instanceof 操作符:

    class A {
    }

    public class instance1 {
    public static void main(String args[]) {
    try {
    Class cls = Class.forName("A");
    boolean b1 = cls.isInstance(new Integer(37));
    System.out.println(b1);
    boolean b2 = cls.isInstance(new A());
    System.out.println(b2);
    } catch (Throwable e) {
    System.err.println(e);
    }
    }
    }


      在这个例子中创建了一个 A 类的 Class 对象,然后检查一些对象是否是 A 的实例。Integer(37) 不是,但 new A()是。


    3.找出类的方法

      找出一个类中定义了些什么方法,这是一个非常有价值也非常基础的 reflection 用法。下面的代码就实现了这一用法:

    import java.lang.reflect.*;

    public class method1 {
    private int f1(Object p, int x) throws NullPointerException {
    if (p == null)
    throw new NullPointerException();
    return x;
    }

    public static void main(String args[]) {
    try {
    Class cls = Class.forName("method1");
    Method methlist[] = cls.getDeclaredMethods();
    for (int i = 0; i < methlist.length; i++) {
    Method m = methlist[i];
    System.out.println("name = " + m.getName());
    System.out.println("decl class = " + m.getDeclaringClass());
    Class pvec[] = m.getParameterTypes();
    for (int j = 0; j < pvec.length; j++)
    System.out.println("param #" + j + " " + pvec[j]);
    Class evec[] = m.getExceptionTypes();
    for (int j = 0; j < evec.length; j++)
    System.out.println("exc #" + j + " " + evec[j]);
    System.out.println("return type = " + m.getReturnType());
    System.out.println("-----");
    }
    } catch (Throwable e) {
    System.err.println(e);
    }
    }
    }


      这个程序首先取得 method1 类的描述,然后调用 getDeclaredMethods 来获取一系列的 Method 对象,它们分别描述了定义在类中的每一个方法,包括 public 方法、protected 方法、package 方法和 private 方法等。如果你在程序中使用 getMethods 来代替 getDeclaredMethods,你还能获得继承来的各个方法的信息。
    取得了 Method 对象列表之后,要显示这些方法的参数类型、异常类型和返回值类型等就不难了。这些类型是基本类型还是类类型,都可以由描述类的对象按顺序给出。

      输出的结果如下:

    name = f1

    decl class = class method1


    param #0 class java.lang.Object

    param #1 int

    exc #0 class java.lang.NullPointerException

    return type = int

    -----
    name = main

    decl class = class method1

    param #0 class [Ljava.lang.String;

    return type = void


    4.获取构造器信息

      获取类构造器的用法与上述获取方法的用法类似,如:

    import java.lang.reflect.*;

    public class constructor1 {
    public constructor1() {
    }

    protected constructor1(int i, double d) {
    }

    public static void main(String args[]) {
    try {
    Class cls = Class.forName("constructor1");
    Constructor ctorlist[] = cls.getDeclaredConstructors();
    for (int i = 0; i < ctorlist.length; i++) {
    Constructor ct = ctorlist[i];
    System.out.println("name = " + ct.getName());
    System.out.println("decl class = " + ct.getDeclaringClass());
    Class pvec[] = ct.getParameterTypes();
    for (int j = 0; j < pvec.length; j++)
    System.out.println("param #" + j + " " + pvec[j]);
    Class evec[] = ct.getExceptionTypes();
    for (int j = 0; j < evec.length; j++)
    System.out.println("exc #" + j + " " + evec[j]);
    System.out.println("-----");
    }
    } catch (Throwable e) {
    System.err.println(e);
    }
    }
    }


      这个例子中没能获得返回类型的相关信息,那是因为构造器没有返回类型。

      这个程序运行的结果是:

    name = constructor1

    decl class = class constructor1

    -----
    name = constructor1

    decl class = class constructor1

    param #0 int

    param #1 double


    5.获取类的字段(域)
    找出一个类中定义了哪些数据字段也是可能的,下面的代码就在干这个事情:

    import java.lang.reflect.*;

    public class field1 {
    private double d;
    public static final int i = 37;
    String s = "testing";


    public static void main(String args[]) {
    try {
    Class cls = Class.forName("field1");
    Field fieldlist[] = cls.getDeclaredFields();
    for (int i = 0; i < fieldlist.length; i++) {
    Field fld = fieldlist[i];
    System.out.println("name = " + fld.getName());
    System.out.println("decl class = " + fld.getDeclaringClass());
    System.out.println("type = " + fld.getType());
    int mod = fld.getModifiers();
    System.out.println("modifiers = " + Modifier.toString(mod));
    System.out.println("-----");
    }
    } catch (Throwable e) {
    System.err.println(e);
    }
    }
    }


      这个例子和前面那个例子非常相似。例中使用了一个新东西 Modifier,它也是一个 reflection 类,用来描述字段成员的修饰语,如“private int”。这些修饰语自身由整数描述,而且使用 Modifier.toString 来返回以“官方”顺序排列的字符串描述 (如“static”在“final”之前)。这个程序的输出是:

    name = d

    decl class = class field1

    type = double

    modifiers = private

    -----
    name = i

    decl class = class field1

    type = int

    modifiers = public static final

    -----
    name = s

    decl class = class field1

    type = class java.lang.String

    modifiers =


      和获取方法的情况一下,获取字段的时候也可以只取得在当前类中申明了的字段信息 (getDeclaredFields),或者也可以取得父类中定义的字段 (getFields) 。


    6.根据方法的名称来执行方法

      文本到这里,所举的例子无一例外都与如何获取类的信息有关。我们也可以用 reflection 来做一些其它的事情,比如执行一个指定了名称的方法。下面的示例演示了这一操作:

    import java.lang.reflect.*;
    public class method2 {
    public int add(int a, int b) {
    return a + b;
    }
    public static void main(String args[]) {
    try {
    Class cls = Class.forName("method2");
    Class partypes[] = new Class[2];
    partypes[0] = Integer.TYPE;
    partypes[1] = Integer.TYPE;
    Method meth = cls.getMethod("add", partypes);
    method2 methobj = new method2();
    Object arglist[] = new Object[2];
    arglist[0] = new Integer(37);
    arglist[1] = new Integer(47);
    Object retobj = meth.invoke(methobj, arglist);
    Integer retval = (Integer) retobj;
    System.out.println(retval.intValue());
    } catch (Throwable e) {
    System.err.println(e);
    }
    }
    }

    假如一个程序在执行的某处的时候才知道需要执行某个方法,这个方法的名称是在程序的运行过程中指定的 (例如,JavaBean 开发环境中就会做这样的事),那么上面的程序演示了如何做到。

      上例中,getMethod用于查找一个具有两个整型参数且名为 add 的方法。找到该方法并创建了相应的Method 对象之后,在正确的对象实例中执行它。执行该方法的时候,需要提供一个参数列表,这在上例中是分别包装了整数 37 和 47 的两个 Integer 对象。执行方法的返回的同样是一个 Integer 对象,它封装了返回值 84。


    7.创建新的对象

      对于构造器,则不能像执行方法那样进行,因为执行一个构造器就意味着创建了一个新的对象 (准确的说,创建一个对象的过程包括分配内存和构造对象)。所以,与上例最相似的例子如下:

    import java.lang.reflect.*;

    public class constructor2 {
    public constructor2() {
    }

    public constructor2(int a, int b) {
    System.out.println("a = " + a + " b = " + b);
    }

    public static void main(String args[]) {
    try {
    Class cls = Class.forName("constructor2");
    Class partypes[] = new Class[2];
    partypes[0] = Integer.TYPE;
    partypes[1] = Integer.TYPE;
    Constructor ct = cls.getConstructor(partypes);
    Object arglist[] = new Object[2];
    arglist[0] = new Integer(37);
    arglist[1] = new Integer(47);
    Object retobj = ct.newInstance(arglist);
    } catch (Throwable e) {
    System.err.println(e);
    }
    }
    }


      根据指定的参数类型找到相应的构造函数并执行它,以创建一个新的对象实例。使用这种方法可以在程序运行时动态地创建对象,而不是在编译的时候创建对象,这一点非常有价值。


    8.改变字段(域)的值

      reflection 的还有一个用处就是改变对象数据字段的值。reflection 可以从正在运行的程序中根据名称找到对象的字段并改变它,下面的例子可以说明这一点:

    import java.lang.reflect.*;

    public class field2 {
    public double d;

    public static void main(String args[]) {
    try {
    Class cls = Class.forName("field2");
    Field fld = cls.getField("d");
    field2 f2obj = new field2();
    System.out.println("d = " + f2obj.d);
    fld.setDouble(f2obj, 12.34);
    System.out.println("d = " + f2obj.d);
    } catch (Throwable e) {
    System.err.println(e);
    }
    }
    }


      这个例子中,字段 d 的值被变为了 12.34。


    9.使用数组

      本文介绍的 reflection 的最后一种用法是创建的操作数组。数组在 Java 语言中是一种特殊的类类型,一个数组的引用可以赋给 Object 引用。观察下面的例子看看数组是怎么工作的:

    import java.lang.reflect.*;

    public class array1 {
    public static void main(String args[]) {
    try {
    Class cls = Class.forName("java.lang.String");
    Object arr = Array.newInstance(cls, 10);
    Array.set(arr, 5, "this is a test");
    String s = (String) Array.get(arr, 5);
    System.out.println(s);
    } catch (Throwable e) {
    System.err.println(e);
    }
    }
    }


      例中创建了 10 个单位长度的 String 数组,为第 5 个位置的字符串赋了值,最后将这个字符串从数组中取得并打印了出来。

      下面这段代码提供了一个更复杂的例子:

    import java.lang.reflect.*;

    public class array2 {
    public static void main(String args[]) {
    int dims[] = new int[]{5, 10, 15};
    Object arr = Array.newInstance(Integer.TYPE, dims);
    Object arrobj = Array.get(arr, 3);
    Class cls = arrobj.getClass().getComponentType();
    System.out.println(cls);
    arrobj = Array.get(arrobj, 5);
    Array.setInt(arrobj, 10, 37);
    int arrcast[][][] = (int[][][]) arr;
    System.out.println(arrcast[3][5][10]);
    }
    }


      例中创建了一个 5 x 10 x 15 的整型数组,并为处于 [3][5][10] 的元素赋了值为 37。注意,多维数组实际上就是数组的数组,例如,第一个 Array.get 之后,arrobj 是一个 10 x 15 的数组。进而取得其中的一个元素,即长度为 15 的数组,并使用 Array.setInt 为它的第 10 个元素赋值。

      注意创建数组时的类型是动态的,在编译时并不知道其类型。
    展开全文
  • 镜像矩阵(Reflection

    千次阅读 2018-10-11 15:53:46
    镜像(反射)矩阵是n维空间中的沿n-1维平面的一种矩阵变换,常见的应用场景是在2维空间图像处理、3维空间物体场景变换。先直观看看镜像变换的效果:    直观的感受了镜像变换的效果之后,接下来我们看看这个变换...

            镜像(反射)矩阵是n维空间中的沿n-1维平面的一种矩阵变换,常见的应用场景是在2维空间图像处理、3维空间物体场景变换。先直观看看镜像变换的效果:

                                                     

            直观的感受了镜像变换的效果之后,接下来我们看看这个变换的数学表达式是什么样的。首先n维度空间的镜像变换是基于某个n-1维度平面(对于2维度就是某条直线)来说的,线性代数的知识知道n维空间的n-1维平面存在法向量,假设u=(u_{1},u_{2},...,u_{n})是要做镜像平面的单位法向量,单位法向量||u||=1,定义镜像矩阵Q=I-2uu^{T}

            1. Q是对称和标准正交的,\because Q^{T}=(I-2uu^{T})^{T}=I-2uu^{T}\therefore Q是对称的。\becauseQ^{T}Q=I-4uu^{T}+4uu^{T}uu^{T}=I\thereforeQ是标准正交的。如果对矩阵运算背后的原理不太熟悉,我们也可以将Q展开:

            Q=I-2uu^{T}=\begin{bmatrix} 1-2u_{1}^{2} &-2u_{1}u_{2} &... &-2u_{1}u_{n} \\ -2u_{2}u_{1}&1-2u_{2}^{2} &... &-2u_{2}u_{n} \\ ...& ... & ... &... \\ -2u_{n}u_{2} & -2u_{n}u_{2} &... & 1-2u_{n}^{2} \end{bmatrix}

            由Q的矩阵展开形式,很明显看到Q_{ij}=Q_{ji}=-2u_{i}u_{j},i\neq j,所以Q是对称的。标准正交:q_{i},q_{j}是Q的两列,由标准正交的定义,需要满足如下条件:

            q_{i}q_{j}=\begin{cases} 0& \text{ if } x\neq j \\ 1& \text{ if } x=j \end{cases}

            q_{i}q_{j}=(1-2u_{i}^2)^{2}+4u_{i}^2u_{1}^2+...+4u_{i}^{2}u_{n}^2

                    =1+4u_{i}^4-4u_{i}^2+4u_{i}^2u_{1}^2+...+4u_{i}^{2}u_{n}^2

                    =1+4u_{i}^2(u_{1}^{2}+...+u_{n}^{2})-4\overset{||u||^{2}=1}{\rightarrow}

                    =1 (i=j)

             q_{i}q_{j}=(1-2u_{i}^2)(-2u_{i}u{j})+(1-2u_{j}^{2})(-2u_{j}u_{i})+4u_{i}u_{j}u_{1}^2+...4u_{i}u_{j}u_{k}^2...+4u_{i}u_{j}u_{n}^2,k\neq i,j

                          =-4u_{i}u_{j}+4u_{i}u{j}(u_{1}^2+...+u_{n}^2)

                          =0

             2.Q^{2}=Q^{T}Q=I,这条性质反应了镜像的特点,镜像两次等于原空间。

            上面是镜像矩阵的定义和它的一些性质和推导,那么我们再做一点深层次的思考:为什么镜像的表达会是一个矩阵变换,如果我做旋转是不是也是一个矩阵变换?首先,问题2的答案:YES,2维空间的旋转的变换矩阵是:\begin{bmatrix} cos\Theta & -sin\Theta \\ sin\Theta& cos\Theta \end{bmatrix}

            对于问题1,矩阵变换的本质可以理解成坐标系的变换,对于镜像和旋转我们都是对原坐标系中的向量(坐标系中的点可以表示成原点指向该点的向量)用新的坐标系中的基进行了表示。比如二维直角坐标系x0y的坐标基向量是(1,0)和(0,1),如果用矩阵表示:\begin{bmatrix} 1 &0 \\ 0 &1 \end{bmatrix},基向量就是矩阵的列向量,(1,1)点这个坐标系下的坐标(x,y)由方程组\begin{bmatrix} 1 &0 \\ 0 &1 \end{bmatrix}\begin{bmatrix} x\\ y \end{bmatrix}=\begin{bmatrix} 1\\ 1 \end{bmatrix}求得(x,y)=(1,1)因为在原坐标系下,假设我们对(1,1)点做沿x轴做镜像,这里的镜像很简单,x轴和原坐标系相同,y轴与原坐标系反号,所以镜像之后新的坐标系基向量是(1,0)和(0,-1)(如果你通过上面的镜像公式可以求得同样的答案,u=(0,1)),新的坐标系的矩阵表示\begin{bmatrix} 1 &0 \\ 0 &-1 \end{bmatrix},原坐标系下(1,1)点在新坐标系下的坐标有方程组\begin{bmatrix} 1 &0 \\ 0 &-1 \end{bmatrix}\begin{bmatrix} x\\ y \end{bmatrix}=\begin{bmatrix} 1\\ 1 \end{bmatrix}求得(x,y)=(1,-1),和我们直观认知一样:

                                                         

            最后我们说说2维度空间和3维空间的镜像矩阵的表达式,首先是2维空间,对于2-D空间的某个条直线做镜像,假设该直线的单位法向量u(x,y),由Q=I-2uu^{T}计算得到2-D空间的镜像矩阵:

            Q_{2d}=\begin{bmatrix} 1-2x^{2} &-2xy \\ -2xy& 1-2y^{2} \end{bmatrix}

            对于3-D空间的某平面做镜像:

            Q_{3d}=\begin{bmatrix} 1-2x^{2} &-2xy &-2xz \\ -2xy& 1-2y^{2} &-2yz \\ -2xz& -2yz &1-2z^{2} \end{bmatrix}

            镜像矩阵的另一种表示形式:Q'=2P-I, 其中P是投影矩阵,这个表达式和Q=I-2uu^{T}等价。我们证明一下2纬空间沿着某条线做镜像的情况下这两个矩阵的等价性。

    证明:

            假设a是P投影方向上的单位向量,u是垂直与投影方向上的单位向量,那么p=aa^{T},Q'=2P-I=2aa^{T}-I

            Q'-Q=2aa^{T}+2uu^{T}-2I=\begin{bmatrix} 2a_{1}^{2}+2u_{1}^{2} -2 &2a_{1}a_{2}+2u_{1}u_{2} \\ 2a_{2}a_{1}+2u_{2}u_{1}&2a_{2}^{2}+2u_{2}^2-2 \end{bmatrix}

            假设a与x轴的夹角为\theta,那么u与x轴的夹角为\theta +\pi /2,那么:

             a_{1}=cos\theta ,a_{2}=sin\theta

            u_{1}=cos(\theta+\pi/2)=-sin(\theta),u_{2}=sin(\theta+\pi/2)=cos\theta

            带入Q’-Q中得到:

            2a_{1}^{2}+2u_{1}^{2}-2=0

            2a_{2}^{2}+2u_{2}^{2}-2=0

            2a_{1}a_{2}+2u_{1}u_{2}=0

            所以Q'-Q=0,所以Q'-Q得证。

     

     

     

    展开全文
  • Java反射(Reflection

    2020-10-27 09:44:25
    Java反射(Reflection) 反射是Java被视为动态语言的关键,能直接操作任意对象的内部属性和方法。 反射方式: #mermaid-svg-6Jd2KNORYVX9IxMl .label{font-family:'trebuchet ms', verdana, arial;font-family:var(-...

    Java反射(Reflection)

    反射是Java被视为动态语言的关键,能直接操作任意对象的内部属性和方法。
    反射方式:

    实例化对象
    getClass方法
    得到完整的''包类''名称

    优点

    可以动态创建对象和编译,体现出很大的灵活性。

    缺点

    对性能有影响。(反射是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求)这类操作总是慢于直接执行相同的操作。

    反射机制提供的功能

    • 在运行时判断任意一个对象所属的类。
    • 在运行时构造任意一个类的对象。
    • 在运行时判断任意一个类所具有的成员变量和方法。
    • 在运行时获取泛型信息。
    • 在运行时调用任意一个对象的成员变量和方法。
    • 在运行时处理注解。
    • 生成动态代理。
    • 。。。。

    反射相关的主要API

    • java.lang.Class:代表一个类
    • java.lang.reflect.Method:代表类的方法
    • java.lang.reflect.Field:代表类的成员变量
    • java.lang.reflect.Constructor:代表类的构造器

    获取Class类的实例

    1. 通过类的class属性获取,该方法最为安全可靠,程序性能最高。
      // 通过class属性获取
      Class clazz = Person.class;
      
    2. 通过调用实例的getClass()方法获取Class对象。
      // 通过getClass()方法获取
      Class clazz = person.getClass();
      
    3. 通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException。(一般推荐使用这种)
      // 通过Class类的静态方法forName()获取
      Class clazz = Class.forName("路径");
      
    4. 内置基本数据类型可以直接用类名.Type。
      利用反射机制能获得类的所有信息 ,类中有什么信息,它就可以获得什么信息。

    反射的实现主要借助以下四个类

    Class:类的对象
    Constructor:类的构造方法
    Field:类中的属性对象
    Method:类中的方法对象

    我们知道所有类的对象其实都是Class的实例,所以要获得对象,首先要获得class实例

    1. 获得class实例

    newInstance();创建对象的实例,这里需要一个无参的构造函数

    1. 获得构造函数

    Constructor getConstructor(Class[] params)//根据指定参数获得public构造器
    Constructor[] getConstructors() //获得public的所有构造器
    Constructor getDeclaredConstructor(Class[] params) //根据指定参数获得public和非public的构造器
    Constructor[] getDeclaredConstructors() //获得所有的public和非public的构造器

    1. 获得类方法

    Method getMethod(String name, Class[] params) //根据方法名,参数类型获得方法
    Method[] getMethods() //获得所有的public方法
    Method getDeclaredMethod(String name, Class[] params)//根据方法名和参数类型,获得public和非public的方法
    Method[] getDeclaredMethods() //获得所有的public和非public方法

    1. 获得类中属性

    Field getField(String name) //根据变量名得到相应的public变量
    Field[] getFields() //获得类中所以public的方法
    Field getDeclaredField(String name)//根据方法名获得public和非public变量
    Field[] getDeclaredFields() //获得类中所有的public和非public方法

    1. 关闭安全检测权限

    setAccessible(true);

    Java内存分析

    1. 存放new的对象和数组。
    2. 可以被所有线程共享,不会存放别的对象引用。

    1. 存放基本变量类型(包含具体的数值)。
    2. 引用对象的变量(存放这个引用在堆里面的具体地址)。

    方法区

    1. 可以被所有线程共享。
    2. 包含所有的class和static变量。

    类加载器

    作用:将class文件字节码内容加载到内存,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的Class对象,作为方法区中类数据的访问入口。(JVM垃圾回收机制可以回收这些Class对象)

    类的加载过程

    1. 加载:类加载器的过程。
    2. 链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。
      (1)验证:保证加载的信息符合JVM规范,没有安全方面的问题。
      (2)准备:为类(static)变量分配内存并默认初始化(这些内存都在方法区中进行分配)
      (3)解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
    3. 初始化(执行类构造器()方法的过程):先初始化父类。
    展开全文
  • 反射(Reflection)详解

    2018-08-09 13:37:24
    Reflection 产生原因:运行时获取、修改数据(类信息、成员数据信息)。 反射入口 java.lang.Class Class对象分为基本类型(8种)、引用类型:(具体内容在文章末尾) JVM会为每个对象(基础和引用类型)实例化一...

    Reflection

    产生原因:运行时获取、修改数据(类信息、成员数据信息)。

    反射入口 java.lang.Class

    Class对象分为基本类型(8种)、引用类型:(具体内容在文章末尾)

    JVM会为每个对象(基础和引用类型)实例化一个java.lang.Class实例。通过这个Class对象,可以在运行时访问对象的属性和类信息、也可以创建新的对象和类。反射的实现,首先要获取Class实例。

    获取Class实例的方法:

    • Object.getClass();
      Class class = object.getClass();
      枚举类型的对象获取的是枚举类的Class,数组对象获取的是数组元素的Class
    • .class
      Objcet.class; 
    
      int.class.newInstance()
    • Class.forName().
      只能用于引用类型,需要类的完整路径:如java.lang.String
    
      Class<?> class = Class.forName("java.lang.String");
    • static属性TYPE
      Class<String> class = String.TYPE;
      TYPE的定义:public static final Class<String> TYPE = (Class<String>) String[].class.getComponentType();

    获取相关类的Class对象:

    • 父类 getSuperclass()
    • 公共类、接口、枚举等 getClasses()
    • 显示申明的所有类、接口、枚举 getDeclaredClasses()
    • 成员声明类 getDeclaringClasses()

    Class对象获取类的信息:

    • 获取类的修饰符(修饰符介绍见本文末)
    
      int modifier = class.getModifiers() ;
    
      String modifierStr = Modifier.toString(int modifiers);
    
      同时因为Field继承了AnnotatedElement,所以在运行时可以获取注解,获取的注解必须是RUNTIME所修饰的注解

    获取类成员(Member)

    • 构造函数(Constructor)
    getDeclaredConstructor(Class<?>... parameterTypes)获取指定的构造方法,可获取私有方法
    getConstructor(Class<?>... parameterTypes) 获取指定的构造方法,不可获取私有方法
    getDeclaredConstructors() 获取所有构造方法,可获取私有方法
    getConstructor(Class<?>... parameterTypes) 获取所有构造方法,不可获取私有方法
    • 成员变量(Field)

    获取变量:

    getDeclaredField(String name);// 获取指定的变量   类自有变量  包括取私有变量,但是不能获取继承父类的
    
    getField(String name);  //获取指定的变量,可获取自身和继承自父类的public变量。
    
    getDeclaredFields(); //获取类自有的所有变量集合,包括私有变量,不包括继承变量
    
    getFields(); //获取自身和继承自父类的public变量的集合。

    获取变量类型:

    Field.getType() :返回Class对象  ,这个变量的类型
    Field.getGenericType():返回Type接口  ,如果类型是泛型,getGenericType可以得到这个泛型的参数类型(T),getType()只能得到这个类型的接口类型(Object)。

    设置变量的值

    Class cls = object.getClass();
    
    Field field = objcet.getField("name");
    
    field.set(object,"new Name");
    
    //修改变量的值时,编译器不会拆装箱操作,设置时必须设置相同的类型
    
    Integer itg;
    
    Class cls = object.getClass();
    
    Field field = objcet.getField("itg");
    
    field.set(object,new Integer(666));
    
    //直接修改final类型的变量会报错`IllegalAccessException` 需要setAccessible(true),
    //就可以访问修改了。(由于 `Field` 继承自 `AccessibleObject` , 我们可以使用 
    //`AccessibleObject.setAccessible()` 方法告诉安全机制,这个变量可以访问。 )
    • 成员方法(Method:java.lang.reflect.Method)
    //获取的方法属性同成员变量。
    getDeclaredMethod(String name,Class parameterTypes.....)
    getMethod(String name,Class parameterTypes.....)
    getDeclaredMethods()
    getMethods()
    

    继承于父类的方法因强制执行无法被反射,因此反射方法仅限本类方法。

    反射方法得到的数据由:修饰符、返回值、参数、注解、抛出异常五点组成:

    getName());  //获得单独的方法名 
    
    toGenericString()); //获得完整的方法信息(包括修饰符、返回值、路径、名称、参数、抛出值) 
    
    int modifiers = declaredMethod.getModifiers();Modifier.toString(modifiers)    /获得修饰符 
    
    getReturnType();   //获得返回值 
    
    getGenericReturnType();//获得完整信息的返回值 
    
    //获得参数类型 
    Class<?>[] parameterTypes = method.getParameterTypes(); 
    Type[] genericParameterTypes = method.getGenericParameterTypes();
    
    //获得异常名称 
    Class<?>[] exceptionTypes = declaredMethod.getExceptionTypes();   
    Type[] genericExceptionTypes = declaredMethod.getGenericExceptionTypes();   
    
     //获得注解 
    Annotation[] annotations = declaredMethod.getAnnotations(); 
    annotations[i].annotationType();

    三种特殊的方法类型:

    synthetic(合成,内部类访问权限), varagrs(参数可变), bridge(桥接,泛型相关)
    

    反射 调用方法

    invoke() ;
    //java.lang.reflect.Method.invoke(Object receiver,Object... args)
    //该方法抛异常:java.lang.reflect.InvocationTargetException
    receiver 是方法所属于的对象,静态方法可直接传null,args传方法的参数
    //当访问private属性的方法时,需要设置setAccessible(true) 否则报`IllegalAccessException`异常
    
    

    相似概念:Introspection(自省):

    区别:

    Introspection 是在运行时获取对象的信息,Reflection是获取或者修改对象的信息
    Introspection多用于 instanceof 的判断,Reflection多用来实现访问私有方法,创建对象等
    总的说,Reflection是多了可进行修改信息。
    

    附录 :

    Class对象的基本类型(8种)、引用类型:

    基本类型:

    • 整型:默认类型int

      • byte : 8位、有符号的二进制补码表示整数、范围-128~127(-2^7~2^7-1)
      • short : 16位、有符号的二进制补码表示整数、范围-32768~32767(-2^15~2^15-1)
      • int : 32位、有符号的二进制补码表示整数、范围-214748348~2147483647(-2^31~2^31-1)
      • long : 64位 、 范围-9223372036854775808~9223372036854775807(-2^63~2^63-1) 。
        long a =1000000000000L;
    • 浮点类型:默认类型double

      • float : 单精度、32位浮点数,存储大型浮点数组较为节省空间、不能用来表示精确值如货币
      • double : 双精度、64位、也不可表示精确的数。
    • bool值
      boolean : true/false、 默认值false

    • 字符型

      • char : 单一的16位Unicode字符、最大值0(\u0000)、最大值65535(\uffff) 。char letter=”A”;

    引用类型:

    • 引用类型都是继承自java.lang.Object
    • 类、枚举、数组、接口
    • java.io.Serializable接口及其实现类、包装类Double、Integer。

    修饰符Modifier

    修饰符用来定义类、方法、变量,通常在语句首位,分为两大类:访问修饰符和非访问修饰符

    访问修饰符:

    default:

        缺省值,不写明修饰符,在同一包内可见(类,接口,变量,方法可用)
    
        接口中变量隐式声明为public static final,方法隐式声明为public
    

    public:

        对所有的类可见(类、接口、方法、变量可用)
    
        java 中main方法一定为共有的
    

    protected:

        同一个包中的所有子类和其他类都可以访问(变量、方法可用,不能修饰类(外部类)和接口(及接口的变量和方法))
    
        不同包中的子类可见(变量、方法可用,不能修饰类(外部类)和接口(及接口的变量和方法)),其他类不能访问。
    
        不同包中的子类不能使用父类的实例对象访问其父类的protect属性的变量和方法。即:superClass.protectParameter不可见。只能subClass.protectParameter访问。
    
        避免不相关的类访问。
    

    private:

        最严格访问级别,为了隐藏类实现的细节,保护类的数据,外部类和接口不能声明为private。
    
        只能在同一个类内可见(变量、方法可用,不能修饰外部类和接口(及接口的变量和方法))
    

    访问修饰符在继承中的规则:子类权限必须大于父类,具体如下:

        1.父类public子类必为public.
        2.父类protected子类必须protected/public.
        3. 父类private子类无法继承.
    

    非访问修饰符:

    abstract:

        创建抽象类和抽象方法
    
        一个类不能同时被abstract和final修饰,一个类只要包含抽象方法,就一定要声明为抽象类。抽象类可以包含抽象和非抽象的方法,也可以不包含抽象方法。
    
        抽象方法不能被声明为static 和final,子类必须实现父类的抽象方法,除非子类也是抽象类
    

    static:

        可以直接通过类名访问static修饰的变量和方法,如StaticClass.variableName /StaticClass.methodName().
    
        static 变量:也叫类变量,属于类所有,独立于类的实例对象(实例对象可以有多个,类变量只有一份),
        只能修饰成员变量,不可修饰局部变量。
    
        static 方法:类方法,独立于类的实例对象,方法内不能包含非静态的成员变量。
    

    final:

        final修饰的类不能被继承,方法不能被子类重写,变量为常量不可修改。
    
        final修饰的变量必须显示初始化并且只能赋值一次。
    
        final变量不可修改,是指的其引用不可修改,引用变量的值改变,fianl变量包含的数据是可以改变的。:
        final Person p = new Person(24,name);
        p.setAge(25);
    
        final一般结合static创建常量。static final String CONSTANT_STRING = "I'M CONSTANT STRING"
    
        final修饰的方法不可被子类修改,可以防止该方法被改动
    

    synchronized:

        说明被修饰的方法在同一个时间只能被一个线程访问,synchronized修饰符可以用应于 所有访问修饰符(public、default、private、protected)
    

    transient:

        序列化对象时,JVM会跳过transient修饰的变量。public transient String str = "I'll be ignored";
    

    volatile

        volatile修饰的成员变量在每次被线程访问时,都需要从共享内存中重新读取该成员变量的值,
        当此成员变量发生变化时,会强制线程将变化值写回共享内存,因此,在任何时刻,多个线程中此成员变量的值都相同。
    

    native

        在JAVA中调用非JAVA语言写的方法(如C、C++) :native void nativeMethod(.....);
        native 不可以和abstract修饰符一起使用。(native虽然在JAVA代码没有方法体,但本地方法是有实现的)
        使用native主要是为了和java环境和操作系统等交互,本地方法在JAVA加载是,放在DLL文件中,方法native方法调用前,本地方法会被加载。
    

    Thanks:

    https://blog.csdn.net/u011240877/article/details/54604146

    展开全文
  • 以下分析来源:Seeing Deeply and Bidirectionally: A Deep Learning Approach for Single Image Reflection Removal 这篇文章说它提出了级联深度神经网络(cascade deep netural network),尽管每个深度学习都是...
  • 反射(Reflection

    2020-10-09 11:49:01
    反射(Reflection) java是一种静态语言 反射是java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。 Class c = Class.for...
  • 什么是反射(Reflection )? 主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。 什么是Java反射? Java反射指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法;对于给定...
  • Reflection

    2019-04-21 14:12:04
    目录Reflection是什么Type应用 Reflection是什么 一般的程序的操作对象是数据(data),但有时候,我们想要在运行期获取有关程序自身的信息,例如我们想在编译器界面有一个类浏览器,这个时候,我们需要获取的就是...
  • 简介 反射效果,是一个渲染中很重要的一个效果。在表现光滑表面(金属,光滑地面),水面(湖面,地面积水)等材质的时候,加上反射,都可以画面效果有很大的提升。来看几张图: 先来张最近比较火爆的国产大作...
  • reflection removal

    2020-07-15 13:23:55
    文章目录Single image reflection removal beyonf linearity Single image reflection removal beyonf linearity 章博推的cvpr2019的文章 开篇题图就告诉我们,以前做反射消除严重依赖线性仿真数据,文章提出基于非...
  • Java Reflection

    千次阅读 2004-11-20 18:05:00
    Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。例如,使用它能获得 Java 类中各成员的名称并显示出来。 Java 的这一能力在...
  • Exploiting Reflection Change for Automatic Reflection Removal.去除像反光
  • 1. 发现运行中对象的信息,调用其中的方法、属性值等,用到的是system.reflection命名空间下的类中的方法; 2. 在运行时动态产生代码,用到的是system.reflection.emit命名空间下的类中的方法。   第一部分: ...
  • unity Reflection Probe

    千次阅读 2017-09-08 16:33:08
    Reflection Probe
  • 和diffuse reflection对应的是specular reflection。一直以来,本人都将“specular reflection”理解为“镜面反射”。但是,现在来写总结时,发现牵涉到一个叫做“perfect specular reflection”的东东,这下有点乱...
  • 转载需注明出处:java反射机制(1)- 知识点总结Java Reflection API操作1 什么是反射机制  什么是反射机制?简单点说就是程序在运行时能够获取自身的信息。在java中,只要给定类的全名,就可以通过反射机制来获取...
  • Reflection probes

    2019-09-03 12:10:21
    Reflection probes: Reflection probes就是得到一个点的反射贴图,它由一张cubemap组成,包括六个方向,包含了它此时反射的环境. 每一个点都可以有一个reflection probes 来反映他此时的反射环境 reflection ...
  • System.Reflection简介

    2016-07-01 17:13:53
    转载注明出处:点击打开链接 .net的元数据可以完整地描述类型,那么通过System.Reflection,可以在运行时发现类型格式,我们来看一下元数据: class Class2 { private int x; private int y; public Class2
  • 使用C#进行Reflection编程

    千次阅读 2004-07-30 17:03:00
    using System.Reflection;using System.Reflection.Emit ; public class TestReflection { private String file = @"TestReflection.exe"; static void Main(String[] args) { TestReflection
  • 2016-06-28 09:31:41.0699 | Error | 每隔 1 分钟获取数据并保存异常 System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Web.Services....
1 2 3 4 5 ... 20
收藏数 104,899
精华内容 41,959
关键字:

reflection