Java中的static关键字浅析

这是我结合一些自己的思想写的对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();
    }
    
}

结果:

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

发布了6 篇原创文章 · 获赞 10 · 访问量 1932

猜你喜欢

转载自blog.csdn.net/qq_42581682/article/details/104535193