java 反射 内存_Java内存到反射入门

本文介绍了Java内存区域的结构,特别是方法区,然后详细讲解了反射的概念和作用。通过源代码、字节码和运行时阶段的剖析,阐述了如何利用反射获取和操作类的成员变量、方法和构造器。最后展示了如何使用Class类进行实际操作,以及不同获取Class对象方式的比较。
摘要由CSDN通过智能技术生成

Java内存到反射入门(一)

初识Java内存

平常我们最常提到的的JAVA分区是这三个分区

033ea5706ea25e4dbdf17f42476360dd.png

其中方法区是一个特殊的堆,功能如图上所示。

初识反射:框架设计的灵魂

反射的功能:将类的各个组成部分封装为对象,并在程序运行的过程中可以调用它们。

Java代码的三个阶段

我们平时书写的java代码,从书写完成到内存中执行主要经历了三个阶段:Source 源代码阶段,class类对象阶段,Runtime运行时阶段。下图以一个简单的Person类来举例说明。

462e4492d93b5ded507dd87f24111158.bmp

第一阶段:Source源代码阶段

首先,我们编写好了一个Person类的代码,它由成员变量,构造方法,成员方法三部分组成。

public class Person{

private String name;

private int age;

public Person(){}

public void eat(){}

}

此时它是一个Person.java文件。还不能运行,接着我们要用javac命令编译它,使生成一个Person.Class字节码文件。

43c346428c2126b56a4f1f7d9724211b.png 这个文件我们并不能看懂,其实里面主要包含三部分内容:成员变量,成员方法和构造方法,还有一些诸如包名的信息。

至此,源代码和字节码都是以文件的形式储存在硬盘上的,还未进入内存,此阶段我们称之为Source源代码阶段。

第二阶段:Class类对象阶段

要想由第一个阶段进入第二个阶段,要经过一个加载的过程。由类加载器ClassLoder将class文件加载到内存中,并生成该类的class类对象。class类对象是来描述字节码文件的,字节码文件被封装为三大部分:

1.成员变量被封装为Field对象,并用Filed[]存储。

2.构造方法被封装为Constructor对象,并用Constructor[]存储。

3.成员方法被封装为Method对象,并用Method[]存储。

这样的封装就是反射机制,经过了这样的封装后,我们就可以在程序运行的过程中来操作这些对象了。即获取,修改变量和执行方法等。

举个栗子:在IDEA等IDE中,写如下一段代码:

//定义了一个字符串变量,并尝试调用它自带的方法

String str = "abc";

str.

在按下str后面这个.后,IDEA会提示许多的方法。

cefe9436cc929ff558912dce55a87ae4.png 那么为什么IDEA会提示这些方法呢?其实内部就是反射机制。 定义了一个String变量后,则字符串的字节码文件就会被加载进内存。在内存中就有了String的class类对象,里面封装了Method[]存储了所有String的方法。所以只要挨个显示一下就可以了。

第三阶段:Runtime运行时阶段

第二阶段通过创建对象等操作就会进入第三阶段,创建对象时就会根据这个class类对象创建一个真正的Person对象。

获得class类的三种方法

Class.forName("全类名"):将字节码文件加载进内存,返回Class对象 * 多用于配置文件,将类名定义在配置文件中。读取文件,加载类

//如获取Person类的.Class文件

Class a = Class.forName("Domain.Person");//Domian是Person类所在包

类名.class:通过类名的属性class获取,该方法多用于参数的传递。

Class a = Person.calss;

对象.getClass():getClass()方法在Object类中定义着,该方法多用于对象的获取字节码的方式

Person person = new Person();

Class a = person.getClass();

Tip:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

//采用多种方式得到.Class文件

Class a = Class.forName("Domain.Person");

Person person1 = new Person();

Person person2 = new Person();

Class b = person1.getClass();

Class c = Person.class;

Class d = person2.getClass();

//不管以哪种方式得到的.Class类,只要是Person类的,那就是一样的。

System.out.println(a==b); //true

System.out.println(c==b); //true

System.out.println(a==c); //true

System.out.println(a==d); //true

Class类的用法

在熟悉了Class类的获取方法后,自然要熟悉其用法。

//以下是测试用的Person类

public class Person {

private String name;

private int age;

private int id;

public Person() {

}

public Person(String name, int age, int id) {

this.name = name;

this.age = age;

this.id = id;

}

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 int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

@Override

public String toString() {

return "Person{" +

"name='" \+ name \+ '\\'' +

", age=" \+ age +

", id=" \+ id +

'}';

}

}

用法一:获取类的名字

方法有两个:

String getName(); //返回类的包名+类名

String getSimpleName();//获取简单类名

Class c1 = Person.class;

System.out.println(c1.getName()); //该方法获取类的全名,输出Domain.Person

System.out.println(c1.getSimpleName());//该方法获取类的简单名,即Person

用法二:获得类的属性

方法有四个:

Field[] getFields() :获取所有public修饰的成员变量

Field getField(String name) 获取指定名称的 public修饰的成员变量

Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符

Field getDeclaredField(String name)

c7c1db92c02fb922988de54ecf86f8e8.png

用法三:获得类的方法

方法有四个:

Method[] getMethods() ;

Method getMethod(String name, 类>... parameterTypes) ;

Method[] getDeclaredMethods() ;

Method getDeclaredMethod(String name, 类>... parameterTypes) ;

45aceba3d3fb027b476f85e5f80856d8.png 注意第一个方法会获取包括本类和父类的所有public方法。 第二个方法只会获取本类的所有方法,包括private的,不包括父类的方法。

6a908bec4ad8d863092900ec7ff0cd46.png 获取指定方法的第一个参数是方法的名称,第二个参数是要获取的方法的参数类型,如setName(String name);函数,参数是String,则此处写String.Class;

用法四:获得构造器(构造方法)

有四种方法:

获取构造方法们

Constructor>[] getConstructors()

Constructor getConstructor(类>... parameterTypes)

Constructor getDeclaredConstructor(类>... parameterTypes)

Constructor>[] getDeclaredConstructors() ;

ce5352a2c7abac53c07b265ea9345b17.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值