【java基础】反射

本文介绍了Java反射的概念,包括如何获取Class对象、构造方法、成员变量和成员方法,并通过示例展示了如何动态创建对象、调用方法和设置字段值。同时,讨论了反射的优缺点,如提高代码灵活性和可扩展性,但可能导致效率降低和安全问题。
摘要由CSDN通过智能技术生成

反射


1 概念

​ 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法(动态获取信息);对于任意一个对象,都能够调用它的任意一个方法和属性(动态调用对象的方法)。

​ 把java类中的各种成分映射成一个个的Java对象


2 使用

2.1 获取class对象

package fanshe;
/**
 * 获取Class对象的三种方式
 * 1 Object ——> getClass();
 * 2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
 * 3 通过Class类的静态方法:forName(String  className)(常用)
 */
public class Fanshe {
	public static void main(String[] args) {
		//第一种方式获取Class对象  
		Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
		Class stuClass = stu1.getClass();//获取Class对象
		
		//第二种方式获取Class对象
		Class stuClass2 = Student.class;
		
		//第三种方式获取Class对象
		try {
			Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
}

2.2 构造方法【java.lang.reflect.Constructor#newInstance(Object… initargs)】

package fanshe;
 
import java.lang.reflect.Constructor;
 
/*
 * 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
 * 
 * 1.获取构造方法:
 * 		1).批量的方法:
 * 			public Constructor[] getConstructors():所有"公有的"构造方法
            public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
     
 * 		2).获取单个的方法,并调用:
 * 			public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
 * 			public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
 * 		
 * 			调用构造方法:
 * 			Constructor-->newInstance(Object... initargs)
 */
public class Constructors {
 
	public static void main(String[] args) throws Exception {
		//1.加载Class对象
		Class clazz = Class.forName("fanshe.Student");
		
		System.out.println("**********************所有公有构造方法*********************************");
		Constructor[] conArray = clazz.getConstructors();
		
		System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
		conArray = clazz.getDeclaredConstructors();
		
		System.out.println("*****************获取公有、无参的构造方法*******************************");
        //1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
		//2>、返回的是描述这个无参构造函数的类对象。
		Constructor con = clazz.getConstructor(null);
		//调用构造方法
		Object obj = con.newInstance();
		
		System.out.println("******************获取私有构造方法,并调用*******************************");
		con = clazz.getDeclaredConstructor(char.class);
        
        //暴力访问(忽略掉访问修饰符)——构造方法为非公有的时候需加这个
		con.setAccessible(true);
        //调用构造方法
		obj = con.newInstance('男');
	}	
}

2.3 成员变量【java.lang.reflect.Field#set(Object obj,Object value)】

package fanshe.field;
import java.lang.reflect.Field;
/*
 * 获取成员变量并调用:
 * 
 * 1.批量的
 * 		1).Field[] getFields():获取所有的"公有字段"
 * 		2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
 * 2.获取单个的:
 * 		1).public Field getField(String fieldName):获取某个"公有的"字段;
 * 		2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
 * 
 * 	 设置字段的值:
 * 		Field --> public void set(Object obj,Object value):
 * 					参数说明:
 * 					1.obj:要设置的字段所在的对象;
 * 					2.value:要为字段设置的值;
 * 
 */
public class Fields {
 
		public static void main(String[] args) throws Exception {
			//1.获取Class对象
			Class stuClass = Class.forName("fanshe.field.Student");

            System.out.println("************获取所有公有的字段********************");
			Field[] fieldArray = stuClass.getFields();
			
			System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");
			fieldArray = stuClass.getDeclaredFields();
			
			System.out.println("*************获取公有字段**并调用***********************************");
			Field f = stuClass.getField("name");
			//获取一个对象
			Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();
			//为字段设置值
			f.set(obj, "刘德华");//为Student对象中的name属性赋值--》stu.name = "刘德华"	
			
			System.out.println("**************获取私有字段****并调用********************************");
			f = stuClass.getDeclaredField("phoneNum");
            //暴力反射,解除私有限定
			f.setAccessible(true);
			f.set(obj, "18888889999");			
		}
	}

2.4 成员方法【java.lang.reflect.Method#invoke(Object obj,Object… args)】

package fanshe.method;
 
import java.lang.reflect.Method;
 
/*
 * 获取成员方法并调用:
 * 
 * 1.批量的:
 * 		public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
 * 		public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
 * 2.获取单个的:
 * 		public Method getMethod(String name,Class<?>... parameterTypes):
 * 					参数:
 * 						name : 方法名;
 * 						Class ... : 形参的Class类型对象
 * 		public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
 * 
 * 	 调用方法:
 * 		Method --> public Object invoke(Object obj,Object... args):
 * 					参数说明:
 * 					obj : 要调用方法的对象;
 * 					args:调用方式时所传递的实参;
):
 */
public class MethodClass {
 
	public static void main(String[] args) throws Exception {
		//1.获取Class对象
		Class stuClass = Class.forName("fanshe.method.Student");

        System.out.println("***************获取所有的”公有“方法*******************");
		stuClass.getMethods();
		Method[] methodArray = stuClass.getMethods();
		
		System.out.println("***************获取所有的方法,包括私有的*******************");
		methodArray = stuClass.getDeclaredMethods();
		
		System.out.println("***************获取公有的show1()方法*******************");
		Method m = stuClass.getMethod("show1", String.class);
		//实例化一个Student对象
		Object obj = stuClass.getConstructor().newInstance();
		m.invoke(obj, "刘德华");
		
		System.out.println("***************获取私有的show4()方法******************");
		m = stuClass.getDeclaredMethod("show4", int.class);
		m.setAccessible(true);//解除私有限定
		Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
	}
}

2.4 main方法(代表静态方法的方法与调用)

package fanshe.main;
 
import java.lang.reflect.Method;
 
/**
 * 获取Student类的main方法、不要与当前的main方法搞混了
 */
public class Main {
	
	public static void main(String[] args) {
		try {
			//1、获取Student对象的字节码
			Class clazz = Class.forName("fanshe.main.Student");
			
			//2、获取main方法
            //第一个参数:方法名称,第二个参数:方法形参的类型,
			Method methodMain = clazz.getMethod("main", String[].class);
			//3、调用main方法
			// methodMain.invoke(null, new String[]{"a","b","c"});
			//第一个参数,对象类型,因为方法是static静态的,所以为null可以,第二个参数是String数组,这里要注意在jdk1.4时是数组,jdk1.5之后是可变参数
			//这里拆的时候将  new String[]{"a","b","c"} 拆成3个对象。。。所以需要将它强转。
			methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一
			// methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

3 优缺点

  • 优点
    • 1.程序灵活:反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力
    • 2.复用:提高代码的复用率,比如动态代理、spring管理bean
    • 3.运行时构造对象:可以在运行时轻松获取任意一个类的方法、属性,并且还能通过反射进行动态调用
  • 缺点
    • 1.效率低:反射会涉及到动态类型的解析,所以jvm无法对这些代码进行优化,导致性能要比非反射调用更低
    • 2.可读性低:使用反射以后,代码的可读性会下降
    • 3.内部暴露:反射可以绕过一些限制访问的属性或者方法,可能会导致破坏代码本身的抽象性
    • 4.安全限制:使用反射技术通常要在一个没有安全限制的程序运行

注:主要供个人学习用,代码及相关注释为参考过来的,做了一次整理,忘了是哪一篇的博客。后续看到会补上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值