zoukankan      html  css  js  c++  java
  • Java第十二章反射机制

    Java Reflection

    Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于ReflectionAPO取得任何类的内部信息,

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

    Java反射机制提供的功能

    》在运行时判断任意一个对象所属的类

    》在运行时构造任意一个类的对象

    》在运行时判断任意一个类所具有的成员变量和方法

    》在运行时调用任意一个对象的成员变量和方法

    》生成动态代理

    主要内容:

      1.理解Class类并实例化Class类对象

      2.运行时创建类对象并获取类的完整结构

      3.通过反射调用类的指定方法、指定属性

      4.动态代理

    反射相关的主要API:

    java.lang.class:代表一个类

    》java.lang.reflect.Method:代表类的方法

    》java.lang.reflect.Field:代表类的成员变量

    》java.lang.reflect.Construtor:代表类的构造方法

    》。。。

    1.理解Class类并实例化Class类对象
    /*
    * java.lang.Class:是反射的源头
    *
    * Class类
    *
    * 我们创建了一个类,通过编译(javac.exe),生成对应的.class文件。之后我们使用java.exe加载(JVM的类加载器完成的)此.class文件,
    * 此.class文件加载到内存以后,就是一个运行时类,存放在缓存区。那么这个运行时类本身就是一个Class的实例!
    * 1.每个运行时类只加载一次!
    * 2.有了Class的实例以后,我们才可以进行如下的操作:
    * 1)   创建对应的运行时类的对象
    * 2)获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在包、异常、注解、。。。)
    * 3)调用对应的运行时类的指定结构(属性、方法、构造器)
    * 4)反射的应用:动态代理

     

    * 在Object类中定义了此方法被所有子类继承:
    * public final Class getClass()
    *
    * 正常方式:引入需要的“包类”名称——>通过new实例化——>取得实例化对象
    * 反射方式:                 实例化对象——>getClass()方法——>得到完整的"包类"名称
    */

        //运用反射机制创建对象,并且调用方法和属性
        @Test
        public void test1() throws Exception{
            //1.创建反射调用运行时类的指定属性
            Class clazz = Person.class;
            Person p1  = (Person) clazz.newInstance();
            //2.通过反射调用运行时类的指定的属性
            Field f1 = clazz.getField("name");
            f1.set(p1,"Yhs");
            System.out.println(p1);
    Field f2
    = clazz.getDeclaredField("age");//对权限为私有的属性进行调用 f2.setAccessible(true); f2.set(p1, 12); System.out.println(p1); //3.通过反射调用运行时类的指定的方法 Method m1 = clazz.getMethod("show"); m1.invoke(p1);//调用方法

    Method m2 = clazz.getMethod("display", String.class); m2.invoke(p1, "HongKong"); }
        //如何获取Class的实例(3种)
        @Test
        public void test3() throws ClassNotFoundException{
            //1.调用运行时类本身的.class属性
            Class clazz1  = Person.class;
            System.out.println(clazz1.getName());//reflect.Person
            Class clazz2 = String.class;
            System.out.println(clazz2.getName());//java.lang.String
            
            //2.通过运行时类的对象获取
            Person p = new Person();
            Class clazz3 = p.getClass();
            System.out.println(clazz3.getName());//reflect.Person
            
            //3.通过Class的静态方法获取
            String className="reflect.Person";
            Class clazz4 = Class.forName(className);
            System.out.println(clazz4.getName());//reflect.Person
            
            //4.(了解)通过类的加载器
            ClassLoader classLoader = this.getClass().getClassLoader();
            Class clazz5 = classLoader.loadClass(className);
            System.out.println(clazz5.getName());//reflect.Person
        }

     

    类加载器ClassLoader:

            
            获取配置文件
        //法一:配置文件在具体的包内 ClassLoader loader = this.getClass().getClassLoader(); InputStream is = loader.getResourceAsStream("配置文件路径"); //法二:在当前目录下 FileInputStream is = new FileInputStream(new File("当前工程下配置文件的文件名")); Properties pros = new Properties(); pros.load(is); String name = pros.getProperty("user"); System.out.println(name); String password = pros.getProperty("password"); System.out.println(password);

    @Test 
        public void test5(){
            //获取系统类加载器
            ClassLoader loader1 = ClassLoader.getSystemClassLoader();
            System.out.println(loader1);//sun.misc.Launcher$AppClassLoader@456d3d51
    
            //扩展类加载器
            ClassLoader loader2 = loader1.getParent();
            System.out.println(loader2);//sun.misc.Launcher$ExtClassLoader@456d3d51
            
         //都属于核心类库,无法被获取 ClassLoader loader3
    = loader2.getParent(); System.out.println(loader3);//null

         
    String className = "java.lang.String";
        
         Class clazz1 = Class.forName(className);

              ClassLoader loader4 = clazz1.getClassLoader();
              System.out.println(loader5);

        }

    2.运行时创建类对象并获取类的完整结构

    创建类的对象:调用Class对象的newInstance()方法

    要求:1)类必须有一个无参数的构造器

       2)类的构造器的访问权限需要足够

            String className1 ="reflect.Person";
            Class clazz = Class.forName(className1);
            //创建对应的运行时类对象,使用newInstance(),实际上就是调用了运行时类的空参构造器
            Object obj= clazz.newInstance();//调用了Person中的空参构造器。
            Person p1 = (Person) obj;
            System.out.println(p1);

    1、获取运行时类的属性结构

        @Test
        public void test1(){
            Class clazz = Person.class;
            //getFields():只能获取到运行时类中及其父类声明为public的属性
             Field[] f1 = clazz.getFields();
             for(int i=0;i<f1.length;i++){
                 System.out.println(f1[i]);
                 //public java.lang.String reflect.Person.name
                 //public double reflect.Man.weight
             }
             
             //getDeclaredFields():获取运行时类本身声明的所有属性。
             Field[] f2 = clazz.getDeclaredFields();
             for(Field f : f2 ){
                 System.out.println(f.getName());
                 //name
                 //age
                 //nation
             }
        }
        @Test
        public void test2(){
            Class clazz = Person.class;
            Field[] f1 = clazz.getDeclaredFields();
            for (Field f : f1) {
                //权限修饰符  数据类型  属性名
                //1.获取每个属性的权限修饰符,但用int型表示(0-default 1-public 2-private)
                int i = f.getModifiers();
                System.out.print(i +" ");
                
                //把int型转换为权限修饰符,并用String类型表示
                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();
            }
        }

    2、获得运行时类的方法结构

        //注解 权限修饰符 返回值类型 方法名 形参列表 异常
        @Test
        public void test4(){
            Class  clazz = Person.class;
            
            Method[] methods = clazz.getDeclaredMethods();
            for (Method m : methods) {
                
            //1、注解
                Annotation[] annotations = m.getAnnotations();
                for (Annotation annotation : annotations) {
                    System.out.println(annotation);
                }
            
            //2、权限修饰符
                System.out.print(Modifier.toString(m.getModifiers()));
                
            //3、返回值类型
                 System.out.print(m.getReturnType());
            
            //4、方法名
                 System.out.println(m.getName());
                 
            //5、形参列表
                  Class[]  params= m.getParameterTypes();//得到参数类型类集合
                  for(int i=0;i<params.length;i++){
                      System.out.println(params[i].getName() + "args -" + i + " ");
                  }
                  
            //6、异常
                  Class[] exc = m.getExceptionTypes();
                  if(exc.length!=0){
                      System.out.println("throws");
                  }
                  for(int i=0;i<exc.length;i++){
                      System.out.println(exc[i].getName());
                  }
                  
                System.out.println();
            }
        }

     3、获取构造器

        @Test
        public void test5() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
            String className = "reflect.Person";
            Class clazz = Class.forName(className);
            Constructor[] constructors = clazz.getDeclaredConstructors();
            for (Constructor constructor : constructors) {
                System.out.println(constructor);
            }
        }

     4、获取父类和泛型

        @Test
        public void test6() throws ClassNotFoundException{
            String className = "reflect.Person";
            Class clazz = Class.forName(className);
            
            //获取父类
            Class class1 = clazz.getSuperclass();
            System.out.println(class1);
            
            //获取带泛型的父类
            Type type1 = clazz.getGenericSuperclass();
            System.out.println(type1);
            
            //获取父类的泛型
            Type type2 = clazz.getGenericSuperclass();
            ParameterizedType param = (ParameterizedType) type2;
            Type[] t1 = param.getActualTypeArguments();
            for (Type type : t1) {
                System.out.println(((Class)type).getName());
            }
        }

     5、获取其他

        @Test
        public void test7() throws ClassNotFoundException{
            String className = "reflect.Person";
            Class clazz = Class.forName(className);
            
            //获取实现的接口(不能获取接口的父接口)
            Class[] interfaces = clazz.getInterfaces();
            for (Class class1 : interfaces) {
                System.out.println(class1.getName());
            }
            
            //获取所在的包
            Package package1 = clazz.getPackage();
            System.out.println(package1);
            
            //获取注解
            Annotation[] annotations = clazz.getAnnotations();
            for (Annotation annotation : annotations) {
                System.out.println(annotation);
            }
        }

     3.通过反射调用类的指定方法、指定属性

    指定属性:

    注: 只有当属性私有,才需要在赋值操作前使得此属性被操作。

        @Test
        public void test8() throws Exception{
            String className = "reflect.Person";
            Class clazz = Class.forName(className);
            
            //1.获取指定的属性
            //getField(String fileName):获取运行时类中声明为public的指定属性名为fileName的属性
                Field field = clazz.getField("name");
        
            //2.创建运行时类的对象
                Person p = (Person) clazz.newInstance();
                
            //3.将运行时类的指定的属性赋值        
                field.set(p, "YHS");
                System.out.println(p);
            
            //getDeclaredField(String fileName):获取运行时类中指定名为filedName的属性
                Field field2 = clazz.getDeclaredField("age");
                
            //由于属性权限修饰符的限制,为了保证可以给属性赋值,需在操作前使得此属性可被操作。
                field2.setAccessible(true);
                field2.set(p,10);
                System.out.println(p);
            //当属性的权限修饰符是默认的,也需要采用getDeclaredField()方法,因为它的权限是包下,所以不同指定权限。

            field2.setAccessible(true);
            field2.set(p,10);
            System.out.println(p);
            Field field3 = clazz.getDeclaredField("nation");
            field3.set(p,"HONgkong");
            System.out.println(p);

        }

     

    指定方法:

        @Test
        public void test9() throws Exception{
            String className = "reflect.Person";
            Class clazz = Class.forName(className);
            Person p = (Person) clazz.newInstance();
            
            //getMethod(String methodName,Class...params):获取运行时类中声名为pulbic的方法
            
            Method method = clazz.getMethod("read");
            
            //调用指定的方法:Object invoke(Object obj,Object ...obj)
            Object returnVal = method.invoke(p);
            System.out.println(returnVal);
            
            Method method2 = clazz.getMethod("toString");
            Object returnVal1 = method2.invoke(p);
            System.out.println(returnVal1);//Person [name=null, age=0, nation=null]
            
            Method method3 = clazz.getMethod("display",String.class);
            Object invoke = method3.invoke(p, "sss");
            System.out.println(invoke);
            
            //对于运行时类中静态方法的调用
            Method method4 = clazz.getMethod("sleep");
            method4.invoke(Person.class);
            
            //getDeclareMethod(String methodName,Class ...params):获取运行时类中声明不是public的方法
            Method declaredMethod = clazz.getDeclaredMethod("swim", String.class,int.class);
            declaredMethod.setAccessible(true);
            declaredMethod.invoke(p, "sdd",12);
        }

     调用指定的构造器

        //调用指定的构造器
        @Test
        public void test10() throws Exception{
            String className = "reflect.Person";
            Class clazz = Class.forName(className);
            
            Constructor conn = clazz.getDeclaredConstructor(String.class,int.class);
            conn.setAccessible(true);
            Person p = (Person) conn.newInstance("sss",12);
            System.out.println(p);
        }

     Java动态代理

     动态代理是指客户通过代理类来调用其他对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象

    动态代理使用场合:

    》调试

    》远程方法调用

    代理设计模式的原理:

    使用一个代理将对象包装起来,然后用该代理对象取代原始对象,任何对原始对象的调用都要通过代理,代理对象决定是否以及何时叫方法调用转到原始对象上。

     

    //动态代理
    //接口
    interface Subject{
        void action();
    }
    //被代理类
    class RealSubject implements Subject{
        @Override
        public void action() {
            // TODO Auto-generated method stub
            System.out.println("我是被代理类,执行我");
        }
    }
    class MyInvocationHanbler implements InvocationHandler{ //实现了接口的被代理类的对象的声明 Object obj; //①给被代理的对象实例化②返回一个代理类的对象 public Object blind(Object obj){ this.obj = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(), this); } //当通过代理类的对象发起对被重写方法的调用时,都会转换为对如下invoke方法的调用 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //method方法的返回值时returnVal Object invokeVal = method.invoke(obj, args); return invokeVal; } } public class ProxyTest2 { public static void main(String[] args) { //1.被代理的对象 RealSubject rs = new RealSubject(); //2.创建一个实现InvocationHanbler接口的对象 MyInvocationHanbler mih = new MyInvocationHanbler(); //3.动态的返回一个同样实现了real所在类实现的接口的代理类的对象 Object pro = mih.blind(rs); Subject sub = (Subject) pro;//此时的sub就是代理类对象 sub.action();//转到对InvacationHandler接口的实现类的invoke()方法的调用 } }

     Java.lang.reflect

    接口 InvocationHandler :是代理实例的调用处理程序实现的接口

    每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法的调用进行编码并将其它的调用处理程序的 invoke 方法

    静态代理:

    //静态代理模式
    //接口
    interface ClothProduct{
        void productCloth();
    }
    //被代理类
    class NikeClothProduct implements ClothProduct{
    
        @Override
        public void productCloth() {
            // TODO Auto-generated method stub
            System.out.println("Nike工厂生产一批衣服");
        }
    }
    //代理类
    class ProxyCloth implements ClothProduct{
        ClothProduct cp;
        
        //创建代理类对象实际传入一个被代理类的对象
        ProxyCloth(ClothProduct cp){
            this.cp = cp;
        }
    
        @Override
        public void productCloth() {
            // TODO Auto-generated method stub
            System.out.println("代理收费1000¥");
            cp.productCloth();
        }
        
    }
    
    public class ProxyTest1 {
        public static void main(String[] args) {
            NikeClothProduct ncp = new NikeClothProduct();
            ProxyCloth pc = new ProxyCloth(ncp);
            pc.productCloth();
        }
    }
  • 相关阅读:
    20165319第五周java学习笔记
    20165319 20165335 结对学习创意照
    20165215 结对编程——四则运算第二周
    20165215 2017-2018-2 《Java程序设计》第八周学习总结
    2017-2018-2 20165215 实验二 Java面向对象程序设计
    20165215 结对编程——四则运算第一周
    20165215 2017-2018-2 《Java程序设计》第7周学习总结
    20165215 2017-2018-2 《Java程序设计》第6周学习总结
    20165215 实验一 Java开发环境的熟悉
    20165215 2017-2018-2 《Java程序设计》第5周学习总结
  • 原文地址:https://www.cnblogs.com/yangHS/p/10701168.html
Copyright © 2011-2022 走看看