问题1、讲一下 static 关键字,有什么用?为什么要这么设计?
问题2、static 方法可以调用哪些资源?不能调用哪些资源?
问题3 、静态方法不能调用非静态成员,编译会报错?
为什么会报错,能不能从类加载机制方面来说?
Static 关键字
在类中,用 static 声明的成员变量为静态成员变量,也叫做类变量。类变量的生命周期和类相同,在整个应用程序期间都有效,因为在类加载的时候,就会分配内存,可以直接通过类名直接去访问;
需要注意的是:
- static 修饰的成员变量和方法,是从属于类的
- 普通的变量和方法是属于对象的
- 静态方法不能调用非静态成员,不能调用非静态方法,编译会出错(为什么?从类加载的角度说)
Static 关键字的用途,为什么要这么设计?
简单的说就是:方便在没有创建对象的情况下进行调用(静态方法/变量)
被 static 关键字修饰的方法或者变量不需要依赖于对象进行访问,只要类被加载了,就可以通过类名进行访问。
1、修饰变量:因为类要被加载进方法区,所以多个对象可以共享 static 修饰的变量。
2、修饰方法:类似工具类的方法(比如 Arrays.sort(nums)),不需要创建对象,直接使用“类名.方法名”的方式调用。
3、修饰静态代码块:这个代码块只会在类初次加载的时候执行一次,可以用于初始化等操作,优化程序性能。
4、静态内部类:通常称为嵌套类
static 方法
static 方法也称为静态方法,由于静态方法不依赖于任何对象就可以直接访问,所以对于静态方法来说,是没有 this 的,因为不依附于任何对象,既然对象都没有,就谈不上用 this 了(this代表什么?this代表当前对象),并且因为此特性,在静态方法中不能访问类的非静态成员变量和非静态方法,因为非静态成员变量和非静态方法都必须依赖于具体的对象才能被调用。
注意: 虽然静态方法中不能访问非静态变量和非静态方法,但是非静态成员方法中是可以访问静态成员方法和静态成员变量的。
问题:静态方法不能调用非静态成员变量/方法,为什么编译会报错?
- 因为在编译期并没有对象生成,非静态成员变量属于对象,需要对象来调用,对象没有生成,所以就会报编译出错。
- 静态方法调用非静态方法,编译失败,这是因为,编译器无法预知非静态成员方法中是否调用了非静态成员变量,所以也禁止在静态方法中调用非静态成员方法。
非静态成员方法访问静态成员方法/变量是没有限制的
总结: - 首先 static 的成员是类加载的时候初始化的, JVM 的 CLASSLOADER 的加载,是首次主动使用加载;而非 static 的成员是在创建对象的时候,即 new 操作的时候才初始化的。
- 从类加载和创建对象先后顺序来说: 静态成员是属于类的,即静态成员是随着类的加载而加载的,在加载类时,程序就会为静态成员分配内存,而非静态方法/变量是属于对象的,对象是在类加载之后创建的,也就说静态成员是先于对象存在,当你创建一个对象时,程序为其在堆中分配内存,一般是通过 this 指针指向该对象。静态方法\变量不依赖于对象的来调用,它通过“类名.静态方法名\成员名” 来调用。 非静态方法\变量,在对象创建的时候程序才会为其分配内存,然后通过类的对象去访问非静态方法\变量。
所以在对象未存在时非静态成员也不存在,静态成员自然不能调用非静态成员。
为什么可以直接通过类名.静态成员名 调用静态成员?
是先加载,才能初始化,那么加载的时候初始化 static 的成员,此时非 static 的成员还没有被加载必然不能使用,而非static 的成员是在类加载之后,通过 new 操作创建对象时初始化,此时 static 已经分配到内存里,所以可以访问!
更细致的说命令为什么 java 静态方法中不能调用非静态方法的原因,点赞!
**总结:**如果想在不创建对象的情况下调用某个方法,就可以将这个方法设置为 static。最常见的静态方法就是 main 方法,程序执行的main 方法的时候没有创建对象,只有通过类名来访问。
注意: static 方法是属于类的,在 JVM 加载类时,就已经在内存中,不会被虚拟机 GC 回收掉,这样就导致内存负荷很大,但是非 static 方法会在运行完毕后就被虚拟机 GC 掉,减轻内存压力。
static 变量
static 变量也叫静态变量,静态变量和非静态变量的区别:
- 静态变量被所有对象共享,在内存中只有一个副本,在类初次加载的时候才会初始化。
- 非静态变量时对象多拥有的,在创建对象的时候才被初始化,存在多个副本,各个对象拥有的副本互不影响。
static块
- 构造方法用于对象的初始化。静态初始化块,用于类的初始化操作。
- 在静态初始化块中不能直接访问非staic成员。
static 关键字不会改变类中成员的访问权限。
静态的特点
- 随着类的加载而加载,随着类的消失而消失,侧面说明了静态的生命周期很长
- static 静态成员是早于对象存在的:因为类加载的过程是先进行加载,再进行初始化,那么类加载的时候初始化static 成员,此时非 static 的成员还没有被加载,所以必然不能使用,那么非 static 的成员是在类加载之后,可以通过 new 操作创建对象的时候初始化,那么 static 静态成员肯定是不能调用非静态成员的。
- 被所有对象共享
- 可以直接被类名调用
静态的成员变量与非静态的成员变量的区别
- 存放位置
静态变量(也可以叫类变量)随着类的加载存放于方法区中,实例变量对着对象的创建存在于堆内存中。 - 生命周期
类变量生命周期最长,随着类的加载而加载,随着类的消失而消失;实例对象随着“对象”的消失而消失。
静态使用注意事项
- 静态方法只能访问静态成员(包括成员变量和成员方法)
- 静态方法中不可以定义 this、super 关键字(因为静态优先于对象存在,所以静态方法中不可以出现this、supuer 关键字)、
- 主函数main() 是静态的
静态的利弊
优点:
节省内存空间:对对象的共享数据进行单独空间的存储(存在方法区),节省空间,没有必要对每一个对象中(在堆内存)都存储一份。
缺点:声明周期过长,访问出现局限性(只能方法访问静态)