Java反射

简介

       反射机制的相关类:java.lang.reflect包

       (1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。

       (2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

       Java反射的主要用途:开发各种通用框架(Spring,Hibernate,Mybatis)。

什么是反射?

       Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。

       这种动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制

获取class对象的3种方式

  • 第一种:不推荐,因为已经知道对象名

    对象名.getClass()

  • 第二种:不推荐,因为要导包,依赖太强,不导包就抛编译错误

    类名.class

  • 第三种:推荐,URL字符串可以写入文件中,但需要处理ClassNotFoundException异常

    Class.forName(String className)

    参数为包名.类名

       在运行期间,同一个类只能产生一个Class对象。

package com.demo.java.reflex;

public class ReflexTest {

	public static void main(String[] args) {

		// 1:对象名.getClass()
		User user = new User();
		Class userClass1 = user.getClass();

		// 2:类名.class
		Class userClass2 = User.class;

		// 3:Class.forName(String className)
		Class userClass3 = null;
		try {
			userClass3 = Class.forName("com.demo.java.reflex.User");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
}

Class类常用方法

方法返回值类型说明
getPackage()Package 对象获取该类的存放路径
getName()String 对象获取该类的名称
getSuperclass()Class 对象获取该类继承的类
getInterfaces()Class 型数组获取该类实现的所有接口
getConstructors()Constructor 型数组获取所有"公有的"构造方法
getDeclaredConstructors()Constructor 型数组获取所有的构造方法,按声明顺序返回
getConstructor(Class… parameterTypes)Comstructor 对象获取指定的"公有的"的构造方法
getDeclaredConstructor(Class… parameterTypes)Comstructor 对象获取指定的构造方法
getFields()Field 型数组获取类中所有public类型的属性
getDeclaredFields()Field 型数组获取类中所有的属性(public、protected、default、private),不包括继承的属性
getField(String name)Field 对象根据公有属性名获取信息
getDeclaredField(String name)Field 对象获取属性信息(可以是保护的,私有的)
getMethods()Method 型数组获取所有"公有方法"
包含了父类的方法,也包含Object类
getDeclaredMethods()Method 型数组获取所有的成员方法,包括私有的(不包括继承的)
getMethod(String name,Class<?>… parameterTypes)Method 对象name : 方法名;Class … : 形参的Class类型对象
getDeclaredMethod(String name,Class<?>… parameterTypes)Method 对象获取方法:可以是保护的或私有的
getClasses()Class 型数组获取所有“public”的内部类
getDeclaredClasses()Class 型数组获取所有内部类
getDeclaringClass()Class 对象如果该类为内部类,则返回它的成员类,否则返回null

反射的使用

bean类

package com.demo.java.reflex;

import java.util.Date;

public class User {

	public String name;
	protected int age;
	private Date date;
	String[] str;

	public User() {
		super();
	}

	public User(String name, int age, Date date, String[] str) {
		super();
		this.name = name;
		this.age = age;
		this.date = date;
		this.str = str;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}

	public String[] getStr() {
		return str;
	}

	public void setStr(String[] str) {
		this.str = str;
	}
	
	void showDefault(String str) {
		System.out.println("default:" + str);
	}
	
	public void showPublic(String str) {
		System.out.println("public:" + str);
	}
	
	protected void showProtected(String str) {
		System.out.println("protected:" + str);
	}
	
	private void showPrivate(String str) {
		System.out.println("private:" + str);
	}

	public static void main(String[] args) {
		System.out.println("main方法");
	}

}

获取成员变量并调用

Class类常用方法:

方法说明
Field[] getFields()获取类中public类型的属性
Field[] getDeclaredFields()获取类中所有的属性(public、protected、default、private),不包括继承的属性
Field getField(String name)根据公有属性名获取信息
Field getDeclaredField(String name)获取属性信息(可以是保护的,私有的)

Field类常用方法:

方法说明
void setAccessible(true)解除私有限定,给私有变量设置值之前调用
否则将抛出IllegalAccessException
set(Object obj,Object value)设置字段的值
obj:要设置的字段所在的对象(clazz.newInstance(),clazz.getConstructor().newInstance())
value:要为字段设置的值
get(Object obj)获取属性值
String getName()获取变量名
Type getGenericType() | Class<?> getType()获取变量类型
int getModifiers()以整数形式返回Field 对象表示的字段的 Java 语言修饰符
Modifier.toString(field.getModifiers())变量的修饰符
	/**
	 * 反射获取成员属性
	 * 
	 * @param clazz
	 */
	public void getVariable(Class clazz) {
		// 公有变量
		System.out.println("获取公有变量:");
		Field[] userField = clazz.getFields();
		for (Field field : userField) {
			System.out.println("公有变量:" + field);
			System.out.println("属性名:" + field.getName());
			System.out.println("属性类型:" + field.getGenericType());
			System.out.println("属性类型:" + field.getType());
			System.out.println("修饰符:" + field.getModifiers());
			System.out.println("修饰符:" + Modifier.toString(field.getModifiers()));
		}
		System.out.println("------------------------------------------");

		// 所有变量
		System.out.println("获取所有变量:");
		userField = clazz.getDeclaredFields();
		for (Field field : userField) {
			System.out.println("变量:" + field);
			System.out.println("属性名:" + field.getName());
			System.out.println("属性类型:" + field.getGenericType());
			System.out.println("属性类型:" + field.getType());
			System.out.println("修饰符:" + field.getModifiers());
			System.out.println("修饰符:" + Modifier.toString(field.getModifiers()));
			System.out.println();
		}
		System.out.println("------------------------------------------");

		System.out.println("获取指定的公有变量并调用:");
		try {
			Field field = clazz.getField("name");
			// 实例化对象
			//Object obj = clazz.getConstructor().newInstance();
			Object obj = clazz.newInstance();
			// 设置属性值
			field.set(obj, "小明");
			// 转换为对象
			User user = (User) obj;
			System.out.println("对象获取值:" + user.name);
			System.out.println("反射获取值:" + field.get(obj));
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("------------------------------------------");

		System.out.println("获取私有与保护变量并调用:");
		try {
			// private
			Field field = clazz.getDeclaredField("date");
			Object obj = clazz.newInstance();
			// 取消java语言检查,否则将抛出IllegalAccessException
			field.setAccessible(true);
			field.set(obj, new Date());
			// User user = (User) obj;
			// user.getDate();
			System.out.println("反射获取值:" + field.get(obj));

			// protected
			field = clazz.getDeclaredField("age");
			Object obj1 = clazz.newInstance();
			field.set(obj1, 18);
			System.out.println("反射获取值:" + field.get(obj1));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

获取成员方法并调用

方法说明return
以下为Class对象调用的方法
getMethods()获取所有"公有方法"
包含了父类的方法,也包含Object类
Method[]
getDeclaredMethods()获取所有的成员方法,包括私有的(不包括继承的)Method[]
getMethod(String name,Class<?>… parameterTypes)name : 方法名;Class … : 形参的Class类型对象Method
getDeclaredMethod(String name,Class<?>… parameterTypes)获取方法:可以是保护的或私有的Method

Method类常用方法:

方法说明return
setAccessible(true)解除私有限定,调用私有方法之前调用
否则将抛出IllegalAccessException
void
invoke(Object obj,Object… args):调用方法
obj:要调用方法的对象,args:调用方式时所传递的实参
Object
getName()获取方法名String
getReturnType()获取方法的返回类型Class<?>
getTypeParameters()获取参数TypeVariable<Method>[]
	/**
	 * 反射获取方法
	 * 
	 * @param clazz
	 */
	public void getMethod(Class clazz) {
		System.out.println("获取公有方法:");
		Method[] method = clazz.getMethods();
		for (Method m : method) {
			System.out.println("公有方法:" + m);
			System.out.println("方法名" + m.getName());
			System.out.println("方法返回类型" + m.getReturnType());
		}
		System.out.println("------------------------------------------");
		
		System.out.println("获取所有的成员方法,不包括继承的:");
		method = clazz.getDeclaredMethods();
		for (Method m : method) {
			System.out.println("方法:" + m);
			System.out.println(m.getName());
		}
		System.out.println("------------------------------------------");

		System.out.println("调用公有方法:");
		Method m;
		try {
			m = clazz.getMethod("showPublic", String.class);
			Object obj = clazz.newInstance();
			m.invoke(obj, "测试public");
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("------------------------------------------");

		System.out.println("调用私有方法:");
		try {
			m = clazz.getDeclaredMethod("showPrivate", String.class);
			Object obj = clazz.newInstance();
			m.setAccessible(true);
			m.invoke(obj, "测试private");
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("------------------------------------------");
		
		System.out.println("调用保护方法:");
		try {
			m = clazz.getDeclaredMethod("showProtected", String.class);
			Object obj = clazz.newInstance();
			m.setAccessible(true);
			m.invoke(obj, "测试protected");
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("------------------------------------------");
		
		System.out.println("调用默认方法:");
		try {
			m = clazz.getDeclaredMethod("showDefault", String.class);
			Object obj = clazz.newInstance();
			m.setAccessible(true);
			m.invoke(obj, "测试default");
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("------------------------------------------");
		
		System.out.println("调用main方法:");
		try {
			m = clazz.getMethod("main", String[].class);
			// 方式一
			m.invoke(null, (Object)new String[]{"a","b","c"});
			// 方式二
			m.invoke(null, new Object[]{new String[]{"a","b","c"}});
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("------------------------------------------");
		
	}

获取构造方法

相关方法:

方法返回值类型说明
getConstructors()Constructor[]获取所有"公有的"构造方法
getDeclaredConstructors()Comstructor[]获取所有的构造方法
getConstructor(Class… parameterTypes)ComstructorClass … : 形参的Class类型对象
getDeclaredConstructor(Class… parameterTypes)Comstructor

Constructor类的常用方法:

方法返回值类型说明
isVarArgs()boolean查看该构造方法是否允许带有可变数量的参数
getParameterTypes()Class 型数组获取该构造方法的各个参数的类型,按照声明的顺序
getExceptionTypes()Class 型数组获取该构造方法可能抛出的异常类型
newInstance(Object … initargs)T通过该构造方法利用指定参数创建一个该类的对象,如果未设置参数则表示采用默认无参数的构造方法
getModifiers()int获取可以解析出该构造方法所采用修饰符的整数
// 通过反射实例化对象
Object obj = clazz.getConstructor().newInstance();
// Object obj = clazz.newInstance();
// newInstance()方法内部实际上调用了无参数构造方法,必须保证无参构造存在才可以。
// 否则会抛出java.lang.InstantiationException异常。

// 所有"公有的"构造方法
Constructor[] cons = clazz.getConstructors();

// 获取所有的构造方法
Comstructor[] cons1 = clazz.getDeclaredConstructors();

// 获取单个的"公有的"构造方法
// 获取无参构造函数,可以不写null
Constructor cdn = clazz.getConstructor(null);

// 获取"某个构造方法"
cdn = clazz.getDeclaredConstructor(int.class);
cdn.setAccessible(true);

// 调用构造方法:
Object object = cdn.newInstance(13);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值