回忆一下之前如何使用一个Java类?
这是正常的使用,已知某个类,创建该类的对象。正向使用,但是这种写法,把代码直接写死了,不能变了。但是框架需要为我们处理不同的类,我们配置什么类它都需要能够创建,new这种方式显然是不能满足的
问题:如果仅仅知道一个类的类名,能否动态得到类的定义信息,包括哪些方法、属性等? 答案:可以通过反射做到
引入案例支持
1.配置servlet,服务器启动时就会创建该类的对象,使用的就是反射机制创建该类的对象
- <servlet>
- <servlet-name>
- <servlet-class>com.ffyc.dorm.servlet.LoginServletservlet-class>
- <servlet-class>com.ffyc.dorm.servlet.DormServletservlet-class>
2.mybatis,配置了哪个类就创建出该类的对象
resultType="com.ffyc.mybatispro.model.Admin">
为什么用反射机制?就是向框架一样,可以写一套机制来处理任意的类,就使得程序更急灵活,以不变应万变。
什么是反射机制?JAVA反射机制是知道类的地址,在运行状态中,可以动态的获取任意一个类的信息,可以创建任意类的对象,调用任意对象中的方法、属性,这种动态获取类信息的功能称为java反射机制,称为反向使用类

Car.class是在硬盘上存储的,把它加载到内存里面;在内存里面怎么表示Car.class类的信息呢?会在内存里面创建一个Class类的对象:用来表示Car类的信息,提供了各种方法来访问Class类的类表示正在运行的Java应用程序中的类和接口。
Java反射相关的类主要包括
除了Class外,其他类都位于java.lang.reflect包中。可见,反射API将类的类型、方法、属性都封装成了类,其中最重要的类是Class,可以说,反射的使用都是从Class开始。
一旦一个类被加载到内存中,都会为该类创建一个Class类的对象,可以通过该对象获取类中的信息。要使用反射机制动态获取,创建对象,首先就是要获得类的Class对象.
反射的起点,就是要获得类的Class对象,通过Class对象获取类的信息。
无论类创建了多少个对象,只有一个类的Class对象。
要使用Class类的方法,必须先获得该类的Class类的实例,获取类的Class对象方式有3种:
- package com.ffyc.javareflect.model;
-
- public class User {
- private int id;
- private String account;
- private String password;
-
- public User() {
- System.out.println("User无参构造");
- }
-
- private User(int id, String account, String password) {
- this.id = id;
- this.account = account;
- this.password = password;
- System.out.println("有参构造");
- }
-
- public int getId() {
- return id;
- }
-
- public void setId(int id) {
- this.id = id;
- }
-
- public String getAccount() {
- return account;
- }
-
- public void setAccount(String account) {
- this.account = account;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
- }
- package com.ffyc.javareflect.model;
-
- public class Test {
- public static void main(String[] args) throws ClassNotFoundException {
- // new User(); 正向使用
-
- Class c1=User.class;//第一种方式
- System.out.println(c1);//class com.ffyc.javareflect.model.User
-
- Class c2=new User().getClass();//第二种方式
- System.out.println(c2);
- System.out.println(c1==c2);//true,无论类创建了多少个对象,只有一个类的Class对象
-
- //根据类的地址加载类,并获得该类的Class类的对象
- String className="com.ffyc.javareflect.model.User";
- Class c3=Class.forName(className);
- System.out.println(c1==c3);//true
- }
- }
通过反射来创建对象
1.Class类中,c.newInstance()是创建对象的一种方式
- public class Test1 {
- public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
- //根据类的地址加载类,并获得该类的Class类的对象
- String className="com.ffyc.javareflect.model.User";
- Class c=Class.forName(className);
- Object obj=c.newInstance();
- }
- }
2.Constructor类中,constructor.newInstance()是创建对象的一种方式
- public class Test1 {
- public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
- //根据类的地址加载类,并获得该类的Class类的对象
- String className="com.ffyc.javareflect.model.User";
- Class c=Class.forName(className);
-
- Constructor constructor=c.getConstructor();//获取类中无参构造方法,封装到Constructor类的对象
- Object obj=constructor.newInstance();//通过无参构造方法创建对象
-
- Constructor constructor1=c.getConstructor(int.class,String.class,String.class);
- System.out.println(Arrays.toString(constructor1.getParameters()));
- }
- }
getDeclaredConstructor:获得类中指定的构造方法(包含了私有方法),打破了封装性。
- Constructor constructor=c.getDeclaredConstructor(int.class,String.class,String.class);
- constructor.setAccessible(true);//设置可以访问私有权限的成员,不然报错
- constructor.newInstance(1,"jim","jim");
getDeclaredConstructors:获得类中所有的构造方法
- Constructor[] constructors=c.getDeclaredConstructors();
- for (Constructor constructor1:constructors){
- if(constructor1.isAccessible()){
- constructor1.setAccessible(true);
- }else {
-
- }
- }
public Field getField(String name)通过指定Field名字,返回Field实例.
注意Field的访问权限
- public class Test2 {
- public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
- //根据类的地址加载类,并获得该类的Class类的对象
- String className="com.ffyc.javareflect.model.User";
- Class c=Class.forName(className);
- Object obj=c.newInstance();
-
- Field[] fields=c.getDeclaredFields();//获取类中所有的属性
- //Field[] methods=c.getDeclaredMethods();//获取类中所有的方法
- for(Field f:fields){
- System.out.println(f.getName());
- Method m=c.getMethod("set"+f.getName().substring(0,1).toUpperCase()+f.getName().substring(1),f.getType());//所有属性的set方法
- m.invoke(obj,"111");//为属性赋值
- }
- }
- }
Method实例都是通过Class类的方法获得
Method getMethod(String name, Class... parameterTypes):通过指定方法名,参数类型,返回一个Method实例
Method类的作用:
1.Method类将类中的方法进行封装,可以动态获得方法的信息,例如
2.除了动态获得方法信息外,Method还能动态调用某一个对象的具体方法
nvoke(Object obj, Object... args) :使用obj调用该方法,参数为args
自定义java对象转json工具类
- package com.ffyc.javareflect.model;
-
- public class MyJson {
- //简单的反射案例
- public static String objToJson(Object obj) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
- String json="{";
- Class c=obj.getClass();
- Field[] fields=c.getDeclaredFields();//获取任意一个类中的所有属性
- for(Field f:fields){
- String name=f.getName();
- json+=name+":";
- Method m=c.getMethod("get"+f.getName().substring(0,1).toUpperCase()+f.getName().substring(1));//动态构成get方法名称,并获取到get方法
- Object value=m.invoke(obj);//调用了属性的get方法
- json+=value+",";
- }
- json=json.substring(0,json.length()-1);
- json+="}";
- return json;//{id:值,account:值}
- }
- public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
- User user=new User();
- user.setId(10);
- user.setAccount("admin");
- user.setPassword("111");
- String json=MyJson.objToJson(user);
- System.out.println(json);//{id:10,account:admin,password:111}
- }
- }
优点:
缺点: