java反射

Java反射

回忆一下之前如何使用一个Java类?

  1. 已知一个类的类名、以及类中的方法属性、构造方法等
  2. 使用new关键字创建对象
  3. 使用对象调用方法或属性

这是正常的使用,已知某个类,创建该类的对象。正向使用,但是这种写法,把代码直接写死了,不能变了。但是框架需要为我们处理不同的类,我们配置什么类它都需要能够创建,new这种方式显然是不能满足的

问题:如果仅仅知道一个类的类名,能否动态得到类的定义信息,包括哪些方法、属性等? 答案:可以通过反射做到

引入案例支持

1.配置servlet,服务器启动时就会创建该类的对象,使用的就是反射机制创建该类的对象


     
     com.ffyc.dorm.servlet.LoginServlet	
     com.ffyc.dorm.servlet.DormServlet	

2.mybatis,配置了哪个类就创建出该类的对象

 resultType="com.ffyc.mybatispro.model.Admin">

为什么用反射机制?就是向框架一样,可以写一套机制来处理任意的类,就使得程序更急灵活,以不变应万变。

什么是反射机制?JAVA反射机制是知道类的地址,在运行状态中,可以动态的获取任意一个类的信息,可以创建任意类的对象,调用任意对象中的方法、属性这种动态获取类信息的功能称为java反射机制,称为反向使用类

java反射_第1张图片

Car.class是在硬盘上存储的,把它加载到内存里面;在内存里面怎么表示Car.class类的信息呢?会在内存里面创建一个Class类的对象:用来表示Car类的信息,提供了各种方法来访问Class类的类表示正在运行的Java应用程序中的类和接口。

Java反射相关API

Java反射相关的类主要包括

  • Class 类型
  • Constructor 构造方法
  • Method 方法
  • Field 属性

除了Class外,其他类都位于java.lang.reflect包中。可见,反射API将类的类型、方法、属性都封装成了类,其中最重要的类是Class,可以说,反射的使用都是从Class开始。

Class类

一旦一个类被加载到内存中,都会为该类创建一个Class类的对象,可以通过该对象获取类中的信息。要使用反射机制动态获取,创建对象,首先就是要获得类的Class对象.

反射的起点,就是要获得类的Class对象,通过Class对象获取类的信息。

无论类创建了多少个对象,只有一个类的Class对象。

要使用Class类的方法,必须先获得该类的Class类的实例,获取类的Class对象方式有3种

  • 类名.class方式:适用于通过类名获得Class实例的情况
  • Object类中的getClass方法:适用于通过对象获得Class实例的情况
  • Class类的静态方法 forName(String name)
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 {

    }
}
通过Class类的对象获取属性(Field实例)

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实例

Method实例都是通过Class类的方法获得

Method getMethod(String name, Class... parameterTypes):通过指定方法名,参数类型,返回一个Method实例

Method类的作用:

1.Method类将类中的方法进行封装,可以动态获得方法的信息,例如

  • getName:获得方法名字
  • getParameterTypes:获得方法参数类型

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}
    }
}

优缺点

优点:

  • 让程序更加灵活,具备动态性(框架、mybatis、servlet-class 可以动态创建操作对象)
  • 可以在运行时轻松获取任意一个类的方法、属性,并且还能通过反射进行动态调用

缺点:

  • 反射对类型进行判断解析,所以效率上低.
  • 通过反射可以对私有成员进行访问操作,安全性低,打破了封装性

你可能感兴趣的:(java,开发语言)