• Java反射概念与基础


    反射机制是Java动态性之一,而说到动态性首先得了解动态语言。那么何为动态语言?

    一、动态语言


    动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化。比如常见的JavaScript就是动态语言,除此之外Ruby,Python等也属于动态语言,而C、C++则不属于动态语言。

    二、Java是动态语言吗?


    从动态语言能在运行时改变程序结构结构或则变量类型上看,Java和C、C++一样都不属于动态语言。 
    但是JAVA却又一个非常突出的与动态相关的机制:反射机制。Java通过反射机制,可以在程序运行时加载,探知和使用编译期间完全未知的类,并且可以生成相关类对象实例,从而可以调用其方法或则改变某个属性值。所以JAVA也可以算得上是一个半动态的语言。

    三、反射机制:


    1.反射机制概念 
    在Java中的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能成为Java语言的反射机制。

    2.反射的应用场合 
    在Java程序中许多对象在运行是都会出现两种类型:编译时类型和运行时类型。 
    编译时的类型由声明对象时实用的类型来决定,运行时的类型由实际赋值给对象的类型决定 
    如:

    Person p=new Student();

    其中编译时类型为Person,运行时类型为Student。 
    除此之外,程序在运行时还可能接收到外部传入的对象,该对象的编译时类型为Object,但是程序有需要调用该对象的运行时类型的方法。为了解决这些问题,程序需要在运行时发现对象和类的真实信息。然而,如果编译时根本无法预知该对象和类属于哪些类,程序只能依靠运行时信息来发现该对象和类的真实信息,此时就必须使用到反射了。

    四、Java反射API


    反射API用来生成JVM中的类、接口或则对象的信息。 
    - Class类:反射的核心类,可以获取类的属性,方法等信息。 
    - Field类:Java.lang.reflec包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。 
    - Method类: Java.lang.reflec包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法。 
    - Constructor类: Java.lang.reflec包中的类,表示类的构造方法。

    五、使用反射的步骤


    1.步骤

    • 获取想要操作的类的Class对象
    • 调用Class类中的方法
    • 使用反射API来操作这些信息

    2.获取Class对象的方法

    • 调用某个对象的getClass()方法
    Person p=new Person();
    Class clazz=p.getClass();
    • 1
    • 2
    • 调用某个类的class属性来获取该类对应的Class对象
    Class clazz=Person.class;
    • 1
    • 使用Class类中的forName()静态方法; (最安全/性能最好)
    Class clazz=Class.forName("类的全路径"); (最常用)
    • 1

    3.获取方法和属性信息

    当我们获得了想要操作的类的Class对象后,可以通过Class类中的方法获取并查看该类中的方法和属性。 
    示例代码

    package reflection;
    
    public class Person {
        private String name;
        private String gender;
        private int age;
    
        public Person() {
    
        }
        public Person(String name, String gender, int age) {
            this.name = name;
            this.gender = gender;
            this.age = age;
        }
        //getter和setter方法
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getGender() {
            return gender;
        }
        public void setGender(String gender) {
            this.gender = gender;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    
        public String toString(){
            return "姓名:"+name+"  性别:"+gender+"  年龄:"+age;
        }
    
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    <<<<<<<<<<<<<<<<使用反射<<<<<<<<<<<<<<<<<<<
    package reflection;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    /*
     * 通过用户输入类的全路径,来获取该类的成员方法和属性
     * Declared获取全部不管是私有和公有
     * 1.获取访问类的Class对象
     * 2.调用Class对象的方法返回访问类的方法和属性信息
     */
    public class Test {
    
        public static void main(String[] args) {
            try {
                //获取Person类的Class对象
                Class clazz=Class.forName("reflection.Person");
    
                //获取Person类的所有方法信息
                Method[] method=clazz.getDeclaredMethods();
                for(Method m:method){
                    System.out.println(m.toString());
                }
    
                //获取Person类的所有成员属性信息
                Field[] field=clazz.getDeclaredFields();
                for(Field f:field){
                    System.out.println(f.toString());
                }
    
                //获取Person类的所有构造方法信息
                Constructor[] constructor=clazz.getDeclaredConstructors();
                for(Constructor c:constructor){
                    System.out.println(c.toString());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }

    输出结果:

    方法信息: 
    public java.lang.String reflection.Person.toString() 
    private java.lang.String reflection.Person.getName() 
    private void reflection.Person.setName(java.lang.String) 
    public void reflection.Person.setAge(int) 
    public int reflection.Person.getAge() 
    public java.lang.String reflection.Person.getGender() 
    public void reflection.Person.setGender(java.lang.String) 
    属性信息: 
    private java.lang.String reflection.Person.name 
    private java.lang.String reflection.Person.gender 
    private int reflection.Person.age 
    构造方法信息 
    private reflection.Person() 
    public reflection.Person(java.lang.String,java.lang.String,int)

    4.创建对象

    当我们获取到所需类的Class对象后,可以用它来创建对象,创建对象的方法有两种:

    • 使用Class对象的newInstance()方法来创建该Class对象对应类的实例,但是这种方法要求该Class对象对应的类有默认的空构造器。
    • 先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建 Class对象对应类的实例,通过这种方法可以选定构造方法创建实例。

    示例代码:

    package reflection;
    
    import java.lang.reflect.Constructor;
    public class Demo01 {
    
        public static void main(String[] args) {
            try {
                //获取Person类的Class对象
                Class clazz=Class.forName("reflection.Person"); 
                /**
                 * 第一种方法创建对象
                 */
                //创建对象
                Person p=(Person) clazz.newInstance();
                //设置属性
                p.setName("张三");
                p.setAge(16);
                p.setGender("男");
                System.out.println(p.toString());
    
                /**
                 * 第二种方法创建
                 */
                //获取构造方法
                Constructor c=clazz.getDeclaredConstructor(String.class,String.class,int.class);
                //创建对象并设置属性
                Person p1=(Person) c.newInstance("李四","男",20);
                System.out.println(p1.toString());
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    
    }

    输出结果:

    姓名:张三 性别:男 年龄: 16 
    姓名:李四 性别:男 年龄: 20

  • 相关阅读:
    一个简单实现的遮罩层
    文字内容过长是自动出现省略号
    Maven入门学习(下)
    Maven入门学习(上)
    使用ODP.NET查询数据参数顺序问题及莫名ORA-01722错误提示
    Xamarin开发Android笔记:TextView行间距设定
    Xamarin开发Android笔记:图片切换ImageSwitcher
    Xamarin开发Android笔记:背景操作
    UI创意求助:手机贪吃蛇游戏方向控制键设计
    做梦想起来的C#简单实现贪吃蛇程序(LinQ + Entity)
  • 原文地址:https://www.cnblogs.com/cat520/p/9472991.html
Copyright © 2020-2023  润新知