简介
本文用示例介绍Java中的static的用法。
使用位置包括:修饰成员属性,修饰成员方法,修饰代码块,修饰内部类,静态导包。
用法1:修饰成员属性
说明
给属性加了static关键字之后,对象就不再拥有该属性了,该属性会由类去管理,即多个对象只对应一个属性。
使用场景
一般用于定义一些常量。
示例:
package com.example.a; class Test{ public static String NAME = "Tony"; } public class Demo { public static void main(String[] args) { System.out.println(Test.NAME); } }
执行结果
Tony
用法2:修饰成员方法
说明
方法本来就是存放在类的定义当中的。static修饰成员方法的作用是可以使用”类名.方法名”的方式操作方法,避免了先要new出对象的繁琐和资源消耗。
示例:
package com.example.a; class Test{ public static void sayHello(String name) { System.out.println("Hello," + name); } } public class Demo { public static void main(String[] args) { Test.sayHello("Tony"); } }
结果
Hello,Tony
用法3:修饰代码块
static { }就是静态块,当类加载器载入类的时候,这一部分代码被执行,常用于对静态变量进行初始化工作。当其他代码用到这个类,类加载器才会将它载入。
代码只能执行一次,不能再调用。在静态块中,可以访问静态变量,调用静态方法。
如果去掉static,{ }中的代码则会在创建类对象的时候才执行,(相当于把这部分代码复制到各个构造函数中),这样可以实现块中的内容在多个构造函数中的复用。
package com.example.a; class Test{ static { System.out.println("This is static Block"); } { System.out.println("This is Block"); } public Test(){ System.out.println("This is Test()"); } public Test(String string){ System.out.println("This is Test(String string)"); } } public class Demo { public static void main(String[] args) { System.out.println("------------------------"); Test test1 = new Test(); System.out.println("------------------------"); Test test2 = new Test("Hello"); } }
执行结果
------------------------ This is static Block This is Block This is Test() ------------------------ This is Block This is Test(String string)
用法4:修饰内部类
static不能修饰普通类,但可以修饰内部类。原因如下:
static修饰的东西被我们成为类成员,它会随着类的加载而加载,比如:静态代码块,静态成员,静态方法(这里只是加载,并没有调用)等等。若把一个Class文件中的外部类设为static,那目的何在呢?难道让这个类随着应用的启动而加载吗?如果我在这次使用过程中根本没有使用过这个类,那么是不是就会浪费内存。这样来说设计不合理,总而言之,设计不合理的地方,Java是不会让它存在的。
为什么内部类可以使用static修饰呢,因为内部类算是类的成员了,如果我们没有使用静态来修饰,那么我们在创建内部类的时候就需要先有一个外部类的对象,如果我们一直在使用内部类,那么内存中就会一直存在外部类的引用,而我们有时候只需要使用内部类,不需要外部类,那么还是会浪费内存,甚至会造成内存溢出。使用static修饰内部类之后,内部类在创建对象时就不需要有外部类对象的引用了。
实例:
单例模式的静态内部类写法(Java设计模式系列–单例模式(6种写法) – 自学精灵)
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } } public class Demo{ public static void main(String[] args) { Singleton singleton = Singleton.getInstance(); System.out.println(singleton); } }
用法5:静态导包
导入时,使用static关键字,而且在引入类的最后还加上了“.*”,它的作用就是将PrintHelper类中的所有类方法直接导入。不同于非static导入,采用static导入包后,在不与当前类的方法名冲突的情况下,无需使用“类名.方法名”的方法去调用类方法了,直接可以采用”方法名”去调用类方法,就好像是该类自己的方法一样使用即可。
/* PrintHelper.java文件 */ package com.dotgua.study; public class PrintHelper { public static void print(Object o){ System.out.println(o); } }
import static com.dotgua.study.PrintHelper.*; public class Demo{ public static void main( String[] args ) { print("Hello World!"); } }
static加载顺序
首先思考,下边程序是否能编译通过?若可以编译通过,那么执行结果是什么?
package com.example.a; class User{ private static String name; public void setName(String name) { this.name = name; } public static String getName() { return User.name; } } public class Demo { public static void main(String[] args) { new User().setName("Tony"); System.out.println(User.getName()); } }
结果
Tony
从上述结果可见,实例对象可以访问访问类变量。
如果将setName改为static类型,则无法编译通过。static里边不能有this,这与类加载流程有关,见:JVM原理–类加载过程(有实例) – 自学精灵
请先
!