Java中的static关键字浅析

  • 2020 年 3 月 18 日
  • 筆記

这是我结合一些自己的思想写的对static关键字的理解。

1. static关键字

【重点】他是单身狗!!!

1.1 static修饰成员变量

1.1.1 static修饰成员变量的需求

“这里不希望大量的数据浪费”,打错字了,在这里纠正一下。

数据区也可以叫做共享区,是一个公共资源的放置地方。

static可以节省大量的冗余空间,堆区的String country指向数据区的首地址,类似于栈区指向于堆区。

1.1.2 静态成员变量使用注意事项
  1. 静态成员变量是使用static修饰的成员变量,定义在内存的【数据区】
  2. 静态成员变量不推荐使用类对象调用,会提示警告 The static field SingleDog.info should be accessed in a static way 使用static修饰的SingleDog类内的info成员变量,应该通过静态方式访问. 强烈不推荐通过对象调用,推荐通过类名调用!!! 知道为啥吗?因为static修饰的成员变量是个单身狗!!! 你用你的对象来找饥渴的单身狗修电脑,你愿意吗???人家单身狗愿意吗???
  3. 静态成员变量使用类名调用是没有任何的问题。【墙裂推荐方式】 但是!!!你通过找电脑店,或者找售后,这个大的一个类,虽然给你对象修电脑的还是一个单身狗,但是人家愿意修…
  4. 在代码中没有创建对象时,可以通过类名直接使用静态成员变量,和【对象无关】 这句话什么意思呢?就是说虽然static是单身狗,但是人家也是有追求的,即使没有对象,人家也是要恰饭的!!!
  5. 代码中对象已经被JVM的GC销毁时,依然可以通过类名调用静态成员变量,和【对象无关】 这句话不用我多说什么了吧?相信你们已经可以看出来了,这static丫的是个直男!!! static是个直男单身狗!!!和对象无关!!!
  6. 不管通过哪一种方式调用静态成员变量,修改对应的静态成员变量数据,所有使用到当前静态成员变量的位置,都会受到影响。 一旦单身狗受到刺激或者改变,那么他周围的一切都会影响。

好了,经过上面的脑补后,相信static的形象已经深入人心,下边我们来认真了解一下为什么静态成员变量和对象无关…

1.1.3 为什么静态成员变量和对象无关
  1. 从内存角度出发分析 静态成员变量是保存在内存的数据区 类对象占用的实际内存空间是在内存的堆区 这两个区域是完全不同的,所有可以说静态成员变量和对象没有关系 【没有对象】 这叫啥?天各一方!!!君住长江头,我住长江尾!!!
  2. 从静态成员变量以及类对象生命周期来分析 静态成员变量是随着类文件(.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社!!!

  1. 静态成员方法推荐使用静态方式调用,通过类名调用【墙裂推荐的】 不推荐使用类对象调用,因为【没有对象】 不用我解释了吧…
  2. 静态成员方法中不能使用非静态成员 ==> (非静态成员方法和非静态成员变量) 因为【没有对象】 嘿嘿嘿,FFF社…
  3. 静态成员方法中不能使用this关键字 回顾:this表示调用当前方法的类对象 因为静态方法中【没有对象】 so…
  4. 静态成员方法中可以使用类内的其他静态成员【难兄难弟】 大FFF社员
  5. 静态成员方法中可以通过new 构造方法创建对象 大FFF社不烧真爱!!!
1.2.3 静态成员方法特征解释
  1. 静态成员方法加载时间问题 静态成员方法是随着.class字节码文件的加载而直接定义在内存的【方法区】,而且此时的静态成员方法已经可以直接运行。可以通过类名直接调用,而此时没有对象存在。【没有对象】
  2. 为什么静态成员方法不能使用非静态成员 非静态成员变量和非静态成员方法时需要类对象调用的,在静态成员方法中,是可以通过类名直接执行的,而此时是【没有对象】的。
  3. 为什么静态成员方法不能使用this关键字 this关键字表示的是调用当前方法的类对象,但是静态成员方法可以通过类名调用,this不能代表类名,同时也是【没有对象】
  4. 静态成员方法可以使用其他静态成员 生命周期一致,调用方式一致

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();      }    }

结果:

执行“静态代码块” 无限递归,栈堆内存满,报错