2019独角兽企业重金招聘Python工程师标准>>>

一、static关键字

  

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

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

  以下面的例子为例说明

 1 package cn.galc.test;
 2
 3 public class Cat {
 4
 5     /**
 6      * 静态成员变量
 7      */
 8     private static int sid = 0;
 9
10     private String name;
11
12     int id;
13
14     Cat(String name) {
15         this.name = name;
16         id = sid++;
17     }
18
19     public void info() {
20         System.out.println("My Name is " + name + ",NO." + id);
21     }
22
23     public static void main(String[] args) {
24         Cat.sid = 100;
25         Cat mimi = new Cat("mimi");
26         Cat pipi = new Cat("pipi");
27         mimi.info();
28         pipi.info();
29     }
30 }

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

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

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

  

  接下来程序执行到:

    Cat  mimi = new Cat(“mimi”);

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

    Cat ( String name){

      this.name = name;

      id=sid++;

    }

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

  

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

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

    this.name=name;

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

  

  接下来执行方法体内的另一句代码:

    id=sid++;

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

  

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

  

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

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

  

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

  

  通过这个程序,看出来了这个静态成员变量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一定是静态的。

再看下面的这段代码

 1 package cn.galc.test;
 2
 3 public class Cat {
 4
 5     /**
 6      * 这里面的sid不再是静态成员变量了,因为没有static修饰符,
 7      * 此时它就是类里面一个普通的非静态成员变量,和id,name一样,
 8      * 成为每一个new出来的对象都具有的属性。
 9      */
10     private  int sid = 0;
11
12     private String name;
13
14     int id;
15
16     Cat(String name) {
17         this.name = name;
18         id = sid++;
19     }
20
21     public void info() {
22         System.out.println("My Name is " + name + ",NO." + id);
23     }
24
25     public static void main(String[] args) {
26         //Cat.sid = 100;这里不能再使用“类.静态成员变量”的格式来访问sid了,因为sid现在变成了非静态的成员变量了。所以必须要把这句话注释掉,否则无法编译通过。
27         Cat mimi = new Cat("mimi");
28         Cat pipi = new Cat("pipi");
29         mimi.info();
30         pipi.info();
31     }
32 }

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

  

  由于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一个对象出来才能访问。

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

转载于:https://my.oschina.net/zhanghaiyang/blog/593567

Java基础学习总结(10)——static关键字相关推荐

  1. java基础提升篇:Static关键字

    Static变量 static关键字 在类中用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时初始化,对于该类的所有对象来说,static成员变量只有一份. 可以通过引用或 ...

  2. Java基础:详解static关键字与类加载顺序

    1. 前言 前文中说到了static关键字,在Java中这是一个很重要的关键字,它有很多的用法,并且在某些特定的情况下使用可以优化程序的性能.本文学习static关键字的应用场景.在这之前了解变量的类 ...

  3. java基础第十七课----static关键字

    在<Java编程思想>当中有这样一段话: "static方法就是没有this的方法.在static方法内部不能调用非静态方法,反过来是可以的.而且可以在没有创建任何对象的前提下, ...

  4. Java学习(静态static关键字,数组工具类Arrays,数学相关工具类(绝对值,向上取整,向下取整),继承,super和this关键字,抽象)

    2022/1/2 (1/6)Java学习 1.静态Static关键字概述 一旦用了static关键字,那么这样的内容不再属于对象自己,而是属于类的,所以凡是本类的对象,都共享同一份. 2.静态stat ...

  5. Java中大数据数组,Java基础学习笔记之数组详解

    摘要:这篇Java开发技术栏目下的"Java基础学习笔记之数组详解",介绍的技术点是"java基础学习笔记.基础学习笔记.Java基础.数组详解.学习笔记.Java&qu ...

  6. 尚学堂JAVA基础学习笔记_2/2

    尚学堂JAVA基础学习笔记_2/2 文章目录 尚学堂JAVA基础学习笔记_2/2 写在前面 第10章 IO技术 1. IO入门 2. IO的API 3. 装饰流 4. IO实战 5. CommonsI ...

  7. Java基础学习Day09--字符串

    Java基础学习Day09--字符串 一.简介: 二.String类字符串 三.String字符串的存储原理 四.字符串常用方法 1.equals()方法 2.字符串的搜索 3.截取子字符串 4.去除 ...

  8. Java基础学习——第十章 枚举类注解

    Java基础学习--第十章 枚举类&注解 一.枚举类(enum) 1. 枚举类的概念 枚举类:类的对象只有有限个,确定的 线程状态:创建.就绪.运行.阻塞.死亡 当需要定义一组常量时,强烈建议 ...

  9. java基础学习-4

    Java基础学习-4 static 注意事项 重新认识main方法 继承 小练习 子类到底能继承父类中的哪些内容(第126集)*** 继承过程中成员变量和成员方法的访问特点 小练习 小总结 构造方法的 ...

  10. Java基础学习——第六章 面向对象编程(下)

    Java基础学习--第六章 面向对象编程(下) 一.关键词:static 1. static关键字的引入 当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new ...

最新文章

  1. mysql5.0镜像_Mysql5.0学习笔记(一)
  2. win mysql修改端口号_Windows10系统下查看mysql的端口号并修改的教程图解
  3. 独家 | Bamboolib:你所见过的最有用的Python库之一(附链接)
  4. Springboot 启动问题
  5. 【计算理论】图灵机 ( 接受状态作用 | 格局 | 图灵机语言 | 图灵机设计复杂性 )
  6. led灯条维修_常见的LED透明屏型号规格,影响LED透明屏价格因素
  7. python-字符串常用方法、文件简单读写
  8. Bzoj 3680 吊打xxx【[模拟退火】
  9. Redis中的Sentinel故障转移
  10. 作者:刘强强(1992-),男,贵州大学公共管理学院硕士生。
  11. 漫步线性代数七——特殊矩阵和应用
  12. leetcode java输入输出方法,有关IntelliJ IDEA中LeetCode插件配置问题
  13. Android开发笔记(四十六)手机相关事件
  14. day059-60 ajax初识 登录认证练习 form装饰器, form和ajax上传文件 contentType
  15. 阿里巴巴CTO程立:CTO就是要给CEO扫清障碍和风险
  16. mysql查询忽略字符编码是什么_MySQL 查询不区分大小写的问题以及编码格式问题...
  17. tomcat修改端口号后无法访问
  18. cad字体安装_拿了CAD字体不知道怎么装?看过来
  19. MRI T1、T2mapping
  20. Go 学习笔记 Go 第三方库之 viper(解析配置文件、热更新配置文件)

热门文章

  1. 趣谈Linux操作系统学习笔记:用户态内存映射:如何找到正确的会议室?(第25讲)...
  2. Python机器学习笔记:深入理解Keras中序贯模型和函数模型
  3. 计算机网络---物理层
  4. HTML5 表单 中
  5. jquery 判断元素内容是否为空
  6. iOS 10 SceneKit 新特性 – SceneKit 制作 3D 场景框架
  7. 高频焊台源码,改进版V2
  8. webdriver(python)学习笔记一
  9. 孙庆新:做产品,感觉从何而来
  10. 不得不爱开源 Wijmo jQuery 插件集(4)-【手风琴效果】(附页面展示和源码)