Java的动态加载和反射

什么是动态加载?静态呢?    

    new创建对象的方式称作为静态加载,而使用Class.forName("XXX")称作为动态加载,它们俩本质的区别在于静态加载的类的源程序在编译时期加载(必须存在),而动态加载的类在编译时期可以缺席(源程序不必存在)。

哪些语言是静态的?哪些是动态的?
    

    程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。
    从这个观点看,Perl,Python,Ruby是动态语言,而C++,Java,C#不是动态语言。
    但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。


什么是反射?


    Reflection 是 Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时 通过 Reflection APIs 取得任何一个已知名称的 class 的内部信息,包括其 modifiers(诸如 public, static 等等)、superclass(例如 Object)、实现的 interfaces,也包括 fields 和 methods 的所有 信息,并可于运行时改变 fields内容或调用 Constructor,methods。
    
    简而言之,JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

    
原来的加载用的好好的,为什么要使用反射?             


    动态加载最大限度体现了程序的灵活性,降低了类之间的耦合性。方便了框架和其他的使用。或者游戏更新的时候,不可能将游戏删除重新下载,只是下载更新包,然后由游戏程序运行时动态加载代码文件,得到更新的代码编译,这就用到了反射。反射的目的就是为了扩展未知的应用。
    
    反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。

话不多说。进入ctrl + v 贴代码模式测试。

为了更好的使用反射,这里写了两个类用来熟悉动态加载。

被加载类

准备了公有的属性、构造方法、无参方法以及有参数的方法,还有私有的属性、构造方法、无参方法以及有参数的方法。

package com.example.反射;

public class One {
	
	public int a = 1;
	private int b = 2;
	
	public One() {}
	
	private One(int a) {
		System.out.println("私有构造方法");
	}
	
	public void demo1() {
		System.out.println("调用公有方法demo1");
	}
	
	private void demo2() {
		System.out.println("调用私有方法demo2");
	}
	
	public void demo3(int a) {
		System.out.println("调用有参数的公有方法demo3,参数为"+a);
	}
	
	private void demo4(int b) {
		System.out.println("调用有参数的私有方法demo4,参数为"+b);
	}
}

测试

1    首先是对文件class文件进行加载,获得Class文件对象,获取Class文件对象的方法有三种:

     1.Object ——> getClass();
     2.任何数据类型(包括基本数据类型)都有一个“静态”的class属性
     3.通过Class类的静态方法:forName(String  className)(常用),className是'包名.类名'

Class cl = Class.forName("com.example.反射.One");

2    获取Class对象的构造方法,通过class对象 cl 调用方法获取构造方法 

    *    这里需要用到Constructor类,Constructor 提供关于类的单个构造方法的信息以及对它的访问权限

        *    setAccessible(true)方法表示取消java语言访问检查,在访问私有属性、方法之类时需要使用

			//获得公有的构造方法
			Constructor con1 = cl.getConstructor();
			System.out.println("调用公有"+con1);
			//获得私有的构造方法
			Constructor con2 = cl.getDeclaredConstructor(int.class);
			con2.setAccessible(true);
			System.out.println("调用私有"+con2);

3    创建 Class类对象,也可以说是上面创建的Class文件对象的对象

    *    创建Class类的对象时,可以通过构造方法创建,也可以通过Class文件对象创建。

			// 创建类的对象,这里通过Class文件对象创建
			Object obj = cl.newInstance();

     *   通过构造方法创建,自定义的构造方法创建对象时可以传入参数。

			Object obj1 = con1.newInstance();
			Object obj2 = con2.newInstance(5);

4    获得Class类的属性,通过Class类的对象 cl 获得属性

    *    getField()是获得public修饰的属性,getDeclaredField()是获得已经声明的属性(包括public,private,default,protected)

     *     getFields(),getDeclaredFields()返回一个属性集 

			//公有属性
            Field field1 = cl.getField("a");
			System.out.println(field1.get(obj));//得到变量的值
			//私有属性
			Field field2 = cl.getDeclaredField("b");
			field2.setAccessible(true);//该方法表示取消java语言访问检查
			
            //field2.set(obj, 5);//这里可以给变量重新赋值
			
            System.out.println(field2.get(obj));

 5    获取Class类的无参方法以及调用

    *    getMethod()是获得public修饰的方法,getDeclaredMethod()是获得已经声明的方法(包括public,private,default,protected​​​​​​​)

    *     getMethods(),getDeclaredMethods()返回一个方法集

    *    调用方法时通过方法对象找到Class类的对象

			// 获取类对象的无参公有方法
			Method m1 = cl.getMethod("demo1");

			//无参私有方法
			Method m2 = cl.getDeclaredMethod("demo2");
			m2.setAccessible(true);//该方法表示取消java语言访问检查	
		
			// 调用方法
			m1.invoke(obj);
			m2.invoke(obj);

 6    获取Class类的有参方法以及调用

			//有参公有方法
			Method m3 = cl.getMethod("demo3",int.class);
			//有参私有方法
			Method m4 = cl.getDeclaredMethod("demo4", int.class);
			m4.setAccessible(true);
						
			//调用方法
			m3.invoke(obj,2);
			m4.invoke(obj, 10);

    Java的反射是框架的基础,也用于程序的更新,这些都归功于Java可以实现动态创建对象和编译。但并不是Java反射是完美的,相反,有利就有弊。反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作

猜你喜欢

转载自blog.csdn.net/weixin_42621338/article/details/82684289