1.初始反射
反射的定义:反射是指在Java运行状态中
-
- 给定一个类对象(Class对象),通过反射获取这个对象(Class对象)的所有成员结构;
- 给定一个具体的对象,能够动态的调用它的方法及对任意属性值进行获取和赋值
- 这种动态获取类的内容、创建对象、以及动态调用对象方法及操作属性的机制,就叫做Java的反射机制。
反射的优点:
-
- 增加程序的灵活性,避免将固有的逻辑程序写死到代码里
- 代码简洁,可读性强,可提高代码的复用率
反射的缺点:
-
- 相较直接调用在创建对象比较多的情 景下反射性能下降
- 内部暴露和安全隐患(破坏单例)
反射性能慢的原因:
-
- 寻找类Class字节码的过程,比如通过ClassName找到对应的字节码Class,然后加载、解析,会比较慢,而new的方式则无需寻找,因为在Linking的解析阶段已经将符号引用转为了直接引用
- 安全管理机制的权限验证等
- 若需要调用native方法调用时JNI接口的使用
- 入参校验
2.反射的基本操作
缺点:判别使用反射和不使用反射的时间损耗
/**
* 缺点:性能损耗
*/
public class EfficMain {
public static void main(String[] args) {
long start = System.currentTimeMillis();
for(int i=0;i<1000000;i++){
// User user = new User(); //使用构造函数创建对象
getInstanceByRef("com.javacore.reflection.pojo.User");
}
long end = System.currentTimeMillis();
System.out.println("总耗时"+(end-start));
}
private static void getInstanceByRef(String key){
try {
Class<?> clazz = Class.forName(key);
clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
}
反射获取Class对象的组成:

获取Class对象的四种方式
- 通过ClassLoader对象的loadClass()方法
- 类名.class
- Class.forName()
- object.getClass()
/**
* 获取Class文件的方式
* 1、类名.class
* 2、Class.forName //反射
* 3、对象.getClass()
* 4、通过类加载器.loadClass()
*/
public class CoreMain {
public static void main(String[] args) throws Exception{
//1、 不会堆类初始化
Class<Person> clazz01 = Person.class;
System.out.println(clazz01);
//2、MySQL
Class<?> clazz02 = Class.forName("com.javacore.reflection.pojo.Person");
System.out.println(clazz02);
//3、已知实例对象
Class<? extends Person> clazz03 = new Person().getClass();
System.out.println(clazz03);
//4、通过类加载器
Class<?> clazz04 = CoreMain.class.getClassLoader().loadClass("com.javacore.reflection.pojo.Person");
System.out.println(clazz04);
//通过Clazz获取基本信息;属性信息;方法信息;注解信息
/**
* 获取的是类的修饰符
*/
System.out.println("--------------");
// 类中存在的修饰符,返回的是一个整数,可以通过toString方法展示出来是哪个修饰符
int modifiers = clazz01.getModifiers();
System.out.println(Modifier.toString(modifiers);
System.out.println(clazz01.getPackage());
System.out.println(clazz01.getName());
System.out.println(clazz01.getSimpleName());
System.out.println(clazz01.getClassLoader());
System.out.println(clazz01.getInterfaces());
System.out.println(clazz01.getSuperclass());
System.out.println(clazz01.getAnnotations());
/**
* 属性基本操作
*/
System.out.println("--------------");
Class<User> clazz = User.class;
User user = clazz.newInstance(); // 反射调用的无参的构造方法
Field[] fields = clazz.getFields(); //所有public字段、包括继承来的
for(Field field:fields){
System.out.println(field.getName());
}
System.out.println("--------------");
Field[] declaredFields = clazz.getDeclaredFields();//获取当前类中定义的
for(Field field:declaredFields){
System.out.println(field.getName());
}
System.out.println("--------------");
Field addField = clazz.getDeclaredField("address");
addField.setAccessible(true); //设置字段的强制访问,代表反射的不安全,private的都能访问
addField.set(user,"北京西三旗");
System.out.println(user.getAddress());
System.out.println("--------------");
Field nationalty = clazz.getDeclaredField("nationalty");
nationalty.set(null,"中国");
System.out.println(user.nationalty);
System.out.println("--------------");
// 构造函数
clazz.getDeclaredConstructors();
Constructor<User> declaredConstructor = clazz.getDeclaredConstructor(String.class, String.class);
declaredConstructor.setAccessible(true);
User user1 = declaredConstructor.newInstance("idCard", "address");
User user2 = clazz.newInstance(); //通过无参的构造函数反射出来的,无参的构造函数需要是public
System.out.println(user1);
System.out.println("--------------");
SingleDemo instance1 = SingleDemo.getInstance();
SingleDemo instance2 = SingleDemo.getInstance();
System.out.println(instance1==instance2);
Constructor<? extends SingleDemo> constructor = instance1.getClass().getDeclaredConstructor();
constructor.setAccessible(true);
SingleDemo instance3 = constructor.newInstance();
System.out.println(instance1==instance3);//false
// System.out.println("--------------");
// ClassPathXmlApplicationContext con = new ClassPathXmlApplicationContext("spring-ioc.xml");
// Object user2 = con.getBean("user");
// System.out.println(user2);
/**
* class.newInstance();底层使用的是反射出的无参的构造器,需要可见
* Constructor.newInstance()’;任何的构造器都能够构造出一个实例,private也可以
*/
}
}
3.反射安全性问题
- 可以通过setAccessible(true)方法设置对象可被强制访问
- 可以破坏单例的封装性
public class SingleDemo {
private static SingleDemo instance; //
private SingleDemo(){
// 防止反射直接调用构造函数
if (instance!=null){
throw new RuntimeException("单例,不能重复调用");
}
}
public static SingleDemo getInstance(){
if(instance == null){
instance = new SingleDemo();
}
return instance;
}
}
public class SingleMain {
public static void main(String[] args) throws Exception {
SingleDemo instance = SingleDemo.getInstance();
SingleDemo instance1 = SingleDemo.getInstance();
// 单例肯定一样
System.out.println(instance == instance1); //true
Class<? extends SingleDemo> clazz = instance.getClass();
Constructor<? extends SingleDemo> constructor = clazz.getDeclaredConstructor();
// 强制使私有的构造函数可以访问
constructor.setAccessible(true);
SingleDemo singleDemo = constructor.newInstance();
// 通过反射破坏了单例的封装性
System.out.println(singleDemo==instance);//false
}
}
4.反射在Spring中的应用
-
- JDBC的封装
- SpringIOC