提起static关键字,相信大家绝对不会陌生,但是,想要完全说明白,猛的一想,发现自己好像又说不太明白... ...比方说,昨天被一个同学问起的时候... ... 当然,不是所有人都像我一样学艺不精的,但是像这样的基础不牢的人应该不少,因为常用,所以用大家都会,但是谈到精细之处都够呛。这篇博客是我翻出我原来的学习笔记再加上自己看的一些博客整理出来的,供基础知识不怎么牢靠的同学参考参考。

1. static 关键字要解决的问题

  这里摘录一下《Java编程思想(第四版)》里关于static关键字的一段原话:(P29)通常来说,当创建类时,就是在描述那个类的对象的外观与行为。除非用new创建那个对象,否则,实际上并未获得任何对象。执行new来创建对象的时候,数据存储空间才被分配,其方法才供外界调用。有两种情形用上述方法是无法解决的。一种情形是,只想为某特定域分配单一存储空间,而不去考虑究竟要创建多少个对象,甚至根本不需要创建任何对象。另一种情形是,希望某个方法不与包含他的类的任何对象关联在一起。也就是说,即使没有创建对象,也能够调用方法。简单来说,static的主要目的就是创建独立于具体对象的域变量与方法。

2. static修饰的变量或方法或类的加载时机

  在加载类的同时加在static修饰的部分。(注意:这个时候,还不存在具体对象,并且这个过程只进行一次

3. 通过代码示例来分别看看静态变量、静态方法、静态类的效果

3.1 静态变量

public class StaticTest{

    public static int count =0;

    @SuppressWarnings("static-access")
public static void main(String[] args) {
// TODO Auto-generated method stub
StaticTest test1 = new StaticTest();
System.out.println(test1.count);
StaticTest test2 = new StaticTest();
test2.count++;
System.out.println(test1.count+" "+test2.count+" "+StaticTest.count);
} }

输出结果:

0
1 1 1

可见,static变量并不是所在类的某个具体对象所有,而是该类的所有对象所共有的,静态变量既能被对象调用,也能直接拿类来调用。

除此之外,静态变量不能引用非静态方法,原因正如前面描述静态加载时机中说的那样,加载静态的时候,非静态的变量、方法等还不存在,当然就无法引用了。但是,非静态方法或类却能正常引用静态变量或方法。因为非静态总是在静态之后出现的。

3.2 静态方法

  静态方法和静态变量一样,属于类所有,在类加载的同时执行,不属于某个具体的对象,所有对象均能调用。对于静态方法需要注意以下几点:

  • 它们仅能调用其他的static 方法。
  • 它们只能访问static数据。
  • 它们不能以任何方式引用this 或super。
class Simple {
static void go() {
System.out.println("Welcome");
}
} public class Cal {
public static void main(String[] args) {
Simple.go();
}
}

  静态方法一般用于工具类中,可以直接拿类名调用工具方法进行使用。

3.3 静态类

  一般来说,一个普通类是不允许被声明为static的,但是,在内部类中可以将其声明为static的,这个时候,外部类可以直接调用内部类,因为static的内部类是在加载外部类的同时加载的,所以也就是说,并不要实例化外部类就能直接调用静态内部类。看例子:

public class BaseStatic {
  static {
System.out.println("Load base static");
} public BaseStatic(){
System.out.println("BaseStatic constructor");
} static class BaseInnerClass{
static{
System.out.println("Base inner class static");
} public BaseInnerClass(){
System.out.println("BaseInnerClass constructor");
}
} } public class StaticLoadOrderTest{ public static void main(String[] args) {
// TODO Auto-generated method stub
new BaseStatic.BaseInnerClass();
} }

在看答案之前,自己想想这个输出结果是什么?

先不急着看答案,我们先来看看这个执行过程:首先,在进入StaticLoadOrderTest的main方法之前,加载StaticLoadOrderTest类,然后执行new BaseStatic.BaseInnerClass();这里需要注意:因为BaseInnerClass是静态的,所以这里并不需要加载外部类和实例化外部类,可以直接加载BaseInnerClass并实例化。所以输出:

 Base inner class static
BaseInnerClass constructor

这里留个坑:当直接使用外部类类名.静态内部类进行实例化的时候,如果外部类没有加载的话(实际上也是没有加载),那么这个statement: BaseStatic.BaseInnerClass中的BaseStatic是个什么存在????难道只是与静态内部类发生了简单的名称关联吗?若是这样还设计静态内部类干嘛呢?我觉得java设计者们不至于犯这种错误吧?也可能因为自己对于JVM并不熟悉,对于底层不太了解,若是路过的大神能帮忙解决一下,感激不尽!!!!

3.4 关于静态加载顺序的示例

下面这段代码的输出是什么?

public class BaseStatic {
static {
System.out.println("Load base static");
} public BaseStatic(){
System.out.println("BaseStatic constructor");
} static class BaseInnerClass{
static{
System.out.println("Base inner class static");
} public BaseInnerClass(){
System.out.println("BaseInnerClass constructor");
}
} } public class StaticLoadOrderTest { static {
System.out.println("Load test");
} public StaticLoadOrderTest(){
System.out.println("Test constructor");
} public static void main(String[] args) {
// TODO Auto-generated method stub
new BaseStatic();
new StaticLoadOrderTest();
new BaseStatic.BaseInnerClass();
} }

  和上面一样,分析一下过程:在进入main方法之前,需要加载StaticLoadOrderTest类,这时候发现有static代码块,先加载静态代码块,然后进入main方法内部,new BaseStatic(),这时候需要加载BaseStatic类,同时也要先加载静态代码块,然后调用构造器。注意:这里并没有加载BaseInnerClass,因为它是内部类只有在真正用到的时候才会进行加载,相信聪明的读者看到这个是不是想到了又一种单例设计模式的实现方式?自己研究吧。回到main方法中,接下来该执行new StaticLoadOrderTest()了,因为StaticLoadOrderTest类之前已经被加载过一次了,并且类只加载一次,所以这里就直接构造了;然后是最后一句new BaseStatic.BaseInnerClass()了,和上面例子一样,这里就不再细讲。所以输出结果为:

Load test
Load base static
BaseStatic constructor
Test constructor
Base inner class static
BaseInnerClass constructor

  再考虑一下,如果我把上面的例子改成下面这样,输出结果又会是什么呢?

public class BaseStatic {
static {
System.out.println("Load base static");
} public BaseStatic(){
System.out.println("BaseStatic constructor");
} static class BaseInnerClass{
static{
System.out.println("Base inner class static");
} public BaseInnerClass(){
System.out.println("BaseInnerClass constructor");
}
} } public class StaticLoadOrderTest extends BaseStatic{ static {
System.out.println("Load test");
} public StaticLoadOrderTest(){
System.out.println("Test constructor");
} public static void main(String[] args) {
// TODO Auto-generated method stub
new BaseStatic.BaseInnerClass();new StaticLoadOrderTest();
new BaseStatic();
} }

以上就是关于java中static关键字的一些知识了。

最后,预祝国足世预赛四强赛首站告捷!

Java Static关键字详解的更多相关文章

  1. Java static 关键字详解

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

  2. Java synchronized 关键字详解

    Java synchronized 关键字详解 前置技能点 进程和线程的概念 线程创建方式 线程的状态状态转换 线程安全的概念 synchronized 关键字的几种用法 修饰非静态成员方法 sync ...

  3. Java:final、static关键字 详解+两者结合使用

    一  final关键字 1) 关于final的重要知识点 final关键字可以用于成员变量.本地变量.方法以及类. final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误. ...

  4. java中的static关键字详解

    static对于我们这些初学者在编写代码和阅读代码是一个难以理解的关键字,也是大量公司面试题最喜欢考的之一.下面我就来就先讲述一下static关键字的用法和我们初学者容易误解的地方. static关键 ...

  5. Java中Static关键字详解以及静态变量和成员变量的区别

    一.static关键字的特点 (1)修饰成员变量.成员方法(2)随着类的加载而加载(3)优先于对象存在(4)被所有对象共享(5)可以通过类名调用 它本身也可以通过对象名调用 例如:main()方法由j ...

  6. C/C++中static关键字详解

    静态变量作用范围在一个文件内,程序开始时分配空间,结束时释放空间,默认初始化为0,使用时可以改变其值. 静态变量或静态函数只有本文件内的代码才能访问它,它的名字在其它文件中不可见.用法1:函数内部声明 ...

  7. C/C++中static关键字详解-zz

    静态变量作用范围在一个文件内,程序开始时分配空间,结束时释放空间,默认初始化为0,使用时可以改变其值. 静态变量或静态函数只有本文件内的代码才能访问它,它的名字在其它文件中不可见.用法1:函数内部声明 ...

  8. static 关键字详解(用途、误区、面试题)

    static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键字的用法和平常容易误解的地方,最后列 ...

  9. 【转载】static关键字详解

    上一篇博客中,因为一个static关键字没有设置好,导致浪费了大量的时间来寻找程序的错误,归根结底,就是大一的时候c语言没有学好. 现在总算知道了,你现在所学的每一个知识点在不就的以后可能及时你的救命 ...

随机推荐

  1. SVN的目录说明

    subversion目录说明:*dav目录:是提供apache与mod_dav_svn使用的目录,让他们存储内部数据*db目录:就是所有版本控制的数据存放文件*hooks目录:放置hook脚本文件的目 ...

  2. Unity3D 调用模态对话框/Unity3D MessageBox

    Unity模态对话框/Unity MessageBox 很多时候,我们需要将Unity的exe产品发布到某一个平台.比如某某斗地主发布到某Q游戏.这时候如果需要调试肿么办.办法无外乎那几个.1:源码调 ...

  3. 解析excel表格为DataSet

    using System;using System.Collections.Generic;using System.Data;using System.Data.OleDb;using System ...

  4. 管理员取得所有权(复制以下代码粘贴至记事本然后把后缀名改为reg)

    Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\*\shell\runas] @="获取权限" "NoWo ...

  5. 【ZOJ】3785 What day is that day? ——浅谈KMP在ACM竞赛中的暴力打表找规律中的应用

    转载请声明出处:http://www.cnblogs.com/kevince/p/3887827.html    ——By Kevince 首先声明一下,这里的规律指的是循环,即找到最小循环周期. 这 ...

  6. Essential Phone刷机教程

    安装fastboot驱动(Essential-PH1-WindowsDrivers) 下载ADB刷机指令工具:platform-tools(ADB): 进入开发者选项,打开 USB 调试,OEM解锁选 ...

  7. iOS 10 的一个重要更新-用 UIViewPropertyAnimator 编写动画

    曾经的黑暗年代 用基于 block 的 UIView animation 来编写 view 属性(frame, transform 等等)变化的动画非常简单.只需要短短几行代码: view.alpha ...

  8. 00.嵌入式Linux开发环境搭建

     3.虚拟机上网配置 虚拟机如果要从网上获取资源,就要能够访问外网.虚拟机有三种上网方式:桥接上网,NAT上网,单主机模式[没用过].本节从原理和操作2个方面讲了NAT方式和桥接方式这2种不同的虚拟机 ...

  9. &quot;Only the original thread that created a view hierarchy can touch its views.” 解决方法

    这个主要总是,开启的线程和 UI 线程(主线程)不是同一个线程.可以Runnable方式避免,如下例所示就可以解决这个问题了. public static void updateText(Activi ...

  10. excel中如何让每n行显示同一个数据

    由于需要将数据按照下表格式存储,以方便读取展示,年份列需要每隔7行再递增1 方法: 1. 输入这个公式: = INT((ROW(E1)-1)/ 5)+ 1 进入一个空白单元格,您可以在其中填写序列号, ...