Java反射机制
前言:
最近在看SpringBoot,下午看视频的时候,讲解老师在分析源码,其中源码很多地方用到了反射机制,感觉并没有学习太清楚。之前学习JavaSE的时候有些操之过急,没有好好理解反射机制,于是下午又重新复习了一遍反射机制。
创建对象的几种方式
-
- new关键字 + 该类的构造方法;
-
- 反序列化(和序列化相对应,在I/O流中进行数据传输使用较多,这里篇幅有限,请自行百度);
-
3)java反射机制
反射的概念
- 官方解释:在运行过程中,可以动态根据类的地址来获取类的信息(构造方法,成员方法,成员变量),以及动态根据类的信息来创建对象,来调用对象的方法、属性的功能成为反射机制。
- 个人见解: 反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作
反射的作用
可以动态获取类的信息,进一步实现需要实现的功能
反射相关的类
-
Class
-
- 用来封装每个类的字节码信息,Java 中一旦某个类被加载到内存中,将会把类的信息封装到一个Class对象中。
-
Constructor 构造方法
-
Method 方法
-
Field 属性
Class 对象
使用反射机制来操作,首先我们需要在运行时获取类的Class对象。
Class对象中包含类的信息(一个类的Class对象只有一个,与字节码文件对应)。
获取Class的三种方式:
(1)通过Object中的getClass()
(2)通过类的class属性
(3)通过类的地址(常用的)
package com.homyit.reflect;
public class ClassDemo {
public static void main(String[] args) {
/*
* 使用反射机制来操作,首先我们需要在运行时获取类的Class对象
* Class对象中包含类的信息(一个类的Class对象只有一个,与字节码文件对应)
*/
//获取Class的三种方法
//(1)通过Object中的getClass()
User user1 = new User();
User user2 = new User();
Class c1 = user1.getClass();
Class c2 = user2.getClass();
System.out.println(c1 == c2); //true
//(2)通过类的class属性
Class c3 = User.class;
System.out.println(c1 == c3); //true
//(3)通过类的地址(常用的)
try {
Class c4 = Class.forName("com.homyit.reflect.User");
System.out.println(c1 == c4); //true
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Java 中Field对象
package com.homyit.reflect;
import java.lang.reflect.Field;
public class FieldDemo {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException {
//指定类的路径
String className = "com.homyit.reflect.User";
//获取包含对象信息的Class对象
Class c = Class.forName(className);
//通过Class获取User对象
Object obj = c.newInstance();
//获取属性
Field numf = c.getDeclaredField("num");
//设置私有权限
numf.setAccessible(true);
//给属性赋值
numf.setInt(obj, 10);
//获取所有的属性
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
System.out.println(field.getName());
String name = field.getName();
String getname = "get" + String.valueOf(name.charAt(0)).toUpperCase()+name.substring(1);
System.out.println(getname);
}
}
}
java中的method
package com.homyit.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodDemo {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
//指定类的路径
String className = "com.homyit.reflect.User";
//获取包含对象信息的Class对象
Class c = Class.forName(className);
//通过Class获取User对象
Object obj = c.newInstance();
//获取指定方法
Method m = c.getDeclaredMethod("eat", String.class);
//设置私有权限
m.setAccessible(true);
//调用私有方法
m.invoke(obj, "cat");
//获取所有的方法
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}
反射的经典场景(据说面试常问)
这里给出三个我目前见到过的场景
- JDBC
加载数据库连接驱动,写过JDBC的同学相信都清楚
Class.forName("com.mysql.jdbc.Driver");
- servlet
用于servlet对象在服务器tomcat中的创建
<servlet-class>com.company.project.servlet.XxxServlet</servlet-class>
初学servlet时经常配置,后面使用经常使用注解方式,其实底层也是反射机制
- spring IOC(控制反转)
spring项目中万恶的applicationcontext.xml文件,写过的同学深有体会他的配置有多麻烦
<bean id="course1" class="com.homyit.spring5.collectiontype.Course">
<property name="cname" value="Spring"></property>
</bean>
<bean id="course2" class="com.homyit.spring5.collectiontype.Course">
<property name="cname" value="SpringBoot"></property>
</bean>
<bean id="course3" class="com.homyit.spring5.collectiontype.Course">
<property name="cname" value="SpringCloud"></property>
</bean>
来源:oschina
链接:https://my.oschina.net/u/4303989/blog/4411289