Java 反射使用详解

一、什么是反射?反射就是可以不用通过 new 对象的方式来获的对象。
第一种方式
public class 鞠婧祎 {
	public static void main(String[] args) {
		Class<?> cls = 鞠婧祎.class;
		鞠婧祎 kiku = (鞠婧祎) cls.newInstance();
	}
}
第二种方式
public class 刘亦菲 {
	public static void main(String[] args) {
		String className = "com.yifei.刘亦菲"; // 此处为对象类的全限定名
		Class<?> cls = Class.forName(className);
		刘亦菲 yi = (刘亦菲) cls.newInstance();
	}
}
第三种方式
public class 陈钰琪 {
	public static void main(String[] args) {
		String className = "com.yukee.陈钰琪"; // 此处为对象类的全限定名
		Class<?> cls = Class.forName(className);
		Constructor<?> constructor = cls.getConstructor();
		陈钰琪 yukee = (陈钰琪) constructor.newInstance();
	}
}
第四种方式
public class 景甜 {
	public static void main(String[] args) {
		String className = "com.tian.景甜"; // 此处为对象类的全限定名
		Class<?> cls = Class.forName(className);
		Constructor<?> constructor = cls.getDeclaredConstructor();
		景甜 tian = (景甜) constructor.newInstance();
	}
}

二、它们之间的区别

  • 第一种与第二种的 newInstance:只能调用目标对象非私有的无参构造方法(即非 private),如果构造方法的修饰符非 public,那么 newInstance 必须遵守访问控制符的访问权限,否则会抛出异常
  • 第三种的 newInstance:可以获取无参、也可以获取有参的构造方法,构造方法的修饰符必须是 public,否则会抛出异常
  • 第四种的 newInstance:可以获取无参、也可以获取有参的构造方法,这种方式是可以获取目标对象类的私有属性(方法和变量),它还可以不用遵守访问控制符的访问权限
  • 注意:如果获取有参构造方法,则 newInstance 方法必须传参,反之则亦然
  • 访问控制符的访问权限可以查看此篇文章:Java 里 private,protected,private,default 的区别

三、基于上述第三、四种方式扩展获取有参的构造方法,两者很类似

第三种方式
public class 林允儿 {
	public 林允儿(String name) {
		System.out.println("姓名:" + name);
	}
	
	public 林允儿(String name, int age) {
		System.out.println("姓名:" + name + ",年龄:" + age);
	}
	
	public static void main(String[] args) {
		String className = "com.yoona.林允儿"; // 此处为对象类的全限定名
		Class<?> cls = Class.forName(className);
		Constructor<?> constructor = cls.getConstructor(String.class); // String.class 为构造方法中参数的对象类型
		林允儿 yoona = (林允儿) constructor.newInstance("你需要传入的参数值");
		Constructor<?> constructor = cls.getConstructor(String.class, int.class);	// 构造方法中参数的对象类型
		林允儿 yoona = (林允儿) constructor.newInstance(new Object[] {"林允儿", 18});
	}
}
第四种方式
public class 徐艺洋 {
	public 徐艺洋(String name) {
		System.out.println("姓名:" + name);
	}
	
	public 徐艺洋(String name, int age) {
		System.out.println("姓名:" + name + ",年龄:" + age);
	}
	
	public static void main(String[] args) {
		String className = "com.yiyang.徐艺洋"; // 此处为对象类的全限定名
		Class<?> cls = Class.forName(className);
		Constructor<?> constructor = cls.getDeclaredConstructor(String.class); // String.class 为构造方法中参数的对象类型
		/**
		 * 如果目标对象类的构造方法非 public(不遵守访问权限),那么需要这里加上
		 * constructor.setAccessible(true);
		 * 如果遵守访问权限,那么只有在访问私有的时候加上即可
		 */
		徐艺洋 yiyang = (徐艺洋) constructor.newInstance("徐艺洋");
		Constructor<?> constructor = cls.getDeclaredConstructor(String.class, int.class);	// 构造方法中参数的对象类型
		徐艺洋 yiyang = (徐艺洋) constructor.newInstance(new Object[] {"徐艺洋", 18});
	}
}
  • 私有属性对于类外是不可见的,通过反射可以获取到,但是可能会破坏单例模式,解决方案:做个标记记录次数,当第二次调用私有构造方法的时候抛出异常即可

四、通过反射获取指定方法(包含私有)

public class 程潇 {
	public void
	public static void main(String[] args) {
		String className = "com.xiao.程潇"; 		// 此处为对象类的全限定名
		Class<?> cls = Class.forName(className);
		/** --------------- 以下两者是一样的,二选一即可,区别在于后者可以不遵循访问权限修饰符 --------------- **/
		Constructor<?> con = cls.getConstructor();
		Constructor<?> con = cls.getDeclaredConstructor();
		/**
		 * 如果目标对象类的构造方法非 public(不遵守访问权限),那么需要这里加上
		 * con.setAccessible(true);	// 如果此处不省略,上面获取构造方法只能用后者
		 * 如果遵守访问权限,那么只有在访问私有的时候加上即可
		 */
		程潇 xiao = (程潇) con.newInstance();		// 对象实例化
		/** --------------- 以下两者是一样的,区别在于后者可以不遵循访问权限修饰符 --------------- **/
		Method method = cls.getMethod("程潇"); 		// 方法名
		Method method = cls.getDeclaredMethod("程潇");
		Method method = cls.getMethod("程潇", String.class); 		// 获取有参方法,第一个为方法名,第二个为参数类型,可以有多个参数
		Method method = cls.getDeclaredMethod("程潇", String.class);
		/**
		 * 如果目标对象类的方法非 public(不遵守访问权限),那么需要这里加上
		 * method.setAccessible(true);	// 如果此处不省略,上面获取方法只能用后者
		 * 如果遵守访问权限,那么只有在访问私有的时候加上即可
		 */
		Object o = method.invoke(xiao);					// xiao:目标方法的对象
		Object o = method.invoke(xiao, "程潇");			// xiao:目标方法的对象,如果对象有参数,在此传入
	}
}

五、通过反射获取变量(包含私有)

public class 周洁琼 {
	public void
	public static void main(String[] args) {
		String className = "com.jieqiong.周洁琼"; 		// 此处为对象类的全限定名
		Class<?> cls = Class.forName(className);
		/** --------------- 以下两者是一样的,二选一即可,区别在于后者可以不遵循访问权限修饰符 --------------- **/
		Constructor<?> con = cls.getConstructor();
		Constructor<?> con = cls.getDeclaredConstructor();
		/**
		 * 如果目标对象类的构造方法非 public(不遵守访问权限),那么需要这里加上
		 * con.setAccessible(true);	// 如果此处不省略,上面获取构造方法只能用后者
		 * 如果遵守访问权限,那么只有在访问私有的时候加上即可
		 */
		周洁琼 zjq = (周洁琼) con.newInstance();		// 对象实例化
		/** --------------- 以下两者是一样的,区别在于后者可以不遵循访问权限修饰符 --------------- **/
		Field field = cls.getField("name");
		Field field = cls.getDeclaredField("name");
		/**
		 * 如果目标对象类的方法非 public(不遵守访问权限),那么需要这里加上
		 * field.setAccessible(true);	// 如果此处不省略,上面获取方法只能用后者
		 * 如果遵守访问权限,那么只有在访问私有的时候加上即可
		 */
		Object o = field.get(zjq);		// zjq:目标变量的对象,如果目标变量是静态变量,则为 null 也可以获取到值
	}
}

六、拓展

  • cls.getConstructors(),获取所有修饰符为 public 的构造方法,返回一个 Constructor 数组
  • cls.getDeclaredConstructors(),获取所有的构造方法,包含私有的,返回一个 Constructor 数组
  • cls.getMethods(),获取所有的 public 的普通方法,返回一个 Method 数组。
  • cls.getDeclaredMethods(),获取所有的普通方法,包含私有的,返回一个 Method 数组。
  • cls.getFields(),获取所有的 public 成员变量,返回一个 Field 数组。
  • cls.getDeclaredFields(),获取所有的成员变量,包含私有的,返回一个 Field 数组。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值