面试官上来就问“ 那个Java里面的Static关键字一般是怎么用”一句话Static是“类级别的”不是“实例级别的”。被Static修饰的东西属于整个类所有实例共用一份不用new对象就能直接用而没被Static修饰的东西属于单个实例每个实例有自己的一份必须new对象才能用。对比项静态Static实例非Static归属属于整个类属于单个实例内存位置方法区JDK8 之后叫元空间堆内存访问方式类名.变量/方法或实例.变量/方法不推荐必须通过实例.变量/方法访问共享性所有实例共用一份每个实例有自己的一份初始化时机类加载时初始化创建实例时初始化访问限制只能直接访问静态成员可以访问静态成员和实例成员1. 静态变量静态变量就像是整个类共享的“公共储物柜”所有实例共用这一个柜子你放进去的东西别人也能拿到而实例变量是每个实例自己的“私人储物柜”互不干扰。举个例子用静态变量做全局计数器/** * 网站访问计数器 */publicclassWebsiteCounter{// 静态变量所有实例共用统计总访问次数publicstaticinttotalVisitCount0;// 实例变量每个实例自己的统计单个用户的访问次数publicintuserVisitCount0;/** * 访问方法 */publicvoidvisit(){// 修改静态变量总访问次数1totalVisitCount;// 修改实例变量单个用户访问次数1userVisitCount;}publicstaticvoidmain(String[]args){// 用户1访问WebsiteCounteruser1newWebsiteCounter();user1.visit();user1.visit();System.out.println(用户1访问次数user1.userVisitCount);// 输出2System.out.println(总访问次数WebsiteCounter.totalVisitCount);// 输出2// 用户2访问WebsiteCounteruser2newWebsiteCounter();user2.visit();System.out.println(用户2访问次数user2.userVisitCount);// 输出1System.out.println(总访问次数WebsiteCounter.totalVisitCount);// 输出3}}2. 静态方法静态方法是属于类的“公共工具”不用new对象直接通过【类名.方法名】就能调用而实例方法是属于单个实例的必须new对象之后才能调用。举个例子用静态方法做工具类/** * 字符串工具类 */publicclassStringUtils{// 私有构造方法从根源上禁止外部代码 new StringUtils()// 工具类全是静态方法完全不需要实例化这样做能强制大家用[类名.方法名]的正确用法privateStringUtils(){}/** * 静态方法判断字符串是否为空 */publicstaticbooleanisEmpty(Stringstr){returnstrnull||str.trim().isEmpty();}/** * 静态方法字符串反转 */publicstaticStringreverse(Stringstr){if(isEmpty(str)){returnstr;}returnnewStringBuilder(str).reverse().toString();}publicstaticvoidmain(String[]args){// 直接通过类名调用静态方法不用new对象System.out.println(StringUtils.isEmpty());// 输出trueSystem.out.println(StringUtils.reverse(hello));// 输出olleh}}3. 静态代码块静态代码块是类加载的时候执行一次且只执行一次的代码块用来初始化静态变量或者做一些类级别的准备工作比如加载配置文件、初始化数据库连接池。举个例子用静态代码块初始化静态配置/** * 配置类 */publicclassConfig{// 静态变量数据库连接地址publicstaticStringdbUrl;publicstaticStringdbUsername;publicstaticStringdbPassword;// 静态代码块类加载时执行一次初始化静态变量static{System.out.println(静态代码块执行开始初始化配置...);// 模拟从配置文件读取配置dbUrljdbc:mysql://localhost:3306/test;dbUsernameroot;dbPassword123456;}// 实例代码块创建实例时执行每次new都执行{System.out.println(实例代码块执行...);}// 构造方法创建实例时执行每次new都执行publicConfig(){System.out.println(构造方法执行...);}publicstaticvoidmain(String[]args){// 第一次访问Config类触发类加载静态代码块执行System.out.println(数据库地址Config.dbUrl);System.out.println(---);// new第一个实例实例代码块和构造方法执行newConfig();System.out.println(---);// new第二个实例实例代码块和构造方法执行但静态代码块不再执行newConfig();}}小贴士静态代码块只在类第一次被加载时执行一次之后不管new多少个实例都不会再执行。4. 静态内部类静态内部类是属于外部类的“独立房间”不用依赖外部类的实例就能直接创建而非静态内部类是属于外部类实例的“附属房间”必须先有外部类实例才能创建。静态内部类的作用是利用 Java 的类加载时机实现了懒加载用的时候才创建 线程安全JVM 保证 不用加锁性能高的完美单例。举个例子用静态内部类实现线程安全的单例模式/** * 单例模式静态内部类实现 */publicclassSingleton{// 私有构造方法从根源上禁止外部代码直接 new Singleton()privateSingleton(){}// 静态内部类只有第一次被访问时才会加载实现懒加载用的时候才创建实例不占内存// 因为是在 Singleton 类内部所以可以访问上面的 private 构造方法privatestaticclassSingletonHolder{// 静态变量JVM 类加载过程是天然线程安全的这里初始化唯一的单例实例不用加锁性能高privatestaticfinalSingletonINSTANCEnewSingleton();}// 全局唯一的访问点外部代码只能通过这里获取单例实例publicstaticSingletongetInstance(){returnSingletonHolder.INSTANCE;}publicstaticvoidmain(String[]args){// 获取单例实例Singletoninstance1Singleton.getInstance();Singletoninstance2Singleton.getInstance();// 两个实例是同一个完美实现单例System.out.println(instance1instance2);// 输出true}}小贴士静态变量存放在JVM的方法区元空间不是堆内存。静态变量可以通过【类名.变量名】直接访问也可以通过【实例.变量名】访问不过不推荐因为容易混淆。因为所有线程共用同一个静态变量多线程同时修改会出现并发问题需要加锁保证线程安全。因为实例变量和方法依赖具体的实例静态方法调用时可能还没new对象所以静态方法只能直接访问静态变量和静态方法不能直接访问实例变量和实例方法。this 代表当前实例静态方法属于类调用时可能还没创建实例this 根本不存在所以静态方法不能用 this。静态内部类只能直接访问外部类的静态变量和静态方法不能直接访问实例变量和实例方法。