天天看点

java反射调用成员变量的方法_java中的反射机制,以及如何通过反射获取一个类的构造方法 ,成员变量,方法,详细。。...

首先先说一下类的加载,流程。只有明确了类这个对象的存在才可以更好的理解反射的原因,以及反射的机制。

一、  类的加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

加载

就是指将class文件读入内存,并为之创建一个Class对象--->  而这个对象就是我们反射中将要使用的对象。

任何类被使用时系统都会建立一个Class对象。

连接

验证  是否有正确的内部结构,并和其他类协调一致;

准备  负责为类的静态成员分配内存,并设置默认初始化值;

解析  将类的二进制数据中的符号引用替换为直接引用。

初始化 就是常规的一个类的的初始化步骤,有静态先静态。。。。忘记的自己回去看~

二、类初始化时机

·创建类的实例

·访问类的静态变量,或者为静态变量赋值

·调用类的静态方法

·使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

·初始化某个类的子类

·直接使用java.exe命令来运行某个主类

三.类加载器

l  类加载器

负责将.class文件加载到内在中,并为之生成对应的Class对象。

虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。

l  类加载器的组成

Bootstrap ClassLoader 根类加载器

Extension ClassLoader 扩展类加载器

Sysetm ClassLoader 系统类加载器

四、类加载器的作用

1. Bootstrap ClassLoader 根类加载器

也被称为引导类加载器,负责Java核心类的加载

比如System,String等。在JDK中JRE的lib目录下rt.jar文件中

2.Extension ClassLoader 扩展类加载器

负责JRE的扩展目录中jar包的加载。

在JDK中JRE的lib目录下ext目录

3. Sysetm ClassLoader 系统类加载器  (我们自己定义的类一般在这里)

负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径

//------------------------------------------------代码的分割线

//下面首先介绍的是第一步如何通过Class的方法来获取指定类的class对象,没有该对象就无从反射谈起

1

20 public classReflectDemo {21 public static void main(String[] args) throwsClassNotFoundException {22 //方式1

23 Person p = newPerson();24 Class c =p.getClass();25

26 Person p2 = newPerson();27 Class c2 =p.getClass();28

29 System.out.println(p ==p2);30 System.out.println(c ==c2);31

32 //方式2

33 Class c3 = Person.class;34

35 //方式336 //反射机制.Person 这里很容易出错,我自己写的时候就经常不小心写错。写错了还不好检查。

37

42 Class c4 = Class.forName("反射机制.Person");43 System.out.println(c ==c4);44

45 }46 }

//---------------------------------------------------------

//下面给出上面再main方法中使用的person类,相当简单的一个类

//在后面会陆续使用该类,进行构造方法,字段,以及成员方法的调用,后面就不再给出该类,该类一直代表person

1 public classPerson {2 privateString name;3 intage;4 publicString address;5

6 publicPerson() {7 }8

9 privatePerson(String name) {10 this.name =name;11 }12

13 Person(String name, intage) {14 this.name =name;15 this.age =age;16 }17

18 public Person(String name, intage, String address) {19 this.name =name;20 this.age =age;21 this.address =address;22 }23

24 public voidshow() {25 System.out.println("show");26 }27

28 public voidmethod(String s) {29 System.out.println("method " +s);30 }31

32 public String getString(String s, inti) {33 return s + "---" +i;34 }35

36 private voidfunction() {37 System.out.println("function");38 }39

40 @Override41 publicString toString() {42 return "Person [name=" + name + ", age=" + age + ", address=" +address43 + "]";44 }45 }

//---------------------------------------------

//通过反射获取一个类的构造方法并进行使用。包括如何访问Person类的公共无参构造方法,公共有参构造方法,以及私有带参构造

1 importjava.lang.reflect.Constructor;2 importjava.lang.reflect.InvocationTargetException;3

4

7 public classReflectDemo {8 public static void main(String[] args) throwsException {9 //获取字节码文件对象,此处仍然是上面的person类.

10 Class c = Class.forName("反射机制.Person");11

12 //获取构造方法13 //public Constructor [] getConstructors() => 公共构造方法所有的14 //public Constructor [] getDeclaredConstructors() => 所有的构造方法 ,一旦添加Declared单词修饰获取一般是全部的声明包括自有private,protected。15

16 //Constructor[] cons = c.getConstructors();

17 Constructor[] cons = c.getDeclaredConstructors(); //这种方法虽然获取到了所有的构造方法,但是没什么作用,因此需要使用下面的方法获取单个的构造方法

18 for(Constructor con : cons) {19 System.out.println(con);20 }21

22 //获取单个构造方法,23 //public Constructor getConstructor(Class>... parameterTypes)24 //该方法的参数表示的是:你要获取的构造方法的构造参数的个数以及class字节码文件对象

25

26 Constructor con =c.getConstructor();27

28 //使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。29 //public T newInstance(Object... initargs)

30

31 Object obj = con.newInstance(); //此处创建的是Person类的对象实例,//此处创建的是Person类的对象实例,由于是无参构造因此不需要参数。

32 System.out.println(obj); //Person [name=null, age=0, address=null]

33

36 //获取指定参数的构造函数37 //public Constructor getConstructor(Class>... parameterTypes)

38

41 Constructor con2 =c.getConstructor(String.class, int.class,42 String.class);43

44 //通过构造方法创建对象45 //ublic T newInstance(Object... initargs)

46 Object obj2 = con.newInstance("java", 22, "武汉");47 System.out.println(obj2);48 //----------------------------------49 //通过反射获取私有构造方法并使用。50 //获取私有构造器 ---> getDeclaredConstructor51 //如果直接使用getConstructor则会导致没有该方法的异常NoSuchMethodException

52 Constructor con3 = c.getDeclaredConstructor(String.class);53

54 //私有方法直接访问:--->报错IllegalAccessException非法访问异常

55

60

61 con3.setAccessible(true); //值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查

62 Object obj3 = con.newInstance("android");63 System.out.println(obj3);64

65 }66 }

//-------------------------------------------------

//下面的代码是如何通过反射获取一个类的公有成员变量私有成员变量,并进行赋值显示

1 importjava.lang.reflect.Constructor;2 importjava.lang.reflect.Field;3

4

7 public classReflectDemo {8 public static void main(String[] args) throwsException {9 //获取字节码文件class对象

10 Class c = Class.forName("反射机制.Person");11

12 //获取所有的成员变量,13 //Field[] fields = c.getFields(); 获取所有的公共成员变量,放在数组中不易操作。14 //Field[] fields = c.getDeclaredFields(); 获取所有成员变量,放在数组中不易操作。15

16 //通过无参构造方法获取对象,有了对象才好对成员变量进行赋值,即使在反射中成员变量仍然是属于对象的。

17 Constructor con =c.getConstructor();18 Object obj =con.newInstance();19 //System.out.println(obj);20

21 //获取单个的成员变量,指定成员变量的名字---address

22 Field addressField = c.getField("address");23

24 //对于成员变量,一般是通过对象 : obj.address = "777"进行赋值,25 //public void set(Object obj, Object value)26 //上面方法的意思是将指定对象变量obj上此 Field 对象addressField表示的字段设置为指定的新值value 。

27

28 addressField.set(obj, "java"); //给obj对象的addressField字段设置值为value:java,这个地方很拗口,与java基本思路背道而驰。

29 System.out.println(obj);30

31 //获取name并对其赋值,name是私有成员变量。

32 Field nameField = c.getDeclaredField("name");33 //IllegalAccessException,暴力访问

34 nameField.setAccessible(true);35 nameField.set(obj, "android");36 System.out.println(obj);37

38 //获取age并对其赋值,age是私有成员变量。

39 Field ageField = c.getDeclaredField("age");40 ageField.setAccessible(true);41 ageField.set(obj, 25);42 System.out.println(obj);43

44 }45 }

//-------------------------------------------

// 获取类中的所有方法,公共方法,私有方法。并进行使用。

1 importjava.lang.reflect.Constructor;2 importjava.lang.reflect.Method;3

4

7 public classReflectDemo {8 public static void main(String[] args) throwsException {9

10 //获取字节码class对象

11 Class c = Class.forName("反射机制.Person");12

13 //获取所有方法14 //Method[] methods = c.getMethods();//该方法获取获取本身的以及父亲的所有公共方法,此处无意义。

15 Method[] methods5 = c.getDeclaredMethods(); //获取自己的所有方法,加入了Declared,在实际使用中可以不管你需要的东西的公共还是私有直接使用Declared修饰的方法16 //for (Method method : methods) {17 //System.out.println(method);18 //}19

20 //获取对象,由于其它构造麻烦一些,在获取对象时一律使用无参构造。

21 Constructor con =c.getConstructor();22 Object obj =con.newInstance();23

24 //获取单个的指定方法25 //public Method getMethod(String name, Class>... parameterTypes)26 //第一个参数表示的是方法名,第二个参数表示的方法的参数class类型。

27      // show方法是公共,无形参的方法public void show() { }

28 Method method1 = c.getDeclaredMethod("show");29 //public Object invoke(Object obj, Object... args)30 // 返回值是object接受,第一个参数表示对象是谁,第二个参数表示调用该方法的实际参数(形参)。

31 // 没有返回值就不写,

32 method1.invoke(obj); //调用obj对象的mehod1方法,33

34 //带一个参数方法无返回值的方法调用, public void method(String s){}

35 Method method2 = c.getMethod("method", String.class);36 method2.invoke(obj, "java");37

38 //带两个形参,有返回值的方法的调用public void method(String s),

39 Method method3 = c.getMethod("getString", String.class,40 int.class);41 Object objStr = method3.invoke(obj, "java", 50);42 System.out.println("Method3" +objStr);43

44 //私有方法

45 Method method4 = c.getDeclaredMethod("function");46 method4.setAccessible(true); //暴力访问47 method4.invoke(obj);48

49 }50 }