概述:不依赖于任何对象就可以直接访问
static关键字可以修饰成员变量和成员方法
static修饰的成员变量是一个共享资源,被所有对象共享,在类初次加载的时候才会初始化
static修饰的成员变量的生存期和类对象的生存期完全不同,而是和类的生存期相同,即:static成员变量在类对象创建之前可以使用,类对象销毁之后依然可以使用,所以static修饰的成员变量和类对象无关。
static修饰的成员方法不依赖于任何对象就可以直接访问
主要作用:工具类(静态成员方法使用的数据都是外来数据,且静态成员方法可以摆脱类对象约束,通过类名直接调用。)
优点:
1、节约内存,简化逻辑。(不需要创建对象,不需要申请对象空间,也不需要销毁对象空间。)
2、复用度更高。(摆脱对象限制,更加自由)
1、静态成员变量具有数据共享性,不管通过那种方式修改,都会影响所有人
2、static修饰的成员变量和成员方法,从属于类,普通变量和方法从属于对象
3、静态成员变量与静态成员方法推荐使用类名直接调用
4、static修饰的成员变量的生存期和类对象的生存期完全不同,而是和类的生存期相同
5、静态成员方法中不能够使用类内非静态成员变量与非静态成员方法 ,但是在非静态成员方法中,可以使用静态成员变量与静态成员方法。
6、静态成员方法可以使用类内的其他静态成员变量和静态成员方法
7、不能在static修饰的静态内容中,使用this关键字
eg:
class Person {
public String name;
public static String country = "China";
// 构造方法
public Person() {}
public Person(String name) {
this.name = name;
}
public void test() {
System.out.println("非静态成员方法");
}
public static void test2() {
System.out.println("静态成员方法");
}
// getter与setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Demo {
public static void main(String[] args) {
// 静态成员变量在没有创建对象的情况,可以通过类名使用
System.out.println("Country: " + Person.country);
// 静态成员变量与对象无关
System.out.println("Name: " + new Person("张三").getName() + "\t" + "Country: " + Person.country);
//非静态成员方法,通过匿名对象调用
new Person().test();
//静态成员方法,通过类名调用
Person.test2();
}
}
运行结果:
Country: China
Name: 张三 Country: China
非静态成员方法
静态成员方法
构造代码块:
功能:
初始化当前类所有的类对象,只要【使用new + 构造方法创建当前类对象】,就一定会执行构造代码块中的内容
格式:
在class大括号以内,成员变量之后,构造方法之前
// 构造代码块
{
}
静态代码块:
功能:
类文件加载,静态代码块中的内容一定会执行,有且只执行一次!
类文件的加载是当前代码中的确需要当前类,才会进行加载。
格式:
在class大括号以内,成员变量之后,构造方法之前
// 静态代码块
static {
}
注意:非静态成员变量,非静态成员方法,this关键字都无法在静态代码块中使用。
eg1:
class Demo {
static Demo demo1 = new Demo();
static Demo demo2 = new Demo();
{
System.out.println("构造代码块");
}
static {
System.out.println("静态代码块");
}
public Demo() {
System.out.println("构造方法");
}
public static void main(String[] args) {
Demo demo1 = new Demo();
}
}
运行结果:
构造代码块
构造方法
构造代码块
构造方法
静态代码块
构造代码块
构造方法
分析:
1、找到main方法程序入口,在执行main方法之前应该先加载Demo类,
2、加载Demo类时,按照基本顺序结构(从上至下,从左至右),先执行静态成员变量demo1初始化,又由于构造代码块只要【使用new + 构造方法创建当前类对象】,就一定会执行构造代码块中的内容,所以先输出构造代码块,再输出构造方法
3、静态成员变量demo2同理,输出先输出构造代码块,再输出构造方法
4、然后发现静态代码块,执行静态代码块中的内容,输出静态代码块
5、执行main方法,采用无参数构造方法对Demo类对象demo1进行初始化,先输出构造代码块,在输出构造方法。
eg2:
class Demo {
static int num1 = 10;
static int num2 = 20;
{
System.out.println("构造代码块");
}
static {
num1 = 20;
num2 = 100;
}
public Demo() {
System.out.println("构造方法");
}
public static void main(String[] args) {
new Demo();
}
}
/*
代码执行效果已经num1和num2的值是多少
*/
分析:
1、找到main方法程序入口,在执行main方法之前应该先加载Demo类,
2、加载Demo类时,按照基本顺序结构(从上至下,从左至右),先执行静态成员变量,此时num1 = 10, num2 = 20.
3、然后发现静态代码块,执行静态代码块中的内容,此时num1 = 20, num2 = 100.
4、执行main方法,采用无参数构造方法对匿名对象进行初始化,先输出构造代码块,再输出构造方法。
eg3:
class Demo {
Demo demo1 = new Demo();
Demo demo2 = new Demo();
{
System.out.println("构造代码块");
}
static {
System.out.println("静态代码块");
}
public Demo() {
System.out.println("构造方法");
}
public static void main(String[] args) {
Demo demo1 = new Demo();
}
}
/*
问:
代码执行流程!!!
*/
分析:
1、找到main方法程序入口,在执行main方法之前应该先加载Demo类,
2、加载Demo类时,按照基本顺序结构(从上至下,从左至右),先执行静态代码块,输出静态代码块.
3、然后在main方法中对Demo类对象demo1进行实例化,将非静态成员变量加载到Demo类对象demo1指向的堆空间中,由于该成员变量为Demo类自身对象的实例化,形成了闭环,则会出现无限递归现象造成堆栈溢出错误。