1、什么是反射?
反射是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,也有称作“自省”。反射非常强大,它甚至能直接操作程序的私有属性。我们前面学习都有一个概念,被private封装的资源只能类内部访问,外部是不行的,但这个规定被反射赤裸裸的打破了。
反射就像一面镜子,它可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分。
那么,作为小白的我怎么理解:
概念:反射是Java的一种机制,让我们可以在运行时获取类的信息;
作用:通过反射,我们可以在程序运行时动态创建对象,还能获取到类的所有信息,比如它的属性、构造器、方法、注解等;
2、利用反射动态创建对象
2.1 获取class对象的三种方式
//创建一个实体类
public class Animal {
private String name;
private String sex;
private int age;
public Animal(){
}
public Animal(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
public class TestAnimal {
public static void main(String[] args) {
Animal dog = new Animal("小狗", "公", 2);
Animal cat = new Animal("小猫", "母", 4);
/**
* 获取对象的三种方式
*/
//1、利用 getClass()方法获取对象的class对象
Class c1 = dog.getClass();
Class c2 = cat.getClass();
System.out.println(c1 == c2);//true
//2、利用class属性获取字节码文件
// (类,class:需要输入一个明确的类,任意一个类型都有一个静态的class属性)
Class c3 = Animal.class;
System.out.println(c1 == c3);
//3、利用Class.forName()获取--最常用的方式
//通过Class类的一个forName(String className)静态方法返回一个Class对象,
//className必须是全路径名称;
//Class.forName()有异常:ClassNotFoundException
try {
Class c4 = Class.forName("com.etime.entity.Animal");
System.out.println(c3 == c4);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
2.2 动态创建对象
(1)newInstance()创建对象
//2.2.1 newInstance()创建对象
try {
Object obj = c3.newInstance();
System.out.println(obj.toString());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
通过Class对象的newInstance()方法来创建Class对象对应类的实例。这个方法是使用Class对象对应类的默认构造器创建对象,这就要求Class对象对应类必须要有默认构造器(无参数的构造方法)。
(2)构造方法创建对象
使用Class对象获取指定的Constructor对象,调用Constructor对象的newInstance()方法来创建Class对象对应类的实例。这个方法可以使用Class对象对应类的任意指定的构造器来创建实例。
//2.2.2 构造方法创建对象
try {
Constructor constructor = c3.getConstructor(String.class, String.class, int.class);
Object obj = constructor.newInstance("猪", "母", 2);
System.out.println(obj.toString());
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
三、利用反射调用方法
//获取class对象
Class c1 = Class.forName("edu.etime.reflex.demo1.Animal");
//反射创建类的实例
Animal obj = (Animal) c1.newInstance();
obj.setName("人");
//通过反射获取到method对象
Method m = c1.getMethod("getName");
//通过method对象的invoke方法调用方法
Object o = m.invoke(obj);
System.out.println(o);
四、动态操作属性(调用get,set方法)
//获取class对象
Class c1 = Class.forName("edu.etime.reflex.demo1.Animal");
//反射创建类的实例
Animal obj = (Animal) c1.newInstance();
//获取公有属性
Field[] fileds = c1.getFields();
for(Field f :fileds){
System.out.println("公有属性:"+f.getName());
}
Field[] fileds2 = c1.getDeclaredFields();
for(Field f :fileds2){
System.out.println("私有属性:"+f.getName());
}
//给属性赋值
Field[] fileds2 = c1.getDeclaredFields();
for(Field f :fileds2){
System.out.println("私有属性:"+f.getName());
f.setAccessible(true);
if(f.getType().equals(String.class)){
f.set(obj, "123");
}else if(f.getType().equals(int.class)){
f.set(obj, 123);
}
}
System.out.println(obj.toString());
//调用get,set方法
PropertyDescriptor p = new PropertyDescriptor("name",c1);
//获取写方法
Method mset = p.getWriteMethod();
mset.invoke(obj, "xxxxxxx");
//获取读方法
Method mget = p.getReadMethod();
System.out.println(mget.invoke(obj));
五、反射的应用场景
1、Spring 实例化对象:当程序启动时,Spring 会读取配置文件applicationContext.xml并解析出里面所有的标签实例化到IOC容器中。
2、反射 + 工厂模式:通过反射消除工厂中的多个分支,如果需要生产新的类,无需关注工厂类,工厂类可以应对各种新增的类,反射可以使得程序更加健壮。
3、JDBC连接数据库:使用JDBC连接数据库时,指定连接数据库的驱动类时用到反射加载驱动类