反射的基本概念
Java程序中,所有的对象都有两种类型:编译时类型和运行时类型,而很多时候对象的编译时类型和运行时类型不一致。
例如:某些变量或形参的类型是Object类型,但是程序却需要调用该对象运行时类型的方法,该方法不是Object中的方法,那么如何解决呢?
为了解决这些问题,程序需要在运行时发现对象和类的真实信息,现在有两种方案:
- 方案1:在编译和运行时都完全知道类型的具体信息,在这种情况下,我们可以直接先使用instanceof运算符进行判断,再利用强制类型转换符将其转换成运行时类型的变量即可。
- 方案2:编译时根本无法预知该对象和类的真实信息,程序只能依靠运行时信息来发现该对象和类的真实信息,这就必须使用反射。
因为加载完类之后,就产生了一个Class类型的对象,并将引用存储到方法区,那么每一个类在方法区内存都可以找到唯一Class对象与之对应,这个对象包含了完整的类的结构信息,我们可以通过这个对象获取类的结构。这种机制就像一面镜子,Class对象像是类在镜子中的镜像,通过观察这个镜像就可以知道类的结构,所以,把这种机制形象地称为反射机制。
- 非反射:类(原物)—>类信息
- 反射:Class对象(镜像)—>类(原物)
获取类类对象的四种方法
要想解剖一个类,必须先要获取到该类的Class对象。而剖析一个类或用反射解决具体的问题就是使用相关API(1)java.lang.Class(2)java.lang.reflect.*。所以,Class对象是反射的根源。
获取类类对象的四种方法:
- 使用类名获取该类的类类对象
- 使用类对象获取该类的所属的类类对象
- 使用字符串类获取类类对象
- 使用类加载器获取类类对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.tipdm.demo8;
public class demo01 { public static void main(String[] args) { Class classone = Student.class; System.out.println(classone.getName());
Student student = new Student(); Class classtwo = student.getClass();
try { Class classThree = Class.forName("com.tipdm.demo8.Student"); } catch (ClassNotFoundException e) { e.printStackTrace(); }
try { Class classFore = Student.class.getClassLoader().loadClass("com.tipdm.demo8.Student"); } catch (ClassNotFoundException e) { e.printStackTrace(); }
System.out.println(classone == classtwo); } }
|
1 2 3 4
| com.tipdm.demo8.Student true
进程已结束,退出代码0
|
注意:一个类的类类对象在方法区中只会有一个对象。
类类对象的常用方法
Class类的常用方法
定用代码Class classOne = Student.class;
定义好一个类类对象后,其有以下方法可以调用。
方法 |
意义 |
getName() |
获取类的完整类名 |
getSimpleName() |
获取类的简单类名 |
getPackage() |
获取类的包对象 |
getSuperclass() |
获取父类的类 |
getFields() |
返回类中所有public 修饰的属性,不仅限本类,包含从父类继承到的属性 |
getDeclaredFields() |
返回所有修饰符修饰的属性,仅限本类 |
getField("two") |
根据参数属性名获取单个属性,仅能获取public修饰的属性,不仅限本类,包含从父类继承到的属性 |
getDeclaredField("one") |
根据参数属性名获取单个属性,可以获取所有修饰符修饰的属性,仅限本类 |
getMethods() |
获取所有public 修饰的方法,不仅限本类,包含从父类继承到的 |
getDeclaredMethods() |
获取所有修饰符修饰的方法,仅限本类 |
getMethod("methodOne") |
根据参数方法名获取单个的public 修饰的方法,不仅限本类,包含从父类继承到的方法 |
getDeclaredMethod
("sayHello",String.class,int.class) |
获取单个方法,无参方法只写方法名,有参方法除了方法名还需要写出参数组 |
getConstructors() |
获取所有public 修饰的构造器 |
getDeclaredConstructors() |
获取所有修饰符修饰的构造器 |
getConstructor() |
根据参数列表获取public 修饰的构造器 |
getDeclaredConstructor
(String.class,int.class,String.class) |
根据参数列表获取所有修饰符修饰的构造器 |
Field类的常用方法
方法 |
意义 |
getName() |
获取属性名 |
getType() |
获取属性类型 |
getModifiers() |
获取属性的修饰符(返回为int ,可以使用Modifier 中的toString 将其对应为具体的修饰符) |
set(obj, 'Tom') |
给obj对象传参(静态属性可以省略obj,设置为null ) |
get(obj) |
获取obj 对象的属性 |
代码验证:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package com.tipdm.demo8;
import java.lang.reflect.Field; import java.lang.reflect.Modifier;
public class demo02 { public static void main(String[] args) { Class classOne = Student.class;
System.out.println(classOne.getName()); System.out.println(classOne.getSimpleName()); System.out.println(classOne.getPackage()); System.out.println(classOne.getSuperclass().getName()); Field[] fields = classOne.getFields(); System.out.println(fields.length); System.out.println("-------------------------------------"); for (Field field : fields) { System.out.println(field.getModifiers()); System.out.println(field.getName()); } System.out.println("-----------------------------------"); Field[] fields1 = classOne.getDeclaredFields(); for (Field field : fields1) { System.out.println(field.getModifiers()); String modStr = Modifier.toString(field.getModifiers()); System.out.println(modStr); System.out.println(field.getType().getSimpleName()); System.out.println(field.getName()); } System.out.println("-----------------------------------"); try { Field field = classOne.getField("two"); System.out.println(field); } catch (NoSuchFieldException e) { e.printStackTrace(); } try { Field field = classOne.getDeclaredField("one"); System.out.println(field); } catch (NoSuchFieldException e) { e.printStackTrace(); } } }
|
Method方法的常用方法
方法 |
意义 |
getName() |
获取方法名 |
getSimpleName() |
获取简单的方法名 |
getModifiers() |
获取所有方法的修饰符(返回为int ,可以使用Modifier 中的toString 将其对应为具体的修饰符) |
getParameterTypes() |
获取所有参数类型 |
getReturnType() |
获取方法的返回值类型 |
invoke(obj, "xxxx") |
运行obj 对象的某个方法(如果是静态方法可以省略对象) |
代码验证:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.tipdm.demo8; import java.lang.reflect.Method; import java.lang.reflect.Modifier;
public class demo03 { public static void main(String[] args) { Class classOne = Student.class;
Method[] methods = classOne.getMethods(); for (Method method : methods) { String str = Modifier.toString(method.getModifiers()); System.out.println(str); System.out.println(method.getReturnType().getSimpleName()); System.out.println(method.getName()); Class[] classes = method.getParameterTypes(); for (Class aClass : classes) { System.out.print(aClass.getSimpleName()+" "); } System.out.println(); } System.out.println("---------------------------------------------"); Method[] methods1 = classOne.getDeclaredMethods(); for (Method method : methods1) { System.out.println(method.getName()); } System.out.println("---------------------------------------------"); try { Method method = classOne.getMethod("methodOne"); System.out.println(method); } catch (NoSuchMethodException e) { e.printStackTrace(); }
try { Method method = classOne.getDeclaredMethod("sayHello",String.class,int.class); System.out.println(method); } catch (NoSuchMethodException e) { e.printStackTrace(); } } }
|
构造器
其他内容都有getName
方法去获取相应名称,但是构造器没有,因为构造器的名称与本类一致。
并且构造方法无法从父类继承,所以在获取构造器时只能获取本类的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.tipdm.demo8;
import java.lang.reflect.Constructor;
public class demo04 { public static void main(String[] args) { Class classOne = Student.class;
Constructor[] cs1 = classOne.getConstructors(); System.out.println(cs1.length); Constructor[] cs2 = classOne.getDeclaredConstructors(); System.out.println(cs2.length); try { Constructor c1 = classOne.getConstructor(); } catch (NoSuchMethodException e) { e.printStackTrace(); } try { Constructor c2 = classOne.getDeclaredConstructor(String.class,int.class,String.class); } catch (NoSuchMethodException e) { e.printStackTrace(); } } }
|
应用
利用反射的方式访问类中的属性和方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package com.atguigu.test1;
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method;
public class TestFive { public static void main(String[] args) { try { Class classOne = Student.class; Object obj = classOne.newInstance(); System.out.println(obj); Field field = classOne.getDeclaredField("stuName"); field.setAccessible(true); field.set(obj,"Tom"); System.out.println(field.get(obj)); Field field1 = classOne.getDeclaredField("school"); field1.set(null,"minglog123"); System.out.println(field1.get(obj)); Method method = classOne.getDeclaredMethod("setStuName", String.class); method.invoke(obj,"Jerry"); Method method1 = classOne.getDeclaredMethod("getStuName"); System.out.println(method1.invoke(obj)); Method method2 = classOne.getDeclaredMethod("methodThree"); method2.invoke(null); }catch (Exception ex){ ex.printStackTrace(); } } }
|