标签:
上一篇文章 From C# to Java (1) - 类型、引用与相等关系 对 Java 与 C# 在基本概念上的一些区别进行了简单的叙述,在这里简单做一回顾。第一,Java 的数据类型分为基础数据类型和类类型,类类型均为引用类型;第二,Java 的“==”运算符严格执行引用相等;第三,Java 不支持运算符重载。其中的很多重要特性在本文中也会提到,而且对类设计有重要的意义。
本文试图通过一个实际的 Java 类(Android Open Source Project 中的 BitmapFactory 类)作为例子,对 Java 的类设计特点加以介绍。有一个好消息是,事实上 Java 的类设计特性比 C# 简单一些,对开发人员而言,从 C# 转向 Java 难度并不大,主要区别于写法。
下面给出的就是 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 }
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 的整理。
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 文件中写入多个类。
Java 支持在 class 中定义 class。在 BitmapFactory 中,Options 类记录了进行位图解码时需要用到的各种参数。在 C# 中它们更倾向于被声明为包含访问器的属性(Property)。
由于 Options 类的特点,这里没有进行访问器封装。但是对于经常被访问的成员变量,仍然要求在类设计时完善访问器。Java 中没有在语言层面支持访问器,需要开发人员手动加入 Bar getFoo() 和 void setFoo(Bar value) 方法。
@SuppressWarnings 用于指示编译器忽略下一行中潜在的指定 warning。
native 是 JNI 的特性,声明为 native 的方法,其实现是使用 C/C++ 代码完成的。关于 JNI 的详情,请查阅 JNI 和 Android NDK 的相关资料。
由于成文比较草率,本文仅对一些明显的与 C# 不同的细节点进行了解释。而对于继承、接口等语言特性尚未加以介绍。这些内容将在今后以同样的形式加以补正。如对文中所述的内容存在疑问,或有任何意见和建议,烦请不吝赐教。
Flaris 原创
转载请注明出处
http://www.cnblogs.com/flaris
http://www.zhihu.com/people/flaris
From C# to Java (2) - 类的设计 (1)
标签:
原文地址:http://www.cnblogs.com/Flaris/p/4607221.html