在Java中并不存在全局变量的概念,但是我们可以通过static来实现一个“伪全局”的概念,在Java中static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,当然也可以修饰代码块。

Static变量

  • 在类中用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时初始化,对于该类的所有对象来说,static成员变量只有一份。

  • 可以通过引用或者类名访问静态成员

  • 在类中,用static声明的成员变量为静态变量,或者叫:类属性、类变量。

(注意:静态变量是从属于类,在对象里面是没有这个属性的;成员变量是从属于对象的,有了对象才有那个属性)

  • 它为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显示初始化。

  • 对于该类所有对象来说,static成员变量只有一份.被该类的所有对象共享!!

  • 可以使用“对象.类属性”来调用。不过,一般都是用"类名.类属性”。

  • static变量置于方法区中。

  • 在静态的方法里面不可以调用非静态的方法或变量;但是在非静态的方法里可以调用静态的方法或变量。

Static方法

◆用static声明的方法为静态方法。

  • 不需要对象,就可以调用(类名.方法名

  • 在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static的成员

静态初始化块

  静态初始化块是在类被加载的时候就执行的一块程序,并且一直存在直到程序关闭。也就是说当程序被执行,即classloader将该java程序编译后的class文件加载后,就能执行到静态初始化块这段程序;当程序关闭,我的个人理解也就是java.exe进程被结束的时候,静态初始化块结束(例如在静态初始化块里对一个类的静态变量进行赋值,该变量一直存在到程序关闭)。

下面我们来举例说明:

 public class Test {
//静态变量
public static String testStatic = "testStatic";
//静态初始化块
static {
System.out.println(testStatic);
System.out.println("Proc begin");
testStatic = "testProc";
System.out.println("Proc end");
}
//主方法
public static void main(String[] args) {
System.out.println(testProc);
System.out.println("main begin");
System.out.println("main end");
}
}

执行main方法输出结果:

 testStatic
Proc begin
Proc end
testProc
main begin
main end

也就是说当JVM将要执行main方法的时候,先要将Test.class加载到JVM中,此时就执行了静态初始化块中的程序;然后再执行执行main方法中的程序。这个例子没有将这个类实例化,所以没有用到构造函数。倘若需要实例化该类的时候,则构造方法的执行顺序也是在静态初始化块之后的。

最后我们可以得出这么一个结论:Java类的执行优先顺序

该类的静态变量->该类的静态初始化块->该类的构造方法

若存在父类的情况下则是:

父类的静态变量->父类的静态初始化块->子类的静态变量->子类的静态初始化块

内存分析Static

静态成员变量:

 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。

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

接下来程序执行到:

 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()方法打印出来,打印结果如下:

 My name is mimi,NO.100
My name is pipi,NO.101

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

  这里调用构造方法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一定是静态的。

总结

  • 无论是变量,方法,还是代码块,只要用static修饰,就是在类被加载时就已经"准备好了",也就是可以被使用或者已经被执行,都可以脱离对象而执行。反之,如果没有static,则必须要依赖于对象实例。
  • static的方法只能调用static的变量和方法,非static的方法既可以调用static的,又可以调用非static的。

java基础(五)-----关键字static的更多相关文章

  1. java基础之关键字static

        在java当中有很多关键字,static便是其中一个,它很普通但我们经常需要运用到它,所以要了解static是非常有必要的.   鉴于本人知识结构有限,若有错误忘不吝赐教,甚为感谢.   一. ...

  2. java基础(五)之static关键词的作用

    static关键词的作用 1.静态成员变量的语法特定2.静态函数的语法特定3.静态代码块的语法特定 定义静态成员变量 Person.java class Person{ static int a; } ...

  3. Java基础-synchronized关键字的用法(转载)

    synchronized--同步 顾名思义是用于同步互斥的作用的. 这里精简的记一下它的使用方法以及意义: 当synchronized修饰 this或者非静态方法或者是一个实例的时候,所同步的锁是加在 ...

  4. Java基础(五) final关键字浅析

    前面在讲解String时提到了final关键字,本文将对final关键字进行解析. static和final是两个我们必须掌握的关键字.不同于其他关键字,他们都有多种用法,而且在一定环境下使用,可以提 ...

  5. Java基础(basis)-----关键字final和static的作用

       1.关键字final      final修饰类:这个类就不能被继承      final修饰方法:不能被重写      final修饰属性:此属性就是一个常量,一旦初始化后,不可再被赋值.习惯 ...

  6. Java基础——final、static关键字

    final关键字是最终的意思,可以修饰成员方法.成员变量.类 特点: 1.修饰方法:表示该方法是最终方法,不能被重写 2.修饰变量:表示变量是常量,不能再次被赋值 3.修饰类:表示类是最终类,不能被继 ...

  7. Java基础之关键字,标识符,变量

    Java基础 首先,来看一下Java基础知识图解,以下便是在java学习中我们需要学习设计到的一些知识(当然不是很完全). 这些都是接下来在以后的学习中我们会学到的一些知识. 1 关键字 首次先来学习 ...

  8. java基础---->final关键字的使用

    这里介绍一些java基础关于final的使用,文字说明部分摘自java语言规范.心甘情愿这四个字,透着一股卑微,但也有藏不住的勇敢. Final关键字的说明 一.关于final变量规范说明 .A fi ...

  9. Java面向对象之关键字static 入门实例

    一.基础概念 静态关键字 static 是成员修饰符,直接用于修饰成员. (一)特点: 1.被静态修饰的成果,可以直接被类名所调用. 2.静态成员优先于对象存在. 3.静态成员随着类的加载而加载.随着 ...

随机推荐

  1. 机器学习之--kmeans聚类简单算法实例

    import numpy as np import sklearn.datasets #加载原数据 import matplotlib.pyplot as plt import random #点到各 ...

  2. SOAPA来临,SIEM时代终结?

    安全信息和事件管理(SIEM)产品及服务负责从大量企业安全控件.主机操作系统.企业应用和企业使用的其他软件中收集安全日志数据,并进行分析和报告.有些SIEM还可以试图阻止它们检测到正在进行的攻击,这可 ...

  3. python程序入门 基础教程

    1.VSCode基础使用+VSCode调试python程序入门 2.pip 安装 3.scrapy安装 4.python解析xml

  4. git diff old mode 100644 new mode 100755

    今天执行git diff filename ,出现 old mode 100644 new mode 100755 的提示,如下图: 但是发现文件内容并没有发生改变 想起来中间执行过chmod  的操 ...

  5. 第k个素因子只有3 5 7 的数

    题目描述 有一些数的素因子只有3.5.7,请设计一个算法,找出其中的第k个数. 给定一个数int k,请返回第k个数.保证k小于等于100. 测试样例: 3 返回:7 int findKth(int ...

  6. 微信JS SDK接入的几点注意事项

    微信JS SDK接入,主要可以先参考官网说明文档,总结起来有几个步骤: 1.绑定域名:先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”.备注:登录后可在“开发者中心”查看对 ...

  7. MariaDB dos 下连接

    本地 DOS 连接 将文件目录切换到 bin 文件夹下 cd C:\xampp\mysql\bin 输入连接命令 输入 status,查看数据库版本 远程DOS 连接

  8. meta标签的用处详解

    meta标签的用处: 用来描述html文档的一个属性.列如作者.日期和时间,网页描述,关键字,页面刷新等. 是文档最基本的元数据 元数据(metadata): 用来概括描述数据的一些基本数据 meta ...

  9. [LeetCode] Possible Bipartition 可能的二分图

    Given a set of N people (numbered 1, 2, ..., N), we would like to split everyone into two groups of  ...

  10. CSS面试细节整理(二)

    5.css盒模型: CSS 框模型 (Box Model) 规定了元素框处理元素内容.内边距.边框 和 外边距 的方式