10.反射
反射就是通过操作字节码文件来做两件事
- 创建对象
- 调用方法
对比硬编码效率会低一些,但是代码的灵活性大大提升
10.1 Class类 和 Class对象
运行Java程序,就是解析并且执行字节码文件,而字节码加载到JVM时,Java就会使用面向对象的思想把加载过来的字节码文件(class)封装成对象
问题是这个字节码文件在Java中是谁的对象?
例如:
对象--> “123”,“aaa”,“hello”
能描述以上对象的类型在Java中是String类型,所以以上是String的对象
对象--> 123,100,200
能描述以上对象的类型在Java中是Integer类型,所以以上是Integer的对象
在Java中万物皆对象,也就是说String和Integer也是对象,那他们到底是谁的对象呢?
对象--> String,Integer
能描述以上两种对象的类型是什么呢?
Class类是描述如String.class Integer.class等对象的类
Java中所有的类型都是Class的对象
类型相同, 它们的字节码对象也都是相同的
10.2 反射创建对象
-
获取Class对象
直接使用类名.class获取字节码文件对象
-
使用对象的方法getClass()获取到对象的字节码文件对象
这个方法是来自Object类
-
使用Class类的静态方法forName(全限定名);
static Class<?> forName(String className) 通过类的全限定名获取Class对象
-
无参构造创建对象
//1.获取类的字节码对象 Class<?> clazz = Class.forName("com.example.mu.myapplication.TestCl"); //创建无参构造的对象 TestCl instance = (TestCl) clazz.newInstance();
-
构造器创建对象
如果字节码对象不包含无参构造,你就要通过获取里面的构造器再通过操作构造器来创建对象
-
获取字节码对象中的构造器
-
获取public修饰的构造器
Constructor<T> getConstructor(Class... parameterTypes) 返回一个构造器,parameterTypes为构造器参数的类型 Constructor<?>[] getConstructors() 获得构造器对象的数组
-
获取任意的构造器,包括私有的
Constructor<T> getDeclaredConstructor(Class... parameterTypes) Constructor<?>[] getDeclaredConstructors()
-
-
用构造器创建对象
T newInstance(Object... initargs) Constructor的创建对象方法
-
示例代码
Constructor<?> con= clazz.getConstructor(String.class); Object obj = con.newInstance("一个参数"); //这里的参数是对应构造器的参数 //无参构造 con = clazz.getConstructor(null); Object o2 = con.newInstance(null); //私有构造器 con = clazz.getDeclaredConstructor(String.class); con.setAccessible(true);//私有的构造器需要设置访问权限,暴力反射 con.newInstance("暴力反射");
-
-
方法对象
-
获取字节码对象中的方法对象
-
获取public修饰的方法,包括从父类继承的方法
Method getMethod(String name, Class... parameterTypes) 获取指定的公共方法对象 name:方法名 parameterTypes:方法参数的类型 Method[] getMethods() 返回所有公共的方法对象的数组
-
获取所有访问权限的方法,包括私有的,但不包括从父类继承的方法
Method getDeclaredMethod(String name, Class... parameterTypes) Method[] getDeclaredMethods()
-
-
Method对象调用方法
Object invoke(Object obj, Object... var2) obj:调用该方法的对象 var2:该方法的实参
-
示例代码
lass<?> clazz = Class.forName("com.example.mu.myapplication.TestCl"); TestCl instance = (TestCl) clazz.newInstance(); //调用对象方法 Method m1 = clazz.getMethod("setName", String.class); m1.invoke(instance,"我是谁"); //不强制对象,调用对象的特有方法 String s = "123"; Method m2 = String.class.getMethod("length", null); Object o = m2.invoke(s, null);//invoke的返回值就是调用方法后的返回值 //调用私有的方法 Method work = clazz.getDeclaredMethod("work", null); work.setAccessible(true); work.invoke(instance,null); //调用静态方法 Method m3 = clazz.getDeclaredMethod("lvup", null); //静态方法不需要对象来调用,因此传null m3.invoke(null,null);
-
-
字段对象
-
获取Class对象中的Field对象
-
获取public修饰的字段
Field getField(String name) name:字段名 Field[] getFields() 返回包含所有公共字段的数组
-
获取所有访问权限的字段
Field getDeclaredField(String name) Field[] getDeclaredFields()
-
-
Field对象,设置字段值和获取字段值
Object get(Object obj) 获取指定对象上的此字段的值 void set(Object obj, Object value) 将指定对象上的此字段设置为指定值
-
示例代码
lass<?> clazz = Class.forName("com.example.mu.myapplication.TestCl"); TestCl instance = (TestCl) clazz.newInstance(); Field name = clazz.getField("name"); name.set(instance,"新名字");//设置值 name.get(instance);//获取值
-
-
其他
int getModifiers() 获取修饰符
Class对象,Method,Field都有的方法
int modifiers = name.getModifiers(); //将修饰符编码转出字符串 System.out.println(Modifier.toString(modifiers));