zoukankan      html  css  js  c++  java
  • java基础——反射

    程序运行时,允许改变程序结构或变量类型的语言称为动态语言。

    java不是动态语言,但他有一个动态相关机制:Reflection反射。反射让java语言活了起来。

    在运行状态中:

    1)对于任意一个类,可以指定他的所有属性和方法;
    2)对于任意一个对象,可以调用他的方法和属性。

    总结来说,动态获取信息以及动态调用对象方法的功能成为java反射机制。

    查看类信息

    每个类被加载后,系统会为该类生成一个对应的Class对象。获取Class对象的三种方式分别是:

    public static void main(String[] args) {
            //方法一:
            try {
                Class.forName("Test1");  //必须是该类的完整路径
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
            //方法二:
            Class clazz=Test1.class;
    
            //方法三:调用对象的方法
            Test1 test1=new Test1();
            test1.getClass();
        }

    比较:

    前两种方式都是直接根据类来取得该类的Class对象,第二种方式更推荐使用。原因有两个:代码更安全,程序性能更好。

    下面的例子我们只用第二种方式,第一种很类似,就不再展示了。这里只是测试获取部分类的信息。

    //构造的测试类
    public class ClassTest  {
        public ClassTest() {
        }
        public ClassTest(String name) {
            System.out.println("有参数");
        }
        private Integer id;
        private String name;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "ClassTest [id=" + id + ", name=" + name + "]";
        }
    
        public void info() {
            System.out.println("执行无参数的info");
        }
    
        public void info(String str) {
            System.out.println("执行有参数的info" + str);
        }
       //两个内部类
        class Inner {
    
        }
        static class Student {
    
        }
    
        //main方法进行测试
        public static void main(String[] args) {
            // 获取该类的Class
            Class<ClassTest> clazz = ClassTest.class;
            //返回ClassLoader
            System.out.println(clazz.getClassLoader());
            // 全部构造器
            System.out.println("ClassTest的构造器" + "-----------------");
            Constructor[] ctors = clazz.getDeclaredConstructors();
    
            for (Constructor c : ctors) {
                System.out.println(c);
            }
            System.out.println();
    
            System.out.println("全部public方法"+"------------");
            Method[] meths = clazz.getMethods();
    
            for (Method c : meths) {
                System.out.println(c);
            }
    
            //加载内部类
            Class<?>[] inners=clazz.getDeclaredClasses();
            System.out.println("全部内部类如下:"+"----------");
            for(Class c:inners){
                System.out.println(c);
            }
    
        }
    }



    执行结果如下:

    这里写图片描述

    操作对象

    Class对象可以操作类中的方法、构造器、变量等。
    继续测试上面的例子

          // 操作对象
            System.out.println("操作对象-------");
            try {
                Class<?> class1 = Class.forName("ClassTest");
                ClassTest test = (ClassTest) class1.newInstance();
                System.out.println("调用方法-------");
                test.info();
                test.setId(1);
                test.setName("Sherry");
                System.out.println("增加对象:"+test.toString());
            } catch (ClassNotFoundException | InstantiationException
                    | IllegalAccessException e) {
                e.printStackTrace();
            }

    这里写图片描述

    那些年,我们悄悄用过的

    1、机房收费

    第一次真正接触反射是在做机房收费系统的时候,当时使用的是抽象工厂+反射或者反射+配置文件。回到当年看大话的年代……

    需求:能不能不换DB?

    这里写图片描述

    有没有感觉上面的写法其实跟java中的Class.forName差不多的,毕竟原理是一样的嘛。将程序集、命名空间、类名传入Reflection中,这样做使得配置更加灵活,不需要在写一堆if else,搭配配置文件就更好了。

    2、抽取dao

    在ssh架构中,将增删改查等方法抽取出来做成一个泛型类,运行时动态的传入具体的类。

    抽取的方式:
    1)通过类型

       // 通过反射获取具体对象
       private Class<T> classz;
    
        //由构造函数中确定class
        public DaoSupportImpl() {
    
        // 获取当前new对象的泛型的父类的类型
            ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
            this.classz = (Class<T>) pt.getActualTypeArguments()[0]; // 获取第一个类型参数的真实类型
            System.out.println(classz);
        }

    确定了类之后,CRUD什么的就简单多了,来个例子就好。

    
    //查询所有
    @Override
        public List<T> findAll() {
    
            System.out.println(classz.getSimpleName());
            return getSession().createQuery( //
                    "FROM " + classz.getSimpleName())//
                    .list();
    
        }

    2)通过类名

    //通过构造器注入类名
    public DaoSupportImpl(String className) {
            this.className = className;
        }
    
    // 根据id 查询
        public T findById(Serializable id) {
            Class c = null;
            try {
                c = Class.forName(className);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return (T) this.getHibernateTemplate().get(c, id);
        }
  • 相关阅读:
    cf581B Luxurious Houses
    cf581A Vasya the Hipster
    2015.9.11模拟赛 codevs4162 bzoj1774【无双大王】
    2015.9.11模拟赛 codevs 4160【会玩的】
    2015.9.11模拟赛 codevs 4159【hzwer的迷の数列】
    bzoj2019 [Usaco2009 Nov]找工作
    贪吃蛇!!!
    bzoj3850 ZCC Loves Codefires
    cf509E Pretty Song
    cf509C Sums of Digits
  • 原文地址:https://www.cnblogs.com/saixing/p/6730209.html
Copyright © 2011-2022 走看看