• 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");
    
        }
    
    }
    纸上学来终觉浅,觉知此事需躬行
  • 相关阅读:
    [LeetCode]Add Binary
    基于Servlet、JSP、JDBC、MySQL的一个简单的用户注冊模块(附完整源代码)
    C语言scanf函数详解
    三层架构(我的理解及具体分析)
    HTML5系列之——applicationCache对象
    分布式系统浅析
    HDU 4421 Bit Magic (图论-2SAT)
    软考总结
    javabean总结
    linux经常使用命令
  • 原文地址:https://www.cnblogs.com/dreamHighMjc/p/7446119.html
Copyright © 2020-2023  润新知