前言: 在平时的编码过程中, 相信大家都会频繁地使用到 this 或 static 关键字但可能你仅仅是了解它的用法, 而对其内部机制知之甚少今天我们就一起来探讨一下它们的内部机制
一. this 关键字的详解
首先我们来总结一下 this 常见的应用场景, 下面我们定义一个 User 类, 基本包含了我们常见的 this 的用法, 如下所示:
- public class User {
- private String name;
- private int age;
- public User(String name) {
- this.name = name;
- }
- public User(String name, int age) {
- this(name);
- this.age = age;
- }
- /**
- * 打印名称
- */
- private void printName() {
- System.out.println(name);
- }
- /**
- * 打印年龄
- */
- private void printAge() {
- System.out.println(age);
- }
- /**
- * 打印名称
- */
- private void print() {
- this.printName();
- this.printAge();
- }
- /**
- * 修改信息并返回对象
- */
- private User updateName(String name){
- this.name = name;
- return this;
- }
- }
场景一: 应用 this 在成员变量上
- public User(String name) {
- this.name = name;
- }
在这种情况下, 由于自变量 name 的名字以及成员数据 name 的名字是相同的, 所以会出现混淆为解决这个问题, 可用 this.name 来引用成员数, 经常都会在 Java 代码里看到这种形式的应用 this 是指当前对象, this.name 是指当前对象的成员变量 name
场景二: 构造器里使用 this 调用构造器
- public User(String name, int age) {
- this(name);
- this.age = age;
- }
若为一个类写了多个构建器, 那么经常都需要在一个构建器里调用另一个构建器, 以避免写重复的代码在 User 类中, 两个参数的构造器就通过 this 调用了一个参数的构造器
this 通常是指这个对象或者当前对象而且它本身会产生当前对象的一个句柄在一个构建器中, 若为其赋予一个自变量列表, 那么 this 关键字会具有不同的含义: 它会对与那个自变量列表相符的构建器进行明确的调用这样一来, 我们就可通过一条直接的途径来调用其他构建器构建器调用必须是我们做的第一件事情, 否则会收到编译程序的报错信息
场景三: 方法中通过 this 调用方法
- private void print() {
- this.printName();
- this.printAge();
- }
在 print 方法内调用 printName 方法我们可以用 this.printName(), 亦可以直接调用 printName()事实上, 这里的 this 是没必要的, 编译器能帮我们自动完成
场景四: 通过 this 获取当前对象
- private User updateName(String name){
- this.name = name;
- return this;
- }
在这个方法中, 我们先改变了成员变量 name 的值, 接下来调用了 return this 代码这里的 this 是返回了当前对象相应的句柄, 也就是返回的对象和原调用对象其实是一个对象, 在堆中都指向同一片内存地址这个我们可以通过代码进行验证:
- // 测试代码
- public static void main(String[] args) {
- User user = new User("hello");
- System.out.println("old:" + user);
- System.out.println(user.getName());
- User user1 = user.updateName("world");
- System.out.println("new:" + user1);
- System.out.println(user.getName());
- }
首先创建了一个 user 对象, 给对象的 name 变量赋值为 hello, 打印的结果应该是 user 对象的地址和 name 名称 hello
接下来, 我们通过 updateName 方法修改对象的那么变量值为 world, 如果我们上面结论成立, 打印的 user1 对象地址应给和 user 的地址一样, 对象的 name 变量值应该为 world
结果和我们的预期一样, 因此上面的结论是正确的: 通过 this 返回的是当前对象相应的句柄, 即是方法调用对象的句柄结果如下:
- old:com.cbg.User@511d50c0
- hello
- new:com.cbg.User@511d50c0
- world
重要: 如果再进一步探究内部的原理, 可以从 user 对象调用 updateName 方法入手我们在 Java 代码中一般的调用方式是:
user.updateName("world")
, 但是编译器还会在内部为我们完成一些幕后工作, 将上面的代码转化为如下的调用方式:
User.updateName(user,"world")
, 也就是说, 上面两行代码是等效的只是, 一个是我们平常调用的, 一个事编译器调用的但是, 第二种方式是内部的表达形式, 我们并不能这样书写表达式, 并试图让编译器接受它到这里, 我们就明白, 其实要得到 user 的句柄, 在编译器内部其实就是那么简单, 也就解释了地址相同的问题其实, 返回的 user1 对象, 就是改变了 name 属性的 user 对象
二. static 关键字的详解
将 this 和 static 放在一起, 是因为我们可以在对比中进行更深刻的理解
由 static 修饰的方法或字段, 都是属于类级别的而 this 指代的是当前对象 (对象级别) 意味着在 static 修饰的特定的方法中不存在 this
注意: 利用 static 方法, 我们不必向对象发送一条消息, 因为不存在 this
我们不可从一个 static 方法内部发出对非 static 方法的调用 (特例: 我们将一个对象句柄传到 static 方法内部这时, 在 static 方法内部, 会获取到这个对象的句柄(上文中的 this) 通过这个句柄, 我们可调用非 static 方法, 并访问非 static 字段)
在没有任何对象的前提下, 我们可针对类本身发出对一个 static 方法的调用
三. 总结: 到这里, 相信大家对 this 和 static 的用法都有了或深或浅的理解, 还有更多的关于它们的用法, 就需要自己去探索发散啦! 也可以留言, 一起探讨最后, 希望对大家有帮助额!!
来源: http://blog.csdn.net/chenbaige/article/details/79423647