java必学必会之static关键字


Posted in Javascript onDecember 03, 2015

一、static关键字

java必学必会之static关键字

原来一个类里面的成员变量,每new一个对象,这个对象就有一份自己的成员变量,因为这些成员变量都不是静态成员变量。对于static成员变量来说,这个成员变量只有一份,而且这一份是这个类所有的对象共享。

1.1.静态成员变量与非静态成员变量的区别

以下面的例子为例说明

package cn.galc.test;

public class Cat {

  /**
   * 静态成员变量
   */
  private static int sid = 0;

  private String name;

  int id;

  Cat(String name) {
    this.name = name;
    id = sid++;
  }

  public void info() {
    System.out.println("My Name is " + name + ",NO." + id);
  }

  public static void main(String[] args) {
    Cat.sid = 100;
    Cat mimi = new Cat("mimi");
    Cat pipi = new Cat("pipi");
    mimi.info();
    pipi.info();
  }
}

通过画内存分析图了解整个程序的执行过程

执行程序的第一句话:Cat.sid = 100;时,这里的sid是一个静态成员变量,静态变量存放在数据区(data seg),所以首先在数据区里面分配一小块空间sid,第一句话执行完后,sid里面装着一个值就是100。

此时的内存布局示意图如下所示

java必学必会之static关键字

接下来程序执行到:

  Cat  mimi = new Cat(“mimi”);

这里,调用Cat类的构造方法Cat(String name),构造方法的定义如下:

Cat ( String name){

this.name = name;

id=sid++;

}

调用时首先在栈内存里面分配一小块内存mm,里面装着可以找到在堆内存里面的Cat类的实例对象的地址,mm就是堆内存里面Cat类对象的引用对象。这个构造方法声明有字符串类型的形参变量,所以这里把“mimi”作为实参传递到构造方法里面,由于字符串常量是分配在数据区存储的,所以数据区里面多了一小块内存用来存储字符串“mimi”。此时的内存分布如下图所示:

java必学必会之static关键字

当调用构造方法时,首先在栈内存里面给形参name分配一小块空间,名字叫name,接下来把”mimi”这个字符串作为实参传递给name,字符串也是一种引用类型,除了那四类8种基础数据类型之外,其他所有的都是引用类型,所以可以认为字符串也是一个对象。所以这里相当于把”mimi”这个对象的引用传递给了name,所以现在name指向的是”mimi”。所以此时内存的布局如下图所示:

java必学必会之static关键字

接下来执行构造方法体里面的代码:

this.name=name;

这里的this指的是当前的对象,指的是堆内存里面的那只猫。这里把栈里面的name里面装着的值传递给堆内存里面的cat对象的name属性,所以此时这个name里面装着的值也是可以找到位于数据区里面的字符串对象“mimi”的,此时这个name也是字符串对象“mimi”的一个引用对象,通过它的属性值就可以找到位于数据区里面的字符串对象“mimi”。此时的内存分布如下图所示:

java必学必会之static关键字

接下来执行方法体内的另一句代码:id=sid++;

这里是把sid的值传递给id,所以id的值是100,sid传递完以后,自己再加1,此时sid变成了101。此时的内存布局如下图所示。

java必学必会之static关键字

到此,构造方法调用完毕,给这个构造方法分配的局部变量所占的内存空间全部都要消失,所以位于栈空间里面的name这块内存消失了。栈内存里面指向数据区里面的字符串对象“mimi”的引用也消失了,此时只剩下堆内存里面的指向字符串对象“mimi”的引用没有消失。此时的内存布局如下图所示:

java必学必会之static关键字

接下来执行:Cat  pipi = new Cat(“pipi”);

这里是第二次调用构造方法Cat(),整个调用过程与第一次一样,调用结束后,此时的内存布局如下图所示:

java必学必会之static关键字

最后两句代码是调用info()方法打印出来,打印结果如下:

java必学必会之static关键字

通过这个程序,看出来了这个静态成员变量sid的作用,它可以计数。每当有一只猫new出来的时候,就给它记一个数。让它自己往上加1。

程序执行完后,内存中的整个布局就如上图所示了。一直持续到main方法调用完成的前一刻。

这里调用构造方法Cat(String name) 创建出两只猫,首先在栈内存里面分配两小块空间mimi和pipi,里面分别装着可以找到这两只猫的地址,mimi和pipi对应着堆内存里面的两只猫的引用。这里的构造方法声明有字符串类型的变量,字符串常量是分配在数据区里面的,所以这里会把传过来的字符串mimi和pipi都存储到数据区里面。所以数据区里面分配有存储字符串mimi和pipi的两小块内存,里面装着字符串“mimi”和“pipi”,字符串也是引用类型,除了那四类8种的基础数据类型之外,其他所有的数据类型都是引用类型。所以可以认为字符串也是一个对象。

这里是new了两只猫出来,这两只猫都有自己的id和name属性,所以这里的id和name都是非静态成员变量,即没有static修饰。所以每new出一只新猫,这只新猫都有属于它自己的id和name,即非静态成员变量id和name是每一个对象都有单独的一份。但对于静态成员变量来说,只有一份,不管new了多少个对象,哪怕不new对象,静态成员变量在数据区也会保留一份。如这里的sid一样,sid存放在数据区,无论new出来了多少只猫在堆内存里面,sid都只有一份,只在数据区保留一份。

静态成员变量是属于整个类的,它不属于专门的某个对象。那么如何访问这个静态成员变量的值呢?首先第一点,任何一个对象都可以访问这个静态的值,访问的时候访问的都是同一块内存。第二点,即便是没有对象也可以访问这个静态的值,通过“类名.静态成员变量名”来访问这个静态的值,所以以后看到某一个类名加上“.”再加上后面有一个东西,那么后面这个东西一定是静态的,如”System.out”,这里就是通过类名(System类)再加上“.”来访问这个out的,所以这个out一定是静态的。

再看下面的这段代码

package cn.galc.test;

public class Cat {

  /**
   * 这里面的sid不再是静态成员变量了,因为没有static修饰符,
   * 此时它就是类里面一个普通的非静态成员变量,和id,name一样,
   * 成为每一个new出来的对象都具有的属性。
   */
  private int sid = 0;

  private String name;

  int id;

  Cat(String name) {
    this.name = name;
    id = sid++;
  }

  public void info() {
    System.out.println("My Name is " + name + ",NO." + id);
  }

  public static void main(String[] args) {
    //Cat.sid = 100;这里不能再使用“类.静态成员变量”的格式来访问sid了,因为sid现在变成了非静态的成员变量了。所以必须要把这句话注释掉,否则无法编译通过。
    Cat mimi = new Cat("mimi");
    Cat pipi = new Cat("pipi");
    mimi.info();
    pipi.info();
  }
}

这段代码与上一段代码唯一的区别是把声明sid变量的static修饰符给去掉了,此时的sid就不再是静态成员变量,而是非静态成员变量了,此时每一个new出来的cat对象都会有自己单独的sid属性。所以这段代码执行完成后,内存中的布局如下图所示:

java必学必会之static关键字

由于sid变成了非静态成员变量,所以不再有计数的功能了。sid与id和name属性一样,成为每一个new出来的对象都具有的属性,所以每一个new出来的cat都加上了一个sid属性。由于不能再使用”类名.静态成员对象名”的格式访问sid,所以代码的第一句”Cat.sid =100;”不能这样使用,否则编译会出错,必须把这句话注释掉才能编译成功。既然无法访问得到sid的值,所以sid的值就一直都是初始化时赋给的值0。直到调用构造方法时,执行到方法体内的代码id=sid++;时,sid首先把自身的值0赋值给id,所以id的值是0,然后sid自己加1,所以sid变成了1。

所以静态变量和非静态变量的区别就在于静态变量可以用来计数,而非静态变量则不行。

理解了内存,就理解了一切,就理解了各种各样的语言。所有的语言无非都是这样:局部变量分配内存永远在栈里面,new出来的东西分配内存永远是在堆里,静态的东西分配内存永远是在数据区。剩下的代码肯定是在代码区。所有的语言都是这样。

在一个静态方法里,如果想访问一个非静态的成员变量,是不能直接访问的,必须在静态方法里new一个对象出来才能访问。如果是加了static的成员变量,那么这个成员变量就是一个静态的成员变量,就可以在main方法里面直接访问了。

main方法是一个静态的方法,main方法要执行的时候不需要new一个对象出来。

动态方法是针对于某一个对象调用的,静态方法不会针对某一个对象来调用,没有对象照样可以用。所以可以使用”classname.method()”.的形式来调用静态方法。所以想在main方法里面访问非静态成员变量是不可以的,想在main方法里面访问非静态方法也是不可以的,因为非静态方法只能针对于某个对象来调用,没有对象,就找不到方法的执行者了。

成员变量只有在new出一个对象来的时候才在堆内存里面分配存储空间。局部变量在栈内存里面分配存储空间。

静态方法不再是针对某一个对象来调用,所以不能访问非静态的成员。

非静态成员专属于某一个对象,想访问非静态成员必须new一个对象出来才能访问。

静态的变量可以通过对象名去访问,也可以通过类名去访问,两者访问的都是同一块内存。

以上就是本文的全部内容,信息量很大,需要大家耐心阅读,从而真正的学会java static关键字。

Javascript 相关文章推荐
Javascript this关键字使用分析
Oct 21 Javascript
IE浏览器兼容Firefox的JS脚本的代码
Oct 23 Javascript
jQuery Ajax使用 全解析
Dec 15 Javascript
jQuery及JS实现循环中暂停的方法
Feb 02 Javascript
javascript定时器完整实例
Feb 10 Javascript
vue-cli中打包图片路径错误的解决方法
Oct 26 Javascript
p5.js入门教程之小球动画示例代码
Mar 15 Javascript
JS 正则表达式验证密码、邮箱格式的实例代码
Oct 28 Javascript
微信小程序基于Taro的分享图片功能实践详解
Jul 12 Javascript
JavaScript 类的封装操作示例详解
May 16 Javascript
Vue循环遍历选项赋值到对应控件的实现方法
Jun 22 Javascript
vue中 this.$set的使用详解
Nov 17 Vue.js
详解页面滚动值scrollTop在FireFox与Chrome浏览器间的兼容问题
Dec 03 #Javascript
继续学习javascript闭包
Dec 03 #Javascript
解决js页面滚动效果scrollTop在FireFox与Chrome浏览器间的兼容问题的方法
Dec 03 #Javascript
jQuery 1.9.1源码分析系列(十五)之动画处理
Dec 03 #Javascript
ztree获取选中节点时不能进入可视区域出现BUG如何解决
Dec 03 #Javascript
jQuery 1.9.1源码分析系列(十五)动画处理之缓动动画核心Tween
Dec 03 #Javascript
JS使用post提交的两种方式
Dec 03 #Javascript
You might like
3
2006/10/09 PHP
Windows IIS PHP 5.2 安装与配置方法
2009/06/08 PHP
对PHP新手的一些建议(PHP学习经验总结)
2014/08/20 PHP
从阶乘函数对比Javascript和C#的异同
2012/05/31 Javascript
alert中断settimeout计时功能
2013/07/26 Javascript
jquery 显示*天*时*分*秒实现时间计时器
2014/05/07 Javascript
对于jQuery性能的一些优化建议
2015/08/13 Javascript
javascript实现方法调用与方法触发小结
2016/03/26 Javascript
深入浅析JavaScript中的3DES
2016/08/24 Javascript
Vue ElementUI之Form表单验证遇到的问题
2017/08/21 Javascript
ReactNative中使用Redux架构总结
2017/12/15 Javascript
Bootstrap table中toolbar新增条件查询及refresh参数使用方法
2018/05/18 Javascript
Webpack4+Babel7+ES6兼容IE8的实现
2019/04/10 Javascript
vue组件间的参数传递实例详解
2019/04/26 Javascript
VUE兄弟组件传值操作实例分析
2019/10/26 Javascript
基于p5.js 2D图像接口的扩展(交互实现)
2020/11/30 Javascript
[46:14]完美世界DOTA2联赛PWL S3 Magma vs INK ICE 第一场 12.11
2020/12/16 DOTA
Python3实现Web网页图片下载
2016/01/28 Python
python读文件保存到字典,修改字典并写入新文件的实例
2018/04/23 Python
使用python实现语音文件的特征提取方法
2019/01/09 Python
对python实现模板生成脚本的方法详解
2019/01/30 Python
在tensorflow中设置使用某一块GPU、多GPU、CPU的操作
2020/02/07 Python
python 实现人和电脑猜拳的示例代码
2020/03/02 Python
python 解决函数返回return的问题
2020/12/05 Python
使用Python判断一个文件是否被占用的方法教程
2020/12/16 Python
CSS3 中的@keyframes介绍
2014/09/02 HTML / CSS
阿拉伯世界最大的电子商务网站:Souq沙特阿拉伯
2016/10/28 全球购物
经典演讲稿范文
2013/12/30 职场文书
军训自我鉴定范文
2014/02/13 职场文书
新年晚会主持词
2014/03/24 职场文书
访谈节目策划方案
2014/05/15 职场文书
2014年宣传工作总结
2014/11/18 职场文书
婚礼女方父母答谢词
2015/01/04 职场文书
毕业论文致谢信
2015/05/14 职场文书
2015年政治教研组工作总结
2015/07/22 职场文书
python基础入门之字典和集合
2021/06/13 Python