Java实例化类详解

 更新时间:2016年03月21日 11:05:31   投稿:hebedich  
学习JAVA这门面向对象的语言,实质就是不断地创建类,并把类实例化为对象并调用方法。对于初学JAVA的人总搞清楚对象是如何实例化的,假如类之间存在继承关系,那就更糊涂了。下面我们通过两个例题来说明对象的实例化过程。

Java 中实例化类的动作,你是否还是一成不变 new 对应对象呢?

    经手的项目多了,代码编写量自然会增加,渐渐的会对设计模式产生感觉。

    怎样使书写出来的类实例化动作,高内聚,低耦合,又兼具一定的扩展能力呢?

    本文试图从几段鲜活的代码入手,给大家呈现不一样的 Java 实例化类。

    下面代码取自 com.google.zxing 源码实现:

public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, Map<EncodeHintType, ?> hints) throws WriterException {
    Object writer;
    switch(format.ordinal()) {
    case 1:
      writer = new AztecWriter();
      break;
    case 2:
      writer = new CodaBarWriter();
      break;
    case 3:
      writer = new Code39Writer();
      break;
    case 4:
    case 10:
    case 13:
    case 14:
    default:
      throw new IllegalArgumentException("No encoder available for format " + format);
    case 5:
      writer = new Code128Writer();
      break;
    case 6:
      writer = new DataMatrixWriter();
      break;
    case 7:
      writer = new EAN8Writer();
      break;
    case 8:
      writer = new EAN13Writer();
      break;
    case 9:
      writer = new ITFWriter();
      break;
    case 11:
      writer = new PDF417Writer();
      break;
    case 12:
      writer = new QRCodeWriter();
      break;
    case 15:
      writer = new UPCAWriter();
      break;
    case 16:
      writer = new UPCEWriter();
    }
    return ((Writer)writer).encode(contents, format, width, height, hints);
  }

其中的 BarcodeFormat 是这样的:

public enum BarcodeFormat {
  AZTEC,
  CODABAR,
  CODE_39,
  CODE_93,
  CODE_128,
  DATA_MATRIX,
  EAN_8,
  EAN_13,
  ITF,
  MAXICODE,
  PDF_417,
  QR_CODE,
  RSS_14,
  RSS_EXPANDED,
  UPC_A,
  UPC_E,
  UPC_EAN_EXTENSION;

  private BarcodeFormat() {
  }
}

源码提供的功能是将信息通过几种不同类型条形码 Wirter 输出为位矩阵,然后输出到图片上面,形成随处可见的各种类型的条形码。

BitMatrix bitMatrix = new MultiFormatWriter().encode(_text, BarcodeFormat.QR_CODE, qrcodeWidth, qrcodeHeight, hints);
MatrixToImageWriter.writeToFile(bitMatrix, qrcodeFormat, QrcodeFile);

源码作者在这里使用了JDK 1.5  中引入的新特性 enum 枚举类,编写了BarcodeFormat类,其中定义了不同类型的条形码的属性。

调用 MultiFormatWriter.encode()  根据入参 BarcodeFormat.xx 在枚举类中的序号,来实例化具体的类。

    switch(format.ordinal()) {
    case 1:
      writer = new AztecWriter();
      break;
    case 2:
      writer = new CodaBarWriter();
      break;
    case 3:
      writer = new Code39Writer();
      break;
    ...............

这些条形码 Writer 类,同时都实现了抽象接口 Writer 的 两个encode()方法。

public interface Writer {
  BitMatrix encode(String var1, BarcodeFormat var2, int var3, int var4) throws WriterException;

  BitMatrix encode(String var1, BarcodeFormat var2, int var3, int var4, Map<EncodeHintType, ?> var5) throws WriterException;
}

 具体的条形码 Wirter 类内部根据不同类型的条形码规则,进行不同的逻辑。

使用者不需要过多的关注内部的实现,需要产生什么样子的条形码,入参选用合适的条形码类型即可,笔者上述的例子里面实现的是二维码。

      在来看经典 MVC 框架 Webwork 动态实例化类的一段方法代码:

  private static Configuration getDefaultConfiguration () {
      if (defaultImpl == null) {
        defaultImpl = new DefaultConfiguration();
        try {
          String className = getString("webwork.configuration");
          if (!className.equals(defaultImpl.getClass().getName())) {
            try {
              defaultImpl = (Configuration) ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassLoader().loadClass(className));
            } catch (Exception e) {
              LOG.error("Could not instantiate configuration", e);
            }
          }
          return defaultImpl;
        } catch (IllegalArgumentException localIllegalArgumentException) {
        }
      }
    }

源码取自 webwork-core,可能很多看客老爷没有听闻 Webwork, 但是对 Struts 应该是如雷贯耳,Struts2 核心改写自 Webwork。

上述源码提供的功能为实例化用户自己定义的 配置文件读取类,该定义是在配置文件当中。

源码作者在这里使用 Thread.currentThread().getContextClassLoader().loadClass(className) 线程中类加载器,动态实例化自定义配置文件读取类,可谓是效率最高的一种做法。
类加载器的委托链:SystemClassloader -> ExtensionClassloader -> BootstrapClassloader
委派链左边的ClassLoader就可以很自然的使用右边的ClassLoader所加载的类,类加载的机制为判断自已是否加载该类,没有在询问上级。

而这三个类加载器分别对应着编译器去寻找类文件的优先级别和不同的路径:

  1. BootClassLoader  它是用C++编写的,从%jre%/lib目录中加载类,或者运行时用-Xbootclasspath指定目录来加载。是编译器最优先寻找class的地方
  2. ExtClassLoader  从%jre%/lib/ext目录加载类,或者运行时用-Djava.ext.dirs制定目录来加载。是编译器次优先寻找class的地方
  3. SystemClassloader 也就是我们常说的AppClassloader ,它对应当前路径,所以也是编译器默认找class的地方。

平时项目中使用的 Class.forname() 会从 BootstrapClassloader 开始询问,是最消耗资源的。

源码作者在这里采用线程类加载器,对应为 SystemClassloader ,效率无疑是最高的。

相关文章

  • 数组重排序(如何将所有奇数都放在所有偶数前面)的深入分析

    数组重排序(如何将所有奇数都放在所有偶数前面)的深入分析

    本篇文章是对数组重排序(如何将所有奇数都放在所有偶数前面)的方法进行了详细的分析介绍,需要的朋友参考下
    2013-06-06
  • Java方法调用解析静态分派动态分派执行过程

    Java方法调用解析静态分派动态分派执行过程

    这篇文章主要为大家介绍了Java方法调用解析静态分派动态分派执行过程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Java两个变量的互换(不借助第3个变量)具体实现方法

    Java两个变量的互换(不借助第3个变量)具体实现方法

    这篇文章主要介绍了Java两个变量的互换(不借助第3个变量)具体实现方法,需要的朋友可以参考下
    2014-02-02
  • java swing实现简单计算器界面

    java swing实现简单计算器界面

    这篇文章主要为大家详细介绍了java swing实现简单计算器界面,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • Java Kafka 消费积压监控的示例代码

    Java Kafka 消费积压监控的示例代码

    这篇文章主要介绍了Java Kafka 消费积压监控,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-07-07
  • Java 详解如何获取网络接口信息

    Java 详解如何获取网络接口信息

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实践中才能获得能力的提升,本篇文章手把手带你用Java获取网络接口的信息,大家可以在过程中查缺补漏,提升水平
    2021-11-11
  • Java循环结构之多重循环及continue break

    Java循环结构之多重循环及continue break

    这篇文章主要介绍了Java循环结构之多重循环及continue break,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
    2022-09-09
  • Linux系统下更换jdk版本详细步骤

    Linux系统下更换jdk版本详细步骤

    随着Java语言的不断更新,多个版本的JDK在现在的Linux环境中都存在,使得不同的开发人员可以按照自己的需求使用不同的JDK版本,这篇文章主要给大家介绍了关于Linux系统下更换jdk版本的详细步骤,需要的朋友可以参考下
    2023-12-12
  • Java使用jmeter进行压力测试

    Java使用jmeter进行压力测试

    本篇文章简单讲一下使用jmeter进行压力测试。其压测思想就是 通过创建指定数量的线程,同时请求指定接口,来模拟指定数量用户同时进行某个操作的场景,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • Kafka中使用Avro序列化和反序列化详解

    Kafka中使用Avro序列化和反序列化详解

    这篇文章主要介绍了Kafka中使用Avro序列化和反序列化详解,由于Kafka中的数据都是字节数组,在将消息发送到Kafka之前需要先将数据序列化为字节数组, 序列化器的作用就是用于序列化要发送的消息的,需要的朋友可以参考下
    2023-12-12

最新评论