包字节码加密_反射,从字节码到对象

274a0ceb169d9c8fe3190d55577c054d.png

为了爱你,我学着温柔,把一些情话慢慢熬,尽管我还是想抱着你,或者跳起来吻你。

一、前言

官方解释:Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.(反射使Java代码可以发现有关已加载类的字段,方法和构造函数的信息,并在安全性限制内使用反射的字段,方法和构造函数对其基础副本进行操作。该API容纳需要访问目标对象的公共成员(基于其运行时类)或给定类声明的成员的应用程序。 它还允许程序禁止默认的反射访问控制。)

我的理解:反射,最简单的理解就是不用new而新建对象。Java反射相关的所有内容都是在java.lang.reflect包中,记住这个包,为练习下面的代码做好准备。

二、字节码对象

2.1 Java反射机制中获取字节码对象

Java反射机制中获取字节码对象有三种方式,各个方式各有优缺,如下图:

81a355288412427a2eec9ad9a3f355bf.png

示例代码——获取字节码对象的三种方式:

package mypackage;//获取字节码对象的三种方式//Java中,String是一种特殊的引用类型,这里以java.lang.String为例,获取字节码对象public class Test {  public static void main(String[] args) throws ClassNotFoundException {    // 方式1:使用class属性    // 注意:其实这里可以不用使用java.lang.String.class 直接使用String.class 因为Java程序默认import    // java.lang包    Class class1 = java.lang.String.class;    System.out.println(class1);    class1 = String.class;    System.out.println(class1);    System.out.println("====================");    // 方式2:使用getClass()方法    // 注意:其实这里可以不用使用java.lang.String().getClass 直接使用String.getClass()    // 因为Java程序默认import java.lang包    Class> class2 = new java.lang.String().getClass();    System.out.println(class2);    class2 = new String().getClass();    System.out.println(class2);    System.out.println("====================");    // 方式3:使用Class类的静态方法forName(String className)    // 注意:这里必须写java.lang.String,作为字符串时,不必写全限定类名,否则报错java.lang.ClassNotFoundException    Class> class3 = Class.forName("java.lang.String");    System.out.println(class3);    //class3 = Class.forName("String");    // System.out.println(class3);   //这里必须注释,因为这里报错java.lang.ClassNotFoundException      }}

输出:

class java.lang.Stringclass java.lang.String====================class java.lang.Stringclass java.lang.String====================class java.lang.String

小结:获取字节码对象是反射机制的第一步,后面使用字节码对象获取构造器并新建对象,使用字节码对象获取方法并调用方法。

2.2 Java虚拟机中对于某一个类只保留一份字节码对象

Java虚拟机中对于某一个类只保留一份字节码对象,即表示同一个类的n个不同对象使用的是同一个字节码对象,即同一个类的n个不同对象的字节码引用指向的是同一个字节码对象。

示例代码:

package mypackage比较;//获取字节码对象的三种方式//Java中,String是一种特殊的引用类型,这里以java.lang.String为例,获取字节码对象public class Test {  public static void main(String[] args) throws ClassNotFoundException {    // 方式1:使用class属性    // 注意:其实这里可以不用使用java.lang.String.class 直接使用String.class 因为Java程序默认import    // java.lang包    Class class1 = java.lang.String.class;    System.out.println(class1);    class1 = String.class;    System.out.println(class1);    System.out.println("====================");    // 方式2:使用getClass()方法    // 注意:其实这里可以不用使用java.lang.String().getClass 直接使用String.getClass()    // 因为Java程序默认import java.lang包    Class> class2 = new java.lang.String().getClass();    System.out.println(class2);    class2 = new String().getClass();    System.out.println(class2);    System.out.println("====================");    // 方式3:使用Class类的静态方法forName(String className)    // 注意:这里必须写java.lang.String,作为字符串时,不必写全限定类名,否则报错java.lang.ClassNotFoundException    Class> class3 = Class.forName("java.lang.String");    System.out.println(class3);    //class3 = Class.forName("String");    // System.out.println(class3);   //这里必须注释,因为这里报错java.lang.ClassNotFoundException        //对应同一个类,Java虚拟机中只保存一份字节码对象,    System.out.println("====================");    System.out.println(myCompareFunc(class1,class2,class3));  }    private static boolean myCompareFunc(Class> class1,Class> class2,Class> class3){    if (class1==class2 && class1==class3) {      return true;    }    return false;  }}

输出:

class java.lang.Stringclass java.lang.String====================class java.lang.Stringclass java.lang.String====================class java.lang.String====================true

小结:class1 class2 class3,对于三种不同方式的三个不同引用直接比较,返回为true,说明class1 class2 class3 所指向的是同一地址,所以所指向的是同一对象,同一字节码对象。

附:特殊情况,基本类型和包装类型的字节码对象

package mypackage基本类型和包装类型的字节码对象;//8种基本类型和9种包装类型   包装类型Void没有对应的基本类型//基本类型是值类型,包装类型是引用类型,//又因为同一类在JVM只存放一份字节码对象public class Test {  public static void main(String[] args) {    // boolean和Boolean    System.out.println(boolean.class + " - " + Boolean.class + " - " + Boolean.TYPE);    System.out.println(boolean.class == Boolean.TYPE);    // char和Character    System.out.println(char.class + " - " + Character.class + " - " + Character.TYPE);    System.out.println(char.class == Character.TYPE);    // byte和Byte    System.out.println(byte.class + " - " + Byte.class + " - " + Byte.TYPE);    System.out.println(byte.class == Byte.TYPE);    // short和Short    System.out.println(short.class + " - " + Short.class + " - " + Short.TYPE);    System.out.println(short.class == Short.TYPE);    System.out.println("====================================");// 看着头晕,画一条分割线    // int和Integer    System.out.println(int.class + " - " + Integer.class + " - " + Integer.TYPE);    System.out.println(int.class == Integer.TYPE);    // long和Long    System.out.println(long.class + " - " + Long.class + " - " + Long.TYPE);    System.out.println(long.class == Long.TYPE);    // float和Float    System.out.println(float.class + " - " + Float.class + " - " + Float.TYPE);    System.out.println(float.class == Float.TYPE);    // long和Long    System.out.println(double.class + " - " + Double.class + " - " + Double.TYPE);    System.out.println(double.class == Double.TYPE);  }}

输出:

boolean - class java.lang.Boolean - booleantruechar - class java.lang.Character - chartruebyte - class java.lang.Byte - bytetrueshort - class java.lang.Short - shorttrue====================================int - class java.lang.Integer - inttruelong - class java.lang.Long - longtruefloat - class java.lang.Float - floattruedouble - class java.lang.Double - doubletrue

小结:从上面基本类型.class==包装类型.Type,根据小结2,则int.class和Integer.Type指向的是同一字节码对象,理解清楚了基本类型和包装类型的字节码对象的关联关系。

2.3 小结

字节码对象是Java反射机制的基础,获取到了字节码对象,后面才可以通过字节码对象获取构造器,新建对象,调用属性和方法,本小节中提供三种获取字节码对象的方法——.class属性,getClass()方法,Class.forName(“全限定类名”),然后用代码解释JVM(Java虚拟机)中任何一个类(无论新建多少个对象)只保存一份字节码对象。

三、使用字节码对象获取构造器进而新建对象

3.1 从字节码对象到构造器

获取字节码对象后,我们通过字节码对象获取类的构造器,然后使用构造器新建对象,且看3.2、3.3。

3.2 使用字节码对象获取构造器

package mypackage;//获取构造器的步骤://1、获取字节码对象//2、通过字节码对象获取构造器//获取构造器的方法://public Constructor>[] getConstructors():该方法只能获取当前Class所表示类的public修饰的构造器//public Constructor>[] getDeclaredConstructors():获取当前Class所表示类的所有的构造器,和访问权限无关//public Constructor getConstructor(Class>... parameterTypes) :获取当前Class所表示类中指定的一个public的构造器//public Constructor getDeclaredConstructor(Class>... parameterTypes) :获取当前Class所表示类中指定的一个的构造import java.lang.reflect.Constructor;public class Test {  public static void main(String[] args) throws Exception {    getOne();    System.out.println("==================");    getAll();  }  // 调用一个构造器  private static void getOne() throws Exception {    Class class1 = Student.class;    // 调用无参构造函数 Student()    Constructorconstructor = class1.getConstructor();    System.out.println(constructor);    // 调用指定参数构造函数 Student(String name)    constructor = class1.getConstructor(String.class);    System.out.println(constructor);    // 调用指定参数构造函数 Student(String name,int age)    constructor = class1.getConstructor(String.class, int.class);    System.out.println(constructor);    // 调用指定非public构造器    constructor = class1.getDeclaredConstructor(String.class, int.class, int.class);    System.out.println(constructor);  }  // 调用多个构造器  private static void getAll() throws Exception {    Class class1 = Student.class;    Constructor>[] constructors = class1.getConstructors();    for (Constructor> constructor : constructors) {      System.out.println(constructor);    }    System.out.println("--------------------");    constructors = class1.getDeclaredConstructors();    for (Constructor> constructor : constructors) {      System.out.println(constructor);    }  }}class Student {  public Student() {  }  public Student(String name) {  }  public Student(String name, int age) {  }  private Student(String name, int age, int grade) {  }}

输出:

public mypackage.Student()public mypackage.Student(java.lang.String)public mypackage.Student(java.lang.String,int)private mypackage.Student(java.lang.String,int,int)==================public mypackage.Student(java.lang.String,int)public mypackage.Student(java.lang.String)public mypackage.Student()--------------------private mypackage.Student(java.lang.String,int,int)public mypackage.Student(java.lang.String,int)public mypackage.Student(java.lang.String)public mypackage.Student()

小结:Java反射机制中,获取构造器的四个方法,如:

8d5fd4b9e131681e644bd3d477d7d57b.png

如本小节代码所示,灵活的使用获取构造器的方法,可以用字节码对象获取任意一个构造器。

3.3 使用获取到的构造器新建对象

使用字节码获取到构造器之后,可以调用构造器新建对象。

示例代码:

package mypackage;import java.lang.reflect.Constructor;//步骤://1、获取字节码对象//2、通过字节码对象获取构造器//3、使用构造器新建对象public class Test {  public static void main(String[] args) throws Exception {    Class class1 = Student.class;// 获取字节码对象    // 调用无参构造函数Student()    Constructorconstructor = class1.getConstructor(); // 调用无参构造函数    constructor.newInstance(); // 构造器新建对象    // 调用带参构造函数Student(String name)    constructor = class1.getConstructor(String.class);    constructor.newInstance("小明");    // 调用带参构造函数Student(String name,int age)    constructor = class1.getConstructor(String.class, int.class);    constructor.newInstance("小明", 12);    // 调用带参构造函数Student(String name,int age,int grade)    constructor = class1.getDeclaredConstructor(String.class, int.class, int.class);    constructor.setAccessible(true); // 将私有构造函数设置为可以访问的    constructor.newInstance("小明", 12, 98);  }}class Student {  public Student() {    System.out.println("无参构造函数");  }  public Student(String name) {    System.out.println("带参构造函数,name: " + name);  }  public Student(String name, int age) {    System.out.println("带参构造函数,name: " + name + " ,age: " + age);  }  private Student(String name, int age, int grade) {    System.out.println("带参构造函数,name: " + name + " ,age: " + age + " ,grade: " + grade);  }}

输出:

无参构造函数带参构造函数,name: 小明带参构造函数,name: 小明 ,age: 12带参构造函数,name: 小明 ,age: 12 ,grade: 98

小结:新建对象的方法:public T newInstance(Object… initargs):如调用带参数的构造器,只能使用该方式.

如果是私有构造函数,新建对象前使用: 对象.setAccessible(true); 设置为可以访问的,如代码private Student(String name, int age, int grade)的调用。

附:特殊情况,前面我们是先获得字节码对象,然后使用字节码对象获取构造器,最后调用构造器新建对象,实际上,当一个类中的构造器是外界可以直接访问,同时没有参数.,那么可以直接使用 “字节码对象.newInstance()” 创建对象,如:

package mypackage1;import java.lang.reflect.Constructor;public class Test {  public static void main(String[] args) throws Exception {    Class class1 = Student.class;// 获取字节码对象    // 调用无参构造函数Student()    class1.newInstance();      }}class Student {  public Student() {    System.out.println("无参构造函数");  }}

输出:

无参构造函数

3.4 小结

这样,当某构造器满足公开无参时(默认无参构造器满足此条件),即可直接使用 “字节码对象.newInstance()” 创建对象,这为默认无参构造器的调用提供了快捷方式。

字节码对象是反射机制的基础,有了字节码对象,可以获取构造器,进而新建对象(实现了反射的基本要求,不使用new即可新建对象)。另外,提供一种附加方法,如果一个类中的构造器是外界可以直接访问,同时没有参数.,那么可以直接使用 “字节码对象.newInstance()” 创建对象,上面的附加代码中演示出来了。

四、使用字节码对象获取方法进而调用方法

4.1 从字节码对象到方法调用

构造器不过是一种特殊的函数方法罢了,字节码对象不仅可以调用构造方法,而且可以调用普通方法,本节演示字节码对象获取普通方法进而调用方法的过程

4.2 字节码对象获取方法并调用,无返回值,返回值为void

代码——字节码对象获取方法并调用,无返回值,返回值为void:

package mypackage获取方法void;import java.lang.reflect.Method;//public Method[] getMethods():获取包括自身和继承过来的所有的public方法//public Method[] getDeclaredMethods():获取自身类中所有的方法(不包括继承的,和访问权限无关)////public Method getMethod(String methodName,//                        Class>... parameterTypes):表示调用指定的一个公共的方法(包括继承的)//public Method getDeclaredMethod(String name,//                                Class>... parameterTypes):表示调用指定的一个本类中的方法(不包括继承的)public class Test {  public static void main(String[] args) throws Exception {    Class class1 = Student.class;    // 调用无参study()方法    Method method = class1.getMethod("study");    Object object = method.invoke(class1.newInstance()); // 无参构造参数,可以直接用字节码对象调用,不一定要用constructor构造器调用    method = class1.getMethod("study", String.class);    object = method.invoke(class1.newInstance(), "小明");    method = class1.getDeclaredMethod("learning", String.class, int.class);    method.setAccessible(true);    object = method.invoke(class1.newInstance(), "小明", 12);  }}class Student {  public void study() {    System.out.println("study");  }  public void study(String name) {    System.out.println("study name: " + name);  }  private void learning(String name, int age) {    System.out.println("learning  name: " + name + ",age: " + age);  }}

输出:

studystudy name: 小明learning  name: 小明,age: 12

小结:字节码对象获取方法的四个方法:

75efa58b4cf13a72d6e0a99ed7eaee64.png

调用方法的一个方法:method.invoke

和调用构造器类似,若调用private私有方法,则调用前需 method.setAccessible(true);

如上代码所示,灵活的使用上述方法,可以使用字节码对象方便的调用任意一个方法,而不是使用类对象,这正好符合反射的思维。

上面演示的方法均返回为void,如果返回为非void,情况如何,且看下面。

1、获取方法;2、方法调用

public Method[] getMethods():获取包括自身和继承过来的所有的public方法public Method[] getDeclaredMethods():获取自身类中所有的方法(不包括继承的,和访问权限无关)public Method getMethod(String methodName,Class>... parameterTypes):表示调用指定的一个公共的方法(包括继承的),方法签名=方法名+形参列表,所以获取方法就是传入方法名+形参列表,定位的唯一方法public Method getDeclaredMethod(String name, Class>... parameterTypes):表示调用指定的一个本类中的方法(不包括继承的)// 方法调用,就是调用方method确定唯一方法,然后传入方法参数,非静态方法第一个参数为对象实例,底层使用这个对象来调用方法// static静态方法属于类而不是对象,无对象实例,底层直接使用类名来调用方法,第一个参数为nullobject = method.invoke(class1.newInstance(), "小明", 12);    

object返回值就是方法的返回值。

一句话小结反射方法调用(重要,面试背下来):

1、方法定位:method = 字节码对象class1.getMethod() ,调用对象+参数+返回值

调用对象是字节码对象class1

方法签名=方法名+形参列表,所以获取方法就是传入方法名+形参列表,定位的唯一方法,good 懂了

返回值为method具体方法

2、方法调用:object=method.invoke(),method + 参数 + 返回值

调用方method确定唯一方法,

然后传入方法参数,非静态方法第一个参数为对象实例,底层使用这个对象来调用方法,static静态方法属于类而不是对象,无对象实例,底层直接使用类名来调用方法,第一个参数为null

object返回值就是方法的返回值。

4.3 字节码对象获取方法并调用,有返回值,返回值为String

代码——字节码对象获取方法并调用,有返回值,返回值为String:

package mypackage2获取方法调用方法String;import java.lang.reflect.Method;public class Test {  public static void main(String[] args) throws Exception {    Class class1 = Student.class;    // 调用无参study()方法    Method method = class1.getMethod("study");    Object object = method.invoke(class1.newInstance()); // 无参构造参数,可以直接用字节码对象调用,不一定要用constructor构造器调用    System.out.println(object);    method = class1.getMethod("study", String.class);    object = method.invoke(class1.newInstance(), "小明");    System.out.println(object);    method = class1.getDeclaredMethod("learning", String.class, int.class);    method.setAccessible(true);    object = method.invoke(class1.newInstance(), "小明", 12);    System.out.println(object);  }}class Student {  public String study() {    return "study";  }  public String study(String name) {    return "study name: " + name;  }  private String learning(String name, int age) {    return "learning  name: " + name + ",age: " + age;  }}

输出:

studystudy name: 小明learning  name: 小明,age: 12

小结:此段代码演示当调用的方法有返回值(这里以返回值为String为例)时,反射机制的处理情况,非常简单,只要打印调用方法后的结果即可。

上面演示的都是非static方法,如果是static方法,情况如何呢?且看下面.

4.4 字节码对象获取static方法并调用,无返回值,返回值为void

代码——字节码对象获取static方法并调用,无返回值,返回值为void:

package mypackage3反射调用静态方法void;import java.lang.reflect.Method;public class Test {  public static void main(String[] args) throws Exception{    Class  class1=Student.class;    //调用无参study()方法      Method method=class1.getMethod("study");      Object object=method.invoke(class1.newInstance());  //无参构造参数,可以直接用字节码对象调用,不一定要用constructor构造器调用      method.invoke(null);            method=class1.getMethod("study", String.class);      object=method.invoke(class1.newInstance(), "小明");      method.invoke(null,"小张");            method=class1.getDeclaredMethod("learning", String.class,int.class);      method.setAccessible(true);      object=method.invoke(class1.newInstance(), "小明",12);      method.invoke(null,"小张",20);  }}class Student{  public static void study(){    System.out.println("study");  }  public  static void study(String name){    System.out.println("study name: "+name);  }  private static void learning(String name,int age){    System.out.println("learning  name: "+name+",age: "+age);  }}

输出:

study name: 小张learning  name: 小明,age: 12learning  name: 小张,age: 20

小结:使用反射调用静态方法时,静态方法不属于任何对象,静态方法属于类本身. 所以此时把invoke方法的第一个参数设置为null即可.如果一定要第一个实参设为类对象,也是可以,使用class1.newInstance()。

理由:Java中非static方法只能用对象名调用,因为非static方法只有在对象存在时才有意义,而static方法属于类,可以用类名调用,可以用对象名调用。使用反射实现时,也遵循了同样的原则,非static方法第一个实参一定为class1.newInstance(),static方法第一个实参可以为class1.newInstance(),可以为null。

上面的static方法返回值为void,当返回值为非void,情况如何,且见下面。

4.5 字节码对象获取static方法并调用,有返回值,返回值为String

代码——字节码对象获取static方法并调用,有返回值,返回值为String:

package mypackage4反射调用静态方法String;import java.lang.reflect.Method;public class Test {  public static void main(String[] args) throws Exception {    Class class1 = Student.class;    // 调用无参study()方法    Method method = class1.getMethod("study");    Object object = method.invoke(class1.newInstance()); // 无参构造参数,可以直接用字节码对象调用,不一定要用constructor构造器调用    System.out.println(object);    object = method.invoke(null);    System.out.println(object);    method = class1.getMethod("study", String.class);    object = method.invoke(class1.newInstance(), "小明");    System.out.println(object);    object = method.invoke(null, "小张");    System.out.println(object);    method = class1.getDeclaredMethod("learning", String.class, int.class);    method.setAccessible(true);    object = method.invoke(class1.newInstance(), "小明", 12);    System.out.println(object);    object = method.invoke(null, "小张", 20);    System.out.println(object);  }}class Student {  public static String study() {    return "study";  }  public static String study(String name) {    return "study name: " + name;  }  private static String learning(String name, int age) {    return "learning  name: " + name + ",age: " + age;  }}

输出:

studystudystudy name: 小明study name: 小张learning  name: 小明,age: 12learning  name: 小张,age: 20

小结: 此段代码演示当调用的static方法有返回值(这里以返回值为String为例)时,反射机制的处理情况,非常简单,只要打印调用方法后的结果即可。

当函数参数为可变参数(数组)时,如何处理,且见下面代码.

4.6 演示参数列表为可变参数(数组)时的情况

代码——演示参数列表为可变参数(数组)时的情况:

package mypackage5反射调用数组参数;import java.lang.reflect.Method;import java.util.Arrays;public class Test {  public static void main(String[] args) throws Exception {    Class class1 = Student.class;    Method method = class1.getMethod("learning1", int[].class);    method.invoke(null, new Object[] { new int[] { 1, 2, 3, 4, 5 } });    method = class1.getMethod("learning2", String[].class);    method.invoke(null, new Object[] { new String[] { "A", "B", "C", "D", "E" } });    method = class1.getMethod("learning3", int[].class);    method.invoke(class1.newInstance(), new Object[] { new int[] { 1, 2, 3, 4, 5 } });    method = class1.getMethod("learning4", String[].class);    method.invoke(class1.newInstance(), new Object[] { new String[] { "A", "B", "C", "D", "E" } });    System.out.println("=============================="); // 加一行分割线,看得清楚一点    method = class1.getMethod("learning5", int[].class);    Object object = method.invoke(null, new Object[] { new int[] { 1, 2, 3, 4, 5 } });    System.out.println(object);    method = class1.getMethod("learning6", String[].class);    object = method.invoke(null, new Object[] { new String[] { "A", "B", "C", "D", "E" } });    System.out.println(object);    method = class1.getMethod("learning7", int[].class);    object = method.invoke(class1.newInstance(), new Object[] { new int[] { 1, 2, 3, 4, 5 } });    System.out.println(object);    method = class1.getMethod("learning8", String[].class);    object = method.invoke(class1.newInstance(), new Object[] { new String[] { "A", "B", "C", "D", "E" } });    System.out.println(object);  }}class Student {  // static int数组 void返回值  public static void learning1(int... array) {    System.out.println("learning1被调用, " + Arrays.toString(array));  }  // static String数组 void返回值  public static void learning2(String... array) {    System.out.println("learning2被调用, " + Arrays.toString(array));  }  // 非static int数组 void返回值  public void learning3(int... array) {    System.out.println("learning3被调用, " + Arrays.toString(array));  }  // 非static String数组 void返回值  public void learning4(String... array) {    System.out.println("learning4被调用, " + Arrays.toString(array));  }  // static int数组 String返回值  public static String learning5(int... array) {    return "learning5被调用, " + Arrays.toString(array);  }  // static String数组 String返回值  public static String learning6(String... array) {    return "learning6被调用, " + Arrays.toString(array);  }  // 非static int数组 String返回值  public String learning7(int... array) {    return "learning7被调用, " + Arrays.toString(array);  }  // 非static String数组 String返回值  public String learning8(String... array) {    return "learning8被调用, " + Arrays.toString(array);  }}

输出:

learning1被调用, [1, 2, 3, 4, 5]learning2被调用, [A, B, C, D, E]learning3被调用, [1, 2, 3, 4, 5]learning4被调用, [A, B, C, D, E]==============================learning5被调用, [1, 2, 3, 4, 5]learning6被调用, [A, B, C, D, E]learning7被调用, [1, 2, 3, 4, 5]learning8被调用, [A, B, C, D, E]

小结:此段代码演示参数列表为可变参数(数组)的时候的情况,基本涵盖了所有的数组参数的情况。

4.7 小结

字节码对象获取方法进而调用方法,通过代码1~代码5,演示了非static/static、返回值void/返回值非static、固定参数/可变参数列表的情况,通过上面的代码,字节码对象对方法的调用基本上实现所有类对象对方法的调用。

五、面试金手指

5.1 一句话小结反射方法调用(方法定位+方法调用)

1、方法定位:method = 字节码对象class1.getMethod() ,调用对象+参数+返回值

调用对象是字节码对象class1

方法签名=方法名+形参列表,所以获取方法就是传入方法名+形参列表,定位的唯一方法,good 懂了

返回值为method具体方法

2、方法调用:object=method.invoke(),method + 参数 + 返回值

调用方method确定唯一方法,

然后传入方法参数,非静态方法第一个参数为对象实例,底层使用这个对象来调用方法,static静态方法属于类而不是对象,无对象实例,底层直接使用类名来调用方法,第一个参数为null

object返回值就是方法的返回值。

5.2 反射可以修改final变量的值吗?

分两种情况:

1、当final修饰的成员变量在定义的时候就初始化了值,那么java反射机制就已经不能动态修改它的值了。

2、当final修饰的成员变量在定义的时候并没有初始化值的话,在构造函数中初始化,即空白final,那么就还能通过java反射机制来动态修改它的值。

六、尾声

高级语言反射机制在框架设计广泛运用,本文浅析Java反射机制,从获取字节码对象,到构造方法获取与调用,普通方法获取与调用,希望可以在读者学习Java过程中略尽绵薄之力。

天天打码,天天进步!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值