CodeGym /Java 博客 /随机的 /关于 Java 静态修饰符你需要知道的 10 件事
John Squirrels
第 41 级
San Francisco

关于 Java 静态修饰符你需要知道的 10 件事

已在 随机的 群组中发布
在 Java 中,static 修饰符表示与类直接相关的东西:如果一个字段是静态的,那么它属于该类;如果一个方法是静态的,那么它就属于这个类。因此,您可以使用类的名称来调用静态方法或引用静态字段。例如,如果该count字段在Counter类中是静态的,则意味着您可以使用以下表达式引用该变量:Counter.count. 关于 Java 中的静态修饰符你需要知道的 10 件事 - 1当然,必须考虑访问修饰符。例如,private字段仅在声明它们的类中可用。并且protected字段可用于包内的所有类,以及包外的所有子类。假设该类Counter有一个静态increment()方法,其工作是递增count场地。要调用此方法,您可以使用Counter.increment(). 无需创建类的实例Counter来访问静态字段或方法。这是静态(类)变量和方法与非静态(实例)变量和方法之间的根本区别。一个重要的注意事项。不要忘记类的静态成员直接属于类,而不是类的任何实例。也就是说,静态count变量的值对于所有对象都是相同的Counter。在本文中,我们将了解在 Java 中使用静态修饰符的基本方面,以及一些有助于您理解关键编程概念的功能。

每个程序员都应该了解 Java 中的静态修饰符。

在本节中,我们将了解使用静态方法、字段和类的主要方面。让我们从变量开始。
  1. 您不能在静态上下文中访问类的非静态成员,例如静态方法或块。编译下面的代码将导致错误:

    
    public class Counter {
    private int count;
    public static void main(String args []) {
       System.out.println(count); //  Compile time error
    }
    }
    

    这是 Java 程序员尤其是新手最常犯的错误之一。由于main方法是静态的而count变量不是,在方法println内部使用方法main会产生“编译时错误”。

  2. 与局部变量不同,静态字段和方法不在thread safeJava 中。实际上,这是多线程编程中安全问题最常见的原因之一。考虑到类的每个实例都引用静态变量的相同副本,这样的变量需要被类保护或“锁定”。因此,在使用静态变量时,一定要正确使用,synchronized以免出现race conditions.

  3. 静态方法有一个实用的优点,那就是不需要在每次调用它们时都创建一个新对象。可以使用声明它的类的名称来调用静态方法。这就是为什么这些方法非常适合factory方法和utility方法。该类java.lang.Math是一个很好的例子:它的几乎所有方法都是静态的。Java 的实用程序类被标记final为同样的原因。

  4. 另一个要点是你不能覆盖 ( @Override) 静态方法。如果您在 a 中声明这样一个方法subclass,即具有相同名称和签名的方法,您只是“隐藏”了该方法superclass而不是覆盖它。这种现象被称为method hiding。这意味着如果在父类和子类中都声明了静态方法,那么在编译时调用的方法将始终基于变量类型。与方法覆盖不同,此类方法不会在程序运行时执行。让我们考虑一个例子:

    
    class Vehicle {
         public static void kmToMiles(int km) {
              System.out.println("Inside the parent class / static method");
         } 
    }
    
    class Car extends Vehicle {
         public static void kmToMiles(int km) {
              System.out.println("Inside the child class / static method");
         } 
    }
    
    public class Demo {   
       public static void main(String args []) {
          Vehicle v = new Car();
           v.kmToMiles(10);
      }
    }
    

    控制台输出:

    父类/静态方法内部

    该代码清楚地表明,尽管对象是 a ,但还是调用了类Car中的静态方法,因为该方法是在编译时调用的。Vehicle请注意,没有编译错误!

  5. 此外,除了顶级类之外,您还可以将类声明为静态的。这样的类被称为nested static classes. 它们对于提供更好的凝聚力很有用。嵌套静态类的一个显着例子是HashMap.Entry,它里面是一个数据结构HashMap。值得注意的是,与内部类一样,静态嵌套类是在单独的 .class 文件中声明的。因此,如果您在主类中声明了五个嵌套类,您将拥有 6 个扩展名为 .class 的文件。另一个例子是我们自己的声明Comparator,比如类AgeComparator中的一个年龄比较器()Employee

  6. static 修饰符也可以在静态块中指定,更好地称为“静态初始化块”,它在加载类时执行。如果您不声明这样的块,Java 会将所有静态字段收集到一个列表中,并在加载类时初始化它们。静态块不能抛出已检查的异常,但它可以抛出未经检查的异常。在这种情况下,ExceptionInInitializerError将发生。实际上,在静态字段初始化期间发生的任何异常都会被 Java 包装在这个错误中。这也是最常见的原因NoClassDefFoundError,因为类在被引用时不会在内存中。

  7. 知道静态方法在编译时链接是很有用的,这与虚拟或非静态方法的链接不同,后者在运行时在真实对象上调用时链接。因此,静态方法不能在 Java 中被覆盖,因为多态性在运行时不适用于它们。这是声明静态方法时要考虑的一个重要限制。仅当没有能力或不需要覆盖子类中的方法时,这样做才有意义。工厂方法和实用方法是正确使用静态修饰符的好例子。Joshua Bloch在他的《Effective Java》一书中指出了静态工厂方法相对于构造函数的几个优势,这是每个 Java 程序员必读的一本书。

  8. 初始化是静态块的一个重要方面。静态字段或变量在类加载到内存后进行初始化。初始化的顺序是从上到下,与它们在Java类的源文件中声明的顺序相同。由于静态字段以线程安全的方式初始化,因此该过程也用于实现该Singleton模式。如果您出于某种原因不使用Enumas a Singleton,那么您有一个很好的选择。但在这种情况下,您必须考虑到这不是“惰性”初始化。这意味着静态字段甚至在有人“请求”它之前就已经被初始化了。如果一个对象占用大量资源或很少使用,那么在静态块中初始化它对您不利。

  9. 在序列化期间,静态字段(如transient变量)不会被序列化。事实上,如果您将任何数据保存在静态字段中,它在反序列化后将包含其初始(默认)值。例如,如果静态字段是int,则其值在反序列化后将为零。如果其类型为float,则该值为 0.0。如果字段是Object,则值将为null。老实说,这是 Java 职位面试中关于序列化的最常见问题之一。不要将基本对象数据存储在静态字段中!

  10. 最后说一下静态导入。此修饰符与标准语句有很多共同之处import,但不同之处在于它允许您导入一个或所有静态类成员。一旦导入了静态方法,就可以像在同一个类中声明一样访问它们。同样,通过引入静态字段,我们可以在不指定类名的情况下访问它们。这个特性出现在 Java 1.5 中,如果使用得当,可以提高代码的可读性。这种构造最常出现在 JUnit 测试中,因为几乎所有测试开发人员都对断言方法(例如assertEquals()及其重载变体)使用静态导入。

  11. 目前为止就这样了。每个 Java 程序员都需要了解上面提到的静态修饰符的所有方面。本文回顾了有关静态变量、字段、方法、初始化块和导入的基本信息。它还涉及一些重要的属性,这些属性是编写和理解 Java 程序所必需的。我希望每个开发人员都能完善他们对静态成员的熟练使用,因为这对于认真的软件开发非常重要。”

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION