Java语言this关键字用法全面总结

学习Java编程的时候,无论是谁,当学到面向对象这部分内容时都会遇到一个关键字:this。很多初学者对这个关键字的都会感觉到理解不透,不明白这个神秘的”this”到底表示什么意思。按照官方正规的解释,this关键字的意义被解释为“指向当前对象的引用”。这个解释非常准确并且很精炼,但它太过学术化了,导致很多初学者有点读不懂,更谈不上深入理解它的意义。本文将用大白话的形式帮助初学Java的小伙伴来深入理解this关键字的意义,并且梳理它的各种用法。

其实,我们只要把this理解成”本对象自己的...”就可以了。看到这个解释,很多人可能更懵了,什么叫”本对象自己的...”?不要着急,让我们首先来看一段代码。


在这段代码中,定义了一个表示”人”的类Person,在Person类中,有3个属性name、age和height,分别来表示姓名、年龄和身高。在类当中定义了一个构造方法,构造方法中对3个属性进行了初始化操作。最后定义了一个introduce方法,这个方法能够打印一个Person对象的姓名和年龄。现在,我们在main方法当中创建一个Person类的对象,并且调用这个对象的introduce方法,代码如下:


愉快的运行一下程序,出来的运行结果是这样的:


通过程序的运行结果我们可以看出,在创建对象的时候,对象的属性被赋予了正确初始值。这个程序本身非常的简单,谁都可以理解,但是大家请注意,我们在定义构造方法的时候,把表示姓名、年龄和身高的参数分别命名为:n、a和h,这种命名的可读性有点差,为了提高可读性,我们把构造方法的参数名称修改为name、age和height,如下图所示:


修改之后,再次运行main方法,得到的运行结果变成了这个样子:


为什么这一次的运行结果出现了问题呢?就是因为,修改了构造方法之后,当我们调用构造方法创建对象时,给构造方法所传递的3个参数值“张三”、20和178.5最终并没有赋值到对象的3个属性中。那么,既然参数值没有被赋值到对象的属性中,它们去了哪里呢?修改代码后,构造方法的参数与类所定义的属性同名,根据”同名情况下,局部变量的优先级更高”原则,在构造方法执行的过程中,虚拟机会把参数值赋给”参数本身”,而不是赋值给对象的属性!具体来说,就是我们给构造方法的name参数传递的值是”张三”,而这个”张三”在构造方法执行的过程中,当运行到”name=name;”这条语句时,并没有把”张三”赋值给对象的name属性,而是又重新赋值给了name参数自身。就是因为”张三”最终没有被赋值到对象的name属性中,才导致introduce方法中打印出的name属性是null。当然,age和height这两个参数也是同样的赋值效果。
为了能够让虚拟机明白我们所期望的是:把”张三”这个字符串赋值给对象的name属性,而不是”再一次”把它赋值给构造方法的参数,就需要把构造方法中的赋值语句做出如下修改:

大家来看,这一次,我们在构造方法中,给”=”左边的属性前面都加上了this关键字,经过修改之后,重新运行main方法,就恢复了正常的运行效果。好,现在我们就来探究一下,加了this关键字之后,为什么程序能够”恢复正常”。刚才我们说过,”this”可以被解释为” 本对象自己的...”,按照这个逻辑,”this.name”就可以被解释为”本对象自己的name属性”,所以在执行”this.name=name;”这条语句的时候,虚拟机就会把name参数的值”张三”赋值给对象的name属性。也就是说在这条赋值语句中,”=”左边的”this.name”表示对象的name属性,而”=”右边的name表示方法的name参数。
讲到这里,有的小伙伴可能会问:”this.name”为什么不能被解释为”本对象自己的name参数”呢?因为”参数”这个概念是就某个方法而言的,它相当于某个方法的”局部变量”,只是这个”局部变量”比起在方法中定义的真正的局部变量来讲有点特殊,它能够接收从主调方法中传递过来的值。因此,当我们说到”参数”这个概念的时候,都是相对于一个”方法”而不是一个”对象”而言的,所以也就不会有”某个对象的参数”这一说法。因此,”this.name”只能被虚拟机认定为本对象自己的name”属性”,绝不会被当作name”参数”。

通过这个例子,希望大家能够理解this关键字的意义。在程序中,所出现的”this.属性名”是this关键字最常见的一种用法,也是我们给大家总结的this关键字的第一种用法。既然”this.属性名”可以被解释为”本对象自己的XX属性”,那么会不会有”this.方法名”这种用法呢?当然有这种用法,当程序中出现了”this.方法名”这种写法,就可以被解释为调用”本对象自己的XX方法”。来看下面的代码:

这一次,我们给Person类增加了一个”打招呼”的方法叫做greet。在introduce方法当中,就可以通过”this.方法名”的方式来调用这个方法,表示调用的是”本对象自己的greet”方法。这是this关键字的第二种用法。当然,在introduce方法中并没有出现其他对象,所以方法名前面的this关键字也可以省略不写。

既然this关键字表示的是本对象自己,所以在代码中可以直接用this来代表对象自身。比如说,在Ojbect类当中定义了一个equals()方法,这个方法用来比较自身对象与其他对象是不是相等,就直接可以用this来与其他对象做比较。


上面这段代码就是Object类的equals()方法的源代码,有兴趣的小伙伴可以去看看。在代码中直接用this关键字代表对象本身,并且和另一个对象obj做了比较。(关于==这个运算符到底比的什么,大家可以看我的另一篇博文《你真的掌握了Java语言的"=="运算符吗?我看未必!》)

其实,this关键字还有另外一种很重要的用法,那就是在this关键字的后面加上小括号,这样就表示调用了某个类自身的构造方法,为了讲解这种用法我们再来修改一下Person类。


这一次,我们给Person类又增加了一个构造方法。这个构造方法只有2个参数,并且只初始化2个属性。为了讲述方便,我们把上面的3个参数的构造方法称之为”构造方法①”,把下面的2个参数的构造方法称之为”构造方法②”。通过观察不难发现,这两个构造方法当中前2行代码是相互重复的,为了避免这种重复性的代码出现,我们可以在”构造方法①”当中调用”构造方法②”。调用的方式如下:


在”构造方法①”中,通过”this(参数);”的方式调用了”构造方法②”。这就是this关键字的又一种用法。很多小伙伴可能不理解,为什么要通过这种方式来调用构造方法呢?我们难道不能直接写一个”Person(name,age);”来调用吗?这里必须做出解释:在Java语言中,一个类的构造方法与类名相同。但是,一个类当中也可以定义一个与类名相同的”普通方法”,换句话说就是:并不是只有构造方法与类名相同,”普通方法”也可以取和类相同的名称(只不过全世界的程序员都不会这么干)。那么,在这种情况下,编译器如何区分这个方法是”普通方法”还是”构造方法”呢?很简单,”普通方法”的名称前面必须定义返回值类型,而”构造方法”的名称前面则没有返回值类型的定义。这样,编译器就能够分得清哪个是”构造方法”,哪个是”和类同名的普通方法”。
定义的时候分得清,但是在调用的时候,都是通过方法名来调用的,这时如何分得清代码中哪一句调用的是”构造方法”, 哪一句调用的是”和类同名的普通方法”呢?为了解决这个问题,Java语言规定,在本类中调用构造方法的时候,需要通过”this(参数)”的方式来调用。除此之外,Java语言还规定了这种调用方式所必须遵守的规则。首先,这种”this(参数)”的方式只能在”其他构造方法中”使用,不能在普通方法中用。如果在普通方法中按这种方式使用,将被视为语法错误,如下图所示

可以看到,在普通方法中按这样的方式调用构造方法会出问题。
其次,在一个构造方法中,用”this(参数)”的形式调用构造方法,”this(参数)”必须写在主调方法的第一行。第三,不能出现相互循环嵌套调用,也就是说,不能在构造方法①中调用构造方法②,又同时在构造方法②中调用构造方法①,如下图所示

这种相互调用的写法是绝对不允许的。

接下来我们再来思考两个问题:首先,在main()方法中执行到”new Person("张三",20,178.5);”这句代码时,实际上是调用了构造方法①,而构造方法①中又调用了构造方法②,两个构造方法都被调用到了,那么在内存中会不会创建两个Person对象呢?答案是不会,为什么呢?原因很简单:构造方法①中调用了构造方法②,并没有出现new关键字,调用构造方法②仅仅是完成了name和age这两个属性的初始化,并不会创建出两个对象。

我们要思考的第二个问题是:既然Java语言允许”普通方法”的名称与类名相同,而构造方法也与类名相同,那么在Person以外的类当中如果写上了”Person(参数)”这样的代码,虚拟机如何判断所调用的是普通方法还是构造方法呢?答案也很简单,如果”Person(参数)”的前面出现了new关键字,这就说明调用的是构造方法,否则说明调用的是普通方法。

讲到这里,我们就把this关键字最常用的几种用法讲完了,其实,this关键字在我们编写内部类代码的时候,还有一种用途,那就是区分属性或方法的具体归属。我们来看下面的代码:

在这段代码中,定义了外部类Outter,Outter有一个属性a,并且Outter中又定义了内部类,在内部类的printA()方法中调用了外部类的a属性。我们都知道,一个内部类可以直接访问它所在外部类的属性和方法。这个特性在我们的上面这段代码中得到了体现。但是,如果内部类中出现了与外部类同名的属性或方法时,该如何区分调用的到底是哪个属性或方法呢?比如说,在Inner类中也出现了a属性,那么输出语句中的a到底是指哪个a呢?很简单,如果输出语句中直接写a,那么调用的是内部类的a属性。为了强调它是内部类的a属性,我们也可以在a的前面加this关键字。如果我们希望调用的是外部类的a属性,可以用”外部类名.this.a”的方式来调用,如下图所示:

以上我们就把this关键字的意义和它的各种用法讲完了,简单总结一下:
1、this:表示自身对象,也就是本对象自己
2、this.属性名:表示本对象自己的属性
3、this.方法名:表示本对象自己的方法
4、this(参数)表示本对象自身的构造方法(注:”构造方法”这个概念是相对于”类”而言的,但具体到this(参数)这种用法时,表示”我这个对象自己的构造方法”)
5、外部类名.this.属性:表示在内部类中调用的是外部类的某个属性(调用外部类方法亦同)

希望本文能够帮助初学者深入理解this关键字的作用。

如想系统学习Java编程,欢迎观看我在本站的视频课程。

原文地址:https://blog.51cto.com/2266836/2483097

时间: 2024-11-06 11:11:25

Java语言this关键字用法全面总结的相关文章

Java下static关键字用法详解

Java下static关键字用法详解 本文章介绍了java下static关键字的用法,大部分内容摘自原作者,在此学习并分享给大家. Static关键字可以修饰什么? 从以下测试可以看出, static 可以修饰: 1. 语句块 2. 成员变量(但是不能修饰局部变量) 3. 方法 4. 接口(内部接口) 5. 类(只能修饰在类中的类, 即静态内部类) 6. jdk 1.5 中新增的静态导入 那么static 修饰的表示什么呢? 当创建一个类时,就是在创建一个新类型,描述这个类的对象的外观和行为,除

Java语言Socket接口用法详解

Socket接口用法详解   在Java中,基于TCP协议实现网络通信的类有两个,在客户端的Socket类和在服务器端的ServerSocket类,ServerSocket类的功能是建立一个Server,并通过accept()方法随时监听客户端的连接请求. 扩展: ServerSocket中常用的构造函数及方法 构造函数:ServerSocket(int port) 这是一个构造方法,用于在当前的服务器默认的IP地址上监听一个指定的端口,即在指定的IP和端口创建一个ServerSocket对象

Java语言的关键字

Java语言的关键字有:(所有的关键字都是小写) abstract.boolean.break.byte.case. catch.char.class.continue.default. do.double.else.extends.false. final.finally.float.for.if. implements.import.instanceof.int.interface. long.native.new.null.package. private.protected.public

Java-Runoob-高级教程-实例-方法:09. Java 实例 – continue 关键字用法-un

ylbtech-Java-Runoob-高级教程-实例-方法:09. Java 实例 – continue 关键字用法 1.返回顶部 1. Java 实例 - continue 关键字用法  Java 实例 Java continue 语句语句用来结束当前循环,并进入下一次循环,即仅仅这一次循环结束了,不是所有循环结束了,后边的循环依旧进行. 以下实例使用了 continue 关键字来跳过当前循环并开始下一次循环: Main.java 文件 public class Main { public

Java中static关键字用法总结

1.     静态方法 通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法 声明为static的方法有以下几条限制: · 它们仅能调用其他的static 方法. · 它们只能访问static数据. · 它们不能以任何方式引用this 或super. class Simple { static void go() { System.out.println("Welcome"); } } public class Cal { public static vo

07 JAVA语言基础关键字的概述和使用

关键字概述 被java语言赋予特定含义的单词 关键字特点 组成关键字的字母全部小写 关键字注意事事项 goto和const作为保留字存在,目前并不使用 关键字图表

Java SE02 Java语言基础:关键字,标识符,注释

关键字:一些被赋予了java含义的单词,class  public static void 定义访问权限修饰符的关键字 private protected public 定义类,函数,变量修饰符 abstract final static synchronized 定义类与类之间关系的关键字 extends implements 定义建立实例,引用实例,判断实例 new this super instanceof 处理异常 try catch finally throw throws 用于包的关

Java 中 synchronized的用法详解

Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 1.方法声明时使用,放在范围操作符(public等)之后,返回类型声明(void等)之前.这时,线程获得的是成员锁,即一次只能有一个线程进入该方法,其他线程要想在此时调用该方法,只能排队等候,当前线程(就是在synchronized方法内部的线程)执行完该方法后,别的线程才能进入.例如: public synchronized void synMethod() { //方法体} 2.

java中synchronized的用法与详解

Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行.另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块. 二.然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块.