static关键字
Static初步
定义
1、static翻译为“静态的”;
2、所有static修饰的,都是和类相关的,类级别的;
3、所有static修饰的,都是采用“类名.”的方式访问;
4、static修饰的变量---静态变量;
5、static修饰的方法---静态方法;
变量分类
方法区中存---静态变量(类级别)。静态变量在类加载时初始化。
堆中存---实例变量
栈中存---局部变量
变量根据声明的位置划分:
在方法体中声明的变量---局部变量
在方法体外,类中声明的变量---成员变量
成员变量又可以分为:
实例变量---要先有对象(实例),才能有实例变量
静态变量
class VarTest{
以下实例的,都是对象相关的,访问时采用‘引用.’的方式访问,需要先new对象。
必须先有对象才能访问,可能会发生空指针异常。
//成员变量中的实例变量
int i;
//实例方法
public void m(){}
以下静态的,都是类相关的,访问时采用‘类名.’的方式访问,不需要new对象。
不需要对象的参与即可访问,不会发生空指针异常。
//成员变量中的静态变量
static int k;
//静态方法
public static void m1(){}
}
什么时候使用静态变量
Q:什么时候变量声明为实例的,什么时候声明为静态的?
A:如果这个类型的所有对象的属性值都是一样的,不建议定义为实例变量,浪费内存空间。
建议定义为类级别特征,即定义为静态变量,在方法区中只保留一句,节省内存开销。
(一个对象一份就是实例变量,所有对象一份就是静态变量)
实例做法:
public class StaticTest02 {
public static void main(String[] args) {
Chinese c1 = new Chinese("1234", "张三", "中国");
Chinese c2 = new Chinese("12345", "李四 ", "中国");
System.out.println(c1.idCard);
System.out.println(c1.name);
System.out.println(c1.country);
System.out.println(c2.idCard);
System.out.println(c2.name);
System.out.println(c2.country);
}
}
//定义一个类---中国人
class Chinese{
String idCard;
//一个对象一份,每个人身份证号不同,所以应该是实例变量
String name; //一个人一个姓名,也应该是实例变量。要先有对象才能有实例变量
String country; //对于中国人这个类来说,国籍都是中国,不会随着对象的改变而改变,属于整个类的特征
public Chinese(){
}
public Chinese(String s1,String s2,String s3){
idCard = s1;
name = s2;
country = s3;
}
}
静态做法(静态变量要赋值,否则会输出为null!!!)
public class StaticTest02 {
public static void main(String[] args) {
System.out.println(Chinese.country);
Chinese c1 = new Chinese("1234", "张三");
Chinese c2 = new Chinese("12345", "李四 ");
System.out.println(c1.idCard);
System.out.println(c1.name);
//System.out.println(c1.country);
System.out.println(c2.idCard);
System.out.println(c2.name);
// System.out.println(c2.country);
}
}
//定义一个类---中国人
class Chinese{
String idCard; //一个对象一份,每个人身份证号不同,所以应该是实例变量
String name; //一个人一个姓名,也应该是实例变量。要先有对象才能有实例变量
//重点: 加static的变量叫做静态变量。
//静态变量在类加载时初始化,不需要new对象,静态变量的空间就开出来了。
//静态变量存储在方法区,有默认值
static String country = "中国"; //对于中国人这个类来说,国籍都是中国,不会随着对象的改变而改变,属于整个类的特征
public Chinese(){
}
public Chinese(String s1,String s2){
idCard = s1;
name = s2;
}
}
空指针异常
实例的---一定要用“引用.”来访问;
静态的---建议使用“类名.”来访问,但使用“引用.”也可以。(不建议使用“引用.”)
结论:
空指针异常--只有在“空引用”访问“实例”相关的,都会出现空指针异常。
public class StaticTest03 {
public static void main(String[] args) {
//通过"类名."的方式访问静态变量
System.out.println(Chinese.country);
//创建对象
Chinese c1 = new Chinese("111", "小明");
System.out.println(c1.idCard);
System.out.println(c1.name);
//c1是空引用,
c1 = null;
//分析这里会不会出现空指针异常?
//不会
//因为静态变量不需要对象的存在,通过类名调用即可
//实际上以下的代码在运行的时候还是把赋空的c1看成 Chinese,依然是通过类名去访问。
System.out.println(c1.country);
//这里出现空指针异常,因为name是实例变量,需要对象调用
//System.out.println(c1.name);
}
}
class Chinese01{
String idCard;
String name;
static String country = "中国";
public Chinese01(String x,String y){
idCard = x;
name = y;
}
}
带有Static的方法,要通过‘类名.’的方式访问
对象被称为实例,
实例相关的有:实例变量,实例方法,
实例变量是对象变量,实例方法是对象方法。
实例相关的都需要先 ‘new 对象’,通过‘引用.’的方式去访问
public class MethodTest {
public static void main(String[] args) {
//在同一个类中,’类名.‘可以省略不写
MethodTest.dosome();
dosome();
//调用没有static的方法
//创建对象
MethodTest mt = new MethodTest();
//通过’引用.‘的方式访问实例方法
mt.doother();
}
//带有static
public static void dosome() {
System.out.println("do some!");
}
//这个方法没有static,这样的方法被称为----实例方法。(对象方法,对象级别的方法)。要通过对象的方式访问。
public void doother(){
System.out.println("do other!");
}
}
空指针异常导致的最本质原因是什么?
空引用访问“实例相关的数据”,会出现空指针异常
实例相关的包括:实例变量(属性) + 实例方法
关于方法来说,什么时候定义为实例方法?
A:此方法一般都是描述了一个行为,如果说该行为必须由对象去出发,那么该方法定义为实例方法。
参考标准:
当这个方法体当中,直接访问了实例变量,这个方法一定是实例方法。
以后开发中,大部分情况下,工具类当中的方法一般都是静态方法。(静态方法有一个优点,就是不需要new对象,直接采用类名调用,极其方便。工具类就是为了方便,所以工具类中的方法一般都是静态的。)
使用static关键字可以定义:静态代码块
Q:什么是静态代码块?语法是什么?
A:静态代码块用于初始化类,为类的属性初始化
static{
java语句;
java语句;
}
Q:static静态代码块在什么时候执行?
A:类加载时执行,并且只执行一次
静态代码块有这样的特征
注意:
静态代码块在类加载时执行,并且在main方法执行之前执行。
(主方法执行了,类就加载了)
静态代码块一般按照自上而下的顺序执行。
public class StaticTest04 {
//静态代码块
static{
System.out.println("A");
}
//一个类中可以编写多个静态代码块
static{
System.out.println("b");
}
//程序入口
public static void main(String[] args) {
System.out.println("hello world");
}
//编写一个静态代码块
static{
System.out.println("c");
}
}
Q:静态代码块的作用?
A:第一,静态代码块不常用,不是每一个类都要写
第二,举例;所有编写的程序中,只要是类加载了,请记录一下类加载的日志信息。(在哪年哪月哪日,哪个类加载到JVM中?)
这些记录日志的代码,就应该写在静态代码块中。
静态代码块是一个特殊的时机---类加载时机
代码执行顺序
public class StaticTest05 {
//静态变量在什么时候初始化?---类加载时
//静态变量存储在哪里?---方法区
static int i = 100;
//静态代码块什么时候执行?---类加载时执行,存储在方法区
//只要是代码,一定存储在方法区
static{
//这里可以访问 i 吗?--- 可以,因为静态的东西在同一时间点完成。
System.out.println("i=" + i);
}
//实例变量
int k = 111; //k变量是实例变量,在new对象的时候才会初始化,在构造方法执行时,内存空间才会开辟
//这里可以访问 k 变量吗?--- 不可以。静态代码块在类加载时执行,并且只执行一次,类加载时K变量还没开辟出空间(K还不存在)。
static{
System.out.println("k");
}
//静态变量在静态代码块下面,这里可以访问name吗? --- 不可以
//静态代码块和静态变量都是在类加载的时候执行,时间相同,只能靠代码的顺序来决定谁先谁后。
static{
System.out.println("name=" + name);
}
static String name = "张三";
//程序入口,实际上在main方法执行之前,已经执行了很多代码。
public static void main(String[] args) {
System.out.println("main begin");
}
}
执行顺序总结
到目前为止,你遇到的所有java程序,有顺序的是哪些?
1、对于一个方法来说,方法体中的代码是有顺序的---自上而下;
2、静态代码块1和静态代码块2是有先后顺序的;
3、静态代码块和静态变量是有先后顺序的;
变量在前,代码块在后。
4、在一个类体中,方法是没有先后顺序的。
实例语句块
1、在类加载时不执行,在构造方法执行之前执行
2、语法
{
java语句;
java语句;
}
3、只要是构造方法执行,必然在构造方法之前,执行‘实例语句块’中的代码。--- 对象构建时机
4、可以执行多次,只要调一次构造方法,实例语句块就执行一次。
5、什么时候用?
当有多个构造方法,且每个构造方法的部分代码都一样时,就可以把这段相同的代码放在实例语句块里。这样每次构造方法执行之前,都会执行这段代码。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!