Java反射

本文探讨了JVM内存结构,包括栈中方法执行和局部变量管理,堆中对象存储,方法区的类信息与常量池,以及类的加载过程、ClassLoader的分类和作用。还讲解了Class对象、反射的运用,以及获取Class对象的不同方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JVM

内存

栈  执行代码是以方法为单位的
	遇到方法调用时,会找到该方法,压栈,方法执行完以后弹出,返回值放到上层函数
	代码中定义的临时变量/局部变量,方法的参数,都是在栈中定义的
	是线程隔离的,一个线程要单独分配一个栈 
	
堆  放置对象,数组对象,类的对象,接口的对象,只有是new创建出来的,都是要放在堆里
	常量池所在地(1.8以前实在方法区的)
	是线程共享的,多个线程可以同时访问同一块堆资源
	
方法区  类的信息,保存在Class对象中:类名,父类,有哪些方法/属性,有哪些构造方法
		静态属性所在地
		是线程共享的,多个线程可以同时访问一个类的信息 
		
本地方法区  存放native修饰的本地方法(由c/c++实现,如System.arrayCopy)
			是线程隔离的
			
程序计数器  记录程序执行到哪里了
			是线程隔离的,不同的线程有不同的程序计数器  		

类的加载
使用的是ClassLoader(类加载器),将类的字节码加载到JVM中

类加载器的分类

启动类加载器BootstrapClassLoader  加载JRE下的类的
扩展加载器  ExtClassLoader	jre/lib
系统加载器  SystemClassLoader  当前项目下的

当类加载器加载类时,可以向上委托

类加载的过程

加载    将字节码文件加载到类加载器中
		读取字节码文件的内容
链接	将类的二进制数据合并到JRE中
		校验  校验字节码文件
		准备  将类的信息放在方法区中
			  静态属性的声明,给它分配内存,同时初始化为类0值(但是此时静态属性不可访问)
		解析  解析成JVM认识的东西
初始化  执行静态代码:静态属性的数值,静态块
		当只有一个类被用到时,才会被初始化:创建类的对象,访问类的静态属性/调用类的静态方法,使用反射

加载完类以后,在方法区中就产生了一个Class类型的对象(一个类只加载一次,所以只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这恶鬼对象就像一面镜子,透过这个镜子看到类结构,所以我们形象的称之为,反射。

反射

在一个Java程序运行时,通过读取方法区中类的信息,操作类

Class类(final修饰的)

  • Class对象只能由系统建立对象
  • 一个Class对象对应的时一个加载到JVM中的一个.class文件
  • 每个类的实例都会记得自己是由哪个Class实例所生成
  • 通过Class可以完整地得到一个类中所有被加载的结构
  • Class类时Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象
  • Class的实例就对应着一个运行着的类

如何获取一个类的Class对象

通过已有对象获取 Object.getClass()
Student stu = new Student();//已有对象
Class cls1 = stu.getClass();

通过类名  类名.class
Class cls2 = Student.class

Class.forName("类的全限定名")
Class cls3 = Class.forName("package0222.Student");//可能会抛异常,要加try-catch

通过类加载器//不太会
ClassLoader classloader = ReflectionTest.class.getClassLoader();
Class<?> cls4 = classLoader.loadClass("package0222.Student");

Class实例可以代表的结构

  • class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类

  • interface:接口

  • []:数组

  • enum:枚举

  • annotation:注解

  • 基本数据类型

  • void

  • Serializable, Cloneable 无方法

通过Class对象可以干什么

类名    获取  System.out.println(cls.getName());
父类	获取
父接口  获取  System.out.println(Arrays.toString(cls.getInterfaces()));
包		获取
属性	获取
		获取属性值
		设置属性值  Field age = cls.getField("age");
				   age.setInt(stu1, 18);
		修改访问权限 Field name = cls.getDeclaredField("name");
					name.setAccessible(true);
					name.set(stu1, "tom");
方法	获取  System.out.println(Arrays.toString(cls.getDeclaredMethods()));
		调用  Method toString = cls.getMethod("toString");
			 //调用 str = stu1.toString();
			 String str = (String) toString.invoke(stu1);
构造方法 获取  System.out.println(Arrays.toString(cls.getConstructors()));
		调用

有了反射可以做一些更加通用的东西,比如框架的底层代码就是用反射写的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值