反射机制

反射机制

反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。 简单的来说,就是不通过new,使用类中的属性和方法。

为什么需要反射机制:

1 通过new创建对象 是静态加载类,在编译时刻就需要加载所的有的可能使用的类 (通过动态加载类可以解决该问题)

2 动态加载类是在运行的时刻加载 -------(一般情况下功能性的类使用动态加载类)

编译时刻加载类是静态加载类
运行时刻加载类是动态加载类

反射机制的优缺点:

优势:运行期类型的判断,动态类加载:提高代码灵活度

劣势:性能瓶颈,反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多

反射机制的应用场景:

  1. JDBC 的数据库的连接
  2. Spring 框架的使用

Class类

在面向对象的世界里,万事万物皆对象。

普通的数据类型不是对象,但是Java给我们提供了封装类,类中的静态成员不是对象,他是属于类的,类是对象,他是java.langa.Class类的实例对象

如何不用new,获取类中的属性和方法?

三种方式:

1.

类名.class

// 1.类名.class 方式都返回Class
       Class class1= Foot.class;

2.

类的实例对象.getClass()

//创建类的实例对象
Foot foot = new Foot();
// 类的实例对象.getClass()
Class class2 = foot.getClass();

3.

Class.forName("类的路径")

// 3.Class.forName("类的路径");
Class class3= Class.forName("/ReflesTest/src/cn/reflex/Foot.java"); //包名+类名


 

创建所需要的Person类

package cn.reflex.dome;

public class Person {
//带参构造
   public Person(int age, String name, String sex) {
        this.age = age;
        this.name = name;
        this.sex = sex;
    }
//无参构造
public Person() {
    
    }

//共有属性
public int age;
 public String name;
   
   public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

//私有属性
private String sex;

public String getSex() {
    return sex;
}

public void setSex(String sex) {
    this.sex = sex;
}
   
}

 

1.获取类的包名、类名

    /**
     * 获取包名及类名
     */
    public static void Dome1(){
        Class class1=Person.class;  
        System.out.println("类的包名"+class1.getPackage().getName());
        System.out.println("类的类名"+class1.getName());
    }

 

2.给类的属性赋值

/**
     * 获取类的信息
     * @throws IllegalAccessException 
     * @throws InstantiationException 
     */
    public static void Dome2() throws InstantiationException, IllegalAccessException{
        Class class1=Person.class;
        Person person=(Person) class1.newInstance();  //创建Class的实例
        person.setSex("");
        person.setName("小黑");
        System.out.println(person.getName()+person.getSex());
    }

 

 

3.获取类的构造  给构造属性赋值

/**
     * 获取类的构造函数
     * @throws IllegalAccessException 
     * @throws InstantiationException 
     * @throws InvocationTargetException 
     * @throws IllegalArgumentException 
     */
    public static void Dome3() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
        Class<Person> class1=Person.class;
        //构造          前提条件是类中要有构造  默认构造  无参构造
        Constructor[] constructors = class1.getConstructors();
        //比如在你的类中无参构造在上面[0]   带参构造[1]
        //[0]下标表示类中的第一个构造
        //[0]此代码中带参构造在第一个,在括号中直接的复制
        Person person=(Person)constructors[0].newInstance(18,"小黑","男");
        System.out.println(person.getName()+person.getSex()+person.getAge());
        //[1]表示无参构造
        Person person2 = (Person) constructors[1].newInstance();
        person2.setAge(55);
        System.out.println(person2.getAge());
        
        
    }

 

4.获取类中的成员变量

    /**
     *  获取类中所有的成员变量
     * */
    private static void Dome4() {
        Class class1=Person.class;
        //成员变量不一定是一个,所有用数组接收
        Field[] fields = class1.getDeclaredFields();
        //循环遍历数组
      for (Field field : fields) {
          //如果类中有私有变量也想获取怎么办,那就加上下面这一句话
        field.setAccessible(true);
        //获取成员变量名称
        System.out.println(field.getName());
        //获取成员变量的数据类型
        System.out.println(field.getType().getName());
    }
    }

 

4.1    给类中共有属性赋值

 //获取类中的方法及方法中的参数        三个参数分别是   类中的方法名称   方法中的参数
 Method method1 = class2.getDeclaredMethod("print",int.class,int.class); 
  //给方法中的参数赋值 把类的实例对象传进入
 method1.invoke(foot,1,10);
         

4.2  给类中私有属性赋值

// 获取类中的方法及方法中的参数  方法名  参数1,参数2
Method method1 = class2.getDeclaredMethod("add", int.class, int.class);
// 如果要给私有方法赋值使用setAccessible(true)
method1.setAccessible(true);
// 给方法中的参数赋值 把类的实例对象传进入  类的对象实例,参数1,参数2
method1.invoke(foot, 1, 10);

5.

获取单个成员变量

    /**
     * 获取单个成员变量
     * @throws SecurityException 
     * @throws NoSuchFieldException 
     * 
     * */
    public static void Dome5() throws NoSuchFieldException, SecurityException{
        Class class1=Person.class;
        //想要获取成员变量的名称
        Field field = class1.getDeclaredField("age");
        System.out.println(field.getName());
        System.out.println(field.getType().getName());
        
    }

 

 

6.获取实现的接口名称  、继承的名字、类中的方法

创建所需的接口、类

//接口

package cn.reflex.dome;

public interface ISuper {
    public   void fly();
}
//类   并继承Person类   实现接口
package cn.reflex.dome;

public class Super extends Person implements ISuper  {
    private String type;
    

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    
    public void Wear(String cloths) {
        System.out.println("超人有"+cloths);
    }
    @Override
    public void fly() {
       System.out.println("I Can Fly");        
    }
     
}

6.1获取类中实现的接口名称

1     //获取接口
2         //可以实现多个接口,所有用数组
3         Class[] interfaces = class1.getInterfaces();
4         //遍历数组
5         for (Class<?> class3 : interfaces) {
6             System.out.println(class3.getName());
7         }

6.2获取类继承的父类名称

//获取父类名称
//在这里要得到子类中的信息 
        Class<Super> class1=Super.class;  //子类
        Class<?> class2 = class1.getSuperclass();
        System.out.println(class2.getName());

6.3获取类中的方法

    //获取方法
        //同样方法不是一个,用数组
        Method[] methods = class1.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            System.out.println(methods[i].getName());
        }

6.4获取类中的成员

//获取类中成员
Field[] fields = class1.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());

 

7.调用类中的方法,这里用的是子类

    /**
     * 调用类中的方法
     * @throws SecurityException 
     * @throws NoSuchMethodException 
     * @throws InstantiationException 
     * @throws InvocationTargetException 
     * @throws IllegalArgumentException 
     * @throws IllegalAccessException 
     * */
    public static void  Dome7() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
        Class<Super> class1=Super.class;
        //1.想要调用的方法名称传过去
        Method method = class1.getMethod("fly");
        //创建类的实例
        method.invoke(class1.newInstance());
        //2.想要调用的方法名称和方法中的参数
        Method method2 = class1.getMethod("Wear",String.class);
        method2.invoke(class1.newInstance(), "蓝白相间");
    }

 执行结果:

 

8.使用反射操作泛型集合

比如我们定义一个数组ArrayList<String> list=new ArrayList<String>();    想数组添加的值必须是String类型的,那如果我们想要添加int类型的怎么办?所以就要用到反射。因为

反射是在编译后执行的
泛型集合是在编译前限定的

使用反射可以绕过编译直接添加到集合中

 

    /**
     * 泛型集合
     * @throws SecurityException 
     * @throws NoSuchMethodException 
     * @throws InvocationTargetException 
     * @throws IllegalArgumentException 
     * @throws IllegalAccessException 
     * */
    
    public static void Dome8() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
        //定义集合,向集合添加元素
        ArrayList<String> list=new ArrayList<String>();
        list.add("小花");
        Class<? extends ArrayList> class1 = list.getClass();
                                          //add是自已定义的,可以随便定义
        Method method = class1.getMethod("add",Object.class);
        method.invoke(list, 100);
        System.out.println(list.size());
        
    }

我们怎么知道是否添加到集合了呢?使用list.size()输出集合长度

 

 

原文地址:https://www.cnblogs.com/luoxionghenku/p/8810423.html