首页 > 编程语言 >Java反射机制详解上篇

Java反射机制详解上篇

时间:2023-06-08 22:04:33浏览次数:53  
标签:反射 Java cn class Class boke 详解 xins08 public


1反射机制是什么

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


在面向对象的世界里,万事万物皆对象.在java语言里,静态的成员,普通数据类型是不是对象呢?

类又是谁的对象呢?

首先类是对象,类是java.lang.Class类的实例对象.

新创建一个Foo类

Foo这个类也是一个实例对象,是Class类的实例对象,这个对象在官网被称为(class type).

反射是java程序开发语言的特性之一,它允许运行中的java程序获取自身的信息,并且可以操作类或者对象内部的属性.

反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

了解反射其实需要了解JVM,不过一般的资料不会在这一部分讲到JVM,毕竟学习也是要从浅入深的.


2反射机制能做什么


反射机制主要提供了以下功能: 

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的方法;
  • 生成动态代理。

注意;是运行时获取而不是编译时获取.其实很多时候我们直接用eclipse写代码忽略了编译的过程

在Eclipse,当我们输入一个点的时候(比如 a.)   编译器就会自动列出它的属性和方法,这里就会用到反射


3反射机制的相关API (在这里只说反射机制五种功能的前两种)

java的反射机制的实现要借助于4个类: class,Constructor,Field,Method;

通过一个对象获得完整的包名和类名

package cn.xins08.boke;public class TestReflect {    public static void main(String[] args) {        TestReflect testReflect = new TestReflect();        System.out.println(testReflect.getClass().getName());        // 结果:cn.xins08.boke.TestReflect    }}


实例化Class对象:


实现反射机制获取类有三种方法:



package cn.xins08.boke;public class TestReflect {    public static void main(String[] args) throws Exception {        Class<?> class1 = null;        Class<?> class2 = null;        Class<?> class3 = null;        //第一种方式(在JDBC开发中常用此方法加载数据驱动)        class1 = Class.forName("cn.xins08.boke.TestReflect");      //第三种方式:java中任何一个对象都有getClass方法        class2 = new TestReflect().getClass();                //第三种方式java中任何一个对象都有class属性        class3 = TestReflect.class;        System.out.println("类名称: " + class1.getName());        System.out.println("类名称: " + class2.getName());        System.out.println("类名称: " + class3.getName());        // 打印结果:        /*         * 类名称: cn.xins08.boke.TestReflect 类名称: cn.xins08.boke.TestReflect 类名称:         * cn.xins08.boke.TestReflect         */    }}


获取一个对象的父类与实现的接口:

package cn.xins08.boke;import java.io.Serializable;public class TestReflect implements Serializable {     private static final long serialVersionUID = -2862585049955236662L;    public static void main(String[] args) throws Exception {                                     Class<?> clazz = Class.forName("cn.xins08.boke.TestReflect");                // 取得父类                Class<?> parentClass = clazz.getSuperclass();                System.out.println("clazz的父类为:" + parentClass.getName());                // clazz的父类为: java.lang.Object                // 获取所有的接口                Class<?> intes[] = clazz.getInterfaces();                System.out.println("clazz实现的接口有:");                for (int i = 0; i < intes.length; i++) {                    System.out.println((i + 1) + ":" + intes[i].getName());                }                // clazz实现的接口有:                // 1:java.io.Serializable            }}


创建实例:

通过反射来生成对象主要有两种方式:

(1)使用Class对象的newInstance()方法来创建Class对象对应类的实例。

Class<?> c = String.class;Object str = c.newInstance();

    初始化一个类,生成一个实例的时候,new与newInstance() 有什么区别?

     区别在于创建对象的方式不一样,前者是使用类加载机制,那么为什么会有两种创建对象方式?这个就要从可伸缩、可扩展,可重用等软件思想上解释了。

newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。
newInstance()是实现IOC、反射、面对接口编程 和 依赖倒置 等技术方法的必然选择,new 只能实现具体类的实例化,不适合于接口编程。


(2)先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。

// 获取String所对应的Class对象        Class<?> c = String.class;        // 获取String类带一个String参数的构造器        Constructor constructor = c.getConstructor(String.class);        // 根据构造器创建实例        Object obj = constructor.newInstance("23333");        System.out.println(obj);



注意事项:反射会额外的消耗一定的系统资源,如果不需要动态的创建一个对象,那么就不需要用反射


在文章的最后我们讨论下工厂模式:

package cn.xins08.boke;public interface Fruit {public void eat();}
package cn.xins08.boke;public class Apple implements Fruit{    public void eat(){        System.out.println("吃苹果");    }    }
package cn.xins08.boke;public class Factory {public static Fruit getInstance(String className){    if("apple".equals(className)){        return new Apple();    }    return null;}}
package cn.xins08.boke;public class FactoryDemo {    public static void main(String[] args) {        Fruit f = Factory.getInstance("apple");        f.eat();    }}//返回的结果是"吃苹果"

这种是一个最简单的工厂设计模式,但是有一个很大的问题是,如果现在接口的子类增加了,那么工厂类肯定需要改.而造成这个问题的病因就是new,如果变成反射机制就不一样了.反射的实例化对象只需要包.类就可以了.

package cn.xins08.boke;public interface Fruit {public void eat();}
package cn.xins08.boke;public class Orange implements Fruit{    public void eat(){        System.out.println("吃橘子");    }    }
package cn.xins08.boke;public class Apple implements Fruit{    public void eat(){        System.out.println("吃苹果");    }    }
package cn.xins08.boke;public class Factory {public static Fruit getInstance(String className){   Fruit fruit = null;try{   //这里是Fruit的类类型,做强制类型转换     fruit = (Fruit) Class.forName(className).newInstance() ;    } catch(Exception e) {       e.printStackTrace();   }       return  f ;       }  }}
package cn.xins08.boke;public class FactoryDemo {    public static void main(String[] args) {        Fruit f = Factory.getInstance("cn.xins08.boke.Apple");        f.eat();    }}



这时候我们发现即使增加几个接口的子类,工厂类照样可以完成对象的实例化操作,可以对应所有的变化.


    到目前为止你已经会了最基本的反射使用了,在学习Spring之前先讲这些,等学习了Spring的依赖注入,反转控制之后,相信会对反射有更好的理解.


关于反射以下功能,等写完后会在本文加链接

  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的方法;
  • 生成动态代理。


--java一万小时成神之路--本文首发与51CTO博客---


近期读书计划:

《思考,快与慢》

《浪潮之巅》

java的反射机制一共分为上下两篇,反射机制下篇请参考:http://xinsz08.blog.51cto.com/10565212/1947327


本文出自 “xinsz08の平行时空” 博客,请务必保留此出处http://xinsz08.blog.51cto.com/10565212/1946912

标签:反射,Java,cn,class,Class,boke,详解,xins08,public
From: https://blog.51cto.com/zmedu/6443541

相关文章

  • Java多态综合案例(包含接口,接口实现类)
    首先定义一个接口名为USB其次定义两个实现类分别名为KeyBorad和Mouse此时就可以使用多态了,因为实现类和接口某种意义上来说是继承关系。USBu=newKeyborad();USBu2 =newMouse();因为键盘和鼠标都具有插拔功能,所以为了方便,把这两个功能写入接口,然后实现类重写。pac......
  • 详解HTML5新特性
    HTML5已经火了一段时间了,相信作为web相关开发工程师,肯定或多或少的了解和尝试过一些HTML5的特性和编程。还记得以前我们介绍过的HTML5新标签。作为未来前端开发技术的潮流和风向标,HTML5绝对不容忽视。在今天这篇技术分享文章中,我们将介绍几个HTML5的重要特性,能够帮助你提高整个w......
  • 反射:获取类的构造器
            ......
  • 反射:获取类的构造器的作用
       ......
  • Git远程操作详解
    Git是目前最流行的版本管理系统,学会Git几乎成了开发者的必备技能。Git有很多优势,其中之一就是远程操作非常简便。本文详细介绍5个Git命令,它们的概念和用法,理解了这些内容,你就会完全掌握Git远程操作。gitclonegitremotegitfetchgitpullgitpush本文针对初级用户,从最简单的讲起,但......
  • 一个Java对象到底占用多大内存?
    一个Java对象到底占用多大内存? 最近在读《深入理解Java虚拟机》,对Java对象的内存布局有了进一步的认识,于是脑子里自然而然就有一个很普通的问题,就是一个Java对象到底占用多大内存?在网上搜到了一篇博客讲的非常好:http://yueyemaitian.iteye.com/blog/2033046,里面提供的......
  • (总结)Web性能压力测试工具之Siege详解
    PS:Siege是一款开源的压力测试工具,设计用于评估WEB应用在压力下的承受能力。可以根据配置对一个WEB站点进行多用户的并发访问,记录每个用户所有请求过程的相应时间,并在一定数量的并发访问下重复进行。siege可以从您选择的预置列表中请求随机的URL。所以siege可用于仿真用户请求负载,而......
  • java分页代码
    现在开始编写 Service 层代码:在 com.game.products.services.iface 包中新建 ProductsService 接口,代码如下:packagecom.game.products.services.iface;importjava.util.List;importcom.game.products.model.Products;publicint......
  • javascript操作xml(增删改查)例子代码
    关键字:javascript操作xml(增删改查)自己做了一个小东西,不是很好,但是对初学来说是一个不错的例子!包括了stu.hta(是HTML应用程序);stu.xml注意下面的HTML代码必须保存为后缀名为hta否则当对XML文件进行操作(增删改)的时候就会提示没有权限!!文件stu.hta代码如......
  • javaScript通用数据类型校验_2
    /*要求:一、电话号码由数字、"("、")"和"-"构成二、电话号码为3到8位三、如果电话号码中包含有区号,那么区号为三位或四位四、区号用"("、")"或"-"和其他部分隔开用途:检查输入的电话号码格式是否正确输入:strPhone:字符串返回:如果通过验证返回true,否......