A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 焚雨成灰 中级黑马   /  2014-3-17 10:23  /  1476 人查看  /  1 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

什么是static

在Java中static是类属性,如果一个字段声明为static的,这意味着它属于类字段,同样,static方法属于类方法,并且static方法和字段都可以通过类名访问。例如,假如在Counter类中count字段是static的,你可以通过Counter.count访问,当然受限访问修饰符例如private字段仅可以在声明在字段的类中访问,protected字段可以被同一个包中所有的类和其他包中的子类所访问。同样,如果在Counter类中你有一个static方法increment(),你可以通过Counter.increment()访问。不需要创建Counter类的对象来访问static方法和字段,这是static和非static成员的主要的区别。
另外对于static成员要着重注意的地方,例如,static变量和static方法属于类而不是对象,例如,Counter类的所有对象中static变量的值是相同的。此文中我们会学到Java中的static关键字,什么是static变量和static方法,以及一些重要的static特性,这不仅帮助你明白Java中的重要编程概念而且帮你解决一些2到4年Java经验的面试问题。

每个Java程序员都应该知道static的特性

这部分我们会学到Java中static关键字的重要特性,包括对类、方法和变量的用法。每个Java开发者在进行开发前应该知道的static特性。
1)不要在static上下文中(如static代码块和static方法)访问非static成员。如下代码会报编译错误:

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

这是Java程序员尤其是初学者犯得最普遍的错误。因为Java中的main方法是static的,并且count变量是非static的,main方法的print语法会抛出编译错误。

2)不像局部变量,Java中的static变量和方法是非线程安全的。它们实际上是Java应用中引起各种各样线程问题的一个普遍的原因。因为每个类的对象有对static变量的相同拷贝,需要通过类的锁来管理。这就是为什么如果您使用的是静态变量,那么要确保正确同步的访问,以避免线程安全性问题,包括竞争条件。

3)static方法在用法上有优势,无需创建对象来访问,通过类来调用static方法。这就是为什么他们是最适合作为创建工厂方法和实用方法的实例。java.lang.Math类是很好的例子,几乎所有的方法都是static的,Java的工具类也会同时声明为final的。

4)static方法其他重要的特性是,你不能重载Java中的static方法。如果你在子类中声明相同的方法,例如,具有相同方法名和方法签名的static方法,会隐藏父类的方法,并不是重载它。这就是Java中所谓的方法隐藏。这意味着,如果你调用一个static方法,此方法在父类和子类中都有声明,方法总是使用引用变量的类型在编译时解析。不像方法重载,它们不会在运行时解析。例如:
class Vehicle{
  public static void kmToMiles(int km){
    System.out.println("Inside parent class' staticmethod");
  }
}
class Car extends Vehicle{
  public static void kmToMiles(int km){
    System.out.println("Inside Child class' staticmethod");
  }
}
public class Demo{
public static void main(String args[]){
    Vehicle v = new Car(); v.kmToMiles(10);
  }
}
Output:
Inside parent class' static method

正如你看到的,不是Car的而是Vehicle的static方法所引入,因为方法是在编译时解析的,且无编译时错误。

5)你也可以将Java类声明为static的,除了顶级类。那些类被称作嵌套静态类。嵌套静态类在提供高内聚上是特别有用的。一个嵌套静态类的例子是代表数据结构的HashMap.Entry,用来存放HashMap条目。像任何内部类的方式,静态嵌套类也产生一个单独的类文件。这意味着,如果你在顶级类中定义5个嵌套类,你会得到6个class文件。一个顶级类和5个嵌套静态类。使用嵌套静态类的有用案例是定义自定义的Comparator,例如在Employee类中的AgeComparator。

6)static关键字也可以用来声明在类加载时执行的静态代码块。这个称为Java的静态初始化块。如果你没有声明一个静态初始化块,那么Java会将所有static字段组合成一个代码块,在类加载时执行。虽然静态代码块不能抛检查异常,但是它们会一直抛没有检查的异常,这会导致ExceptionInitializerError。实际上当实例化或初始化静态字段的时候会抛出运行时异常。这是导致NoClassDefFoundError的普遍错误,因为当客户端需要的时候这个类没有在内存中。

7)了解static方法还需要知道static方法在编译时用静态绑定所绑定的。这和根据真实对象在运行时被绑定虚拟或非静态方法的绑定不同。这意味着静态方法不可以在Java作为运行时呈多态性时被重载。这是重要的限制,在声明static方法时你应该考虑到。你应该仅声明方法为static的,如果不可能或不需要重新为子类定义它的行为。工厂方法和工具类方法最好是static的。伟大的Joshua Bloch已经在Effective Java强调了很多益处,这本书是每个Java程序员应该读的。

8)static字段重要属性之一是initialization。静态字段在类加载到内存时被初始化。它们通过在Java文件中所声明的顺序从上到下被初始化。因为静态字段在初始化时是线程安全的,所以这个属性也会用来实现Java的Singleton模式且未使用Enum作为Singleton。需要考虑的是非lazy初始化,这意味着static字段在未调用时就已经被初始化了。如果它是宝贵的对象,还是很少使用,那么它们初始化静态方式不会产生良好的效果。

9)在Serialization中,像transient变量,static变量不会被序列化。意味着,如果你将一些数据存储为static字段,那么反序列化后,新的对象会包含它的默认值,例如,如果static字段是int,那么它会包含0,如果float会包含0.0,如果是对象会包含null。事实上这是面试中经常问的序列化相关的问题之一。确保不要将对象的关键状态数据存为static字段。

10)关于static关键字另外的特性是staticimport。这和标准的Java import语法类似,但是它允许import类中一个或所有的static成员。通过导入静态方法,你可以像在这个类中定义了它们一样来调用它们,同样地,通过静态导入字段,我们可以无需指定类名来访问它们。这个特性是Java 1.5 引入的,改进了Java应用的可读性。你经常看到的静态导入是JUnit测试案例,因为几乎所有的测试人员会静态导入那些assert方法,如assertEquals(),以及它们的重载方法。


1 个回复

倒序浏览
恩 谢谢正在看这里!!!
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马