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数组常用操作技巧汇总
Nov 17 Javascript
javascript实现画不相交的圆
Apr 07 Javascript
Javascript中arguments和arguments.callee的区别浅析
Apr 24 Javascript
jQuery中Ajax全局事件引用方式及各个事件(全局/局部)执行顺序
Jun 02 Javascript
全面解析DOM操作和jQuery实现选项移动操作代码分享
Jun 07 Javascript
NW.js 简介与使用方法
Feb 01 Javascript
浅谈VueJS SSR 后端绘制内存泄漏的相关解决经验
Dec 20 Javascript
实例讲解JavaScript预编译流程
Jan 24 Javascript
Vue内部渲染视图的方法
Sep 02 Javascript
JavaScript canvas绘制折线图
Feb 18 Javascript
15个简单的JS编码标准让你的代码更整洁(小结)
Jul 16 Javascript
Vue CLI中模式与环境变量的深入详解
May 30 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
php 获取可变函数参数的函数
2009/08/26 PHP
php中将html中的br换行符转换为文本输入中的换行符
2013/03/26 PHP
php5.5中类级别的常量使用介绍
2013/10/02 PHP
PHP利用header跳转失效的解决方法
2014/10/24 PHP
PHP的openssl加密扩展使用小结(推荐)
2016/07/18 PHP
javascript new一个对象的实质
2010/01/07 Javascript
jQuery晃动层特效实现方法
2015/03/09 Javascript
jQuery检测鼠标左键和右键点击的方法
2015/03/17 Javascript
js如何准确获取当前页面url网址信息
2020/09/13 Javascript
JavaScript模拟文件拖选框样式v1.0的实例
2017/08/04 Javascript
Angularjs过滤器实现动态搜索与排序功能示例
2017/12/13 Javascript
浅谈ElementUI中switch回调函数change的参数问题
2018/08/24 Javascript
记录一次完整的react hooks实践
2019/03/11 Javascript
详解Webpack如何引入CDN链接来优化编译后的体积
2019/06/21 Javascript
[59:44]2018DOTA2亚洲邀请赛 3.31 小组赛 B组 paiN vs iG
2018/03/31 DOTA
Python实现的数据结构与算法之快速排序详解
2015/04/22 Python
python基于phantomjs实现导入图片
2016/05/13 Python
python获取指定时间差的时间实例详解
2017/04/11 Python
Python用Pillow(PIL)进行简单的图像操作方法
2017/07/07 Python
解决Pycharm无法import自己安装的第三方module问题
2018/05/18 Python
python一行sql太长折成多行并且有多个参数的方法
2018/07/19 Python
Python 输入一个数字判断成绩分数等级的方法
2018/11/15 Python
Python实现SQL注入检测插件实例代码
2019/02/02 Python
利用Django模版生成树状结构实例代码
2019/05/19 Python
Pyinstaller 打包exe教程及问题解决
2019/08/16 Python
关于Python核心框架tornado的异步协程的2种方法详解
2019/08/28 Python
基于Python实现船舶的MMSI的获取(推荐)
2019/10/21 Python
CSS3 文字动画效果
2020/11/12 HTML / CSS
萨克斯第五大道英国:Saks Fifth Avenue英国
2019/04/01 全球购物
英国鞋网:Rubber Sole
2020/03/03 全球购物
亚洲在线旅行门户网站:Expedia.com.hk(智游网)
2020/04/14 全球购物
简历自我评价怎么写呢?
2014/01/06 职场文书
刑事辩护授权委托书格式
2014/10/13 职场文书
晚会开场白和结束语
2015/05/29 职场文书
虎兄虎弟观后感
2015/06/12 职场文书
Java版 简易五子棋小游戏
2022/05/04 Java/Android