Java反射
在学习这种语言基础时,一定要要动手去写一些demo,不要只停留在看的层面
所以我写这篇博客的主要目的就是想要更直观的去了解Java反射,比较适合新手小白入门
正射
反射之中包含了一个「反」字,所以想要解释反射就必须先从「正」开始解释。
正射就是在编写代码时当需要使用到某一个类的时候,我们要先了解这个类是做什么的,然后实例化这个类,接着用实例化好的对象进行操作。
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
| public class Person { public String name; private int age;
public Person(){
}
public Person(String name,int age){ this.name=name; this.age=age; }
public void action(String act){ System.out.println(act); }
public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }
public static void main(String[] args) throws Exception{ Person person = new Person("abc",22); System.out.println("Name: " + person.name); System.out.println(person); } }
|
反射
而反射则是一开始并不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象了。
总结为四个步骤
1.操作Class
2.从原型class里面实例化对象
3.获取类里面属性
4.调用类里面方法
操作Class
加载类,返回Class类型的对象
讲反射的第一个就先了解一下getClass

这个是Object里面的一个final方法,会返回一个大Class类型
可以看一下大Class类里面有什么东西
forname
1 2 3 4 5
| public static Class<?> forName(String className) throws ClassNotFoundException { Class<?> caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }
|
返回的也是一个泛型的Class,就是你把它的名字传进去,就会返回对应的原型类
1
| Class c = Class.forName("Person");
|
实例化对象
newInstance
1 2 3 4 5 6
| public T newInstance() throws InstantiationException, IllegalAccessException { if (System.getSecurityManager() != null) { checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false); }
|
一个无参的方法
getConstructor
1 2 3 4 5
| public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException { checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); return getConstructor0(parameterTypes, Member.PUBLIC); }
|
可以接收参数
1
| Constructor personConstructor = c.getConstructor(String.class, int.class);
|
然后我们再实例化
1 2 3 4 5 6 7
| public static void main(String[] args) throws Exception{ Class c = Class.forName("Person"); Constructor personConstructor = c.getConstructor(String.class, int.class); Person p = (Person) personConstructor.newInstance("abc", 22); System.out.println(p); }
|
获取类里面属性
getFields
它的参数类型是一个数组,我们来打印看一下返回什么
1 2 3 4
| Field[] personfields = c.getFields(); for (Field f:personfields){ System.out.println(f); }
|
返回了
public java.lang.String Person.name
也就是string类型的name,但是要知道我们一开始写的demo里面还有一个age,age并没有打印出来,即这个只可以返回public类型的参数
getDeclaredFields
那么我们就用这个看能否把private的age返回,直接进行修改
public java.lang.String Person.name private int Person.age
ok,成功返回了私有属性的参数
也就是说Declared会把所有的变量都打印出来
getField
我们用这个进行属性值的更改
1 2
| Field namefield = c.getField("name"); namefield.set(p,"aaaaaaaaaa");
|

同理,这个也只是可以修改公有属性的值
getDeclaredField
如果我们直接把它改成这个运行会报access的问题
于是我们需要加上一行赋予权限
namefield.setAccessible(true);

调用类里面的方法
getMethods
1 2 3 4
| Method[] personmethods = c.getMethods(); for (Method f:personmethods){ System.out.println(f); }
|

大部分都是继承的方法,但是也可以看到有我定义的action方法
getMethod
接收一个函数名和一个类的泛型
用这个来调用我们的方法
跟getField类似,但这里不适用set而是用invoke
1 2
| Method actionmethod = c.getMethod("action", String.class); actionmethod.invoke(p,"sdfghhj");
|
getDeclaredMethod
与getDeclaredField一样
总结
反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。