JAVA反射机制

反射背景:

学习重点

         1)创建对应的运行时类的对象

               2)调用对应的运行时类的指定的结构(属性、方法、构造器)

定义

  Reflection(反射)是被视为动态语言的关键,

  反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,

  并能直接操作任意对象的内部属性及方法

好处

    1)大大提高了程序的扩展性

    2)类不确定的情况下,都会用到反射

应用场景: 大多为加载配置文件

实例化Class类对象(四种方法)

1)前提:若已知具体的类,通过类的class属性获取,该方法 最为安全可靠,程序性能最高 实例:Class clazz = String.class;

2)前提:已知某个类的实例,调用该实例的getClass()方法获 取Class对象 实例:Class clazz = “www.atguigu.com”.getClass();

3)前提:已知一个类的全类名,且该类在类路径下,可通过 Class类的静态方法forName()获取,可能抛出ClassNotFoundException 实例:Class clazz = Class.forName(“java.lang.String”);

4)其他方式(不做要求) ClassLoader cl = this.getClass().getClassLoader(); Class clazz4 = cl.loadClass(“类的全类名”);

调用对应的运行时类的指定的结构(属性、方法、构造器)

1)获取对应的运行时类的属性

package com.atguigu.java;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import org.junit.Test;

public class TestField {
    //获取对应的运行时类的属性
    @Test
    public void test1(){
        Class clazz = Person.class;
        //1.getFields():只能获取到运行时类中及其父类中声明为public的属性
        Field[] fields = clazz.getFields();
        for(int i = 0;i < fields.length;i++){
            System.out.println(fields[i]);
        }
        System.out.println();
        //2.getDeclaredFields():获取运行时类本身声明的所有的属性
        Field[] fields1 = clazz.getDeclaredFields();
        for(Field f : fields1){
            System.out.println(f.getName());
        }
    }
    //权限修饰符  变量类型 变量名
    //获取属性的各个部分的内容
    @Test
    public void test2(){
        Class clazz = Person.class;
        Field[] fields1 = clazz.getDeclaredFields();
        for(Field f : fields1){
            //1.获取每个属性的权限修饰符
            int i = f.getModifiers();
            String str1 = Modifier.toString(i);
            System.out.print(str1 + " ");
            //2.获取属性的类型
            Class type = f.getType();
            System.out.print(type.getName() + " ");
            //3.获取属性名
            System.out.print(f.getName());
            
            System.out.println();
        }
    }
    
    //调用运行时类中指定的属性
    @Test
    public void test3() throws Exception{
        Class clazz = Person.class;
        //1.获取指定的属性
        //getField(String fieldName):获取运行时类中声明为public的指定属性名为fieldName的属性
        Field name = clazz.getField("name");
        //2.创建运行时类的对象 
        Person p = (Person)clazz.newInstance();
        System.out.println(p);
        //3.将运行时类的指定的属性赋值
        name.set(p,"Jerry");
        System.out.println(p);
        System.out.println("%"+name.get(p));
        
        System.out.println();
        //getDeclaredField(String fieldName):获取运行时类中指定的名为fieldName的属性
        Field age = clazz.getDeclaredField("age");
        //由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作。
        age.setAccessible(true);
        age.set(p,10);
        System.out.println(p);
        
//        Field id = clazz.getField("id");
        
    }
    
}

2)获取运行时类的方法

package com.atguigu.java;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.junit.Test;

public class TestMethod {
    //1.获取运行时类的方法
    
    @Test
    public void test1(){
        Class clazz = Person.class;
        //1.getMethods():获取运行时类及其父类中所有的声明为public的方法
        Method[] m1 = clazz.getMethods();
        for(Method m : m1){
            System.out.println(m);
        }
        System.out.println();
        
        //2.getDeclaredMethods():获取运行时类本身声明的所有的方法
        Method[] m2 = clazz.getDeclaredMethods();
        for(Method m : m2){
            System.out.println(m);
        }
    }
    //注解 权限修饰符 返回值类型 方法名 形参列表 异常
    @Test
    public void test2(){
        Class clazz = Person.class;
        
        Method[] m2 = clazz.getDeclaredMethods();
        for(Method m : m2){
            //1.注解
            Annotation[] ann = m.getAnnotations();
            for(Annotation a : ann){
                System.out.println(a);
            }
            
            //2.权限修饰符
            String str = Modifier.toString(m.getModifiers());
            System.out.print(str + " ");
            //3.返回值类型
            Class returnType = m.getReturnType();
            System.out.print(returnType.getName() + " ");
            //4.方法名
            System.out.print(m.getName() + " ");
            
            //5.形参列表
            System.out.print("(");
            Class[] params = m.getParameterTypes();
            for(int i = 0;i < params.length;i++){
                System.out.print(params[i].getName() + " args-" + i + " ");
            }
            System.out.print(")");
            
            //6.异常类型
            Class[] exps = m.getExceptionTypes();
            if(exps.length != 0){
                System.out.print("throws ");
            }
            for(int i = 0;i < exps.length;i++){
                System.out.print(exps[i].getName() + " ");
            }
            System.out.println();
        }
    }
    //调用运行时类中指定的方法
    @Test
    public void test3() throws Exception{
        Class clazz = Person.class;
        //getMethod(String methodName,Class ... params):获取运行时类中声明为public的指定的方法
        Method m1 = clazz.getMethod("show");
        Person p = (Person)clazz.newInstance();
        //调用指定的方法:Object invoke(Object obj,Object ... obj)
        Object returnVal = m1.invoke(p);//我是一个人
        System.out.println(returnVal);//null
        
        Method m2 = clazz.getMethod("toString");
        Object returnVal1 = m2.invoke(p);
        System.out.println(returnVal1);//Person [name=null, age=0]
        //对于运行时类中静态方法的调用
        Method m3 = clazz.getMethod("info");
        m3.invoke(Person.class);
        
        //getDeclaredMethod(String methodName,Class ... params):获取运行时类中声明了的指定的方法
        Method m4 = clazz.getDeclaredMethod("display",String.class,Integer.class);
        m4.setAccessible(true);
        Object value = m4.invoke(p,"CHN",10);//我的国籍是:CHN
        System.out.println(value);//10
    }
}

3)调用指定的构造器,创建运行时类的对象

package com.atguigu.java;

import java.lang.reflect.Constructor;

import org.junit.Test;

public class TestConstructor {
    @Test
    public void test1() throws Exception{
        String className = "com.atguigu.java.Person";
        Class clazz = Class.forName(className);
        //创建对应的运行时类的对象。使用newInstance(),实际上就是调用了运行时类的空参的构造器。
        //要想能够创建成功:①要求对应的运行时类要有空参的构造器。②构造器的权限修饰符的权限要足够。
        Object obj = clazz.newInstance();
        Person p = (Person)obj;
        System.out.println(p);
    }
    
    @Test
    public void test2() throws ClassNotFoundException{
        String className = "com.atguigu.java.Person";
        Class clazz = Class.forName(className);
        
        Constructor[] cons = clazz.getDeclaredConstructors();
        for(Constructor c : cons){
            System.out.println(c);
        }
    }
    
    //调用指定的构造器,创建运行时类的对象
    @Test
    public void test3() throws Exception{
        String className = "com.atguigu.java.Person";
        Class clazz = Class.forName(className);
        
        Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
        cons.setAccessible(true);
        Person p = (Person)cons.newInstance("罗伟",20);
        System.out.println(p);
    }
}

反射的应用场景(以下代码均是)

NoteBookMain.java

package cn.itcast.reflect.test;

import java.io.File;
import java.io.FileReader;
import java.util.Properties;

public class NoteBookMain {

    /**
     * @param args
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        /*
         * 案例一:
         *     阶段一:笔记电脑运行。NoteBook run();
         *     阶段二:想要使用一些外围设备,比如鼠标,键盘......
         *             为了提高了笔记本的扩展性,应该降低这些设备和笔记本的耦合性。
         *             需要接口。
         *             只需要在设计之初,定义一个接口。而且笔记本在使用这个接口。
         * 
         *    后期有了usb的设备后,需要不断的new对象才可以用。每一次都要修改代码。
         *
         *    能不能不修改这代码。就可以使用后期的设备呢?
         *    设备不明确的,而前期还要对其进行对象的建立。需要反射技术。
         *    对外提供一个配置文件。
         */

        NoteBook book = new NoteBook();
        book.run();
//        book.useUSB(null);
//        book.useUSB(new MouseByUSB());
        
        //通过反射的方法重新设计应用程序,以提高更好的扩展性。
        
        File configFile = new File("tempfile\usb.properties");
        if(!configFile.exists()){
            configFile.createNewFile();
        }
    
        //2,读取配置文件。
        FileReader fr = new FileReader(configFile);
        
        //3,为了获取其中的键值信息方便,建立Properties。
        Properties prop = new Properties();
        prop.load(fr);
        
        for(int x = 1; x<=prop.size(); x++){
            
            String className = prop.getProperty("usb"+x);
            //反射。
            Class clazz = Class.forName(className);
            
            USB usb = (USB)clazz.newInstance();
            
            book.useUSB(usb);
            
        }
        
        
        fr.close();
    }

}

NoteBook.java

package cn.itcast.reflect.test;

public class NoteBook {

    /**
     * 运行
     */
    public void run(){
        System.out.println("notebook run");
    }
    
    /**
     * 使用usb的设备。
     */
    public void useUSB(USB usb){//多态
        if(usb!=null){
            usb.open();
            usb.close();
        }
    }
}

USB.java

package cn.itcast.reflect.test;

public interface USB {

    /**
     * 开启。
     * 
     */
    void open();
    
    /**
     * 关闭。
     */
    void close();
}

KeyByUSB.java

package cn.itcast.reflect.test;

public class KeyByUSB implements USB {

    @Override
    public void open() {
        System.out.println("key open");

    }

    @Override
    public void close() {
        System.out.println("key close");

    }

}

MouseByUSB.java

package cn.itcast.reflect.test;

public class MouseByUSB implements USB {

    @Override
    public void open() {
        System.out.println("mouse open");
    }

    @Override
    public void close() {
        System.out.println("mouse close");

    }

}
纸上学来终觉浅,觉知此事需躬行
原文地址:https://www.cnblogs.com/dreamHighMjc/p/7446119.html