Java基础与提高-Java反射机制

Java反射机制的定义

Java反射机制是指在运行状态中,对于任意一个类都可以反射来获取程序在运行时刻的内部结构(如:属性与方法)

动态编译与静态编译

静态编译:一次性编译。在编译的时候把你所有的模块都编译进去。

动态编译:按需编译。程序在运行的时候,用到那个模块就编译哪个模块。

反射机制的优点与缺点

使用反射API的时候就好像在看一个Java类在水中的倒影一样。知道了Java类的内部 结构之后,就可以与它进行交互,包括创建新的对象和调用对象中的方法等。这种交互方式与直接在源代码中使用的效果是相同的,但是又额外提供了运行时刻的灵活性,即可扩展性好。

使用反射的一个最大的弊端是性能较差,相同的操作,使用反射所需的时间大概比直接的使用要慢一两个数量级。

不过现在的JVM实现中,反射操作的性能已经有了很大的提升。在灵活性与性能之间,总是需要进行权衡的。应用可以在适当的时机来使用反射。

 

探究Class类与反射API

Class类

Jdk1.0开始就有这样一个类

 * @author  unascribed
 * @see     java.lang.ClassLoader#defineClass(byte[], int, int)
 * @since   JDK1.0
 */
public final class Class implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement {

 

在面向对象的世界里,万事万物皆是对象。类是java.lang.Class类的实例对象,所有类都是Class的实例对象,例如class Person {},Person和A都是Class类的实例对象。

 

 

要对某个类使用反射机制,就必须得到这个类的Class对象(官方称为类类型(class type)),怎么样得到Person类的类类型呢?

普通的类对象的创建是一般通过调用A类里的构造器来进行创建(前提是A类的构造器是public)

A a = new A();

查看Class的源码时,它的构造器是这样的

  private Class(ClassLoader loader) {
        // Initialize final field for classLoader.  The initialization value of non-null
        // prevents future JIT optimizations from assuming this final field is null.
        classLoader = loader;
    }

不能通过构造器直接构造,那怎么样得到Person类的类类型呢?可通过以下三种方式

private static void refGetClass() throws ClassNotFoundException {
		//通过类的全限定名来获取Person类的类类型(class type)。
		Class class1 = Class.forName("com.yang.reflectTest.Person");
		
		//过一个类的对象new Person()来获取Person类的类类型(class type)。
        Class class2 = new Person().getClass();
        
        //通过获取类的静态成员变量class获取Person类的类类型(class type)。
        Class class3 = Person.class;
        System.out.println(class1 == class2); //true
        System.out.println(class1 == class3); //true
        
	}

根据程序的输入结果可知一个类只可能是Class类的一个实例对象。

 

反射API

在java.lang.reflect包中有三个重要的类:

  • Field:描述类的域(属性)
  • Method:描述类的方法
  • Constructor:描述类的构造器

 

获取三个重要的类的对象主要API如下:

对于public域(包括超类成员):

 

  • getConstructor(Class... parameterTypes) 
              返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法(公有、继承)
  • getConstructors() 
              返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。(公有、继承)
  • getField(String name)
              返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。(公有、继承)
  • getFields()
              返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段(公有、继承)
  • getMethod(String name, Class... parameterTypes)
              返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。(公有、继承)
  • getMethods()
              返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。(公有、继承)

对于其它域(包括私有和受保护的成员,不包括超类成员):

 

  • getDeclaredConstructor(Class... parameterTypes) 
              返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。(不包括继承)
  • getDeclaredConstructors() 
              返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。(不包括继承)
  • getDeclaredField(String name)
              返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段(不包括继承)
  • getDeclaredFields()
              返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。(不包括继承)
  • getDeclaredMethod(String name, Class... parameterTypes)
              返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。(不包括继承)
  • getDeclaredMethods()
              返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。(不包括继承)

Java反射相关操作

我们对以下类Person类进行探究

package com.yang.reflectTest;

public class Person {

	private String name = "defaultName";
	public int age;

	public Person() {
		System.out.println("调用了无参public的构造方法"+"name:" + name);
	}

	private Person(String name) {
		this.name = name;
		System.out.println("调用了有参private的构造方法"+"name:" + name);
	}

	public void study() {
		System.out.println("调用了成员方法:study()");
	}

	private void introduce(String name) {
		System.out.println("调用了私有的成员方法: introduce(String name)");
	}
}

 

通过反射获取Person类的对象:

 

	private static void refGetPersonObject() throws Exception {
		//调用了无参public的构造方法
		  Class c = Person.class;
		  Person o1 = (Person)c.newInstance();//相当于new Person();

		//调用了无参public的构造方法
		  Constructor constructor1 = c.getConstructor();
		  Person o2 = (Person)constructor1.newInstance();//相当于new Person();
		  
		//调用了无参private的有参构造方法
		  Constructor constructor2 = c.getDeclaredConstructor(String.class);
		  constructor2.setAccessible(true);//由于private不可见,所以调用该方法使其可见
		  Person o3 = (Person)constructor2.newInstance("yanggg");//相当于new Person("yanggg");
		  
	}

 

运行结果为

 

调用了无参public的构造方法 name: defaultName
调用了无参public的构造方法 name: defaultName
调用了有参private的构造方法 name: yanggg


通过反射获取Person的属性对象

	private static void refGetField() throws Exception {
		//调用了无参public的构造方法
		  Class c = Person.class;
		  Person o1 = (Person)c.newInstance();//相当于new Person();

		  Field f1 = c.getField("age"); 
		 
		  Field f2 = c.getDeclaredField("name");
		  f2.setAccessible(true); //将private设置为可见
		  
		  int age = (Integer)f1.get(o1); //相当 o1.age;
		  String name = (String)f2.get(o1);
		 
		  System.out.println(age);//打印出o1对象的age值
		  System.out.println(name);//打印出o1对象的name值
	}

运行结果为:

调用了无参public的构造方法 name: defaultName
0
defaultName

 

通过反射获取Person类的public构造器对象

	private static void refGetPublicConstructor() throws Exception {
		
		Class c = Person.class;
		
		// 返回无参public的无参构造方法
		Constructor constructor1 = c.getConstructor();

		System.out.println(constructor1);

	}

运行结果为

public com.yang.reflectTest.Person()

通过反射获取Person类的private构造器对象

	private static void refGetPrivateConstructor() throws Exception {
		
		Class c = Person.class;
	
		// 返回无参private的有参构造方法
		Constructor constructor2 = c.getDeclaredConstructor(String.class);
		constructor2.setAccessible(true);// 由于private不可见,所以调用该方法使其可见
		
		System.err.println(constructor2);
	}

运行结果为

private com.yang.reflectTest.Person(java.lang.String)

通过反射获取Person类的private有参方法对象

	private static void refGetMethodWithArg() throws Exception {
		// 调用了无参public的构造方法
		Class c = Person.class;
		Person o1 = (Person) c.newInstance();// 相当于new Person();
		
		Method method1 = c.getDeclaredMethod("introduce", String.class);
		method1.setAccessible(true);
		
		method1.invoke(o1, "yanggg");//调用introduce(String name)方法传入的参数为"yanggg"
		
	}

运行结果:

调用了无参public的构造方法 name: defaultName
调用了私有的成员方法: introduce(String name)

通过反射获取Person类的public无参方法对象

	private static void refGetMethodWithNoArg() throws Exception {
		// 调用了无参public的构造方法
		Class c = Person.class;
		Person o1 = (Person) c.newInstance();// 相当于new Person();

		Method method2 = c.getDeclaredMethod("study");

		method2.invoke(o1);// 调用study()方法
	}

运行结果为

调用了无参public的构造方法 name: defaultName
调用了成员方法:study()

 

总结

在一个普通的java类中,一般含有Field,Method,Constructor三个部分,通过反射能得到这三个类的对象

在java.lang.reflect包中有三个重要的类:

  • Field:描述类的域(属性)
  • Method:描述类的方法
  • Constructor:描述类的构造器

通过三个类的对象调用这三个类中的API,就能灵活地完成一些操作。
本文只是列举一些反射的入门操作。

 

反射的应用

 

  • JUnit
  • Spring
  • JDBC
  • Servlet
  • 常用的设计模式(工厂,代理等)

 

写在最后

 

纸上得来终觉浅绝知此事要躬行

本文的不足欢迎大家提出,谢谢。

https://blog.csdn.net/Yanggg_/article/details/80549063

 

你可能感兴趣的:(Java基础与提高)