如何使用 Java 反射?反射的用法及案例

博主声明:

转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。

本文首发于此   博主威威喵  |  博客主页https://blog.csdn.net/smile_running

· 简介

    Java Reflection,称为 Java 反射,是Java基础部分的一个比较难的点。Reflection(反射)是被视为动态语言的关键,通过反射机制,我们可以在运行时(runtime)获取类的完整结构。例如,可以获取到类的变量名、方法、构造器、内部类、接口、注解等等,并且通过反射机制可以对类内部进行操作。

    Java反射机制在实际开发中是非常常用的,强大一词完全可以用来形容它。作为Java基础内容的一部分,并且在很多开源框架(jdbc、spring、hibermate...)都使用到反射,可谓反射的重要性。

· 例子

首先,定义一个 Person 类及 Student 类,Student 继承自 Person 类,代码非常简单。如下:

package com.test;

public class Person<T> {

	public String weight;
	public String height;

	public Person() {
		super();
	}

	public Person(String weight, String height) {
		super();
		this.weight = weight;
		this.height = height;
	}

	public String getWeight() {
		return weight;
	}

	public void setWeight(String weight) {
		this.weight = weight;
	}

	public String getHeight() {
		return height;
	}

	public void setHeight(String height) {
		this.height = height;
	}

	@Override
	public String toString() {
		return "Person [weight=" + weight + ", height=" + height + "]";
	}

}
package com.test;

import java.io.Serializable;

public class Student extends Person<String> implements Serializable, Runnable {

	public String stuNo;
	private String stuName;

	public Student() {
		super();
	}

	public Student(String stuNo, String stuName) {
		super();
		this.stuNo = stuNo;
		this.stuName = stuName;
	}

	public String getStuNo() {
		return stuNo;
	}

	public void setStuNo(String stuNo) {
		this.stuNo = stuNo;
	}

	public String getStuName() {
		return stuName;
	}

	public void setStuName(String stuName) {
		this.stuName = stuName;
	}

	private int exam(String str, Integer tag) throws NoSuchMethodException {
		System.out.println(str);
		return tag;
	}

	@Override
	public String toString() {
		return "Student [stuNo=" + stuNo + ", stuName=" + stuName + "]";
	}

	@Override
	public void run() {

	}
}

有了这两个类,我们就可以开始利用反射来获取类的内部结构了。我们常规的创建对象操作:


	@Test
	public void test() {
		Student student = new Student();
		student.setStuNo("01");
		student.setStuName("张三");
	}
  • 反射4种方式

在开始之前,我们来学习如何利用反射的方式来获取类的结构,反射的方式有这样 4 种。

* 反射的4种获取方式,反射的源头就是获取到一个 Class 对象进行操作类的内部方法和获取类的结构。

  注意:父类中声明为 public 的变量、方法、接口等也可以被获取到。

	@Test
	public void test() throws Exception {
		/** 第一种反射方式 */
		Class clazz1 = new Student().getClass();

		/** 第二种反射方式 */
		Class clazz2 = Student.class;

		/** 第三种反射方式 */
		// 先声明 xxx 类所在包的完整名
		String className = "com.test.Student";
		Class clazz3 = Class.forName(className);

		/** 第四种反射方式 */
		Class clazz4 = this.getClass().getClassLoader().loadClass(className);
	}

以下都是利用反射来获取类结构的例子。

  • 获取类中的变量,并进行赋值

	@Test
	public void test() throws Exception {
		Class clazz = Student.class;
		Student student = (Student) clazz.newInstance();
		/** 声明为 public 类型的变量可以这样获取 **/
		Field field1 = clazz.getField("stuNo");
		field1.set(student, "01");
		System.out.println(student);
		/** 其他类型变量只能通过如下获取 **/
		Field field2 = clazz.getDeclaredField("stuName");
		field2.setAccessible(true);
		field2.set(student, "张三");
		System.out.println(student);
	}
  • 获取变量的权限修饰符(private、protected、public)

	@Test
	public void test() throws Exception {
		Class clazz = Student.class;
		Student student = (Student) clazz.newInstance();
		Field field1 = clazz.getField("stuNo");
		Field field2 = clazz.getDeclaredField("stuName");
	
		/** 获取 权限修饰符 **/
		String str = Modifier.toString(field1.getModifiers());
		System.out.println(str);
		String str2 = Modifier.toString(field2.getModifiers());
		System.out.println(str2);
	}
  • 获取类中的方法,并调用该方法(需注意权限修饰符)

  • 获取类中方法的返回值

  • 获取类中方法形参列表

  • 获取类中方法异常类型

	@Test
	public void test() throws Exception {
		Class clazz = Student.class;
		Student student = (Student) clazz.newInstance();
	
		Method method = clazz.getMethod("setStuNo", String.class);
		method.invoke(student, "02");
		System.out.println(student);
		/** 获取方法的返回值类型 */
		Class returnType = method.getReturnType();
		System.out.println(returnType);

		Method method2 = clazz.getDeclaredMethod("exam", String.class, Integer.class);
		method2.setAccessible(true);
		method2.invoke(student, "invoke exam method", 1);
		/** 获取方法的形参列表 */
		Class[] params = method2.getParameterTypes();
		for (Class param : params) {
			System.out.println(param);
		}
		/** 获取方法的异常类型 */
		Class[] exceptions =method2.getExceptionTypes();
		for(Class excp : exceptions) {
			System.out.println(excp);
		}
	}
  • 获取类的完整包名、

  • 类中所有的构造器、

  • 类中实现的所有接口

	@Test
	public void test() throws Exception {
		Class clazz = Student.class;
		Student student = (Student) clazz.newInstance();
		//获取包名
		System.out.println(clazz.getPackage());
		/**
		 * 获取 所有构造器
		 */
		Constructor[] constructor = clazz.getDeclaredConstructors();
		for(Constructor cons : constructor) {
			System.out.println(cons);
		}
		/**
		 * 获取 所有接口
		 */
		Class[] interfaces =clazz.getInterfaces();
		for( Class its:interfaces) {
			System.out.println(its);
		}
	}
  • 获取父类的结构

	@Test
	public void test() throws Exception {
		Class clazz = Student.class;
		Student student = (Student) clazz.newInstance();
		//获取父类
		System.out.println(clazz.getSuperclass());
		//获取带泛型的父类
		Type type = clazz.getGenericSuperclass();
		System.out.println(type);
		
		/**
		 * 获取父类的泛型
		 */
		Type type2 = clazz.getGenericSuperclass();
		ParameterizedType args = (ParameterizedType)type2;
		Type[] types = args.getActualTypeArguments();
		String t_Type = (String)types[0].getTypeName();
		System.out.println(t_Type);
	}

  以上的几个例子可以让我们知道反射的作用,反射能够在运行时状态下获取类的完整结构,在框架里显得尤为重要。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 成长之路 设计师:Amelia_0503 返回首页