Java 私有构造函数的应用(转)

在Java中,构造函数的访问级别通常是public, 它提供了一个构造该类对象的接口。可是你知不知道,把构造函数的级别设为private, 有一些特别用处。

先来看一段代码:

//Shape.java
public class Shape {
    private Shape() { 
       /* set something here */
    }

    public static Shape makeShape(/* arglist */) {
       System.out.println("here is the shape you ordered");
       return (new Shape());
    }

    public static void main(String args[]) {
         Shape.makeShape();
    }
}

首先从语言角度分析,我们可以知道, 任何类的使用者都无法使用构造函数来生成一个图形, 因为构造函数是私有的,无法被类以外的函数使用。而只能通过调用makeShape来实现。

也许你会问,为什么不直接使用构造函数来生成图形,而需要使用一个看上去多余的makeShape方法呢?

这样做有以下几个好处:

1。你可以返回任何的Shape类型,包括Shape的子类。比如你可以把makeShape写成这样:

       public static Shape makeShape(/* arglist */) {
       System.out.println("here is the shape you ordered");
       if (retangle)
             return (new Retangle(/* arglist*/));
       if (Circle) 
            return (new Circle(/* arglist */));
    /* you can return as many shapes as you like */
    }
这里假设Retangle 和 Circle 都是shape的子类,并且和Shape类在同一个包內,Shape类可以访问子类的构造函数。这样shape就提供了一个图形工厂。 用户通过一个接口就可以生成不同的图形。事实上,这种用法被称为“工厂模式”。

2。可以实现一个类只有一个对象。请看下面的代码

       //Handler.java
public class Handler {
    
    private Handler handler = null;
    private Handler() { 
       /* set something here */
    }

    public static getHandler(/* arglist */) {
        if (!handler)
             handler = new Handler();
       return handler;
    }

    public static void main(String args[]) {
         Handler.getHandler();
    }
}

当handlerw为空时,那么重新构造一个handler,然后返回;如果已经构造过了,那么就直接返回已经存在的handler。这种用法被称为“Singleton pattern". 如果直接使用构造函数来构造对象,那么你就无法控制生成的数量。在实际应用中,往往会做一些改变。比如使用一个具有一定容量的池,当需要构造一个对象而池的容量仍未满时,就构造一个新的对象,并放入池中,并把对象的状态设为“占用”状态;当需要构造一个对象而池的容量已满,则从池中选一个“空闲”状态的对象返回,并把对象的状态设为“占用”。当对象使用完后再回收到池中并把状态设为“空闲“。

这种模式的一个典型应用场景是:

在一个具有很多用户的web站点里,需要一个对象来单独处理一个连接,而每一个连接的时间比较短。如果每次连接都创建一个对象然后又很快销毁,那么创建和销毁对象的系统开销是很大的。这种时候可以使用对象池,这样就免去了创建和销毁对象的开销。

3。可以方便的拋出异常。请看下列代码:

public class Test {
  public Test() {
                double x = 1.0/0.0;
  }
  public static void main(String args[]) {
        try {
                Test test = new Test();
        }catch (Exception e){
                System.out.println(e.toString());
        }
  }
}

编译,执行,你会发现这个异常不会被捕捉,没有任何输出;即使尝试在构造函数中捕捉异常也不行。看下列代码:

public class Test {
        public Test() {
                try {
                System.out.println("trying to throw an exception");
                double x = 1.0/0.0;
                } catch(Exception e) {
                        System.out.println("Exception captured");
                }finally {
                        System.out.println("inside finally");
                }
        }
        public static void main(String args[]) {
                Test test = new Test();
        }
}

编译,运行,结果为:
trying to throw an exception
inside finally

原因是JVM把构造函数产生的异常丢弃了。试想你正在使用一个第三方的类库提供的类,那个类提供一个共有的构造函数,它允许你通过参数构造一个类的对象,可是如果你的参数不合法,导致在构造函数中产生一个异常,那么你永远不知道具体发生了什么。当然如可以在每次构造对象时进行参数合法性检查,可是假设你要构造好多这样的对象??那将是一场灾难。这时可以通过把构造函数的访问级别设为私有,强迫类的使用者使用一个工厂函数来生成需要的对象,那么就可以在这个函数中统一的进行参数检查了。具体的代码就不写了,留给读者去实践吧!

从上面的分析我们可以知道私有构造函数的威力。需要注意的一点是,即使你的构造函数什么都不做,比如:
private Shape() {}
你仍然要显示的定义,因为如果你不定义,那么Java会自动为你生成一个空构造函数,而这个空构造函数是共有的。

出处:http://blog.csdn.net/my_dream_fly/article/details/3857887

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1.import static是Java 5增加的功能,就是将Import类中的静态方法,可以作为本类的静态方法来...
    XLsn0w阅读 5,014评论 0 2
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,958评论 18 399
  • 一:java概述:1,JDK:Java Development Kit,java的开发和运行环境,java的开发工...
    ZaneInTheSun阅读 7,602评论 0 11
  • 面向对象主要针对面向过程。 面向过程的基本单元是函数。 什么是对象:EVERYTHING IS OBJECT(万物...
    sinpi阅读 4,773评论 0 4
  • 想起母亲的饺子,不仅仅缘于微信圈里各类温馨提示:冬至记得吃饺子,五颜六色的饺子图,令人口馋,加上那亲亲的软语...
    阿惠妹妹阅读 3,089评论 3 7