首页 > 其他分享 >反射

反射

时间:2024-08-18 14:06:22浏览次数:5  
标签:反射 System clazz 获取 println Class out

反射

java.lang.Class类

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

要想解剖一个类,必须先要获取到该类的Class对象。而剖析一个类或用反射解决具体的问题就是使用相关API(1)java.lang.Class(2)java.lang.reflect.*。所以,Class对象是反射的根源。

获取Class对象的四种方式

(1)类型名.class

要求编译期间已知类型

(2)对象.getClass()

获取对象的运行时类型

(3)Class.forName(类型全名称)

可以获取编译期间未知的类型

(4)ClassLoader的类加载器对象.loadClass(类型全名称)

可以用系统类加载对象或自定义加载器对象加载指定路径下的类型

public class TestClass {
	@Test
	public void test05() throws ClassNotFoundException{
		Class c = TestClass.class;
		ClassLoader loader = c.getClassLoader();
		
		Class c2 = loader.loadClass("com.atguigu.test05.Employee");
		Class c3 = Employee.class;
		System.out.println(c2 == c3);
	}
	
	@Test
	public void test03() throws ClassNotFoundException{
		Class c2 = String.class;
		Class c1 = "".getClass();
		Class c3 = Class.forName("java.lang.String");
		
		System.out.println(c1 == c2);
		System.out.println(c1 == c3);
	}
}

反射的应用

获取类型的详细信息

可以获取:包、修饰符、类型名、父类(包括泛型父类)、父接口(包括泛型父接口)、成员(属性、构造器、方法)、注解(类上的、方法上的、属性上的)

获取:包、修饰符、类型名、父类、实现的接口名

public class TestClassInfo {
	public static void main(String[] args) throws NoSuchFieldException, SecurityException {
		//1、先得到某个类型的Class对象
		Class clazz = String.class;
		//比喻clazz好比是镜子中的影子
		
		//2、获取类信息
		//(1)获取包对象,即所有java的包,都是Package的对象
		Package pkg = clazz.getPackage();
		System.out.println("包名:" + pkg.getName());
		
		//(2)获取修饰符
		//其实修饰符是Modifier,里面有很多常量值
		/*
		 * 0x是十六进制
		 * PUBLIC           = 0x00000001;  1    1
		 * PRIVATE          = 0x00000002;  2	10
		 * PROTECTED        = 0x00000004;  4	100
		 * STATIC           = 0x00000008;  8	1000
		 * FINAL            = 0x00000010;  16	10000
		 * ...
		 * 
		 * 设计的理念,就是用二进制的某一位是1,来代表一种修饰符,整个二进制中只有一位是1,其余都是0
		 * 
		 * mod = 17          0x00000011
		 * if ((mod & PUBLIC) != 0)  说明修饰符中有public
		 * if ((mod & FINAL) != 0)   说明修饰符中有final
		 */
		int mod = clazz.getModifiers();
		System.out.println(Modifier.toString(mod));
		
		//(3)类型名
		String name = clazz.getName();
		System.out.println(name);
		
		//(4)父类,父类也有父类对应的Class对象
		Class superclass = clazz.getSuperclass();
		System.out.println(superclass);
		
		//(5)父接口们
		Class[] interfaces = clazz.getInterfaces();
		for (Class class1 : interfaces) {
			System.out.println(class1);
}

成员(属性、构造器、方法)

//(1)类的属性,  你声明的一个属性,它是Field的对象

	/*	Field clazz.getField(name)  根据属性名获取一个属性对象,但是只能得到公共的
		Field[] clazz.getFields();  获取所有公共的属性
		Field clazz.getDeclaredField(name)  根据属性名获取一个属性对象,可以获取已声明的
		Field[] clazz.getDeclaredFields()	获取所有已声明的属性
		*/
		Field valueField = clazz.getDeclaredField("value");
//		System.out.println("valueField = " +valueField);
		
		Field[] declaredFields = clazz.getDeclaredFields();
		for (Field field : declaredFields) {
			//修饰符、数据类型、属性名    
			int modifiers = field.getModifiers();
			System.out.println("属性的修饰符:" + Modifier.toString(modifiers));
			
			String name2 = field.getName();
			System.out.println("属性名:" + name2);
			
			Class<?> type = field.getType();
			System.out.println("属性的数据类型:" + type);
		}

//(2)构造器们
		Constructor[] constructors = clazz.getDeclaredConstructors();
		for (Constructor constructor : constructors) {
			//修饰符、构造器名称、构造器形参列表  、抛出异常列表
			int modifiers = constructor.getModifiers();
			System.out.println("构造器的修饰符:" + Modifier.toString(modifiers));
			
			String name2 = constructor.getName();
			System.out.println("构造器名:" + name2);
			
			//形参列表
			System.out.println("形参列表:");
			Class[] parameterTypes = constructor.getParameterTypes();
			for (Class parameterType : parameterTypes) {
				System.out.println(parameterType);
			}
            
            //异常列表
			System.out.println("异常列表:");
			Class<?>[] exceptionTypes = constructor.getExceptionTypes();
			for (Class<?> exceptionType : exceptionTypes) {
				System.out.println(exceptionType);
			}
		}
//(3)方法们
		Method[] declaredMethods = clazz.getDeclaredMethods();
		for (Method method : declaredMethods) {
			//修饰符、返回值类型、方法名、形参列表 、异常列表 
			int modifiers = method.getModifiers();
			System.out.println("方法的修饰符:" + Modifier.toString(modifiers));
			
			Class<?> returnType = method.getReturnType();
			System.out.println("返回值类型:" + returnType);
			
			String name2 = method.getName();
			System.out.println("方法名:" + name2);
			
			//形参列表
			System.out.println("形参列表:");
			Class[] parameterTypes = method.getParameterTypes();
			for (Class parameterType : parameterTypes) {
				System.out.println(parameterType);
			}
			
			//异常列表
			System.out.println("异常列表:");
			Class<?>[] exceptionTypes = method.getExceptionTypes();
			for (Class<?> exceptionType : exceptionTypes) {
				System.out.println(exceptionType);
			}
		}

创建任意引用类型的对象并赋值(调构造器赋值)

两种方式:

1、直接通过Class对象来实例化(要求必须有无参构造)

2、通过获取构造器对象来进行实例化

方式一的步骤:

(1)获取该类型的Class对象(2)创建对象

	@Test
	public void test2()throws Exception{
		Class<?> clazz = Class.forName("com.atguigu.test.Student");
		//Caused by: java.lang.NoSuchMethodException: com.atguigu.test.Student.<init>()
		//即说明Student没有无参构造,就没有无参实例初始化方法<init>
		Object stu = clazz.newInstance();
		System.out.println(stu);
	}
	
	@Test
	public void test1() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
//		AtGuigu obj = new AtGuigu();//编译期间无法创建
		
		Class<?> clazz = Class.forName("com.atguigu.test.AtGuigu");
		//clazz代表com.atguigu.test.AtGuigu类型
		//clazz.newInstance()创建的就是AtGuigu的对象
		Object obj = clazz.newInstance();
		System.out.println(obj);
	}

方式二的步骤:

(1)获取该类型的Class对象(2)获取构造器对象(3)创建对象

如果构造器的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)

示例代码:

public class TestNewInstance {
	@Test
	public void test3()throws Exception{
		//(1)获取Class对象
		Class<?> clazz = Class.forName("com.atguigu.test.Student");
		/*
		 * 获取Student类型中的有参构造
		 * 如果构造器有多个,我们通常是根据形参【类型】列表来获取指定的一个构造器的
		 * 例如:public Student(int id, String name) 
		 */
		//(2)获取构造器对象
		Constructor<?> constructor = clazz.getDeclaredConstructor(int.class,String.class);
		
		//(3)创建实例对象
		// T newInstance(Object... initargs)  这个Object...是在创建对象时,给有参构造的实参列表
		Object obj = constructor.newInstance(2,"张三");
		System.out.println(obj);
	}
    //访问私有构造器
    @Test
    public void test05() throws Exception{
        //1.获取Class 对象
        Class<Person> personClass = Person.class;
        //2.获取指定的构造器
        Constructor<Person> c = personClass.getDeclaredConstructor(String.class, int.class, double.class);
        //3.禁止java语言的权限访问检测
        c.setAccessible(true);
        //4.给成员变量赋值
        Person person = c.newInstance("王安石", 30, 9898.6);
        //5.展示结果
        System.out.println("person = " + person);
    }
}

操作任意类型的属性

(1)获取该类型的Class对象
Class clazz = Class.forName("com.atguigu.bean.User");

(2)获取属性对象
Field field = clazz.getDeclaredField("username");

(3)设置属性可访问

field.setAccessible(true);

(4)创建实例对象:如果操作的是非静态属性,需要创建实例对象
Object obj = clazz.newInstance();

(4)设置属性值

field.set(obj,"chai");
(5)获取属性值
Object value = field.get(obj);

如果操作静态变量,那么实例对象可以省略,用null表示

示例代码:

//操作静态变量 	
@Test
public void test01() throws NoSuchFieldException, IllegalAccessException {
        //1.获取Class对象
        Class<Monkey> monkeyClass = Monkey.class;
        //2.获取指定的属性
        Field message = monkeyClass.getDeclaredField("message");
        //3.设置私有的属性可以操作
        message.setAccessible(true);
        //4.给属性赋值
        message.set(null,"HelloWorld");
        //5.获取属性值
        Object value = message.get(null);
        System.out.println("value = " + value);
}
//操作普通变量 	
@Test
public void test02() throws Exception {
       //1.获取Class对象
        Class<Monkey> monkeyClass = Monkey.class;
        //2.获取指定的属性
        Field gender = monkeyClass.getDeclaredField("gender");
        //todo 设置私有的属性可以访问
        gender.setAccessible(true);
        //3.创建对象
        Monkey monkey = monkeyClass.newInstance();
        System.out.println("monkey = " + monkey);
        //4.给属性赋值
        //todo 给monkey 对象的gender 属性赋值 为 男
        gender.set(monkey,'男');
        //5.展示对象
        System.out.println("monkey = " + monkey);
}

调用任意类型的方法

(1)获取该类型的Class对象
Class clazz = Class.forName("com.atguigu.service.UserService");
(2)获取方法对象
Method method = clazz.getDeclaredMethod("login",String.class,String.class);
(3)创建实例对象
Object obj = clazz.newInstance();
(4)调用方法
Object result = method.invoke(obj,"chai","123);

如果方法的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)

如果方法是静态方法,实例对象也可以省略,用null代替

示例代码:

//操作静态方法  
@Test
    public void test04() throws Exception{
       //todo 私有的静态方法
        //1.获取Class对象
        Class<Animal> animalClass = Animal.class;
        //2.获取指定的方法
        Method isPrimeNum = animalClass.getDeclaredMethod("isPrimeNum", int.class);
        //3.设置私有方法可以使用
        isPrimeNum.setAccessible(true);
        //4.执行方法 获取结果
        Object invoke = isPrimeNum.invoke(null, 20);
        //5.输出结果
        System.out.println("invoke = " + invoke);

    }
//操作普通方法 
    @Test
    public void test03() throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
       //todo 公共的实例方法
        //1.获取Class对象
        Class<Animal> aClass = Animal.class;
        //2.获取指定的方法
        Method sum = aClass.getMethod("sum", int.class, int.class);
        //3.创建对象
        Animal animal = aClass.newInstance();
        //4.调用方法
        sum.invoke(animal,89,20);

    }

标签:反射,System,clazz,获取,println,Class,out
From: https://www.cnblogs.com/21CHS/p/18365573

相关文章

  • GAMES101——作业5 光线与三角形相交(菲涅尔反射率)
    任务         需要修改的函数是:         Renderer.cpp中的Render():这里你需要为每个像素生成一条对应的光线,然后调用函数castRay()来得到颜色,最后将颜色存储在帧缓冲区的相应像素中。        Triangle.hpp中的rayTriangleInter......
  • 注解反射详解
    注解反射注解1.注解概述//什么是注解publicclassTest01extendsObject{//@Override重写的注解@OverridepublicStringtoString(){returnsuper.toString();}}2.内置注解//什么是注解@SuppressWarnings("all")//镇压警告publi......
  • Java反射机制快速入门与通配符
    1.Java反射的原理​在Java中,每个类在编译后都会生成一个.class文件,JVM会为每个加载的类创建一个Class对象,这个对象包含了类的全部结构信息,包括类名、方法、字段、构造函数等。Class对象存储了类的元数据,这些元数据可以在运行时被访问。通过Class对象,程序可以......
  • Python的反射以及应⽤用场景
    Python中的反射(Reflection)是一种强大的机制,它允许程序在运行时(runtime)检查、修改其自身的结构和行为。这种机制通过内置的函数和模块实现,使得程序能够动态地访问对象的属性和方法。在Python中,反射主要通过type()、isinstance()、issubclass()、getattr()、setattr()、hasattr()......
  • 注解给指定属性开启反射accessible
    要实现在属性上使用注解,并通过AOP给该属性的set方法设置setAccessible(true),可以通过以下步骤进行:定义注解:首先定义一个注解,用于标记需要通过反射访问的属性。importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.......
  • BGP 反射器联邦实验
    要求:1.如图连接网络,合理规划IP地址,AS200内IGP协议为OSPF2.R1属于AS100;R2-R3-R4小AS234  R5-R6-R7小AS567,同时声明大AS200,R8属于AS3003.R2-R5 R4-R7之间为联邦EBGP邻居关系4.R1-R8之间通信 1.如图连接网络,合理规划IP地址,A200内IGP协议为OSPF[r1]interface......
  • java反射简介
    1.反射定义 反射是一种可以间接操作目标对象的机制。当使用反射时,JVM 在运行的时候才动态加载类,对于任意类,知道其属性和方法,并不需要提前在编译期知道运行的对象是谁,允许运行时的Java程序获取类的信息并对其进行操作。2.获取类的四个方式 3.class从类中获取构造器......
  • UE5笔记:虚幻引擎反射系统和对象
    虚幻引擎反射系统使用宏提供引擎和编辑器各种功能,封装你的类。使用虚幻时,可以使用标准的C++类,函数和变量虚幻中对象的基类是UObject,UCALSS宏的作用是标记UObject的子类,以便UObject处理系统可以识别他们UObject创建1.不支持构造器参数。所有的C++UObject都会在引擎启动的时候......
  • 注解和反射
    注解和反射注解1什么是注解(Annotation)从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,注解的作用:不是程序本身,可以对程序作出解释可以在程序编译,类加载,运行时被读取,并执行相应的处理。注解的格式:注解是......
  • BGP反射器(四)
    解决IBGP全互联问题带来的问题:路由器需维护大量的TCP和BGP连接,尤其在路由器数量较多时AS内BGP网络的可扩展性较差角色RR:路由反射器Client:RR的客户端Non-Client:非客户机关系Client只与RR之间建立IBGP会话RR与RR之间建立IBGP全互联Non-Client与Non-Client之间建立IBGP全互联......