先要澄清和区别一些概念,“静态类”和“所有方法皆为静态方法的类”。

严格说来,Java中的静态类,指的是“static class”这样修饰的类定义,语法上的要求,使得这样的类一定是内部类,换言之,“静态内部类”是对它的完整定义。静态内部类最大的好处在于可以隐藏自己(只让自己被所在外层的类用到),同时又可以访问到所在外层类的属性。和“非静态”的内部类相比,它可以放置一些静态的成员变量和方法定义,而非静态类不可以;而且,静态内部类不能访问外层类非静态的属性。

但是,通常我们所说的“静态类”,也是下文所述的“静态类”,是指所有的方法、属性都是静态的类,同时,我们在使用它们的时候,直接调用它们的静态方法、访问其中的静态属性,而不需要对其实例化。这类所谓的“静态类”往往具备这样两个特点,一个是使用final修饰,它们往往没有子类;其二是构造器都被私有化了,不允许被构造实例。

1、单例模式便于mock,可测性好。虽说静态方法也可以mock (比如需要使用一些特殊的注解),但是毕竟相对还是麻烦一些,也没有那么灵活。

2、有人说单例模式可以做到lazy load,但是静态类不行。这肯定是扯淡,静态类也完全可以做到第一次使用的时候再加载。不过,其中值得一提的是单例中的Double Check Lock,这里做一个简单介绍。看下面的代码:

  1. public Singleton {
  2. private static Singleton instance;
  3. private Number n = new Number();
  4. public Number get() {
  5. return this.n; //(1)
  6. }
  7. public static Singleton getInstance() {
  8. if(instance == null) {
  9. synchronized(Singleton.class) {
  10. if(instance == null)
  11. instance = new Singleton();
  12. } //(2)
  13. }
  14. return instance;
  15. }
  16. }

是很常见的一种写法,不过,由于编译器的优化,允许出现主存和线程工作内存数据不一致问题,这就是“DCL失效”的问题。上面的代码是其典型表现:

根据JMM规范,主存数据和工作内存的数据是允许存在不一致的。JDK1.2之后,分配空间、对象初始化等等操作才都放到工作内存中进行了。由于synchronized关键字的关系,执行到语句(2)的时候,走出同步块时,JVM会将主存和工作内存的instance引用的对象刷新到一致,即instance是“可见”的。但问题出在上面的(1),没有synchronized,也没有volatile、final,没有人来保证调用get方法时获得的n是正确的值,即这个n未必是“可见”的。如果n比instance晚同步到主存,就存在一个时间间隙,这个间隙内获取到的instance是一个不健康的instance,其中的this.n是取不到正确的Number对象的。

在JSR133中,对JMM做了一个修正,后引入或增强了synchronized、volatile和final关键字,通过它们的运用,上述问题能够得到解决。另外,还有一种解决的方法可以是使用静态的内部类:

private static class InnerInstance { 
   public static Instance instance = new Instance(); 
public static Instance getInstance() { 
   return InnerInstance.instance; 
}

3、单例可以被继承,这是一个很大的好处,这便于用户overwrite其中的某方法,当然,继承单例的场景较少见;而静态类一般不被继承。关于单例的继承细节,这里暂不讨论,有几种办法,有兴趣的同学可以自行阅读JDK的Calendar类。

4、单例可以实现自某接口,可以继承自某类。静态类也可以继承自某类,但是就没法使用父类里面的protect成员了。推广来说,这一点和上一点都可以看做是面向对象带来的好处:封装、继承和多态,静态类不能很好地具备其中的后两点。

5、单例可以比较方便地扩展为有限实例。根据需要,我可以通过工厂,生产出两个内部状态不同的单例对象——这在静态类中是难以做到的。Spring可以看做一系列大工厂,但其中的bean也只有singleton和prototype两种,生产不出static的新类型;当你的工具成为了对象,就能够保持良好的扩展性。

还有一个有趣的例子是JDK的Calendar.getInstance()方法,从方法看很像是获得一个单例,其实不是,每次都去创建了新的Calendar对象;同时,使用abstract修饰它自己,保证了无法使用new实例化,又开放了getInstance这样一个接口来获取默认实现,而获取的默认实现,又恰恰是Calendar的子类。这种形式可以看做是单例的一个变体。

6、有人说,单例在使用过程中申请的资源可以被及时释放并回收内存,但是静态类不行。这也是没有道理的,别忘了静态类也是可以存放状态的,在确定不再使用资源后,及时将资源的引用置为null就可以了。

7、如果希望在类加载的时候做复杂的操作,那么在静态类中,需要引入static块来初始化数据,如果期间抛出了异常,就可能发生一个“ClassDefNotFoundError”的诡异错误,这对问题定位是不利的。

转自:http://www.raychase.net/257

Java静态类的更多相关文章

  1. java静态类与非静态类区别

    java静态与非静态区别   这里的静态,指以static关键字修饰的,包括类,方法,块,字段. 非静态,指没有用static 修饰的. 静态有一些特点: 1.全局唯一,任何一次的修改都是全局性的影响 ...

  2. Java 静态类 static

    静态的方法是非虚方法(Java中的非虚方法有private,final,static,构造器,非虚方法无需根据具体的对象遍历方法区的方法表,决定调用关系) 也就是说,对于静态类型方法的调用,是其声明类 ...

  3. java 静态类与静态方法应用场景

    静态类:工具类 例如 Array.sort(arry) 静态方法:设置文件名

  4. java静态类、静态方法、静态代码块,静态变量及实例方法,实例变量初始化顺序及内存管理,机制

    1.当一个类被第一次使用时,它需要被类加载器加载,而加载过程涉及以下两点: (1)在加载一个类时,如果它的父类还未被加载,那么其父类必须先被加载: (2)当类加载到内存之后,按照在代码中的出现顺序执行 ...

  5. Java学习笔记(七):内部类、静态类和泛型

    内部类 在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类.广泛意义上的内部类一般来说包括这四种:成员内部类.局部内部类.匿名内部类和静态内部类.下面就先来了解一下这四种 ...

  6. Java关键字--static

    在Java中,将关键字static分为三部分进行讨论,分别为Java静态变量.Java静态方法.Java静态类 Java Static Variables Java instance variable ...

  7. java 小记

    1.获取web项目根目录的绝对路径 request.getContextPath()  获取项目名称,如    /BiYeSheJi getServletContext().getRealPath(& ...

  8. 实战系列之 Node.js 玩转 Java

    这些年以来,Node.js的兴起,JavaScript已经从当年的“世界最被误解的语言”变成了“世界最流行的语言”.且其发展之势,从语言本身的进化,库和包的增长,工具支持的完善,star项目和领域解决 ...

  9. Java 基础 内部类

    Java 基础 内部类 内部类(嵌套类) nested class 目的为外围类enclosing class提供服务. 四种: 静态成员类 static member class 非静态成员类 no ...

随机推荐

  1. xhEditor与Java结合使用

    xhEditor是一个轻量级的html编辑器,使用它可以非常方便的编辑图文内容,然而官方文档中只有php的演示,没有Java版的,最近两天参考网上各种各样的文档,琢磨了一下用法,现已可以正常运行,现在 ...

  2. Android开发之sharedpreferences 详解

    SharedPreferences简介:   做软件开发应该都知道,很多软件会有配置文件,里面存放这程序运行当中的各个属性值,由于其配置信息并不多,如果采用数据库来存放并不划算,因为数据库连接跟操作等 ...

  3. WPF学习之资源-Resources

    WPF学习之资源-Resources WPF通过资源来保存一些可以被重复利用的样式,对象定义以及一些传统的资源如二进制数据,图片等等,而在其支持上也更能体现出这些资源定义的优越性.比如通过Resour ...

  4. CentOS 6.7安装Tomcat 7

    1.下载Tomcat 7 wget http://apache.fayea.com/tomcat/tomcat-7/v7.0.67/bin/apache-tomcat-7.0.67.tar.gz 2. ...

  5. centos 6.3 编译安装 nginx +mysql + php

    这篇文章是对另一篇文章的整理,作为记录收藏 1,配置防火墙,开启80端口.3306端口 配置iptables,开启80端口.3306端口 vi /etc/sysconfig/iptables -A I ...

  6. Java的浮点数

    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/5160771. ...

  7. 《转载》CSS中的三种样式来源:创作人员、读者和用户代理

    CSS中的样式一共有三种来源:创作人员.读者和用户代理,来源的不同会影响到样式的层叠方式,很多第一次学习CSS的朋友,对这三种来源可能会存在一些困惑,下面我写一下自己的理解,若有错误的地方还请指正. ...

  8. 关于C++和C#类型比较的相关内容

    转载:http://www.csharpwin.com/csharpspace/6825r9922.shtml   C#类型比较 类别 类名 说明 Visual Basic 数据类型 C# 数据类型 ...

  9. (九)Struts2 防重复提交

    所有的学习我们必须先搭建好Struts2的环境(1.导入对应的jar包,2.web.xml,3.struts.xml) 第一节:重复提交示例演示 struts.xml <?xml version ...

  10. Photon引擎开发实战(1)——Photon 简介

    Photon简介 Photon是一套使用广泛的socket server引擎,服务端底层C++编写,客户端C#编写,跨多平台,收费,效率可观的一款引擎.实用上前有九城游戏(原魔兽世界代理),现在笔者发 ...