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 相关文章推荐
jquery 添加节点的几种方法介绍
Sep 04 Javascript
JS简单实现登陆验证附效果图
Nov 19 Javascript
JS实现DIV容器赋值的方法
Dec 14 Javascript
Javascript必知必会(四)js类型转换
Jun 08 Javascript
基于JavaScript代码实现自动生成表格
Jun 15 Javascript
vue中如何实现变量和字符串拼接
Jun 19 Javascript
js实现文字列表无缝滚动效果
Jun 23 Javascript
vue.js指令v-for使用以及下标索引的获取
Jan 31 Javascript
vue+iview/elementUi实现城市多选
Mar 28 Javascript
灵活使用console让js调试更简单的方法步骤
Apr 23 Javascript
一文读懂vue动态属性数据绑定(v-bind指令)
Jul 20 Javascript
js 实现Material UI点击涟漪效果示例
Sep 23 Javascript
详解页面滚动值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引用符&的用法详细解析
2013/08/22 PHP
phpMyAdmin自动登录和取消自动登录的配置方法
2014/05/12 PHP
Laravel5.7框架安装与使用学习笔记图文详解
2019/04/02 PHP
RGB颜色值转HTML十六进制(HEX)代码的JS函数
2009/04/25 Javascript
JavaScript中的细节分析
2012/06/30 Javascript
模拟一个类似百度google的模糊搜索下拉列表
2014/04/15 Javascript
jQuery简单实现点击文本框复制内容到剪贴板上的方法
2016/08/01 Javascript
深入分析javascript中console命令
2016/08/14 Javascript
Bootstrap警告框(Alert)插件使用方法
2017/03/21 Javascript
JavaScript使用readAsDataURL读取图像文件
2017/05/10 Javascript
详解vue项目接入微信JSSDK的坑
2018/12/14 Javascript
微信小程序实现购物页面左右联动
2019/02/15 Javascript
webpack结合express实现自动刷新的方法
2019/05/07 Javascript
解决layui table表单提示数据接口请求异常的问题
2019/09/24 Javascript
JS几个常用的函数和对象定义与用法示例
2020/01/15 Javascript
多种类型jQuery网页验证码插件代码实例
2021/01/09 jQuery
下载给定网页上图片的方法
2014/02/18 Python
python中self原理实例分析
2015/04/30 Python
基python实现多线程网页爬虫
2015/09/06 Python
Python实现excel转sqlite的方法
2017/07/17 Python
Python中的错误和异常处理简单操作示例【try-except用法】
2017/07/25 Python
python分析作业提交情况
2017/11/22 Python
Python使用MD5加密算法对字符串进行加密操作示例
2018/03/30 Python
完美解决Pycharm无法导入包的问题 Unresolved reference
2018/05/18 Python
Python 字符串换行的多种方式
2018/09/06 Python
Python实现按逗号分隔列表的方法
2018/10/23 Python
Python玩转Excel的读写改实例
2019/02/22 Python
keras中的卷积层&池化层的用法
2020/05/22 Python
Python+Kepler.gl实现时间轮播地图过程解析
2020/07/20 Python
美国领先的奢侈美容零售商:Bluemercury
2017/07/26 全球购物
2014年信用社工作总结
2014/11/25 职场文书
2015年乡镇发展党员工作总结
2015/03/31 职场文书
机关工会工作总结2015
2015/05/26 职场文书
《蟋蟀的住宅》教学反思
2016/02/17 职场文书
十大最帅动漫男主 碓冰拓海上榜,第一是《灌篮高手》男主角
2022/03/18 日漫
微软发布Windows 11今年最大更新22H2(附 ISO 镜像官方下载)
2022/09/23 数码科技