这是我结合一些自己的思想写的对static关键字的理解。
1. static关键字
【重点】他是单身狗!!!
1.1 static修饰成员变量
1.1.1 static修饰成员变量的需求

“这里不希望大量的数据浪费”,打错字了,在这里纠正一下。
数据区也可以叫做共享区,是一个公共资源的放置地方。
static可以节省大量的冗余空间,堆区的String country指向数据区的首地址,类似于栈区指向于堆区。
1.1.2 静态成员变量使用注意事项
- 静态成员变量是使用static修饰的成员变量,定义在内存的【数据区】
-
静态成员变量不推荐使用类对象调用,会提示警告
The static field SingleDog.info should be accessed in a static way
使用static修饰的SingleDog类内的info成员变量,应该通过静态方式访问.
强烈不推荐通过对象调用,推荐通过类名调用!!!
知道为啥吗?因为static修饰的成员变量是个单身狗!!!
你用你的对象来找饥渴的单身狗修电脑,你愿意吗???人家单身狗愿意吗???
-
静态成员变量使用类名调用是没有任何的问题。【墙裂推荐方式】
但是!!!你通过找电脑店,或者找售后,这个大的一个类,虽然给你对象修电脑的还是一个单身狗,但是人家愿意修…
-
在代码中没有创建对象时,可以通过类名直接使用静态成员变量,和【对象无关】
这句话什么意思呢?就是说虽然static是单身狗,但是人家也是有追求的,即使没有对象,人家也是要恰饭的!!!
-
代码中对象已经被JVM的GC销毁时,依然可以通过类名调用静态成员变量,和【对象无关】
这句话不用我多说什么了吧?相信你们已经可以看出来了,这static丫的是个直男!!!
static是个直男单身狗!!!和对象无关!!!
-
不管通过哪一种方式调用静态成员变量,修改对应的静态成员变量数据,所有使用到当前静态成员变量的位置,都会受到影响。
一旦单身狗受到刺激或者改变,那么他周围的一切都会影响。
好了,经过上面的脑补后,相信static的形象已经深入人心,下边我们来认真了解一下为什么静态成员变量和对象无关…
1.1.3 为什么静态成员变量和对象无关
-
从内存角度出发分析
静态成员变量是保存在内存的数据区
类对象占用的实际内存空间是在内存的堆区
这两个区域是完全不同的,所有可以说静态成员变量和对象没有关系 【没有对象】
这叫啥?天各一方!!!君住长江头,我住长江尾!!!
-
从静态成员变量以及类对象生命周期来分析
静态成员变量是随着类文件(.class) 字节码文件的加载过程中,直接定义在内存的数据区。静态成员变量从程序运行开始就已经存在。
类对象是在代码的运行过程中,有可能被创建,也有可能不被创建的。程序的运行过中,有可能会被JVM的CG垃圾回收机制销毁,程序在退出之前一定会销毁掉当前Java程序使用到的所有内存。
而静态成员变量在程序退出之后,才会销毁
静态成员变量的生命周期是从程序开始,到程序结束
类对象只是从创建开始,而且随时有可能被JVM的GC销毁
生命周期不在同一个时间线上,所以静态成员变量和类对象无关,【没有对象】
唉…可悲可叹,我(static)生君(对象)未生,我(static)生君(对象)已老!!!
我就像一粒原子,世界创立时我已存在,经历世间波澜壮阔,沉沉浮浮数万亿年;
而你,一个美丽的女子,你需要我时,我就在你身边任你使用,你不需要我时,我就静静待在这世界中看着你。
我的生命与世界相同,而你的出现却不是定数,即使有那造物主的怜惜,让你出现数十年,却也只相当于我生命的亿万分之一,你不在后,我还要在没有你的世界里待到末日…
代码展示
/*
* 演示static关键字修饰成员变量
*/
class SingleDog {
// static修饰的静态成员变量
public static String info = "单身狗";
// 非静态成员变量
public String name;
public SingleDog() {}
public SingleDog(String name) {
this.name = name;
}
// 非静态成员方法
public void test() {
System.out.println("test方法");
}
}
public class Demo2 {
public static void main(String[] args) {
// 在没有类对象的情况下,可以直接通过类名调用静态成员变量
System.out.println(SingleDog.info);
// 曾经有过一个对象,31行代码运行完成,对象销毁
new SingleDog();
// 在类对象被销毁之后,依然可以通过类名调用静态成员变量
System.out.println(SingleDog.info);
}
}
复制
1.2 static修饰成员方法
1.2.1 静态成员方法的格式
异常熟悉的格式
public static 返回值类型 方法名(形式参数列表) {
}
1.2.2 静态成员方法注意事项 【FFF社】
静态成员方法就是我大FFF社!!!
-
静态成员方法推荐使用静态方式调用,通过类名调用【墙裂推荐的】
不推荐使用类对象调用,因为【没有对象】
不用我解释了吧…
-
静态成员方法中不能使用非静态成员 ==> (非静态成员方法和非静态成员变量)
因为【没有对象】
嘿嘿嘿,FFF社…
-
静态成员方法中不能使用this关键字 回顾:this表示调用当前方法的类对象
因为静态方法中【没有对象】
so…
-
静态成员方法中可以使用类内的其他静态成员【难兄难弟】
大FFF社员
-
静态成员方法中可以通过new 构造方法创建对象
大FFF社不烧真爱!!!
1.2.3 静态成员方法特征解释
-
静态成员方法加载时间问题
静态成员方法是随着.class字节码文件的加载而直接定义在内存的【方法区】,而且此时的静态成员方法已经可以直接运行。可以通过类名直接调用,而此时没有对象存在。【没有对象】
-
为什么静态成员方法不能使用非静态成员
非静态成员变量和非静态成员方法时需要类对象调用的,在静态成员方法中,是可以通过类名直接执行的,而此时是【没有对象】的。
-
为什么静态成员方法不能使用this关键字
this关键字表示的是调用当前方法的类对象,但是静态成员方法可以通过类名调用,this不能代表类名,同时也是【没有对象】
-
静态成员方法可以使用其他静态成员
生命周期一致,调用方式一致
1.3 类变量和类方法
类变量 ==> 静态成员变量
类方法 ==> 静态成员方法
类成员 ==> 静态成员变量和静态成员方法
面试题
类方法中是否可以使用成员变量?
类方法可以使用当前类内的静态成员变量,但是不允许使用非静态成员变量
1.4 静态代码块
补充知识点 代码块
构造代码块(动态代码块)
初始化当前类的所有类对象,只要调用构造方法,【一定】会执行对应的构造代码块
执行顺序【成员变量之后 构造方法之前】
格式
{
}
复制
静态代码块
初始化程序,只要类文件加载,静态代码块中所有内容全部执行
格式:
static {
// 静态代码块
}
复制
只要【类文件】加载,当前静态代码块中的内容就一定会执行,并且有且只【执行一次】。
注意:
是.class文件加载,不是文件加载,如果主类中没有用到这个类,那么就不会加载这个类中的静态代码块。
作用:整个类的初始化过程
局部代码块
提高效率,解决内存,让JVM回收内存的效率提升。
for () {
{
int num
}
}
复制
1.5 静态题
public class Demo3 {
static Demo3 demo1 = new Demo3();
static Demo3 demo2 = new Demo3();
{
System.out.println("构造代码块"); // 1
}
static {
System.out.println("静态代码块"); // 2
}
public Demo3() {
System.out.println("构造方法"); // 3
}
public static void main(String[] args) {
Demo3 demo1 = new Demo3();
}
}
复制
请问输出结果应该是什么呢?做题,不是写代码实践,思考…
答案:
//答案
/*
构造代码块
构造方法
构造代码块
构造方法
静态代码块
构造代码块
构造方法
*/
//解释
//首先代码执行static Demo3 demo1 = new Demo3(); 是new一个对象,是new构造方法,所以执行
//构造代码块和构造方法
//然后执行static Demo3 demo2 = new Demo3();是new一个对象,是new构造方法,所以执行
//构造代码块和构造方法
//然后执行
static {
System.out.println("静态代码块"); // 2
}
//然后执行
public static void main(String[] args) {
Demo3 demo1 = new Demo3();
}
//又是创建新的类对象,所以执行构造代码块和构造方法
复制
那么接下来我们将上边两个代码去掉static,结果会怎样?
如下:
public class Demo3 {
Demo3 demo1 = new Demo3();
Demo3 demo2 = new Demo3();
{
System.out.println("构造代码块"); // 1
}
static {
System.out.println("静态代码块"); // 2
}
public Demo3() {
System.out.println("构造方法"); // 3
}
public static void main(String[] args) {
Demo3 demo1 = new Demo3();
}
}
复制
结果:
执行“静态代码块”
无限递归,栈堆内存满,报错