• static关键字的用法


    静态变量和静态方法

    static关键字的基本用法:

    1.修饰变量:被static修饰的变量属于类变量,可以用类名.变量名来引用,而不用直接new一个对象来引用。

    2.修饰方法:被static修饰的方法属于类方法,可以用类名.方法名来引用,而不用直接new一个对象来引用。

    被static修饰的变量和方法是属于类所有的,是类的静态资源,而静态资源是类初始化的时候被加载的,为类的所有实例所共享,非静态资源是new一个对象的时候被加载的。类的初始化早于类的new,比如Class.forName(“xxx”)方法,就是初始化了一个类,但是并没有new它,只是加载这个类的静态资源罢了。所以对于静态资源来说,它不知道有哪些非静态资源,对于非静态资源来说,由于它是在类初始化加载静态资源之后new对象的时候加载的,所以它知道有哪些静态资源。因此,可以回答以下问题:

    静态方法能不能引用非静态资源?非静态方法里面能不能引用静态资源?

    1、静态方法能不能引用非静态资源(包括变量和方法)?不能,非静态资源是new对象的时候产生的,对于类初始化后就存在的静态资源来说,根本不认识它。

    2、非静态方法里面能不能引用静态资源(包括变量和方法)?可以,非静态方法就是是new之后才产生的,那么在它之前被加载的类的静态资源它都认识。

     1 public class TestController {
     2 
     3     private int num;
     4     private static int num2;
     5 
     6     public static void main(String[] args) {
     7         num = 1;//报错 Non-static field 'num' cannot be referenced from a static context
     8         num2 = 2;
     9     }
    10 
    11     public void noneStaticMethod(){
    12         num = 1;
    13         num2 = 2;
    14     }
    15 
    16 }

    静态代码块

    静态代码块也是static的重要应用之一,和静态变量、静态方法一样,静态代码块里面的代码只执行一次,且只在初始化类的时候执行

    1.举例说明为什么使用静态代码块?

    以下程序判断一个人的出生日期是否在婴儿潮之内

     1 public class Person {
     2     private Date birthDate;
     3 
     4     boolean isBabyBoom() throws ParseException {
     5         Date startBabyBoomDate = DateUtil.parse("1946-01-01");
     6         Date endBabyBoomDate = DateUtil.parse("1964-12-31");
     7         return birthDate.compareTo(startBabyBoomDate) >= 0 && birthDate.compareTo(endBabyBoomDate) <= 0;
     8     }
     9 
    10     public static void main(String[] args) throws ParseException {
    11         Person person = new Person();
    12         person.birthDate = DateUtil.parse("1960-01-10");
    13         boolean babyBoom = person.isBabyBoom();
    14         System.out.println(babyBoom);
    15     }
    16     
    17 }

    结果:

    true

    但是每次调用isBabyBoom()这个方法的时候,都会new出两个对象 startBabyBoomDate ,和 endBabyBoomDate ,造成内存的浪费。而将这两个对象放入静态代码块中的话,只会在类加载的时候执行一次,为所有的实例共享。

     1 public class Person {
     2     private Date birthDate;
     3     private static Date startBabyBoomDate,endBabyBoomDate;
     4 
     5     static{
     6         try {
     7             startBabyBoomDate = DateUtil.parse("1946-01-01");
     8             endBabyBoomDate = DateUtil.parse("1964-12-31");
     9         } catch (ParseException e) {
    10             e.printStackTrace();
    11         }
    12     }
    13 
    14     boolean isBabyBoom() throws ParseException {
    15         return birthDate.compareTo(startBabyBoomDate) >= 0 && birthDate.compareTo(endBabyBoomDate) <= 0;
    16     }
    17 
    18     public static void main(String[] args) throws ParseException {
    19         Person person = new Person();
    20         person.birthDate = DateUtil.parse("1960-01-10");
    21         boolean babyBoom = person.isBabyBoom();
    22         System.out.println(babyBoom);
    23         person.birthDate = DateUtil.parse("1989-01-10");
    24         boolean babyBoom1 = person.isBabyBoom();
    25         System.out.println(babyBoom1);
    26     }
    27 
    28 }

    结果:

    true
    false

    因此,一些操作只需要在初始化的时候执行一次的话,就可以放在静态代码块中。

    关于static代码块的执行顺序:

    1.静态资源的加载顺序是严格按照静态资源的定义顺序来加载的。

    2.有继承关系下,静态代码块是严格按照父类静态代码块->子类静态代码块的顺序加载的,且只加载一次。

    举例:

    //父类
    public class Person {
        static{
            System.out.println("父类Person 静态代码块1");
        }
        static{
            System.out.println("父类Person 静态代码块2");
        }
        public Person(){
            System.out.println("父类Person 构造器");
        }
    }
    //子类
    public class Student extends Person{
        static{
            System.out.println("子类Student 静态代码块");
        }
    
        public Student(){
            System.out.println("子类Student 构造器");
        }
    }
    //测试
    public class Test {
        public static void main(String[] args){
            new Student();
            new Student();
        }
    }

    结果:

    父类Person 静态代码块1
    父类Person 静态代码块2
    子类Student 静态代码块
    父类Person 构造器
    子类Student 构造器
    父类Person 构造器
    子类Student 构造器

    由此可见,无论创建多少对象,静态代码块只执行一次,且按照定义的顺序执行。

    static修饰类

    这个用得相对比前面的用法少多了,static一般情况下来说是不可以修饰类的,如果static要修饰一个类,说明这个类是一个静态内部类(注意static只能修饰一个内部类),也就是匿名内部类。像线程池ThreadPoolExecutor中的四种拒绝机制CallerRunsPolicy、AbortPolicy、DiscardPolicy、DiscardOldestPolicy就是静态内部类。静态内部类相关内容会在写内部类的时候专门讲到。

    静态导包

    import static是JDK1.5之后的新特性,这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名.资源名,可以直接使用资源名。注意一下,import static必须这么写,而不能写成static import。

    举例:

    1 package com.dajia.test;
    2 
    3 import static java.lang.Math.*;
    4 
    5 public class Test {
    6     public static void main(String[] args){
    7         System.out.println(round(3.85));
    8     }
    9 }

    但是这样降低了代码的可读性,如非要求,个人不会使用这种方式。

    参考资料:

    https://www.cnblogs.com/xrq730/p/4820992.html

    https://www.cnblogs.com/dolphin0520/p/3799052.html

  • 相关阅读:
    iOS开发多线程篇—创建线程
    【C语言】23-typedef
    李洪强经典面试题10
    李洪强经典面试题9
    李洪强经典面试题8
    李洪强经典面试题7
    多态性
    Oracle exp使用正則表達式导出部分表
    Android NDK开发初步
    HDU1864 最大报销额 01背包
  • 原文地址:https://www.cnblogs.com/zfyang2429/p/10309972.html
Copyright © 2020-2023  润新知