反射

反射

  类字节码文件是在硬盘上存储的,是一个个的.class文件。我们在new一个对象时,

JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用再加载了,而是直接

使用缓存的这个字节码信息。

  字节码的信息包括:类名、声明的方法、声明的字段等信息。在Java中"万物皆对象",

这些信息当然也需要封装一个对象,这就是Class类、Method类、Field类。

  通过Class类、Method类、Field类等等类可以得到这个类型的一些信息,甚至可

以不用new关键字就创建一个实例,可以执行一个对象中的方法,设置或获取字段的值,

这就是反射技术

 常用方法:

先获得class对象

getConstructors()获取一个类的所有公共的构造方法

getDeclaredConstructors() 获取到一个类的所有构造方法,包括私有的在内 。

getConstructor(int.class,String.class);  // getConstructor 获取单个指定的构造方法。

newInstance()创建一个对象

 

getMethods() 获取所有 的公共方法而已。

getDeclaredMethods(); //获取到所有的方法,但是不包含父类的方法。

 

Method m = clazz.getMethod("eat", int.class);//获取指定方法
m.invoke(p, 3); //invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。

//执行私有的方法

m.setAccessible(true);   //设置访问权限允许访问

 

getDeclaredFields()//获取 到所有的成员变量

Field field = clazz.getDeclaredField("id"); //获取 指定的成员变量

//设置访问权限可以访问
        field.setAccessible(true);
        field.set(p, 110); //第一个参数: 设置该数据 的成员变量, 第二个参数:属性值。
        System.out.println(p);

1.1. Class类

 

1.1.1.  获取Class对象的三种方式

  Java中有一个Class类用于代表某一个类的字节码。

  Java提供了三种方式获取类的字节码

  1.   forName()。forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装

  2.   类名.class

  3.   对象.getClass()

public class Person {
    private int id;

    String name;

    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public Person() {
    }

    public void eat(int num) {
        System.out.println(name + "吃很" + num + "斤饭");
    }

    private static void sleep(int num) {
        System.out.println("明天睡上" + num + "小时");
    }

    public static void sum(int[] arr) {
        System.out.println("长度是:" + arr.length);
    }

    @Override
    public String toString() {
        return " 编号:" + this.id + " 姓名:" + this.name;
    }
}

 

/*
反射: 当一个字节码文件加载到内存的时候,jvm会对该字节码进行解剖,然后会创建一个对象的Class对象,把字节码文件的信息全部都
存储到该Class对象中,我们只要获取到Class对象,我们就可以使用字节码对象设置对象的属性或者调用对象的方法等操作....

注意: 在反射技术中一个类的任何成员都有对应 的类进行描述。  比如:  成员变量(Field)   方法----> Method类  

*/
public class Demo1 {
    Person p;
    public static void main(String[] args) throws ClassNotFoundException {
        //Person p = new Person(110,"狗娃");

        //推荐使用: 获取Class对象的方式一
        Class clazz1 = Class.forName("com.it.reflect.Person");
        System.out.println("clazz1:"+ clazz1);

        //获取Class对象的方式二: 通过类名获取
        Class clazz2 = Person.class;
        System.out.println("clazz1==clazz2?"+ (clazz1==clazz2));

        //获取Class对象的方式三 :通过对象获取
        Class clazz3 = new Person(110,"狗娃").getClass();
        System.out.println("clazz2==clazz3?"+ (clazz2==clazz3));

    }

}

 

1.1.2.  通过Class类获取类型的一些信息

   1. getName()类的名称(全名,全限定名)

   2 getSimpleName()类的的简单名称(不带包名)

   3. getModifiers(); 类的的修饰符

   4.创建对象

      无参数构造创建对象

      newInstance()

   5.getConstructors()获取一个类的所有公共的构造方法

   6. 获取指定参数的构造器对象,并可以使用Constructor对象创建一个实例

    

      Constructor<T> getConstructor(Class<?>... parameterTypes)

/**
     * 通过Class对象获取类的一些信息
     *
     * @throws Exception
     * */
    private static void test2() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        // 获取类的名称
        String name = clazz1.getName();
        System.out.println(name); // cn.itcast.gz.reflect.Person
        // 获取类的简单名称
        System.out.println(clazz1.getSimpleName()); // Person
        // 获取类的修饰符
        int modifiers = clazz1.getModifiers();
        System.out.println(modifiers);
        // 构建对象(默认调用无参数构造.)
        Object ins = clazz1.newInstance();
        Person p = (Person) ins;
        System.out.println(p); // cn.itcast.gz.reflect.Person@c17164
        // 获取指定参数的构造函数
        Constructor<?> con = clazz1.getConstructor(String.class, int.class);
        // 使用Constructor创建对象.
        Object p1 = con.newInstance("jack", 28);
        System.out.println(((Person) p1).getName());
    }

 

1.1.3.  通过Class类获取类型中的方法的信息

  1.获取公共方法包括继承的父类的方法

        getMethods()返回一个数组,元素类型是Method

/**
     * 获取公有方法.
     * @throws Exception
     * */
    private static void test3() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        // 1.获取非私用方法(包括父类继承的方法)
        Method[] methods = clazz1.getMethods();
        System.out.println(methods.length);
        for (Method m : methods) {
            // System.out.println(m.getName());
            if ("eat".equals(m.getName())) {
                m.invoke(clazz1.newInstance(), null);
            }
        }

    }

 

  2.获取指定参数的公共方法

        getMethod("setName", String.class);

/**
     * 获取指定方法签名的方法
     *
     * @throws Exception
     * */
    private static void test4() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        // 获取指定名称的函数
        Method method1 = clazz1.getMethod("eat", null);
        method1.invoke(new Person(), null);
    }

 

/**
     * 获取指定方法名且有参数的方法
     *
     * @throws Exception
     * */
    private static void test5() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        Method method = clazz1.getMethod("eat", String.class);
        method.invoke(new Person(), "包子");
    }

    /**
     * 获取指定方法名,参数列表为空的方法.
     *
     * @throws Exception
     * */
    private static void test4() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        // 获取指定名称的函数
        Method method1 = clazz1.getMethod("eat", null);
        method1.invoke(new Person(), null);
    }

 

  3.获得所有的方法,包括私有

        Method[] getDeclaredMethods() 

/**
     * 反射静态方法
     * @throws Exception
     * */
    private static void test7() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        Method method = clazz1.getMethod("play", null);
        method.invoke(null, null);
    }

    /**
     * 访问私有方法 暴力反射
     * @throws Exception
     * */
    private static void test6() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        Method method = clazz1.getDeclaredMethod("movie", String.class);
        method.setAccessible(true);
        method.invoke(new Person(), "苍老师");
    }

 

  4.获得指定参数的方法,包括私有

        Method getDeclaredMethod(String name, Class<?>... parameterTypes)

1.1.4.  通过Class类获取类型中的字段的信息

  1.获取公共字段

      Field[] getFields() 

  2.获取指定参数的公共字段

      Field getField(String name) 

/**
     * 获取公有的字段
     * */
    private static void test8() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        Field[] fields = clazz1.getFields();
        Person p = new Person();
        System.out.println(fields.length);
        for (Field f : fields) {
            System.out.println(f.getName());
            if ("name".equals(f.getName())) {
                System.out.println(f.getType().getName());
                f.set(p, "jack");
            }
        }
        System.out.println(p.getName());

    }

 

  3.获取所有的字段

      Field[] getDeclaredFields() 

  4.获取指定参数的字段,包括私用

      Field getDeclaredField(String name) 

/**
     * 获取私有的字段
     * @throws Exception
     * */
    private static void test9() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        Field field = clazz1.getDeclaredField("age");
        System.out.println(field.getName());
        field.setAccessible(true);
        Person p = new Person();
        field.set(p, 100);
        System.out.println(p.getAge());
    }

 

时间: 2024-09-10 21:08:08

反射的相关文章

从反射看委托与事件 委托真的是一个类

关于委托与事件,网上介绍得非常之多,在此不再赘述,本人最近需要捣鼓一些委托,因而对委托进行一 定的寻根究底,故用反射把委托的成员揪出来,且看如下代码: delegate void DelegateDemo(); static event DelegateDemo delHandle; static void Main() { delHandle += new DelegateDemo(MyDelegate_delHandle); MemberInfo[] mis = delHandle.GetT

JAVA核心层--反射--动态代理

本文发表于2010年,时间较早,部分问题解释不是十分准确,所以需要进一步了解,请参看2012年版本: java之架构基础-动态代理&cglib 要在JAVA技术上突破普通的层面,并拥有一翻设计理念的高度,除了要有很好的设计思维之外,反射在适当的使用下,将会把框架做得非常清晰,并且代码编写也非常简便. 在面向对象的编程中,我们为什么要忌讳去大量使用if else switch语句,因为这样写是将逻辑硬编码了,JAVA的思想就是将其配置化,一旦可配置化后,就逐渐可管理化,并随着产品的成熟逐步实现自动

程序集和反射(二)

上篇文章主要介绍了程序集的内容:程序集和反射(一),时隔这么久,今天终于腾出点时间,把反射部分的知识点给整理一下,不把这个写完,心里总觉得有点堵.对于反射,我相信很多人跟LZ一个德行,不会,所以不用,不用,所以永远不会.      通过System.Reflection命名空间中的类已经System.Type,您可以获取有关已加载的程序集和在其中定义的类型(如类.接口.值类型)的信息.您也可以使用反射在运行时创建类型实例,以及调用和访问这些实例.      程序集包含模块,而模块包含类型,类型又

Android中利用反射技术实现加减乘除

JAVA反射机制定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有 属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取 的信息以及动态调用对象的方法的功能称为java语言的反射机制. Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类: 在运行时构造任意一个类的对象:在运行时判断任意一个类所具有的成员变量和 方法:在运行时调用任意一个对象的方法:生成动态代理. 有时候我们说某个语言具有很强的动态性,有时候我们会区分动态和静态的

结合AJAX和反射Refrection,实现页面无刷执行函数体

ajax|函数|页面|执行 其实做这么个东西没什么具体用途,只是在看到这个帖子和这篇BLOG后来了兴趣,突发其想来试试能不能做个在线的编译器,顺便也研究下ajax和反射: ajax是看很长时间了,比较关注微软的开发包Atlas的动态,也有很多资源: ·MSDN的Atlas 网站 ·ASP.NET "Atlas" 官方网站 ·ASP.NET "Atlas" 预览文档 ·Atlas  快速入门教程 以上几个连接来自思归 的blog,看来他也很关心这项技术: 前面好长一段

C#反射技术的简单操作(读取和设置类的属性)

要想对一个类型实例的属性或字段进行动态赋值或取值,首先得得到这个实例或类型的Type,微软已经为我们提供了足够多的方法. 首先建立一个测试的类 复制代码 代码如下: public class MyClass { public int one { set; get; } public int two { set; get; } public int five { set; get; } public int three { set; get; } public int four { set; ge

谈.NET反射的封装

.NET反射提供了在运行时获取对象类型元数据的途径,使程序可以动态地调用对象的属性.方法.动态性带来的代价是反射调用不像基于静态类型的直接调用那样简洁,且缺乏类型检查机制,失去了IDE智能提示,容易出错:于是,不少朋友尝试对.NET反射进行封装. 这个话题是仁者见仁,智者见智,这里我也谈谈自己对.NET反射封装的思路,请先看下面的示例代码: static void Main(string[] args) { Person liu = new Person("liu", 26); Ref

学习反射中的动态创建对象

Assembly的CreateInstance有三个重载,第一个参数需要是一个字符串表示的完整的类名.第二个参数是一个bool类型,如果为true,表示对第一个参数不区分大小写. 第三个: 影响执行搜索的方式的位屏蔽.此值是 System.Reflection.BindingFlags 中的位标志的组合. // binder: 一个启用绑定.参数类型强制.成员调用以及通过反射进行 MemberInfo 对象检索的对象.如果 binder 为 null,则使用默认联编程序.// args: Obj

简化繁琐的赋值——反射在Jdbc和Struts中的应用

缘起在Jdbc应用中,我们经常需要有这么样的一个Javabean:当我们从数据库里取值时,我们希望把对应的值赋给Javabean,而后再操作Javabean进行各种业务处理:而我们保存数据的时候,也希望把经过业务处理后的值赋给Javabean,再由该Javabean与Jdbc交互,将数据保存在数据库里. 而在Struts应用中,我们经常要跟ActionForm或DynaActionForm打交道,例如从业面取得用户输入的数据,在Struts应用中,我们实际上是从ActionForm中取得数据:而

对.NET Framework 反射的反思

清晰的组件化目标是否因在库间共享过多类型信息而落空?或许您需要高效的强类型化数据存储,但如果每次对象模型发展后都需要更新您的数据库架构,那会耗费很大成本,所以您更愿意在运行时推断出其类型架构吗?您需要交付能接受任意用户对象的组件,并以某种智能化的方式处理它们吗?您希望库的调方者能以编程方式向您说明它们的类型吗? 如果您发现自己在苦苦维持强类型化数据结构的同时,又冀望于最大化运行时灵活性,那么您大概会愿意考虑反射,以及它如何改善您的软件.在本专栏中,我将探讨 Microsoft .NET Fram