提起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的更多相关文章
-
java关键字(详解)
目录 1. 基本类型 1) boolean 布尔型 2) byte 字节型 3) char 字符型 4) double 双精度 5) float 浮点 6) int 整型 7) long 长整型 8) ...
-
Java 关键字详解
Java 关键字是 Java 语言中被赋予特殊意义的一些单词(每个关键字都代表着不同场景下的不同含义),不可以把它当作标识符来使用(不能用作变量名.方法名.类名.包名和参数名等).Java 中的关键字 ...
-
Java 关键字详解(持续更新中)
abstract: 表明类或者成员方法具有抽象熟悉. 修饰类,抽象类: 抽象类不能被实例化: 抽象类中可以有属性.方法.构造,都是用来给子类继承的: ...
-
static 关键字详解 static方法调用非static属性和方法
静态的属性和方法在内存中的存放地址与非静态的是不同的,静态的是存放在static区,它意味着静态方法是没有this的,所以我们不可以从一个static方法内部发出对非static方法的调用.但是反之是 ...
-
Java面试题04-final关键字详解
Java面试题04-final关键字详解 本篇博客将会讨论java中final关键字的含义,以及final用在什么地方,感觉看书总会有一些模糊,而且解释的不是很清楚,在此做个总结,以备准备面试的时候查 ...
-
Java多线程(三)—— synchronized关键字详解
一.多线程的同步 1.为什么要引入同步机制 在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源.必须对这种潜在资源冲突进行预防. 解决方法:在线程使用一个资源时为其加锁即可. 访问资 ...
-
Java synchronized 关键字详解
Java synchronized 关键字详解 前置技能点 进程和线程的概念 线程创建方式 线程的状态状态转换 线程安全的概念 synchronized 关键字的几种用法 修饰非静态成员方法 sync ...
-
java continue break 关键字 详解 区别 用法 标记 标签 使用 示例 联系
本文关键词: java continue break 关键字 详解 区别 用法 标记 标签 使用 示例 联系 跳出循环 带标签的continue和break 嵌套循环 深入continue ...
-
“全栈2019”Java多线程第十六章:同步synchronized关键字详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
随机推荐
-
安卓开发_深入学习ViewPager控件
一.概述 ViewPager是android扩展包v4包(android.support.v4.view.ViewPager)中的类,这个类可以让用户左右切换当前的view. ViewPager特点: ...
-
socket服务器开发中的SO_REUSEADDR选项与让人心烦的TIME_WAIT
1 发现问题 我在开发一个socket服务器程序并反复调试的时候,发现了一个让人无比心烦的情况:每次kill掉该服务器进程并重新启动的时候,都会出现bind错误:error:98,Address al ...
-
hduacm 5104
http://acm.hdu.edu.cn/show #include <cstdio> #include <cstring> #include <algorithm&g ...
-
面向对象程序设计-C++ Inheritance &; Multiple inheritance &; RTTI【第十三次上课笔记】
Sadly, 这节课带过去的笔记本没电了 T^T 导致没有一行 Code, Sorry 笔记如下: Shape * p1; //使用指针创建对象的方法 p = new Circle (2.0); Sh ...
-
python语言学习4——使用文本编辑器
在Python的交互式命令行写程序,好处是一下就能得到结果,坏处是没法保存,下次还想运行的时候,还得再敲一遍. 所以,实际开发的时候,我们总是使用一个文本编辑器来写代码,写完了,保存为一个文件,这样, ...
-
spring 学习笔记1
Spring 学习记录 任何一个成功的应用都是由多个为了实现某一个业务目标而相互协作的组件构成的.这些组件必须彼此了解,并相互协作来完成工作. 在Spring 中,对象无需自己负责查找或创建与其关联的 ...
-
在VM虚拟机中安装Centos操作系统
首先我们要下载 Centos https://www.centos.org/ 这个是Centos官方 最新版本 7 https://www.centos.org/download/ 提供有 DVD安 ...
-
PAT 1056 组合数的和
https://pintia.cn/problem-sets/994805260223102976/problems/994805271455449088 给定 N 个非 0 的个位数字,用其中任意 ...
-
简单的linux命令
1.cd命令: 这是一个最基本的命令,用于切换当前目录,可以是绝对路径,也可以是相对路径例: cd /root/doc #切换到目录/root/doc cd ./path 切换到当前目录下的pat ...
-
好玩的Python库tqdm (转载)
原文地址: https://blog.csdn.net/zejianli/article/details/77915751 可以显示循环的进度条的库,再也不用担心不知道程序跑到哪里还要跑多久了 tqd ...