static 代表着什么
1.在 Java 中并不存在全局变量的概念,但是我们可以通过 static 来实现一个“伪全局”的概念,在 Java 中 static 表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,当然也可以修饰代码块。
2.被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享。
3.只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。
4.用static修饰的成员变量和成员方法是所有实例共享同一个static变量或方法
5.用private修饰的static表示 可以在类的静态代码块中,或者类的其他静态成员方法中使用(当然也可以在非静态成员方法中使用--废话),但是不能在其他类中通过类名来直接引用,public就可以
6.用static修饰的代码块表示静态代码块,当Java虚拟机(JVM)加载类时,就会执行该代码块。
是否静态的对类成员变量进行分类:
种是被static修饰的变量,叫静态变量或类变量;
另一种是没有被static修饰的变量,叫实例变量。
静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配
实例变量每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)
加载了解
![](https://img.haomeiwen.com/i12058546/2680146b828c9854.png)
Java 把内存分为栈内存和堆内存
其中栈内存用来存放一些存放函数的参数、局部变量、临时变量、基本变量,函数返回地址等
堆内存主要存放所有new 创建的对象和 数组的数据等。堆中不存放基本类型和对象引用,只存放对象本身
静态变量存放在方法区中,并且是被所有线程所共享的,方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量
静态方法
静态方法可以直接通过类名调用,任何的实例也都可以调用, 因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。 因为实例成员与特定的对象关联!!
因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。
静态方法是类内部的一类特殊方法,只有在需要时才将对应的方法声明成静态的,一个类内部的方法一般都是非静态的。
总结
它们仅能调用其他的static 方法。
它们只能访问static数据。
它们不能以任何方式引用this 或super。
static代码块
static代码块也叫静态代码块,是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。例如:
public class Solution {
public static int x=200;//静态变量
public final static int y=100;//静态常量
private static int a;
private int b;
static{
Solution.a=3;
System.out.println(a);
Solution t=new Solution();
t.f();
t.b=1000;
System.out.println(t.b);
}
static{
Solution.a=4;
System.out.println(a);
}
static{
Solution.a=5;
System.out.println(a);
}
public void f() {
System.out.println("hhahhahah");
}
public static void display(){
System.out.println("hello world");
}
public static void main(String[] args) {
}
/*
3
hhahhahah
1000
4
5
*/
}
static{}语句块执行的时机
(1)用Class.forName()显示加载的时候;
(2)实例化一个类的时候,如将main()函数的内容改为:Test t=new Test();//这种形式其实和1相比,原理是相同的,都是显示的加载这个类,读者可以验证Test t=new Test();和Test t=(Test)Class.forName().newInstance();这两条语句效果相同。
(3)调用类的静态方法的时候,如另外起一个类将main()函数的内容改为:Solution.display();
public class Main {
public static void main(String[] args) {
// Solution.display();
}
}
(4)调用类的静态变量的时候,如另外起一个类将main()函数的内容改为:System.out.println(Solution.x);
public class Main {
public static void main(String[] args) {
System.out.println(Solution.x);
}
}
注意注意注意
调用类的静态常量的时候,是不会加载类的,即不会执行static{}语句块
public class Main {
public static void main(String[] args) {
System.out.println(Solution.y);
//3
}
}
这是java虚拟机的规定,当访问类的静态常量时,如果编译器可以计算出常量的值,则不会加载类,否则会加载类,例如:public static final int a = math.PI
用Class.forName()形式的时候,我们也可以自己设定要不要加载类将Class.forName("Solution")
改为
Class.forName("Solution",false,StaticBlockTest.class.getClassLoader())
static和final一块用表示什么
static final用来修饰成员变量和成员方法,可简单理解为“全局常量”!
对于变量,表示一旦给值就不可修改,并且通过类名可以访问。对于方法,表示不可覆盖,并且可以通过类名直接访问。
综合示例
public class UseStatic {
static int a = 3;
static int b;
static void meth(int x) {
System.out.println("x = " + x);
System.out.println("a = " + a);
System.out.println("b = " + b);
}
static {
System.out.println("Static block initialized.");
b = a * 4;
}
public static void main(String args[]) {
meth(42);
}
}
/*
Static block initialized.
x = 42
a = 3
b = 12
*/
一旦UseStatic 类被装载,所有的static语句被运行。
1.首先,a被设置为3,
2.接着static 块执行(打印一条消息),b被初始化为a*4 或12。
3.然后调用main(),main() 调用meth() ,把值42传递给x。3个println ( ) 语句引用两个static变量a和b,以及局部变量x 。
静态初始化块,非静态初始化,构造函数
在Java中,有两种初始化块:静态初始化块和非静态初始化块。它们都是定义在类中,用大括号{}括起来,静态代码块在大括号外还要加上static关键字。
所有的静态初始化块都优先执行,其次才是非静态的初始化块和构造函数,它们的执行顺序是:
父类的静态初始化块
子类的静态初始化块
父类的初始化块
父类的构造函数
子类的初始化块
子类的构造函数
非静态初始化块的好处
对于普通的类而言,可以放在初始化块中的初始化工作其实完全可以放到构造函数中进行,只不过有时会带来些许不便,如有多个构造器,就要在多个地方加上初始化函数完成初始化工作,而如果放到初始化块中的话则只要写一次即可。
但是,如果只是这一点便利的话,还不足以使用初始化块,其实初始化块真正体现其独一无二的作用是在匿名内部类中,由于是匿名内部类,因而无法写构造方法,但是很多时候还是要完成相应的初始化工作,这时就需要用到初始化块了,特别是Android中大量地使用匿名内部类,初始化块的作用就十分突出
static关键字小结:
(1)特点:
1、static是一个修饰符,用于修饰成员。(成员变量,成员函数)static修饰的成员变量 称之为静态变量或类变量。
2、static修饰的成员被所有的对象共享。
3、static优先于对象存在,因为static的成员随着类的加载就已经存在。
4、static修饰的成员多了一种调用方式,可以直接被类名所调用,(类名.静态成员)。
5、static修饰的数据是共享数据,对象中的存储的是特有的数据。
(2)成员变量和静态变量的区别:
1、生命周期的不同:
成员变量随着对象的创建而存在随着对象的回收而释放。
静态变量随着类的加载而存在随着类的消失而消失。
2、调用方式不同:
成员变量只能被对象调用。
静态变量可以被对象调用,也可以用类名调用。(推荐用类名调用)
3、别名不同:
成员变量也称为实例变量。
静态变量称为类变量。
4、数据存储位置不同:
成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据。
静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。
(3)静态使用时需要注意的事项:
1、静态方法只能访问静态成员。(非静态既可以访问静态,又可以访问非静态)
2、静态方法中不可以使用this或者super关键字。
3、主函数是静态的
参考文章
https://zhuanlan.zhihu.com/p/42961231
https://zhuanlan.zhihu.com/p/70110497
网友评论