zoukankan      html  css  js  c++  java
  • 反射

    反射:在类运行时,能够动态获取并访问其构造结构的机制称为反射机制。

    反射是Java中框架设计的核心,通过对类的构造、属性、方法等数据的获取提供抽象的底层构建

    反射机制:
    反射需要先获得类的class字节码,由JVM类加载器(ClassLoader)负责加载,并在内存中缓存class的内部结构。借助于Java的反射机制允许快速对类的结构数据进行访问和调用

    获得class字节码文件的三种方式:
      1.Object对象的getClass()方法

    获得方式一
    Class<User> userClass = (Class<User>) user.getClass();

      2.类的class静态属性(一个类只有一个class,实例化多次对应的都是同一个class,所以class可以用==进行比较,a.getClass==b.getClass)

    获得方式二
    Class<User> userClass = User.class;

      3.Class.forName(String classPath)的加载(反射应用的核心

    获得方式三  通过类路径访问类的Class信息,在不知道类型的情况下,可以不写泛型
    Class<User> userClass = (Class<User>) Class.forName("com.igeek.pojo.User");

    反射允许获取到类的各种构造结构,包括构造方法、方法、属性、接口、注解等
    反射能够对类完成实例构建,并能对方法进行实例调用

    第三种方法的使用:

    Class objClass = Class.forName(“com.igeek.pojo.User”)
    Object obj = objClass.newInstance()

    获取类的构造方法

    getConstructor(Class<T>… parameterTypes)
    getConstructors()

    获取类的属性

    getField(String fieldName)
    getFields()

    获取类的方法

    getMethod(String methodName,Class<T>…parameterType)
    getMethods()

    获取类的接口

    getInterfaces()

    获取类的超类

    getSuperclass()

    XML
    Extensible Markup Language 可扩展标记语言

    作用:
      1.用于对工程进行外部配置
      2.用于描述复杂格式的数据,对数据进行存储管理
      3.用于跨应用进行数据的交互

    每一个XML文件都以标签的方式进行编写,并且必须要有一个跟标签
    XML中每个标签都称为节点或元素,标签体的文本也是节点元素,称为文本节点

    定义根标签:使用DTD或者是Schema文件来定义XML的内容

    解析XML文档主要有两种方式:
    1.DOM解析
    特点: 将整个XML文档全部加载至内存中,在内存中对文档进行解析
    2.SAX解析
    特点:使用事件驱动方式进行解析,一边读取一边解析

    DOM解析的使用步骤:

    1.DOM4j架包导入:

    File——Project Structures——Libraries——选择DOM所在的位置——OK

    2.创建XML

    Setting——Editor——File and Code templates——"+"——名称为“new.xml”——输入“<?xml version="1.0" encoding="UTF-8"?>”——单击"OK"

    3.新建文件

    新建文件进行new一个new.xml文件

    MyInterfaceA

    package com.igeek;
    
    public interface MyInterfaceA {
    }

    MyInterfaceB

    package com.igeek;
    
    public interface MyInterfaceB {
    }

    Human类

    package com.igeek.pojo;
    
    public class Human {
        public int age;
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }

    User类

    package com.igeek.pojo;
    
    import com.igeek.MyInterfaceA;
    import com.igeek.MyInterfaceB;
    
    //实现了A、B两个接口,继承了Human类
    public class User extends Human implements MyInterfaceA, MyInterfaceB {
        //三个属性
        private int userId;
        private String userName;
        public String password;
    
        //空参构造方法
        public User() {
        }
    
        //带参构造方法
        public User(int userId, String userName, String password) {
            this.userId = userId;
            this.userName = userName;
            this.password = password;
        }
    
        //属性的get 、set方法
        public int getUserId() {
            return userId;
        }
        public void setUserId(int userId) {
            this.userId = userId;
        }
    
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
    }

    获取类的方法

    package com.igeek;
    
    import com.igeek.pojo.Human;
    import com.igeek.pojo.User;
    
    /**
     * 获得class文件
     * 反射是基于Class类型访问的
     * Class对象封装缓存了类的数据结构
     */
    public class Demo1 {
    
        public static void main(String[] args) {
            User user = new User();
            Human human = new User();
    
            //获得方式一:返回值为Class,不写泛型默认为object类型,写了泛型就要进行强转
         //将类实例化以后对对象进行获取class处理
    
            Class<User> userClass = (Class<User>) user.getClass();
    
            //获得方式二:不用对类进行实例化,直接对类进行获取class处理
            Class<User> userClass = User.class;
    
         //获得方式三 通过类路径访问类的Class信息
            try {
                //这个方法是因为:这个方法是可以在不明确类型和其结构时使用,
           (第一个方法都已经将对象实例化出来了,不需要使用反射。)
    Class<User> userClass = (Class<User>) Class.forName("com.igeek.pojo.User"); } catch (ClassNotFoundException e) { e.printStackTrace(); }     //上面两种(第一种和第二种获取class方法)方式主要用于多态场景下的类型匹配
    if(human instanceof User){ System.out.println("human的实例类型是user类型"); } if(human.getClass() == User.class){ System.out.println("human的实例类型是user类型"); } } }

    第三种获取class方法的应用:

    package com.igeek;
    
    import com.igeek.pojo.User;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    /**
     * 使用反射解析类的数据结构
     */
    public class Demo2 {
    
        public static void main(String[] args) {
    
            try {
                //获得类的Class对象(第三种方法),该对象封装了类的数据结构信息
                Class objClass =  Class.forName("com.igeek.pojo.User");
                //使用反射将类进行实例化
                //该方式只能通过类的无参构造进行实例化
                Object obj = objClass.newInstance();
                System.out.println("实例化后的结果:"+obj);
    
    
                //获得类的所有的构造方法:返回值是构造方法的数组  构造方法的类型是Constructor类型
                Constructor[] constructors = objClass.getConstructors();
           //可获得私有的构造方法
           Constructor[] constructors=ObjClass.getDeclareConstructors(); System.out.println(
    "该类有"+constructors.length+"个构造方法"); //遍历所有的构造 for (Constructor constructor : constructors) { System.out.println(" -----------------------------"); //获得构造方法的参数数量 int paramCount = constructor.getParameterCount(); System.out.println("构造方法的参数数量:"+paramCount); //获得构造方法的参数类型 Class[] paramClassArray = constructor.getParameterTypes(); for (Class paramClass : paramClassArray) { System.out.print(paramClass.getName()+" "); } } System.out.println(); //根据参数获得指定的构造方法 //获得无参的构造 Constructor constructor1 = objClass.getConstructor(); System.out.println(constructor1); //根据构造方法来实例化对象 Object obj1 = constructor1.newInstance(); System.out.println(obj1); //获得带参构造方法:通过参数的class获取指定的构造方法
           //基本类型和包装类的class是不同的
    Constructor constructor2 = objClass.getConstructor(int.class,String.class,String.class); //使用带参的构造方法实例化对象
           //可以用Object接收
           Object obj2=constructor2.newInstance(100,"tom","123");
           //也可强转后用User接收 User user = (User) constructor2.newInstance(100,"tom","123"); System.out.println(user.getUserId()+" "+user.getUserName()+" "+user.getPassword()); //获得当前类的父类 Class superClass = objClass.getSuperclass(); System.out.println(" ------------父类------------");
           //若结果是Object则这个类没有手动进行extends继承 System.out.println(superClass);
    //获取实现的接口 Class[] interfaceClasses = objClass.getInterfaces(); System.out.println(" ---------实现的接口---------"); for (Class interfaceClass : interfaceClasses) { System.out.println(interfaceClass.getName()); }

    //获得属性 //访问当前允许访问(具有访问权限)到的属性,包括父类继承得到的属性
           (不同包中加了protect或者加了private或者没加访问修饰符的都没有访问权限)
    Field[] fields = objClass.getFields(); //访问当前类(本类)直接声明的属性,不论访问修饰符是什么 Field[] fields = objClass.getDeclaredFields(); System.out.println(" ------------属性-------------"); for (Field field : fields) { //获得属性的名称 System.out.println("属性名称:"+field.getName()); //获得属性的类型 System.out.println("属性类型:"+field.getType()); } System.out.println(" -------------------------------"); //获得指定名称属性 Field nameField = objClass.getDeclaredField("userName"); //为属性提供访问权限,即使是私有属性也将允许访问处理 nameField.setAccessible(true); //属性进行赋值,第一个参数表示该属性从属的对象,第二个参数表示要设置的值 //set方法允许对属性进行赋值,但是会根据属性本身的访问修饰符来决定是否可以成功操作
           (paivate时不能被set,但是setAccessible后即可不管是什么访问修饰符都可以进行设置可以访问处理)
    nameField.set(user,"jack"); //System.out.println(user.getUserName()); //获取属性的值 Object value = nameField.get(user); System.out.println(value); System.out.println("--------------方法的访问-------------");
           //获取所有方法,包括私有的
           Method[] methods=objClass.getDeclareMethods();
           //获取所有方法 Method[] methods
    = objClass.getMethods(); for (Method method : methods) { //获取方法的名称 System.out.println("方法名:"+method.getName()); //获取返回值类型 Class returnClass = method.getReturnType(); System.out.println("返回值类型:"+returnClass); //获取方法的参数类型 Class[] paramClassArray = method.getParameterTypes(); System.out.println("方法的参数:"); for (Class paramClass : paramClassArray) { System.out.println(paramClass); } System.out.println("------------------"); } //获取一个指定名称的方法:第一个参数是方法的名称,第二个参数是参数的类型,可以多个可以一个可以没有 Method setMethod = objClass.getMethod("setUserName", String.class); //使用反射调用方法(修改原内容):第一个参数是代表修改的哪个对象中的内容,第二个参数是要修改成的值 setMethod.invoke(user, "admin"); Method getMethod = objClass.getMethod("getUserName"); //调用方法(获得返回值):返回值是Object类型,如果调用的方法没有返回值,则返回的值null Object returnValue = getMethod.invoke(user); System.out.println("返回值是:"+returnValue); } catch (Exception e) { e.printStackTrace(); } } }

    例子:

    使用反射动态解析javax.swing.JFrame类

    使用反射实例化该对象

    使用反射动态解析该类的构造方法,获得构造方法的参数数量和类型

    并使用无参构造以及带有String的构造
    方法来实例化JFrame对象

    package Demo1;
    import java.lang.reflect.Constructor;
    
    public class Demo {
        public static void main(String[] args) {
            //获取类方法
            try {
                Object objClass=Class.forName("javax.swing.JFrame");
                //使用反射实例化该对象
                Object obj=((Class) objClass).newInstance();
                System.out.println("实例化后的对象是:"+obj);
    
                //使用反射动态解析该类的构造方法,获得构造方法的参数数量和类型
                Constructor[] constructors=((Class) objClass).getConstructors();
                System.out.println("共有"+constructors.length+"个构造方法");
                //获得构造方法的参数数量和类型
                for (Constructor constructor : constructors) {
                    //获取参数数量
                    int count=constructor.getParameterCount();
                    System.out.println("该构造方法有"+count+"个参数");
                    //获取参数类型
                    Class[] classes=constructor.getParameterTypes();
                    for (Class aClass : classes) {
                        System.out.println(aClass.getName()+"	");
                    }
                }
                //使用无参构造
                Constructor con1=((Class) objClass).getConstructor();
                Object Obj1=con1.newInstance();
                System.out.println("无参构造实例化对象是:"+Obj1);
    
                //带有String的构造
                Constructor con2=((Class) objClass).getConstructor(String.class);
                Object Obj2=con2.newInstance("我是一个标题");
                System.out.println("带参构造实例化对象是:"+Obj2);

    若是想要获得父类和子类所以的属性,则需要进行递归,先对子类进行属性的获得,然后获得子类的父类,如果不是Object类型,则使用递归将父类传入继续进行属性的获得

     XML的使用:

    根标签:(user是标签名称,    id是标签属性,   1001是标签值,     userName和password是标签体的内容)

    XML中每个标签都称为节点或元素,标签体的文本也是节点元素,称为文本节点

    (紫色标记的都是节点,红色标记的都是文本加点,所以一共11个节点)

    框架中灵活处理的内容都要写成配置文件,通过底层代码对配置文件进行解析,解析完成后通过反射进行处理调用

    <?xml version="1.0" encoding="UTF-8"?>
    //相当于集合存储用户信息 <users>   //用户一   <user id="1001" age=20>     //标签体(标签内容)     <userName>tom</userName>     <password>tom123</password>   </user>   //标签二:用户二   <user id="1002" age=21>     //标签体(标签内容)     <userName>jack</userName>     <password>jack123</password>   </user> </users>
    package com.igeek;
    
    import org.dom4j.Attribute;
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    import java.util.List;
    
    /**
     * 使用DOM4J对XML文档进行解析
     */
    public class Demo3 {
    
        public static void main(String[] args) {
    
            //使用ClassLoader获取资源是在类路径(src文件夹内)中访问的
            //System.out.println(Demo3.class.getClassLoader().getResource("").getPath());
            //使用类自身Class对象获取资源是在类所在的包路径中访问的
            //System.out.println(Demo3.class.getResource("").getPath());
            //从类路径中访问文件并将文件转换为输入流
            //System.out.println(Demo3.class.getClassLoader().getResourceAsStream("test.xml"));
            try {
                //创建SAX解析器对象
                SAXReader reader = new SAXReader();
                //通过获取xml文件的输入流,加载文档
           //通过类的class获取classLoader ,在通过classLoader读取文件的输入流
           //这个方式是从当前类所在的包中查询test.xml文件
           //Document document=reader.read(Dome3.class.getClass().getResourceAsStream("test.xml"));
           //这个方式是从整个项目的路径中查询test.xml文件 Document document = reader.read(Demo3.class.getClassLoader().getResourceAsStream("test.xml")); //获取文档的根节点对象 Element root = document.getRootElement(); //访问节点的名字 System.out.println(root.getName()); //访问节点中的所有下一层子节点 List<Element> list = root.elements();//获取的是数组:所有的节点 //遍历user标签 for (Element element : list) { System.out.println(element.getName()); //访问标签的所有属性,也可以通过attribute通过名称获取单独的一个属性 List<Attribute> attributeList = element.attributes();//得到的是集合所有的属性 //遍历属性(属性的类型是:Attibute标签的类型是:Element for (Attribute attribute : attributeList) { //获取属性的名称 System.out.print(" "+attribute.getName()+":"); //获取属性的值 System.out.println(" "+attribute.getValue()); } //获得指定的userName子标签 Element nameNode = element.element("userName"); System.out.println(" "+nameNode.getName()); //获取userName的标签体文本:trim是去除空格(如果只是需要查找不需要操作,也可以不用接收直接打印) String name = nameNode.getTextTrim(); System.out.println(" "+name); //获取password子标签 Element pwdNode = element.element("password"); System.out.println(" "+pwdNode.getName()); System.out.println(" "+pwdNode.getTextTrim()); } } catch (DocumentException e) { e.printStackTrace(); } } }
  • 相关阅读:
    deleted
    deleted
    HDU
    FZU 1901 Period II(KMP中的next)题解
    HDU 3374 String Problem(最大最小表示+KMP)题解
    HDU 4300 Clairewd’s message(扩展KMP)题解
    POJ 2923 Relocation(状压DP+01背包)题解
    HDU 4272 LianLianKan (状压DP+DFS)题解
    POJ 1185 炮兵阵地(状压DP)题解
    POJ
  • 原文地址:https://www.cnblogs.com/gfl-1112/p/12683069.html
Copyright © 2011-2022 走看看