一、静态概念 点击此处返回总目录 二、static的内存图 三、static的注意事项 四、静态修饰什么时候使用?应用场景是什么? 五、多态中的静态调用 六、定义静态常量 一、静态概念 1 被静态修饰的数据,不再是对象特有的内容,而是所有对象的共享内容。 ![](https://i-blog.csdnimg.cn/blog_migrate/973992c73a97720c098aeca50a768a06.png) 如上图所示,student类中,每个同学都有自己的姓名和年龄,但是所有同学的学校名都是“itcast”。如果当作普通变量的话,在创建对象时,每个对象都会创建这个变量,造成浪费。 因此把schoolName对象拿出来,让大家共享。这样节约空间。 2 被static修饰的成员,可以通过类名直接调用。 例1: //Person.java
package cn.itcast.demo01; public class Person{ String name; static String className; } |
//Test.java
package cn.itcast.demo01; public class Test{ public static void main(String[] args){ System.out.println(Person.className); //null。说明在内存中,对象还没创建,但是静态变量已经存在了。 Person p1 = new Person(); Person p2 = new Person(); p1.name = "haha"; p1.className = "aaa"; System.out.println(p1.name); //haha System.out.println(p1.className); //aaa System.out.println(p2.name); //null。特有数据。 System.out.println(p2.className); //aaa。说明static修饰的变量是共享的。 System.out.println(Person.className); //aaa。说明静态变量可以通过类名直接调用。 } } |
二、static的内存图 左边是栈,右边是堆,下方是方法区(方法区很广,其中右边一部分是静态区)。 步骤1:class文件进入到方法区,首先要加载自己的静态成员。 step1.1:Test.class进入到方法区,加载静态成员main到静态区(类名Test也一起过来)。 step1.2:Person.class进入到方法区,加载静态成员className到静态去(所属Person也加载过来),并赋默认值null。 步骤2:程序开始执行,运行main方法。JVM到静态区将main方法复制出来一份,压栈执行。 步骤3:执行main的第一句:System.out.println(Person.className);,JVM到静态区找属于Person类的静态属性className,输出 null。此时还没创建对象呢。说明在内存中,静态是优于非静态存在的。 步骤4:在堆中创建对象。 ![](https://i-blog.csdnimg.cn/blog_migrate/b0ef74f8faadbaf77b7b222987f4fd21.png) 三、static的注意事项 在静态中不能调用非静态。因为静态先存在,非静态才存在。静态是先人,非静态是后人。静态方法中既不能写this,也不能写super。 //Person.java
package cn.itcast.demo01; public class Person{ private String name; private static int age; public static void fun(){ //System.out.println(name); //错误。因为静态存在的时候,非静态还不存在呢。 System.out.println(age); //正确。因为都是静态的。生命周期相同。 } public void fun2(){ System.out.println(age); //正确。非静态的可以调用静态的。后人可以调用前人。 } } |
四、静态修饰什么时候使用?应用场景是什么? static是成员修饰符。可以修饰成员方法,也可以修饰成员变量。不能修饰局部变量。 成员变量什么时候加static:要具体分析,当定义事物的时候,要看多个事物有没有共性。如,每个人的学校名称。可以定义为 static。 成员方法什么时候加static:跟着变量走。如果方法调用的都是静态变量,那么就把这个方法定义为static。如果方法调用了非静态 的变量,那么只能定义为非静态方法了。 记住:用到了非静态成员变量,就只能非静态。没用到非静态成员变量,就用静态。能静态就静态。 //Person.java
package cn.itcast.demo01; public class Person{ private String name; private static int age; public static void fun(){ //应该定义成静态的方法。因为用到的成员变量都是static的。 System.out.println(age); } public void fun2(){ //必须定义成非静态的方法。因为用到了非静态的成员变量。 System.out.println(name); } public static int sum(int a, int b){ //应该定义为静态方法。因为根本没有用到任何成员变量。仅需要类名就能调用了。 //调用这个方法根本不用对象。 return a+b; } } |
五、多态中的静态调用 静态和对象没有什么关系。 1.静态成员变量:
//Fu.java package cn.itcast.demo01; public class Fu{ int a = 1; static int b = 1; } //Zi.java package cn.itcast.demo01; public class Zi{ int a = 2; static int b = 2; } //Zi.java package cn.itcast.demo01; public class Test{ public static void main(String[] args){ Fu f = new Zi(); System.out.println(f.a); //1。 System.out.println(f.b); //1。 } } | //Fu.java package cn.itcast.demo01; public class Fu{ } //Zi.java package cn.itcast.demo01; public class Zi{ int a = 2; static int b = 2; } //Zi.java package cn.itcast.demo01; public class Test{ public static void main(String[] args){ Fu f = new Zi(); System.out.println(f.a); System.out.println(f.b); } } //运行结果: 程序报错。 //编译看父类。父类没有,则编译失败。 |
//Fu.java package cn.itcast.demo01; public class Fu{ int a = 1; static int b = 1; } //Zi.java package cn.itcast.demo01; public class Zi{ } //Zi.java package cn.itcast.demo01; public class Test{ public static void main(String[] args){ Fu f = new Zi(); System.out.println(f.a); //1。 System.out.println(f.b); //1。 } } | |
2.静态成员函数
//Fu.java package cn.itcast.demo01; public class Fu{ public static void show(){ System.out.println("fu..."); } } //Zi.java package cn.itcast.demo01; public class Zi{ public static void show(){ System.out.println("zi..."); } } //Zi.java package cn.itcast.demo01; public class Test{ public static void main(String[] args){ Fu f = new Zi(); f.show(); //fu... } } //因为静态跟对象无关。静态属于类,不属于对象。f毕竟是父类的引用。 | //Fu.java package cn.itcast.demo01; public class Fu{ } //Zi.java package cn.itcast.demo01; public class Zi{ public static void show(){ System.out.println("zi..."); } } //Zi.java package cn.itcast.demo01; public class Test{ public static void main(String[] args){ Fu f = new Zi(); f.show(); } } //运行结果: 编译失败。 //编译看父类。 |
总结: 在多态的方法调用中: 编译:都是看父类,父类有则编译成功;父类没有则编译失败。 运行:静态方法:运行的是父类中的静态方法。 //因为静态跟对象无关。 非静态方法:运行的是子类的重写方法。 多态的成员变量: 编译运行全部看父类。 六、定义静态常量 public static final String COMPANY_NAME = "传智播客"; //java中,常量的名字要求全大写,两个词之间以下划线相连。 注意: 接口中的每个成员变量都默认使用public static final 修饰。 所有接口中的成员变量已经是静态常量,由于接口没有构造方法,所以必须显示赋值。可以直接用接口名访问。 |