反射概念
反射是框架的灵魂。
反射:将类的各个组成部分封装成为其他对象,就是反射机制。
下图是java从写到运行进过的阶段,第一个阶段当你写完后就会自动编译,然后通过类加载器变为类对象(java里面一起皆是对象)。
第二阶段是将字节码文件加载到内存中,内存Class类是用来描述字节码文件的类。
所以我们可以通过Class里面的方法直接来创建对象和调用类的方法而不用new对象。
反射可以在程序的运行中操作对象。
获取Class对象的方式(字节码对象)
-
Class.forName()方式
Class.forName(“全类名”)将字节码文件加载进内存,返回类对象。(因为此时还还字节码未加载入内存生成类对象)。
多用于配置文件,将类名定义在配置文件中,读取文件,加载类。 -
类名.class
通过类名的属性进行获取。
多用于参数的传递 -
对象.getClass()
因为这个.getClass()是封装在Object类里面的,而我们知道所有的类的都继承自Object。
多用于对象的字节码获取方式。
public class Reflect_Demo1 {
public static void main(String[] args) throws Exception {
//方式1Class的静态方法forName
Class clas1 = Class.forName("reflect.Person");
System.out.println(clas1);
//方式2类名.class
Class clas2 = Person.class;
System.out.println(clas2);
//方式3对象.
Person person=new Person();
Class clas3 = person.getClass();
System.out.println(clas3);
//判断三个获取的class对象
System.out.println(clas1==clas2);
System.out.println(clas2==clas3);
}
}
结论:同一个.class生成的class对象是同一个对象,在一次程序的加载中只会被加载一次,不论通过哪一种方式获取的class对象都是同一个。*
Class对象用处
从我们文章开始那张图中就可以得到答案
- 1:获取成员方法们 Method[] getDeclaredMethods() 、Method[] getMethods()
- 2:获取构造方法们 Constructor<?>[] getConstructors() 、Constructor<?>[] getDeclaredConstructors() 、Constructor getConstructor(类<?>… parameterTypes)
- 3:获取成员变量们 Field[] getFields() 、Field[] getDeclaredFields() 、Field getDeclaredField(String name) 、Field getField(String name)
- 4:获取类名 String getName()
- 5:获取包名 软件包 getPackage()
上面那些都是对应的带Declared可以获取所有,不带Declared只能获取public修饰的。
public static void main(String[] args) {
Class<Person> personClass = Person.class;
Field[] fields = personClass.getFields();
for (Field field: fields ) {
System.out.println(field);
}
}
**这里这个getFields只能获取public修饰的成员变量。**其他还有别的方法属性请大家到Class类中查看。
获取到成员变量
获取到成员变量、成员方法、、、后可以用来干嘛?
- 获取到成员变量
可以设置和获取成员变量的值
具体方法到Filed类中查看。
Object get(Object obj)
返回该所表示的字段的值 Field ,指定的对象上。
这里参数是你需要的到成员变量所属的对象。
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Class<Person> personClass = Person.class;
Field name = personClass.getField("name");
Person person=new Person();
//得到person的name,因为String默认值为null
Object value = name.get(person);
System.out.println(value);
//设置person对象的name
name.set(person,"张三");
System.out.println(person.name);
}
对于加了Declared的personClass.getDeclaredFields()方法这种是得到所有的成员变量(包括私有,保护),但是当要设置和得到时候那就要用暴力反射,忽略访问权限修饰符的安全检查。
Field age = personClass.getDeclaredField("id");
age.setAccessible(true);//暴力反射,这样可以设计和得到私有成员
age.set(person,10);
System.out.println(person.getId());
获取到构造方法
获取构造方法们 Constructor<?>[] getConstructors() 、Constructor<?>[] getDeclaredConstructors()
构造Constructor是用来创建对象的。
Class<Person> personClass = Person.class;
Constructor<Person> constructor = personClass.getConstructor(String.class,int.class);
Person person = constructor.newInstance("张三", 10);
System.out.println(person);
上面那个方法也可以用空参构造方法创建对象,但是当需要使用空参构造方法时Class类里面的new会更加便捷。
Class<Person> personClass = Person.class;
Constructor<Person> constructor = personClass.getConstructor();
Person person1 = constructor.newInstance();
System.out.println(person1);
Person person2 = personClass.newInstance();
System.out.println(person2);
Constructor constructor = personClass.getConstructor();注意这行代码getConstructor()你要创建用无参数的构造方法创建对象那个这个getConstructor()也要无参数。
构造器方法里面也有暴力反射,有setAccesss方法,当需要用到带Declared的方法时可以用到,这里和上面获取成员变量用法相同,大家可以自行查阅。
获取成员方法
用来的到Method对象执行成员方法。这里通过方法名和参数类型.class来确定是类中的哪个函数,然后确定是哪个对象的函数。
Person person=new Person();
Class<Person> personClass = Person.class;
//无餐eat
Method eat = personClass.getMethod("eat");
eat.invoke(person);
//有餐eat
Method eatapple = personClass.getMethod("eat", String.class);
eatapple.invoke(person,"apple");
Person类中的l两个eat方法
public void eat(String foodname){
System.out.println("吃"+foodname);
}
public void eat(){
System.out.println("吃");
}
案例-反射的运用
案例需求:写一个类,可以帮我们创建任意类的对象,并且执行任意的方法。
package reflect;
public class student {
public void sleep(){
System.out.println("睡觉");
}
}
package reflect;
public class ReflectMain {
public static void main(String[] args) throws Exception {
Object getobject = ReflectTest.setObject("reflect.student");
ReflectTest.getMethod("reflect.student","sleep",getobject);
}
}
public class ReflectTest {
//创建指定类对象
static public Object setObject(String classallname) throws Exception {
Class<?> makeClass = Class.forName(classallname);
Constructor<?> constructor = makeClass.getConstructor();
Object newobject = makeClass.newInstance();
return newobject;
}
//调用指定类的方法
static public void getMethod(String classallname,String methodname,Object object) throws Exception {
Class<?> makeClass = Class.forName(classallname);
Method method = makeClass.getMethod(methodname);
method.invoke(object);
}
}