Java反射-再次认识

最近的学习发现在很多方面,基础知识掌握的还很不牢固,所以对于架构、知识点等属于那种问啥啥知道,做啥啥不出来的那种类型。前些日子,老师一直在抓基础,做什么都要从最简单的demo开始,只有懂了原理之后再去用一些高深的东西如框架等才会理解的更深刻。现在首先需要理解的就是基本上每个Java框架都在用的反射技术。

要想理解反射,首先得了解类的加载过程,看下图:

我们的源代码经过编译之后变成字节码,然后在JVM中运行时通过类加载器加载字节码在内存中生成Class类对象,这个Class类对象内包含有field对象(类的成员变量生成)、constructor对象(类的构造方法生成)和method对象(类的方法生成)。当我们拿到一个类或者对象的时候就可以通过反射对它们进行操作,下面再来看反射:

  • 什么是反射

    •  Java反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力,是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。

      Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。

  • 反射用在哪儿
    • 多用于框架和组件,写出复用性高的通用程序。

      • 如struts的form只要有了form对象和 property名字就可以利用反射给property赋值和取值 对这类操作 一个方法就可以搞定。如果hibernate不用字段进行反射映射 那么每个HQL的编译和结果处理 将无法进行等等。
  • 怎么用
    • 针对我们所知的不同情况分别有3种方法获取Class字节码对象

      • 当已知类名的时候,通过 “类名.class”获得
      • 当已知对象的时候,通过 “对象.getClass”获得
      • 当已知包括包名在内的完整类名(假设为String格式)的时候,可通过 “Class.forName(String)”获得
    • 获取Class字节码对象之后可以构造对象实例、获取对象中的属性对象、方法对象和构造函数对象
    • 获取以上需要的各种对象之后就可以操作它们,进行增删改查等操作了。
  • 优点与缺点是什么
    • 优点

为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念,

静态编译:在编译时确定类型,绑定对象,即通过。

动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,用以降低类之间的藕合性。

一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中 它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。

    • 缺点

它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。

  • 例子

    • 获取Class字节码对象的方法
<span style="font-size:18px;"><span style="font-size:14px;">/**
	 * 获取字节码Class对象的方法
	 * @throws ClassNotFoundException
	 */
	@Test
	public void demo1() throws ClassNotFoundException{
		//获取Class对象三种方式

		//1.已知类
		Class  c1 = ReflectTest.class;

		//2.已知对象
		Object o = new ReflectTest();
		Class c2 = o.getClass();

		//3.未知类和对象,知道完整类名
		String className = "com.lc.reflect.ReflectTest";
		Class c3 = Class.forName(className);

		System.out.println(c1);
		System.out.println(c2);
		System.out.println(c3);
	}</span></span>
    • 操作构造方法
<span style="font-size:18px;"><span style="font-size:14px;">/**
	 * 获取构造方法练习
	 * @throws Exception
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Test
	public void demo2() throws Exception{

		//获取的Person类字节码对象
		String className = "com.lc.reflect.Person";
		Class c = Class.forName(className);

		//通过字节码对象获得所有的构造方法
		Constructor[] constructors = c.getConstructors();
		for (int i = 0; i < constructors.length; i++) {
			System.out.println(constructors[i]);
		}

		//获取指定的构造方法
		Constructor constructorDefault = c.getConstructor();
		System.out.println(constructorDefault);
		//Sring.class为String的字节码对象
		Constructor constructor = c.getConstructor(String.class); //带参数类型为String的构造方法
		System.out.println(constructor);

		//创建对象实例的正常写法:
		Person person1 = new Person();
		Person person2 = new Person("lc");

		//使用反射构造Person对象的实例
		Person reflectPerson1 = (Person)constructorDefault.newInstance();  //无参构造方法
		Person reflectPerson1_1 = (Person)c.newInstance();  //通过Class对象直接newInstance,将会默认调用目标类无参构造方法
		Person reflectPerson2 = (Person)constructor.newInstance("lc");//参数为String类型的构造方法

	}</span></span>
    • 操作成员变量
<span style="font-size:18px;"><span style="font-size:14px;">/**
	 * 使用反射操作类成员变量的练习
	 */
	@SuppressWarnings("rawtypes")
	@Test
	public void demo3() throws Exception{

		//面向对象的写法是对象调用属性,而反射就正好相反了。。
		Person p = new Person("lc");
		System.out.println("对象调用属性的写法=====>:"+p.getName());

		//使用反射操作类成员变量 --Field类
		//1.必须获得目标类的字节码对象
		Class c = Class.forName("com.lc.reflect.Person");

		//2.操作成员实例变量name--获得name代表Field对象
		Field[] f1 = c.getFields(); //获取所有public成员变量,包括父类继承
		for (int i = 0; i < f1.length; i++) {
			System.out.println(f1[i]);
		}
		Field[] f2 = c.getDeclaredFields(); //获取当前类定义的所有成员,包括private
		for (int i = 0; i < f2.length; i++) {
			System.out.println(f2[i]);
		}

		//获得name成员变量
		Field field = c.getDeclaredField("name"); //当前field是private
		//设置private变量可以访问
		field.setAccessible(true);

		//获得p对象指定name属性值
		Object value = field.get(p); //相当于p.getName();
		System.out.println("反射操作成员变量的写法=====>"+value);

	}

	/**
	 * 使用反射改变成员变量的值(包括私有)
	 * @throws Exception
	 */
	@Test
	public void demo4() throws Exception{
		Person p = new Person();
		//调用p对象中setName设置name的值
		//1.获取字节码对象
		Class c = Class.forName("com.lc.reflect.Person");
		//2.操作setName获得setName对象反射对象的Method对象
		//String类型参数setName方法
		Method setName = c.getDeclaredMethod("setName", String.class);
		//调用p对象中setName
		setName.invoke(p, "sky"); //相当于p.setName("sky");
		//3.读取name的值getName方法
		Method getName = c.getDeclaredMethod("getName");
		Object name = getName.invoke(p); //相当于p.getName();
		System.out.println("反射获取成员变量的值======>"+name);
	}</span></span>
    • 操作普通方法
<span style="font-size:18px;"><span style="font-size:14px;">/**
	 * 操作方法对象
	 * @throws Exception
	 */
	@Test
	public void demo5() throws Exception{
		//已知String类型完整类名---获得字节码对象
		String className = "com.lc.reflect.Person";
		Class c = Class.forName(className);

		//已知Class对象,构造实例
		Object obj = c.newInstance(); //调用无参构造方法

		//获得字节码对象中指定属性和方法
		//获得name属性
		Field f = c.getDeclaredField("name");
		//获得setName方法
		Method setName = c.getDeclaredMethod("setName", String.class);

		//修改属性的值,执行相应方法
		f.setAccessible(true);
		f.set(obj, "sky");

		setName.invoke(obj, "sky_lc");

		//以上代码等价于下面的代码
		Person p = new Person();
		//p.name = "sky";
		p.setName("sky_lc");
	}</span></span>

Java语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象,无需提前硬编码目标类。这些特性使得反射特别适用于创建以非常普通的方式与对象协作的库。Java reflection 非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中操作这些信息。Java 的这一特性非常强大,并且是其它一些常用语言,如 C、C++、Fortran 或者 Pascal 等都不具备的。

由于用于字段和方法接入时反射要远慢于直接代码,反射在性能上会有所影响,但性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。所以,合理的使用反射将大大提高我们程序的通用性和复用性。

时间: 2024-10-10 08:25:23

Java反射-再次认识的相关文章

黑马程序员-Java 反射

--Java培训.Android培训.iOS培训..Net培训.期待与您交流!-- 一.概述 Java 反射机制是在运行状态中,对于程序中的任意一个类,通过反射机制都能够知道这个类的所有属性和方法,包括共有.包含.默认和私有.对于任意的一个对象,通过反射机制都可以去调用它的每一个方法,这种机制就称为Java的反射机制.一般的操作都在java.lang.reflect包中,常用到的类有Constructor,Field和Method三种.既然是对Java类的反射,当然也有个比不可少的类Class,

java 反射机制 观点

反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧! 一,先看一下反射的概念: 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接.但是反射使用不当会成本很高! 看概念很晕的,继续往下看. 二,反射机制的作用:

java反射机制(1)

反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧! 一,先看一下反射的概念: 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射是java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接.但是反射使用不当会成本很高! 看概念很晕的,继续往下看. 二,反射机制的作用:

利用java反射机制 读取配置文件 实现动态类加载以及动态类型转换

作者:54dabang 在spring的学习过程之中,我们可以看出通过配置文件来动态管理bean对象的好处(松耦合 可以让零散部分组成一个整体,而这些整体并不在意之间彼此的细节,从而达到了真正的物理上的疏散耦合,而非逻辑,有了IOC之后,我们可以让SPRING充当各框架中的整合器,把技术框架进行完美的结合). Spring实现的一个重要的机制是通过反射(java.lang.reflect)读取配置文件,通过配置文件来动态生成配置文件中的类对象.Java动态加载类主要是为了不改变主程序代码,通过修

java反射教程

什么是反射,为什么它是有用的,以及如何使用它? 1.什么是反射? "反射通常是JVM中运行的程序需要检测和修改运行时程序的行为的一种能力."这个概念通常与内省(Introspection)混淆.以下是这两个术语在维基百科中的定义: 内省是指计算机程序在运行时检查对象类型的一种能力,通常也可以称作运行时类型检查. 反射是指计算机程序在运行时可以访问.检测和修改它本身状态或行为的一种能力. 从他们的定义可以看出,内省是反射的一个子集.有些语言支持内省,但不支持反射,如C++. 内省例子:i

Java进阶 六 Java反射机制可恶问题NoSuchFieldException

作为一种重要特性,Java反射机制在很多地方会用到.在此做一小结,供朋友们参考. 首先从一个问题开始着手. 可恶的问题又来了,NoSuchFieldException,如下图所示: 完全不知道这个question是从哪里来的.以前也遇到过这样的问题,后来解决了,但是没有写文档,再次相遇这样的问题,傻了. 经过上网一番查找,发现遇到这个问题的小盆友还真不少,这个问题是属于java反射机制里的. 这是一个反射对象时候的异常,已经被捕获了的.这个报错代码是混淆了的,是不是这个question对象被混淆

Java反射

1. 介绍 反射是一种能够在程序运行时动态访问.修改某个类中任意属性和方法的机制. 具体:对于任意一个类,都能够知道这个类的所有属性和方法对于任意一个对象,都能够调用它的任意一个方法和属性 在运行时,当加载完类之后,JVM在堆内存中会自动产生一个Class类型的对象,这个对象包含了完整的类的结构信息 这个Class对象就像一面镜子,透过这个镜子看到类的结构 那么,如何得到这个Class对象呢?以下可否 Class c = new Class(); 答案是不行的,因为Class的构造函数定义为私有

Java 反射详解

反射反射,程序员的快乐,今天你快乐了吗?如果你不快乐,没关系,接下来让你快乐起来! 一.什么是反射? 通过百度百科我们可以知道,Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:并且能改变它的属性.而这也是Java被视为动态(或准动态,为啥要说是准动态,因为一般而言的动态语言定义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言.从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C

java反射机制(一)—— 利用反射机制实例化对象

一.Java有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载.探知.使用编译期间完全未知的classes.换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体.或对其fields设值.或唤起其methods.(度娘文库是这么说的) 二.这篇文章主要介绍一下通过反射机制去实例化一个类的对象,然后调用其方法.本文主要介绍两种方式,第一种就是通过构造函数来实例化,第二种就是通过Cl