Java中为什么this可以调用当前实例

目录
  • 1. 前言
  • 2. 栈帧
  • 3. 分析
  • 4. 总结

1. 前言

在刚开始学习Java的时候,大家肯定都接触过this关键字,尤其是在构造函数赋值的时候,如下示例:

public class Person {
 private String name;
 private int age;

 public Person(String name, int age) {
  // 必须加this关键字,否则无法完成成员变量的赋值
  this.name = name;
  this.age = age;
 }
}

在构造函数中,如果成员变量名称和参数名称相同时,必须加this关键字,否则你只是将参数name赋值给它本身,并没有赋值给Person.name,因为局部变量的优先级高于成员变量。一旦加上this关键字,由于this指向的是当前实例,就可以完成对象的成员变量赋值。

那为什么可以通过this关键字访问到当前对象呢?

2. 栈帧

要弄清这个问题,首先要了解JVM在执行方法时,方法栈的栈帧结构。

Java虚拟机以【方法】作为最基本的运行单元,【栈帧】就是用于支持JVM进行方法调用背后的数据结构,它也是JVM运行时数据区中【虚拟机栈】中的栈元素。

简单点说,方法的执行过程可看作是一个个栈帧从入栈到出栈的过程。

栈帧中存储了方法的:局部变量表、操作数栈、动态连接和方法返回地址等信息。

当使用javac程序将源码编译成字节码后,一个方法的栈帧需要多大的局部变量表,多深的操作数栈就已经被计算出来,并且写入到方法表的【Code】属性中了,这一切和程序运行时无关。

换言之,一个方法它有多少个局部变量,在编译时就已经确定,不会随着程序的运行而改变。今天我们要探究的【this】问题,就在方法栈的局部变量表中。

3. 分析

我们仍然用javap命令来分析编译后的Class文件,这是最有说服力的。

public class Person {

 public void say() {

 }

 public static void staticSay() {

 }
}

如上一段代码,分别有一个实例方法和静态方法,我们已经知道,在静态方法中,是无法访问【this】的,但是在实例方法中可以。

先javac Person.java再javap -verbose Person,得到的信息有点长,我只贴这两个方法的信息。

public void say();
descriptor: ()V
flags: ACC_PUBLIC
Code:
  stack=0, locals=1, args_size=1
  0: return
  LineNumberTable:
 line 8: 0

public static void staticSay();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
  stack=0, locals=0, args_size=0
  0: return
  LineNumberTable:
 line 12: 0

重点关注【Code】那一栏,say()有一个局部变量,有一个参数。staticSay()没有局部变量,也没有参数。

是不是感到很疑惑?say()方法形参是空的,方法体也是空的,为什么编译后会显示它有一个局部变量和一个形参呢?

其实,对于实例方法而言,它至少有一个参数和一个局部变量,那就是当前对象。JVM在调用对象的实例方法时,会将对象本身的引用作为第0号参数传递过去,这样你就可以通过this关键字访问到对象本身了,其实也就是访问第0个参数而已。

如下,这两个方法其实是等价的。

public void say(Person this, String text) {
    System.out.println(text);
}

public void say(String text) {
    System.out.println(text);
}

4. 总结

Java虚拟机在执行方法时,会将方法打包成一个【栈帧】,栈帧中有【局部变量表】,参数也是局部变量表的一部分,一个方法的局部变量表有多大在编译时就已经确定,不会随着程序的运行而改变。
对于实例方法而言,在编译时会自动加上一个隐藏的0号参数,就是当前类。JVM在调用对象的实例方法时,会自动将对象引用作为第0号参数传递过去,访问【this】其实就是访问第0号参数。

到此这篇关于Java中为什么this可以调用当前实例的文章就介绍到这了,更多相关Java this调用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java使用this调用构造函数的实现方法示例

    本文实例讲述了java使用this调用构造函数的实现方法.分享给大家供大家参考,具体如下: 一 点睛 如果在程序中想用某一个构造函数调用另一个构造函数,也可以用this来实现. 二 实战 1 代码 class Person { String name; int age; public Person() { System.out.println("1. public Person()"); } public Person(String name, int age) { // 调用本类中无

  • Java中为什么this可以调用当前实例

    目录 1. 前言 2. 栈帧 3. 分析 4. 总结 1. 前言 在刚开始学习Java的时候,大家肯定都接触过this关键字,尤其是在构造函数赋值的时候,如下示例: public class Person { private String name; private int age; public Person(String name, int age) { // 必须加this关键字,否则无法完成成员变量的赋值 this.name = name; this.age = age; } } 在构造

  • java 中序列化与readResolve()方法的实例详解

    java 中序列化与readResolve()方法的实例详解 readResolve方法是作用是什么?这个方法跟对象的序列化相关(这样倒是解释了为什么 readResolve方法是private修饰的). 怎么跟对象的序列化相关了? 下面我们先简要地回顾下对象的序列化.一般来说,一个类实现了 Serializable接口,我们就可以把它往内存地写再从内存里读出而"组装"成一个跟原来一模一样的对象.不过当序列化遇到单例时,里边就有了个问题:从内存读出而组装的对象破坏了单例的规则.单例是要

  • Java中常见死锁与活锁的实例详解

    本文介绍了Java中常见死锁与活锁的实例详解,分享给大家,具体如下: 顺序死锁:过度加锁,导致由于执行顺序的原因,互相持有对方正在等待的锁 资源死锁:多个线程在相同的资源上发生等待 由于调用顺序而产生的死锁 public class Test { Object leftLock = new Object(); Object rightLock = new Object(); public static void main(String[] args) { final Test test = ne

  • Java中final关键字详解及实例

    final在Java中可以声明成员变量.方法.类以及本地变量.一旦你将引用声明作final,你将不能改变这个引用了,如果你试图将变量再次初始化的话,编译器会报编译错误.  final的含义在不同的场景下有细微的差别,但总体来说,它指的是"不可变". 1. final变量 凡是对成员变量或者本地变量(在方法中的或者代码块中的变量称为本地变量)声明为final的都叫作final变量.final变量经常和static关键字一起使用,作为常量.用final关键字修饰的变量,只能进行一次赋值操作

  • Java中finally和return的关系实例解析

    本文研究的主要是Java中finally和return的关系,具体介绍和实例如下所示. finally 和 return 关系的总结 1.try块中有System.exit(0)这样的语句,由于它是终止Java虚拟机JVM的,连JVM都停止了,所有都结束了,当然finally语句也不会被执行到. 2.其它情况下,finally语句都必然会被执行.因此可以在这里执行一些资源的释放操作. (1)finally中的return会覆盖try/catch中的renturn. (2)在finally中写re

  • java中封装JDBC工具类的实例分析

    对于能够重复使用的代码,我们最好的方法是对它们进行封装,然后在下次使用的使用就可以直接调用了.本篇所要提到的是JDBC工具类,相信大家在学习java时都接触过.那么对于封装它的方法,本篇先对工具类进行简单的说明,列出有关的封装步骤,然后带来相关的实例. 1.说明 在java开发过程中,代码中时常用到一些Scanner.Random一样的类,他们是键盘录入,生成随机数的类,像一个工具一样,在java中被称为工具类. 2.步骤 封装JDBC工具类 加入获取数据库连接对象的方法 加入释放连接的方法 3

  • java 中Excel转shape file的实例详解

    java  中Excel转shape file的实例详解 概述: 本文讲述如何结合geotools和POI实现Excel到shp的转换,再结合前文shp到geojson数据的转换,即可实现用户上传excel数据并在web端的展示功能. 截图: 原始Excel文件 运行耗时 运行结果 代码: package com.lzugis.geotools; import com.lzugis.CommonMethod; import com.vividsolutions.jts.geom.Coordina

  • JAVA 中解密RSA算法JS加密实例详解

    JAVA 中解密RSA算法JS加密实例详解 有这样一个需求,前端登录的用户名密码,密码必需加密,但不可使用MD5,因为后台要检测密码的复杂度,那么在保证安全的前提下将密码传到后台呢,答案就是使用RSA非对称加密算法解决 . java代码 需要依赖 commons-codec 包 RSACoder.Java import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import java.security.

  • java中判断字段真实长度的实例(中文2个字符,英文1个字符)

    实例如下: public class Char_cn { public static void main(String[] args) { // TODO Auto-generated method stub String haha = "我叫兜兜abcd"; int true_num = String_length(haha); System.out.println("true" + true_num); int false_num = haha.length()

  • java中volatile不能保证线程安全(实例讲解)

    今天打了打代码研究了一下java的volatile关键字到底能不能保证线程安全,经过实践,volatile是不能保证线程安全的,它只是保证了数据的可见性,不会再缓存,每个线程都是从主存中读到的数据,而不是从缓存中读取的数据,附上代码如下,当synchronized去掉的时候,每个线程的结果是乱的,加上的时候结果才是正确的. /** * * 类简要描述 * * <p> * 类详细描述 * </p> * * @author think * */ public class Volatil

随机推荐