看完博主的这一篇博客不仅让你满脸问号,还让你浑身充满问号
皮一下很开心(小声bb)
目录:
1static的作用
2.static的应用场景
3.静态实例变量的区别
4.访问静态变量和方法的方式
5.静态代码块和其他代码块的执行顺序
6.静态内部类
7.静态导包
1.static的作用
(1)static是一个能创建独立于具体对象的域变量或者方法
即使没有创建对象也能使用的属性和方法(这一点很重要),这些方法和属性不单独属于某一个实例化的对象,而是为所有对象共享有点中央空调的意思,相当于中央空调有n个女朋友(女朋友指代这里的对象),然后这些女朋友都有同一个男朋友
(2)形成静态代码块优化性能
静态代码块能放在类的任何一个地方,当类首次被加载的时候就会执行静态代码块里边的内容(一般代码块都是初始化的作用),而且是只会加载一次并且在第一次加载的时候分配内存空间(以后创建对象不用重新分配),第二次加载类的时候就不会再执行
注意这里虽然只初始化一次但是还可以根据自己的意愿去更改它初始化的值的,被一个对象更改所有对象的值都会更改因为它是共享
由于它只会加载一次的特性,所以很多只需要初始化一次的东西放在里边,比那些只要创建对象就会加载一次的代码块效率高得多,所以就会优化程序性能
2.static的应用场景
(1)修饰成员变量
(2)修饰成员方法
(3)静态代码块
(4)静态内部类
3.静态变量和实例变量的区别(重点)
(1)简单来说就是用static修饰的成员变量就是静态变量,不用static修饰的成员变量就是实例变量
(2)不同对象的实例变量都有不同的内存空间,而所有对象的静态变量都是同一块地址的值
(3)访问方式有所区别
静态方法和实例有相同的区别。我们有时候把静态的方法和静态变量称为类方法和类变量
4.访问静态的变量和静态方法
(1)访问静态变量:
类名.静态变量
实例对象.静态方法
(2)访问静态方法:
类名.静态变量
对象.静态方法
(3)关于静态方法访问的注意事项:
我们知道静态方法只能访问静态方法和静态属性,但是有时我们却能在main方法中调用非静态的方法这是为啥,如下图:
这为啥不报错
这里就要讲一下静态和非静态变量是何时被初始化的:
首先静态变量在类被jvm加载的时候就会分配内存然后初始化,这时候非静态变量并没有分配内存,你在静态的方法初始化的时候调用这些还没分配内存的数据就会发生错误,所以静态方法里边不能调用非静态成员,当我们创建一个新的对象的时候,那么那些非静态的属性就会被分配内存和初始化,这时候你再在静态方法里边调用就能想应的属性和方法就不会产生错误了,所以当在静态方法里边实例化对象后就可以调用那些非静态的属性
可能这里有杠精又来了,那么照你这么说非静态方法不是也不能调用非静态方法吗(事实上是可以的),
这里的非静态方法之所以能调用非静态方法是因为他们同时分配内存,编译器不会认为那个调用别的方法的方法头大就先给它分配内存,而是同时分配(都是在创建一个实例化对象的时候分配),所以只要非静态方法调用别的非静态方法,那么他俩都是已经存在的,自然就可以正常调用
5.静态代码块和其他代码块等的执行顺序
1.先讲几个块(当作休息😁):
(1)构造代码块:也叫构造初始化块
如图:只有一个中括号的代码块就是构造初始化块
(2)普通代码块:也是一个只有一个中括号的代码块和构造代码块不同的是他是存在方法里边的
如图:
(3)静态代码块:
和构造代码块写法上没有大的区别就是在中括号后边加一个static
如图;
接下来很重要:
由于普通代码块需要我们手动调用,而其他代码块系统自动调用所有我们就不把普通代码块拿出来和另外两个比较了(因为它稳
的最后执行),顺便把自动调用的构造方法拿来比较
如图:
package untl1;public class aaa {public static void main(String[] args) {A a=new C();}}class A{A(){System.out.println("我是爷爷辈的构造函数");}{System.out.println("我是爷爷辈的构造初始化块");}static{System.out.println("我是爷爷辈的静态初始化块");}}class B extends A{B(){System.out.println("我是爸爸辈的构造函数");}{System.out.println("我是爸爸辈的构造初始化块");}static{System.out.println("我是爸爸辈的静态初始化块");}}class C extends B{C(){System.out.println("我是孙子辈的构造函数");}{System.out.println("我是孙子辈的构造初始化块");}static{System.out.println("我是孙子辈的静态初始化块");}}
结果是
没想到吧哈哈,构造函数平时np哄哄的,现在倒数,三个静态代码块高居前三
总之
在单个类中执行顺序:静态代码块>构造代码块>构造函数
在继承中:父类静态代码块>子类静态代码块>父类构造代码块>父类构造函数>子类构造代码块>子类构造函数
这里的构造代码块和静态代码块区别在于,构造代码块在每次创建新的对象的时候都会执行一遍代码块里边的内容,而且是每个对象独有的,每个对象此代码块所在内存空间不同(一个用情专一,一个朝三暮四,博主当然是第一种人)
6.静态内部类
如果你对内部类不熟或者就只是对静态内部类不熟悉那么就来围观博主的另一篇博客:
java内部类详解
7.静态导包
(1)格式:
import static
(2)作用:
这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名调用类中静态成员可以直接使用类中静态成员变量和成员方法
例子:
// Math. --- 将Math中的所有静态资源导入,这时候可以直接使用里面的静态方法,而不用通过类名进行调用// 如果只想导入单一某个静态方法,只需要将换成对应的方法名即可import static java.lang.Math.;// 换成import static java.lang.Math.max;具有一样的效果public class Demo {public static void main(String[] args) {int max = max(1,2);System.out.println(max);}}
最后有一个注意点
局部变量不能用static修饰