java 反射类的理解与应用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 反射类的理解与应用相关的知识,希望对你有一定的参考价值。

本文主要解析的类是:

ClassLodaer,Class,Field,Method,Constructor.

本文的目标很简单,只是对这些常用的反射类进行简单解释。对这些类中常用方法进行介绍。

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

Class:

public final class Class<T> extends Object implements Serializable, GenericDeclaration, Type, AnnotatedElement

class 的声明表示class是一个终类,是一个对象,并且可序列化。

Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

以下示例使用 Class 对象来显示对象的类名:(利用Object.getClass())

Object obj=new Object();
        
System.out.println(obj.getClass().getName());

 这里注意下getClass() 方法:

public final native Class<?> getClass();

调用了本地方法来获取该类的Class。

class 关键字 和 getClass() 的区别。

public  class Animal{}

public class Dog extends Animal {
    public static void main(String[] args) {
       Animal animal = new Dog();
       System.out.println("getClass():  "+animal.getClass().getName());
       System.out.println("class:  "+Animal.class.getName());
    }
}
 
输出结果
getClass():  com.abc.Dog
class:  com.abc.Animal

由于object.getclass()的方法存在,内存中任意对象都可以获得自身的类型。而反射的是通过对字节码文件进行解析。

反射方法: forName()

@CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

 这是最常用的反射方法。对于一个字节码文件名进行解析,得到class。其中也可以看到,forName()在解析时,类加载器也进行了参与。

ClassLoader是什么?有什么作用?

大家都知道,一个Java程序是由若干个.class文件组织而成的。当程序在运行时,即会调用该程序的一个入口函数来调用系统的相关功能,而这些功能都被封装在不同的class文件当中,所以经常要从这个class文件中要调用另外一个class文件中的方法,如果另外一个文件不存在的,则会引发系统异常。而程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,通过Java的类加载机制(ClassLoader)来动态加载某个class文件到内存当中的,从而只有class文件被载入到了内存之后,才能被其它class所引用。所以ClassLoader就是用来动态加载class文件到内存当中用的。

 

类加载器所创建对象的方法和构造方法可以引用其他类。为了确定引用的类,Java 虚拟机将调用最初创建该类的类加载器的 loadClass 方法。

例如,应用程序可以创建一个网络类加载器,从服务器中下载类文件。示例代码如下所示:

   ClassLoader loader = new NetworkClassLoader(host, port);
   Object main = loader.loadClass("Main", true).newInstance();

 (classLoader的相关知识点,不在本文中进行梳理。)

 Class.forName(String className);

有效类名称的示例包括:(package.className)

   "java.lang.String"
   "javax.swing.JSpinner$DefaultEditor"
   "java.security.KeyStore$Builder$FileBuilder$1"
   "java.net.URLClassLoader$3$1"

Class.forName(String className) 需抛出异常:ClassNotFoundException。

 

Class clazz=Class.forName("testReflect.ATest");
System.out.println(clazz.getClass().getName());
System.out.println(clazz.getClassLoader());
			
Object obj=clazz.newInstance();
System.out.println("此对象是"+obj.getClass().getName());

输出结果
java.lang.Class
[email protected]
此对象是testReflect.ATest

 后面所介绍类采用代码介绍

被用来反射的类

package testReflect;

public class ATest {
	
	private int field1=1;
	public String field2="field2";
	
	private int method1(){
		return 1;
	}
	
	public String method2(String a){
		return "method2";
	}
	
	public ATest(){}
	
	public ATest(int b){}
	

}

  

测试类

package testReflect;


import java.lang.reflect.*;

public class Main {
	
	
	
	
	public static void main(String[] args) {
		
		
		
		try {
			Class clazz=Class.forName("testReflect.ATest");
			System.out.println(clazz.getClass().getName());
			System.out.println(clazz.getClassLoader());
			
			Object obj=clazz.newInstance();
			System.out.println("此对象是"+obj.getClass().getName());
			
			/**
			 * class 中获取field 的方法为
			 * 1.getDeclaredField("field1");
			 * 2.getDeclaredFields(); 返回 Field 对象的一个数组,这些对象反映此 Class 
			 * 对象所表示的类或接口所声明的所有字段。包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段。
			 * 3.getFields();
			 * 4.getFields("field2");
			 * 
			 * 
			 * 
			 * */
			
			Field field1=clazz.getDeclaredField("field1");
			field1.setAccessible(true);
			System.out.println(field1);
			System.out.println(field1.getName()+":"+field1.get(obj));
			
			Field[] fields1=clazz.getFields();
			Field[] fields2=clazz.getDeclaredFields();
			
			System.out.println(fields1.length);
			System.out.println(fields2.length);
			
			
			Method method1=clazz.getDeclaredMethod("method1", null);
			
			method1.setAccessible(true);
			System.out.println(method1);
			Object value1=method1.invoke(obj, null);
			System.out.println("method1 返回的值为"+value1);
			
			
			Method method2=clazz.getDeclaredMethod("method2",String.class);
			System.out.println(method2);
			System.out.println(method2.getParameterTypes().length);
			System.out.println("method2 返回的值为"+method2.invoke(obj,"1"));
			
			Method[] methods1=clazz.getDeclaredMethods();
			//返回的方法数组,方法的顺序并不确定
			
			for(int i=0;i<methods1.length;i++){
				System.out.println(methods1[i]);
				if("method2".equals(methods1[i].getName()))
						System.out.println("method2的参数列表"+methods1[i].getParameterTypes());
			}
			
			
			Constructor cons1=clazz.getDeclaredConstructor(null);
			
			Constructor cons2=clazz.getDeclaredConstructor(int.class);
			
			System.out.println(cons1);
			System.out.println(cons2);
			
			Object o1=cons2.newInstance(1);
			System.out.println(o1.getClass());
			
			
			
			
		} catch (ClassNotFoundException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		
	}
}




 

输出结果:
java.lang.Class
[email protected]
此对象是testReflect.ATest
private int testReflect.ATest.field1
field1:1
1
2
private int testReflect.ATest.method1()
method1 返回的值为1
public java.lang.String testReflect.ATest.method2(java.lang.String)
1
method2 返回的值为method2
private int testReflect.ATest.method1()
public java.lang.String testReflect.ATest.method2(java.lang.String)
method2的参数列表[Ljava.lang.Class;@52e922
public testReflect.ATest()
public testReflect.ATest(int)
class testReflect.ATest

本文的目的,不在于详解。所以大家也可直接拿代码去做测试。

以上。

 

























以上是关于java 反射类的理解与应用的主要内容,如果未能解决你的问题,请参考以下文章

Java Demo 学习 理解 反射机制 (基础学习)

java反射的理解与应用(某大神博客中看到的博文,写的真的太好了,果断转载作为笔记)

理解Java的反射与内省及其区别

java反射基础知识反射应用实践

Java的反射

java 面向对象(三十八):反射 Class类的理解与获取Class的实例