static(静态)关键字
用Ststic后产生的效果分析图
静态变量代表方法共有的变量【JAVA中没有全局变量的概念】

静态特点【例二】
①随着类的加载而加载,随着类的消失而消失
也就是说,静态会随着类的消失而消失,说明他的生命周期最长
注意:当类一旦被加载时,static定义的静态变量就存在
②优先于对象存在
明确一点:静态变量是先存在的,对象是后存在的
③被所有对象共享
④可以直接被类名所调用
⑤只要一个实例把它改变,所有实例都会改变
静态变量【类变量】和普通变量【实例变量】的区别
  随着类的加载而加载,存在于方法区中
实例变量随着对象的建立存在于堆内存中,实例成员与特定的对象关联
生命周期
类变量生命周期最长,随着类的消失而消失
实例变量随着对象的消失而消失
图像分析

用法
是一个修饰符,用于修饰(成员变量,成员函数)
当成员被静态修饰后,就多了一种调用方式,除了可以被对象调用外,还可以直接被类名调用
调用方式:类名.静态成员【例一】
例一
1 public class Exam { 2 public static void main(String[] args) { 3 Person person = new Person(); 4 // person.show(); 5 System.out.println(Person.country); //CN 6 } 7 } 8 9 class Person { 10 static String country = "CN"; 11 12 void show() { 13 System.out.println(country); 14 } 15 16 }
例二
1 public class Exam { 2 public static void main(String[] args) { 3 Person person = new Person(); 4 // person.show(); 5 System.out.println(Person.country); // CN 6 } 7 } 8 9 class Person { 10 String name; // 成员变量,实例变量 11 static String country = "CN"; // 静态成员变量,类变量 12 13 void show() { 14 System.out.println(name + ":" + country); 15 } 16 17 }
静态变量使用注意事项
①静态方法只能访问静态成员【方法和变量】
        非静态方法可以访问非静态变量,也可以访问静态变量【因为根据先来后到,有方法时已经有了静态变量,所以可以调用】
函数加上static就是说明这个函数是静态的,如果要使用这个函数不需要先new出这个对象,可以直接使用类名.方法名
示例代码
代码一
1 public class Exam { 2 public static void main(String[] args) { 3 4 Person.show(); //CN 5 } 6 } 7 8 class Person { 9 String name; // 成员变量,实例变量 10 static String country = "CN"; // 静态成员变量,类变量 11 12 public static void show() { 13 System.out.println(country); 14 } 15 16 }
代码二
1 public class Exam { 2 public static void main(String[] args) { 3 4 Person.show(); //CN 5 } 6 } 7 8 class Person { 9 String name; // 成员变量,实例变量 10 static String country = "CN"; // 静态成员变量,类变量 11 12 public static void show() { 13 System.out.println(name); 14 } 15 16 }
编译错误提示

原因:因为连对象都没创建,name也不存在,根据先来后到顺序,static已经存在时对象还不存在,所以静态方法不能调用实例变量
②静态方法中不可以定义this,super关键字,因为静态优先于对象存在,不可以出现this
静态方法利弊
利:对对象共享数据进行单独空间的存储,节省空间,没有必要每个对象中都存一份
可以直接被类名调用
换一种解释
对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。
弊端:生命周期过长,访问出现局限性(静态虽好,只能访问静态)
③主函数是静态的
换一种解释
对于实例变量,没创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)
注意:静态方法是类内部的一类特殊方法,只有在需要时才将对应的方法声明成静态的,一个类内部的方法一般都是非静态的
所以一般在需要实现以下两个功能时使用静态变量:
- 在对象之间共享值时
 - 方便访问变量时
 
什么时候使用静态
要从以下两方面入手:
因为静态修饰的内容有成员变量和函数
什么时候定义静态变量(类变量)?
当对象中出现共享数据时,该数据被静态所修饰,这里的共享数据指的不只是属性相同,内容也要相同
如【某某学校的学生的共享属性就是:他们是某某学校的学生,而像性别,姓名,年龄这些都不是】
对象中的特有数据要定义为非静态存在于堆内存中
什么时候定义静态函数?
当功能内部没有访问到非静态数据(对象的特有数据)
那么该功能可以定义为静态【例三】
例三
代码一【可以定义静态,功能中没有涉及到非静态变量】
1 public class Exam { 2 public static void main(String[] args) { 3 Dog dog = new Dog(); 4 dog.test(); //我是静态方法 5 } 6 } 7 8 class Dog { 9 String name = "ABC"; 10 11 public static void test() { 12 System.out.println("我是静态方法"); 13 } 14 }
代码二【不可以定义静态,功能中涉及到非静态变量】
1 public class Exam { 2 public static void main(String[] args) { 3 Dog dog = new Dog(); 4 dog.test(); //我是静态方法ABC 5 } 6 } 7 8 class Dog { 9 String name = "ABC"; 10 11 public void test() { 12 System.out.println("我是静态方法"+name); 13 } 14 }
静态的应用【待看】
每一个应用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用
静态代码块
书写规则
1 static 2 { 3 静态代码块中的执行语句 4 }
特点
随着类的加载而执行,只执行一次,用于给类进行初始化,并优先于主函数先执行
1 public class Exam { 2 3 static { 4 System.out.println("A"); 5 } 6 7 public static void main(String[] args) { 8 new Demo(); 9 new Demo(); 10 System.out.println("over"); 11 } 12 13 static { 14 System.out.println("B"); 15 } 16 } 17 18 class Demo { 19 static { 20 System.out.println("C"); 21 } 22 }
执行结果

之所以C只出现了一次是因为static方法随着类的加载而执行,只执行了一次
注意:容易考察执行顺序
静态代码块>构造代码块>构造方法>普通方法
例题
1 public class Exam { 2 3 Exam() { 4 System.out.println("A"); 5 } 6 7 Exam(int a) { 8 System.out.println("B"); 9 } 10 11 { 12 System.out.println("C"); 13 } 14 15 static { 16 System.out.println("D"); 17 } 18 19 public static void main(String[] args) { 20 new Exam(5); 21 22 } 23 24 }
执行结果

对象初始化过程
代码
1 public class Exam { 2 3 public static void main(String[] args) { 4 Test test = new Test("张三", 10); 5 } 6 } 7 8 class Test { 9 private String name; 10 private int a; 11 12 Test(String name, int a) { 13 this.name = name; 14 this.a = a; 15 System.out.println(name + "," + a); 16 } 17 18 { 19 System.out.println("A"); 20 } 21 22 static { 23 System.out.println("B"); 24 } 25 26 public static void Test1() { 27 System.out.println("C"); 28 } 29 30 }
运行结果

代码解析
Test test = new Test("张三",10)
这句话做了什么事情?
1.因为new用到了Test.class,所以会找到Test.class文件加载到内存中
2.执行该类中的static代码块,如果有的话,给Test.class类进行初始化
3.在堆内存中开辟空间,分配内存地址
4.在堆内存中建立对象的特有属性,并进行默认初始化
5.对属性进行显示初始化
6.对对象进行构造代码块初始化
7.对对象进行与之对应的构造函数初始化
8.将内存地址付给栈内存中的test变量
图像分析

1 public class Exam { 2 3 public static void main(String[] args) { 4 Test test = new Test("张三", 10); 5 test.Test2("李四"); 6 test.Test1(); 7 } 8 } 9 10 class Test { 11 private static String country = "BJ"; 12 private String name; 13 private int a; 14 15 Test(String name, int a) { 16 this.name = name; 17 this.a = a; 18 System.out.println(name + "," + a); 19 } 20 21 { 22 System.out.println("A"); 23 } 24 25 public void Test2(String name) { 26 this.name = name; 27 } 28 29 static { 30 System.out.println("B"); 31 } 32 33 public static void Test1() { 34 System.out.println(country); 35 } 36 37 }
运行结果

图像分析

                    
                
                
            
        
浙公网安备 33010602011771号