java反射

这里先介绍一些概念请大家不要晕

反射机制概念

主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。

反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!

类中有什么信息,利用反射机制就能可以获得什么信息,不过前提是得知道类的名字。

反射机制的作用

  1. 在运行时判断任意一个对象所属的类;

  2. 在运行时获取类的对象;

  3. 在运行时访问java对象的属性,方法,构造方法等。

反射机制的优点与缺点

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

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

学了这么多年java原来这就是java的反射和动态加载类

这里我们通过new进行相关类的实例化,这里如果new的类是不存在的会编译不通过,因为静态需要预先加载进去

如果不存在的话加载不进去也就会报错

假想如下场景,此类中有100个功能,你只想使用A功能,如果你使用的是静态加载的机制,你必须定义其余的99种功能才能使用A功能,如果使用动态加载机制,不仅不用定义99中功能,通过实现某种标准(继承某个接口),将大大方便了代码的编写。

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

public class StaticClassDemo2 {
	public static void main(String[] args) {
		try {
			Class c=Class.forName(args[0]);
			NewStandard me=(NewStandard)c.newInstance();
			me.print();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

public interface NewStandard {
	public void print();
}

public class TestA implements NewStandard {
	@Overridepublic void print() {
		System.out.println("TestA...print");
	}
}

public class TestB implements NewStandard{
	@Overridepublic void print() {
		System.out.println("TestB....print");
	}
}

学了这么多年java原来这就是java的反射和动态加载类

这时候我们使用一个此类就可以完成对所有的功能的引用而不用每一个都去创建

反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。

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

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

最能以简单的例子体现反射的强大之处,但是又感觉没有太具体,在自己思考了许久后,终于想到一个体现这个场景的简单例子。

不用反射:

假设有个生产环境,数据库连接是用的mysql,所以代码应该是这样 ,以伪代码书写,忽略细节

conn =new MysqlConnection()

然而,某一天突然要改成oracle。所以,这时要做的是改成

conn =new OracleConnection()

或者你机灵一点,新建一个配置文件,里面填mysql或oracle,然后代码中取得配置文件的字符串,if是 mysql就 conn =new MysqlConnection() 是oracle就 conn =new OracleConnection,

然后。最重要的是。你要停掉生产环境,重新把java代码用javac编译一遍,再把编译后的class文件把生产环境给起起来。

让我们再来看看用反射,

最开始,如果我们就考虑到会有时切换数据库,我们写成配置文件,然后用Class.forName(str)什么的来new 数据库驱动,更改数据库时就仅需简单的更改配置文件了,这样就不需要重新编译代码了,但好像还需要重新启动生产环境。哦,如果想不重新启动生产环境来切换数据库也是可以的(不考虑任何效率),自行造轮子咯。

这里用反射和不用反射的区别在于,是否要重新编译一遍


原文:https://www.toutiao.com/a6518705921139409411/



在JDK中,提供了以下类来实现Java反射机制,这些类都位于java.lang.reflect包下:

Class类:代表一个类(注意:Class类位于java.lang包下);

Field类:代表类的成员变量;

Method类:代表类的方法;

Constructor类:代表类的构造方法;

Array类:提供了动态创建数组,以及访问数组的元素的静态方法。

通过API提供的这些类里的方法,我们可以动态获取想要的类的内部信息。

另外一点重要的是:

Class类中存在以下几个重要的方法:

1.getName()

一个Class对象描述了一个特定类的特定属性,而这个方法就是返回String形式的该类的简要描述。由于历史原因,对数组的Class对象

调用该方法会产生奇怪的结果。

2.newInstance()

该方法可以根据某个Class对象产生其对应类的实例。需要强调的是,它调用的是此类的默认构造方法。例如:

MyObject x = new MyObject();

MyObject y = x.getClass().newInstance();

3.getClassLoader()

返回该Class对象对应的类的类加载器。

4.getComponentType()

该方法针对数组对象的Class对象,可以得到该数组的组成元素所对应对象的Class对象。例如:

int[] ints = new int[]{1,2,3};

Class class1 = ints.getClass();

Class class2 = class1.getComponentType();

而这里得到的class2对象所对应的就应该是int这个基本类型的Class对象。

5.getSuperClass()

返回某子类所对应的直接父类所对应的Class对象。

6.isArray()

判定此Class对象所对应的是否是一个数组对象。

知道了基本概念后,具体的代码内容:

假设测试类为 TestReflect,对应的路径为 singTest.invoke.TestReflect。

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

TestReflect testReflect = new TestReflect();

System.out.println("===="+ testReflect.getClass().getName());

System.out.println("===="+ testReflect.getClass().getName());

输出内容分别为:

singTest.invoke.TestReflect

class singTest.invoke.TestReflect

【2】 实例化Class类对象

Class<?> class1 = null;

Class<?> class2 = null;

Class<?> class3 = null;

class1 = Class.forName("singTest.invoke.TestReflect");

class2 = new TestReflect().getClass();

class3 = TestReflect.class;

System.out.println("===类名称 1===" + class1);

System.out.println("===类名称 2===" + class2);

System.out.println("===类名称 3===" + class3);

上述三种都是实例化对应的类,输出结果均为:class singTest.invoke.TestReflect。

【3】获取某个类的全部属性

Class<?> clazz = Class.forName("singTest.invoke.TestReflect");

//取得本类中全部属性

//TestReflect 类中属性就是 serialVersionUID 与 test1

Field[] field = clazz.getDeclaredFields();

for(int i=0;i<field.length;i++){

//权限修饰符

int mo = field[i].getModifiers();

System.out.println("==mo=="+mo);

String priv = Modifier.toString(mo);

System.out.println("==priv=="+priv);

//属性类型

Class<?> type = field[i].getType();

System.out.println(priv + " " + type.getName() + " " + field[i].getName() + ";");

}

会输出对应类下所有变量属性,具体可自己操作实验。

【4】通过反射机制调用某个类的方法

Class<?> clazz = Class.forName("singTest.invoke.TestReflect");

//调用 TestReflect 类中的 reflect1 方法

Method method = clazz.getMethod("reflect1");

//调用reflect1 方法

method.invoke(clazz.newInstance());

//输出:Java 反射机制 - 调用某个类的方法1

//调用reflect2方法

method = clazz.getMethod("reflect2",int.class,String.class);

method.invoke(clazz.newInstance(),20,"Tom");

//输出:Java 反射机制-调用某个类的方法2

原文:https://www.toutiao.com/a6514627914544185869/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值