Java基础语法之this关键字与static关键字

一、this

按照教科书式的说法,this代指的是当前对象。This关键字不能在方法之外被使用,而只能用于方法内部,常见的使用场景有两个:

1)用于构造方法或setter方法内字段的赋值语句,如下:

public  class Apple {
    private String color;
 
     public Apple(String color) {
         This.color = color;
     }
 
     public  void setColor(String color) {
        This.color= color;
     }
}


显然,在这种场景下,this关键字只是为了区分方法中的参数与字段,因为二者的名字一般写成一样的。如果没有this,那么赋值语句就是这样的:

color = color;

这会引起混淆。

        2)直接用于调用构造方法:

public class Apple{
    private Stringcolor;
    private float weight;
 
    public Apple(Stringcolor, float weight) {
        This.color = color;
        This.weight = weight;
    }
 
    public Apple(floatweight) {
        This(“green”, weight);
    }
}

可以看到,第二个构造方法重载了第一个,且比第一个的参数要少,然后直接调用了一个构造方法,并将第一个参数写死。调用的方式并非传统的构造方法名,而是直接使用this()。其实这时,从语法的角度,this不再是一个对象引用,而是一个方法名,是构造方法的替身,跟直接调用构造方法没有区别。

这里所说几句关于调用构造方法的注意事项:构造方法只能被构造方法调用而不能被普通方法调用;构造方法调用别的构造方法时,只能调用一个;构造方法的调用语句必须是方法体的第一句。

 

其他就回归this的本质了,它就是一个引用类型的变量,指向当前对象,因而可以出现在任何正常变量可以出现的地方。比如:

return this;

那就是返回当前对象。


如果之前对面向对象的思维方法不太熟悉的话,可能会疑惑什么是当前对象?对此我有一点自己的思考:我们写代码的时候,写的其实是模板,也就是对象的母体——类,这个时候(源代码阶段)对象还没new出来呢。哪怕是类加载之后,这时方法代码编译后的字节码都进入了内存,可是对象也还没出生,但是我们经常会遇到这种需求,即一旦某个对象new了出来,我们希望能获得这个对象的引用,而且是在模板创造阶段。这类似于超前使用,或者预知、透支、未来、whatever,故需要一个符号提前占位,这个占位的符号就是this。

那么有了这个this,是不是就可以在代码中到处使用这个关键字呢?主流的意见是能不用就不用,除非必须得用。。比如,一个方法调用同一个类的另一个方法,也可以在方法体内加上this.methodB(),然而这毫无必要。

 

语法说完了,我们就要深入研究一下this是如何实现的。《Java编程思想》中提到“编译器在幕后做了一些工作,它暗自把‘所操作对象的引用’作为一个参数传递给方法”,这意思就是说,尽管我们在写代码时没做啥,但是其实经过编译器的编译之后,方法的第一个参数其实都成了this。而《深入理解Java虚拟机》中的6.3.7节讲属性表集合的时候也提到“任何实例方法里面,都可以通过this关键字访问到此方法所属的对象……实例方法的局部变量表中至少会存在一个指向当前对象实例的局部变量……”这样其实就比较清楚了。

但是还有一个疑问,为啥要这样做呢?为啥非要偷偷的把当前对象的引用作为第一个参数传给实例方法呢?通过一个对象引用调用它的字段跟调用它的方法有什么不一样的地方吗?比如:

Apple a = new Apple();

a.color = “green”;

a.setColor(“green”);

由前面的分析我们知道,a.setColor(“green”)实际上是setColor(a, “green”),而a.color就是a.color,在对象a上调用自己的方法为啥还要把自己当参数传递过去呢?方法不知道自己属于谁吗?

       讲真,还真不知道,必须得传。大家都知道,类的非static字段是对象私有的,对象在堆上new出来的时候,就获取一块空间存放自己的数据,那么数据里面肯定包括字段的值。那么问题是,会不会还包括方法体的那些代码(编译后就是字节码,也就是指令)呢?进一步,类中定义的字段是对象私有的,但是方法呢?也是每个对象都存储一份?可是方法的逻辑其实都是一样的嘛,不同的只是传入的参数,有必要每个对象存一份吗?

       答案是否定的。要是真这么做了,得浪费多少空间?Java的设计者又不是傻子。Java运行时的内存模型大家都是知道的,大体上就是七块:PC计数器,方法区,虚拟机栈,本地方法栈,堆,运行时常量池,直接内存。大家看到方法区,就没怀疑过里面装的到底都是些什么?方法区嘛,肯定就是那些方法体的代码喽,不然干嘛叫方法区?可是我查了很多资料,大家都没有直接说里面确实有方法代码,而是说了很多无关的东西,比如“类信息、常量、静态变量、即时编译器编译后的代码”,难道是因为太明显了所以不屑于说出来?

       我的想法就是,方法体的代码可定都在方法区,那些逻辑或者说指令流都存放在类的方法区里,而方法区一个类就只有一块,类似于static变量,而不是对象那样每个一块地盘。说到底,方法是所有对象共享的,所以通过对象引用调用方法时必须得传入对象引用。

       以上就算是对this关键字底层的一个分析,可以看出this是与对象紧密相关的,所以在static方法中绝对不能出现this,而且static方法也不能调用实例方法(反之是可以的),大家想想这是为什么?

我的答案:static方法时可以直接通过类名调用的,这时可能还没有该类的对象new出来;假如内部调用了一个实例方法,那么编译后就需要传入this引用,可是这时this到底指向谁?有对象吗?

        没有(哭……)


二、static

        从意义上讲,static和this关键字是相对的,前者表示“类的”,后者表示“对象的”。

        static关键字提供了一种可能,即不必new该类的对象而直接访问字段或方法。被static 修饰字段或方法,可以直接通过类名来访问这些字段或方法。
        被static修饰的字段称为静态变量,由上面的介绍,我们知道它们存储在方法区,而不是堆上;被所有对象共享,但不属于任何一个对象;并且它们的初始化在类加载的时候就进行了,而不是创建对象的时候。
        static方法与非static方法的区别就是,前者可以通过类名直接访问,也可以通过对象来访问(虽然没有必要);而后者只能通过对象来访问。非static方法不能调用static方法,但反之是可以的。static方法不能访问非static字段,而非static方法可以访问任何字段。

你可能感兴趣的:(java)