Java反射学习积累
什么是反射
Java反射机制是在运行状态中,对于任何一个类,都能够知道这个类的所有属性和方法;
对于任何一个对象,都能够调用它的任何一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
怎么使用反射
对于这样一个类
interface Fruit{
public void squeeze();
}
class Apple implements Fruit{
public void squeeze() {
System.out.println("榨出苹果汁");
}
}
class Orange implements Fruit{
public void squeeze() {
System.out.println("榨出橘子汁");
}
}
...
class Juicer{
public void run(Fruit f) {
f.squeeze();
}
可以看到,为了“喝到不同的果汁”,我们就需要使用多态完成。即run()方法的参数Fruit f = new Apple();
public static void main(String[] args){
//没有反射,只有多态
Juicer j = new Juicer();
j.run(new Apple());
j.run(new Orange());
}
但是这样的代码不易维护,一旦需求不同,就需要在源码上修改。
public static void main(String[] args){
BufferedReader br = new BufferedReader(new
FileReader("27.config.properties"));//关联配置文件
Class clazz = Class.forName(br.readLine());//读取到配置信息(类名)
Fruit f = (Fruit) clazz.newInstance();//获得实例
Juicer j = new Juicer();
j.run(f);
}
配置文件内容
com.heima.day27.reflect.Apple
这样当我们需要修改时,只需要修改配置文件内容就可以,而不需要改动源码。
我们刚才已经使用了newInstance()方法来创建对象,但这个方法是使用该类的无参构造器创建对象,如果一个类没有无参构造,就不能这样创建。
解决方法:使用Class类的getConstructor
public class Demo3 {
public int age;
private String name;
public Demo3(int age) {
super();
this.age = age;
System.out.println(age);
}
public void eat() {
System.out.println("今天我好饿");
}
@Override
public String toString() {
return "Demo3 [age=" + age + ", name=" + name + "]";
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
Class clazz = Class.forName("com.heima.day27.reflect.Demo3");
/* Demo3 d = (Demo3) clazz.newInstance(); *///有参构造无法创建对象
Constructor c = clazz.getConstructor(int.class);//获取有参构造
Demo3 d = (Demo3) c.newInstance(5);//通过有参构造创建对象
}
}
- Class.getField(String)方法可以获取类中的指定字段(可见的)
- 如果是私有属性可以用getDeclaedField(“name”)方法获取
- 通过set(obj, “李四”)方法可以设置指定对象上该字段的值
- 私有属性还需要使用setAccessi(true)设置访问权限
public class Demo4 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException {
Class clazz = Class.forName("com.heima.day27.reflect.Demo3");
Constructor c = clazz.getConstructor(int.class);//获取有参构造
Demo3 d = (Demo3) c.newInstance(5);//通过有参构造创建对象
Field f1 = clazz.getField("age");
/* Field f2 = clazz.getField("name"); *///私有属性无法找到
Field f2 = clazz.getDeclaredField("name");//暴力反射获取字段
f2.setAccessible(true);//去除私有权限
f1.set(d, 12);
f2.set(d, "张三");
System.out.println(d);
}
}
与获取属性相似,我们可以使用类似的方法获取并使用某一个类的方法
- Class.getMethod(String, Class…)和Class.getDeclaredMethod(String, Class…)获得方法
- invok(Object, Object…)可以调用该方法
- 使用setAccessi(true)设置访问权限
public class Demo5 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.heima.day27.reflect.Demo3");
Constructor c = clazz.getConstructor(int.class);//获取有参构造
Demo3 d = (Demo3) c.newInstance(5);//通过有参构造创建对象
Method m = clazz.getMethod("eat");
m.invoke(d);
}
}
反射应用实例
例题:向ArrayList添加字符串数据
public class Test1 {
public static void main(String[] args) throws Exception {
ArrayList<Integer> list = new ArrayList<>();
list.add(111);
list.add(222);
/*list.add("abc");*///由于泛型的存在,直接添加会出异常
Class clazz = Class.forName("java.util.ArrayList");// 获取字节码对象
Method m = clazz.getMethod("add", Object.class);//获取add方法
m.invoke(list, "abc");
System.out.println(list);
}
}