From C# to Java (2) - 类的设计 (1)

  上一篇文章 From C# to Java (1) - 类型、引用与相等关系 对 Java 与 C# 在基本概念上的一些区别进行了简单的叙述,在这里简单做一回顾。第一,Java 的数据类型分为基础数据类型和类类型,类类型均为引用类型;第二,Java 的“==”运算符严格执行引用相等;第三,Java 不支持运算符重载。其中的很多重要特性在本文中也会提到,而且对类设计有重要的意义。

  本文试图通过一个实际的 Java 类(Android Open Source Project 中的 BitmapFactory 类)作为例子,对 Java 的类设计特点加以介绍。有一个好消息是,事实上 Java 的类设计特性比 C# 简单一些,对开发人员而言,从 C# 转向 Java 难度并不大,主要区别于写法。

1 代码一览

  下面给出的就是 BitmapFactoy 类的代码,为了体现类设计的主体部分,部分具体实现被注释掉了,部分成员说明也被删减。因此,这段代码不能直接用于实际工程。请读者注意。BitmapFactoy 类是 Android 中用来进行外部图片资源解码的工厂类,通过这段代码,我们也可以对工厂类等概念的具体实现产生大致的印象。

  1 /*
  2  * Copyright (C) 2007 The Android Open Source Project
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16
 17 package android.graphics;
 18
 19 import android.content.res.AssetManager;
 20 import android.content.res.Resources;
 21 import android.os.Trace;
 22 import android.util.DisplayMetrics;
 23 import android.util.Log;
 24 import android.util.TypedValue;
 25
 26 import java.io.FileDescriptor;
 27 import java.io.FileInputStream;
 28 import java.io.IOException;
 29 import java.io.InputStream;
 30
 31 /**
 32  * Creates Bitmap objects from various sources, including files, streams,
 33  * and byte-arrays.
 34  */
 35 public class BitmapFactory {
 36     private static final int DECODE_BUFFER_SIZE = 16 * 1024;
 37
 38     public static class Options {
 39
 40     public Options() {
 41             inDither = false;
 42             inScaled = true;
 43             inPremultiplied = true;
 44         }
 45
 46         public Bitmap inBitmap;
 47
 48         @SuppressWarnings({"UnusedDeclaration"}) // used in native code
 49         public boolean inMutable;
 50
 51         /*...*/
 52
 53         public boolean inPreferQualityOverSpeed;
 54
 55         public int outWidth;
 56
 57         public int outHeight;
 58
 59         public String outMimeType;
 60
 61         public byte[] inTempStorage;
 62
 63         private native void requestCancel();
 64
 65         public void requestCancelDecode() {
 66             requestCancel();
 67         }
 68     }
 69
 70     public static Bitmap decodeFile(String pathName, Options opts) {
 71         Bitmap bm = null;
 72         InputStream stream = null;
 73         try {
 74             stream = new FileInputStream(pathName);
 75             bm = decodeStream(stream, null, opts);
 76         } catch (Exception e) {
 77             /*  do nothing.
 78                 If the exception happened on open, bm will be null.
 79             */
 80             Log.e("BitmapFactory", "Unable to decode stream: " + e);
 81         } finally {
 82             if (stream != null) {
 83                 try {
 84                     stream.close();
 85                 } catch (IOException e) {
 86                     // do nothing here
 87                 }
 88             }
 89         }
 90         return bm;
 91     }
 92
 93     public static Bitmap decodeFile(String pathName) {
 94         return decodeFile(pathName, null);
 95     }
 96
 97     public static Bitmap decodeResourceStream(Resources res, TypedValue value,
 98             InputStream is, Rect pad, Options opts) {
 99
100         if (opts == null) {
101             opts = new Options();
102         }
103
104         if (opts.inDensity == 0 && value != null) {
105             final int density = value.density;
106             if (density == TypedValue.DENSITY_DEFAULT) {
107                 opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
108             } else if (density != TypedValue.DENSITY_NONE) {
109                 opts.inDensity = density;
110             }
111         }
112
113         if (opts.inTargetDensity == 0 && res != null) {
114             opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
115         }
116
117         return decodeStream(is, pad, opts);
118     }
119
120     public static Bitmap decodeResource(Resources res, int id, Options opts) {
121         /*...*/
122     }
123
124     public static Bitmap decodeResource(Resources res, int id) {
125         return decodeResource(res, id, null);
126     }
127
128     public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
129         /*...*/
130
131     }
132
133     public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
134         return decodeByteArray(data, offset, length, null);
135     }
136
137     private static void setDensityFromOptions(Bitmap outputBitmap, Options opts) {
138         /*...*/
139     }
140
141     public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
142         /*...*/
143     }
144
145     private static Bitmap decodeStreamInternal(InputStream is, Rect outPadding, Options opts) {
146         // ASSERT(is != null);
147         byte [] tempStorage = null;
148         if (opts != null) tempStorage = opts.inTempStorage;
149         if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
150         return nativeDecodeStream(is, tempStorage, outPadding, opts);
151     }
152
153     public static Bitmap decodeStream(InputStream is) {
154         return decodeStream(is, null, null);
155     }
156
157     public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
158         /*...*/
159
160     }
161
162     public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
163         return decodeFileDescriptor(fd, null, null);
164     }
165
166     private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
167             Rect padding, Options opts);
168     private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
169             Rect padding, Options opts);
170     private static native Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts);
171     private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
172             int length, Options opts);
173     private static native boolean nativeIsSeekable(FileDescriptor fd);
174 }

2 package 与 import

  package 用于说明该类位于哪个包(Package)下。类比 C# 的 Namespace 概念。

  import 用于引用其他类。类比 C# 用于引用其他类的 using 概念。

  import 也可以引入一个 Package 下的所有类,例如:

import android.util.*;

可以引入该包下的所有类,例如 Log 类、XML 与 JSON 相关类等等。

  在 Eclipse 环境下,快捷键 Ctrl + Alt + O 可以对所有 import 进行整理和排序;查看引用的快捷键为 F3。同时,在 Preferences 对话框(在 Window 菜单下)的 Java / Editor / Save Actions 中,还可以制定 IDE 在保存类时自动进行 import 的整理。

3 工厂类的声明,final 关键字

  Java 默认不能指定一个 package 中的类为静态(static),且只支持 public、protected 和 final 三个关键字。

  其中 final 关键字可类比 C# 中的 sealed 关键字(需要注意这种说法对于非 class 来说是不成立的。参考 http://stackoverflow.com/questions/1327544)。

  对 BitmapFactory 类的代码进一步简化:

 1 public class BitmapFactory {
 2     private static final int DECODE_BUFFER_SIZE = 16 * 1024;
 3
 4     public static class Options {
 5     }
 6
 7     public static Bitmap decodeFile(String pathName, Options opts);
 8
 9     public static Bitmap decodeFile(String pathName);
10
11     private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
12             Rect padding, Options opts);
13
14     private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
15             Rect padding, Options opts);
16
17     private static native Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts);
18
19     private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
20             int length, Options opts);
21
22     private static native boolean nativeIsSeekable(FileDescriptor fd);
23 }

可以发现,其所有成员变量与所有方法都采用了 static 修饰符。这一点与 C# 是类似的。

  另外,Java 要求 package 中的类的文件名与类名必须一致、包名与文件夹路径必须一致,不支持一个 .java 文件中写入多个类。

3 在类中声明类,访问器

  Java 支持在 class 中定义 class。在 BitmapFactory 中,Options 类记录了进行位图解码时需要用到的各种参数。在 C# 中它们更倾向于被声明为包含访问器的属性(Property)。

  由于 Options 类的特点,这里没有进行访问器封装。但是对于经常被访问的成员变量,仍然要求在类设计时完善访问器。Java 中没有在语言层面支持访问器,需要开发人员手动加入 Bar getFoo() 和 void setFoo(Bar value) 方法。

4 其他关键字

  @SuppressWarnings 用于指示编译器忽略下一行中潜在的指定 warning。

  native 是 JNI 的特性,声明为 native 的方法,其实现是使用 C/C++ 代码完成的。关于 JNI 的详情,请查阅 JNI 和 Android NDK 的相关资料。

5 总结

  由于成文比较草率,本文仅对一些明显的与 C# 不同的细节点进行了解释。而对于继承、接口等语言特性尚未加以介绍。这些内容将在今后以同样的形式加以补正。如对文中所述的内容存在疑问,或有任何意见和建议,烦请不吝赐教。

Flaris 原创
转载请注明出处
http://www.cnblogs.com/flaris
http://www.zhihu.com/people/flaris

时间: 2024-08-27 22:36:55

From C# to Java (2) - 类的设计 (1)的相关文章

Java基础-继承-编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight。小车类Car是Vehicle的子类,其中包含的属性有载人数 loader。卡车类Truck是Car类的子类,其中包含的属性有载重量payload。每个 类都有构造方法和输出相关数据的方法。最后,写一个测试类来测试这些类的功 能。

#29.编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数 wheels和车重weight.小车类Car是Vehicle的子类,其中包含的属性有载人数 loader.卡车类Truck是Car类的子类,其中包含的属性有载重量payload.每个 类都有构造方法和输出相关数据的方法.最后,写一个测试类来测试这些类的功 能. package hanqi; public class Vehicle { private int wheels; private int weight

Selenium Webdriver自动化测试设计(webdriver自动化架构设计、定义接口、日志处理、Java Robot类应用)

给各位网友分享一套课程,有兴趣的可以加我 2748165793 更多免费资料,可以查看http://blog.sina.com.cn/sonyandnokia码农的开心乐园 课程大纲第1章节:课程介绍概要介绍selenium介绍webdirver介绍webdriver环境搭建 第2章节Selenium IDE介绍IDE实例讲解录制回放过程录制脚本的导出IDE插件的介绍以及安装方法 第3章节Selenium 识别对象的方法包括:id,name,class name,link text,partia

在线数据库表(sql语句)生成java实体类工具

相信每个做java开发的读者,都接触过SQL建表语句,尤其是在项目开发初期,因为数据库是项目的基石. 在现代项目开发中,出现了许多ORM框架,通过简单的实体映射,即可实现与数据库的交互,然而我们最初设计的一定是数据库表结构,而不是实体类.实体类仅仅是对底层数据结构的有损压缩,它仅仅是数据载体,不具备数据归档能力. 因此,很多时候,我们需要将原始的SQL建表语句转换成java实体类,这项工作看似简单,但若人工完成,工作量也是相当可观的,而且难免会出现差错. 到目前为止,笔者还没有发现比较靠谱的此类

类的设计

1001: 类的设计(1) Time Limit: 1 Sec  Memory Limit: 65535 MB   64bit IO Format: %lldSubmitted: 9  Accepted: 7[Submit][Status][Web Board] Description 设计clock类,成员数据包含时(hour)分(minute)秒(second),都是int类型,根据给定的main函数设计必要的成员函数. main函数已给定,提交时只需要提交main函数外的代码部分. int

java Timer类

java.util 类 Timer java.lang.Object java.util.Timer public class Timerextends Object 一种工具,线程用其安排以后在后台线程中执行的任务.可安排任务执行一次,或者定期重复执行. 与每个 Timer 对象相对应的是单个后台线程,用于顺序地执行所有计时器任务.计时器任务应该迅速完成.如果完成某个计时器任务的时间太长,那么它会“独占”计时器的任务执行线程.因此,这就可能延迟后续任务的执行,而这些任务就可能“堆在一起”,并且

java基础知识回顾之java Thread类学习(七)--java多线程通信等待唤醒机制(wait和notify,notifyAll)

1.wait和notify,notifyAll: wait和notify,notifyAll是Object类方法,因为等待和唤醒必须是同一个锁,不可以对不同锁中的线程进行唤醒,而锁可以是任意对象,所以可以被任意对象调用的方法,定义在Object基类中. wait()方法:对此对象调用wait方法导致本线程放弃对象锁,让线程处于冻结状态,进入等待线程的线程池当中.wait是指已经进入同步锁的线程,让自己暂时让出同步锁,以便使其他正在等待此锁的线程可以进入同步锁并运行,只有其它线程调用notify方

17.并发类容器设计

并发类容器设计 1.ConcurrentHashMap:代替散列普通的hashTable,添加了复合操作支持. private ConcurrentHashMap<String, Object> resultMap = new ConcurrentHashMap<String, Object>(); for (Map.Entry<String, Object> m : resultMap.entrySet()) { count += (Long) m.getValue(

Java虚拟机类装载的原理及实现(转)

Java虚拟机类装载的原理及实现(转) 一.引言 Java虚拟机(JVM)的类装载就是指将包含在类文件中的字节码装载到JVM中, 并使其成为JVM一部分的过程.JVM的类动态装载技术能够在运行时刻动态地加载或者替换系统的某些功能模块, 而不影响系统其他功能模块的正常运行.本文将分析JVM中的类装载系统,探讨JVM中类装载的原理.实现以及应用. 二.Java虚拟机的类装载实现与应用 2.1 装载过程简介 所谓装载就是寻找一个类或是一个接口的二进制形式并用该二进制形式来构造代表这个类或是这个接口的c

项目OA之实体类的设计

1.明天中秋啦,苦逼啊,自己一个人过啊,不过幸好有OA项目陪着也不孤单,继续做我的笔记,接着昨天的. 2.昨天笔记已经搭建好了SSH环境和SSH的整合,今天需要做的就是实体类的设计和分析,首先我们将资源结构分好建立一个config文件夹用来放置所有的配置文件,前文已经说过,注意需要放置在类路径下也就是直接在项目名右击建立sourcefolder,建立对应的jsp 存放页面,style存放样式,script存放脚本语言等等 3.根据项目的需求设计实体类,我这里是使用的starUml工具画的UML图