1 静态成员
配套学习资料【含授课视频、源码】:https://link3.cc/ashao
static修饰类中的数据成员,该成员就成了静态数据成员,也称为类成员;
类成员,是属于类的,为这个类所有对象共享,只占用一块内存空间。
生活中案例:
-
普通成员变量
就像教室中,同学们的水杯,每个同学都有一个自己的水杯,和其他人相互不影响
-
静态数据成员
就像教室中,角落里的饮水机,它是这个教室中所有同学共享的,张三接一杯水,李四就会看到饮水机中的水少了一些,同样的李四接一杯水,张三也会看到饮水机中的水少了一些
static成员特点:
-
被类的所有对象共享
-
随着类的加载而加载,先于对象存在
对象需要类被加载后,才能被创建出来
-
可以通过类名调用,也可以通过对象名调用,推荐使用类名调用
格式:
类名.静态数据成员;
-
方法区中有一块专门的区域:静态区,专门用来存储类的static成员
静态成员访问方式,案例描述:
class Demo {
public static int num;
}
public static void main(String[] args) {
//可以使用类名来访问,推荐用法
Demo.num = 10;
Demo demo = new Demo();
//也可以对象来访问,但不推荐
demo.num = 20;
}
静态数据成员是属于类的,并且为这个类所有对象共享,案例描述:
class Demo {
public static int num;
}
public static void main(String[] args) {
//1.静态数据成员会随着类的加载而加载(开辟内存并进行默认初始化)
//先于对象存在
Demo.num = 10;
//2.实例化两个对象,然后通过对象访问静态成员,输出其值
Demo demo1 = new Demo();
Demo demo2 = new Demo();
System.out.println(demo1.num);//输出结果为 10
System.out.println(demo2.num);//输出结果为 10
//3.通过类名修改静态成员值,再借助对象.static成员,输出其值
Demo.num = 20;
System.out.println(demo1.num);//输出结果为 20
System.out.println(demo2.num);//输出结果为 20
//4.通过对象名修改静态成员值,再借助类名.static成员,输出其值
demo1.num = 30;
System.out.println(Demo.num);//输出结果为 30
System.out.println(demo2.num);//输出结果为 30
}
可以看出,无论是使用类访问静态属性,还是使用这个类的某个对象访问静态属性,效果是一样的,这个属性对这个类的所有对象都是可见的、共享的。
静态属性存储位置:
在方法区中有一块静态区,专门用来存储各个类静态数据成员。当操作静态数据成员时,不论是通过类名,还是通过对象名操作,都是操作静态区中对应的内存区域。
静态数据成员初始化:
-
静态数据成员随着类加载而加载(开辟相应内存),并会进行默认的初始化
其默认初始化值为
null(引用类型)、0(整形)、0.0(浮点型)、false(布尔类型)
。
案例描述:
class Demo {
public static int num;
public static String str;
public static double dNum;
public static boolean flag;
}
public class Test0102_StaticValue {
public static void main(String[] args) {
System.out.println(Demo.num); //0
System.out.println(Demo.str); //null
System.out.println(Demo.dNum); //0.0
System.out.println(Demo.flag); //false
}
}
-
对静态数据成员的初始化,一般采用两种方式
显式初始化、静态代码块初始化(后面章节介绍)
-
显式初始化格式:
[修饰符] static 数据类型 静态成员名 = 初始值;
例:
public static String library = "栋梁图书馆";
注意:尽量不要在构造方法中对static成员进行初始化,因为只要创建对象,构造方法就会自动被执行,导致static成员值不经意间被修改!
案例描述:
请根据讲解内容,修改上一章节中School类代码,并完成测试。
//学校类
class School {
private String name; //名称
private int num; //师生数量
//该类所有对象共享的图书馆,显示初始化
public static String library = "栋梁图书馆";
//定义构造器
public School() {}
public School(String name, int num) {
this.name = name;
this.num = num;
}
//该构造器不合适,尽量不要在构造方法中 对static成员进行初始化
// public School(String name, int num, String library) {
// this.name = name;
// this.num = num;
// this.library = library;
// }
public void show() {
System.out.println("学校名称: " + this.name);
System.out.println("师生数量: " + num);
System.out.println("图书馆: " + School.library);
}
}
public class Test0102_School {
public static void main(String[] args) {
//1.在创建School对象前,输出 static成员值
//此时程序正常输出,说明static成员的创建与初始化先于对象
//结论:static成员依赖类,而与该类对象无关
System.out.println(School.library);
//2.创建类对象
School s1 = new School("第一中学",3000);
System.out.println(s1.library);
s1.show();
System.out.println("-------------");
School s2 = new School("秀峰中学",2500);
s2.show();
System.out.println("-------------");
School s3 = new School("娄江中学",1800);
s3.show();
}
}
运行效果:
2 静态方法
在类中,使用static修饰的方法,就是静态方法;
static方法的作用,主要是用来操作static成员;
static方法可以使用类名来调用,也可以使用对象来调用,但推荐使用类名。
案例描述:
public class Demo{
//定义静态方法
public static void test() {
System.out.println("我是static静态方法...");
}
}
//测试方法
public static void main(String[] args){
//借助类名调用static方法,推荐方式
Demo.test();
Demo demo = new Demo();
//借助对象调用static方法,可以调用,但不推荐
demo.test();
}
static方法和普通成员方法区别:
-
静态方法只能访问静态的成员
-
非静态方法可以访问静态的成员,也可以访问非静态的成员
-
静态方法中没有this关键字 (本质区别)
案例描述:
//学校类
class School {
private String name; //名称
private int num; //师生数量
//用private修饰static成员,则该类外无法直接访问该static成员
private static String library = "栋梁图书馆";
//定义public修饰的static方法,专门来操作static成员
public static String getLibrary() {
//注意1:static方法中没有this
//return this.library; //error
//注意2:static方法中不可以访问普通数据成员
//name = "一高"; //error
return library;
}
}
//测试方法
public static void main(String[] args) {
//1.在创建School对象前,输出 static成员值
//编译报错,library为private,只能School类内访问
//System.out.println(School.library);
//2.借助类名调用static方法,推荐用法
String lib = School.getLibrary();
System.out.println(lib);
//3.借助方法名调用static方法,不推荐
School s1 = new School("第一中学",3000);
System.out.println(s1.getLibrary());
}
思考:为什么静态方法中不能访问普通数据成员?
静态方法也称为类方法,该类方法的调用不依赖对象,可以直接通过类名调用。
假设静态成员方法中能够访问普通数据成员,静态方法中有this引用,我们来看下面场景:我们通过类名调用static方法,此时根本不会传递对象的地址值给this引用,static方法内部也无法找到普通数据成员对应的内存空间进行取值,这与我们要实现的功能是矛盾的。
故而,大家记住结论:静态只能访问静态。