精华内容
下载资源
问答
  • 公元2021年6月2日,鸿蒙系统迎来了第2次开源,同时,用于开发鸿蒙App的DevEco Studio也迎来了重大的更新,这次更新是具有里程碑意义的,因为增加了很多非常牛叉的功能,而且编译速度得到了显著的提升。尤其是分布式...

    目录

    1. 分布式远程模拟器

    2. 本地模拟器

    3. 改变了创建工程的方式

    4. 原子化服务

    5. 学习的好帮手:Samples

    6. 应用自签名


    公元2021年6月2日,鸿蒙系统迎来了第2次开源,同时,用于开发鸿蒙App的DevEco Studio也迎来了重大的更新,这次更新是具有里程碑意义的,因为增加了很多非常牛叉的功能,而且编译速度得到了显著的提升。尤其是分布式模拟器,可以在无需真机的情况下开发分布式鸿蒙App。本文将深入讲解DevEco Studio推出的一些核心特性。

    1. 分布式远程模拟器

     

    分布式远程模拟器是新版DevEco Studio中最值得使用的功能。以前的远程模拟器只能测试单机和网络应用,而鸿蒙的分布式特性却只能用真机测试。而分布式远程模拟器允许同时创建两个远程模拟器(P40+P40或P40+MatePad Pro),这两个远程模拟器可以互相访问,利用相关的分布式API可以获取另一个的设备ID,所以可用来开发分布式鸿蒙App。

    在默认情况下,分布式远程模拟器是不开启的。要想开启该功能,进入IDE的设置窗口,点击左侧树的DevEco Labs,在右侧选中Enable Super Device复选框即可,如下图所示。

    然后点击Tools > Device Manager菜单项,就会打开HarmonyOS Virtual Device Manager窗口(需要先登录华为开发者网站),如下图所示。

     

     

    最下面会出现一个Super device节点,里面有两种组合方式:P40+P40和P40+MatePad Pro,选中一种组合方式即可。

     

    搞定后,就会在IDE主窗口右侧出现两个模拟器,如下图所示。他们的端口号分别是18888和18889。

     

    执行hdc list targets命令,会显示如下两个设备:

    127.0.0.1:18888 device 127.0.0.1:18889 device

    如果嫌模拟器窗口太小,可以直接用scrcpy远程投屏,命令行如下:

    scrcpy -s 127.0.0.1:18888

    投屏后的效果如下图所示,这样可以拥有一个独立窗口的远程模拟器。

     

    现在可以运行一个支持分布式的App,如下面的应用可以获取网内其他的设备,目前只获得一个设备,就是双模拟器中的另外一个。

     

    2. 本地模拟器

    尽管远程模拟器使用起来非常方法,而且占用资源少,但却有如下2个缺点:

    (1)使用远程模拟器,必须联网,这对于没有网络环境或网络环境不好的用户并不友好;

    (2)由于网络的差异,远程模拟器可能会反应比较迟钝,用户体验并不好;

    基于以上两个缺点,最新版DevEco Studio还推出了本地模拟器,也就是将HarmonyOS安装在本地虚拟环境中,这样运行效率得到了很大提升。

    想使用本地模拟器,可以在DevEco Labs中打开Enable Local Emulator选项,如下图所示。

     

    然后在设备管理里就会看到Local Emulator标签页,如下图所示。不过目前本地模拟器的镜像还没有放出,稍后华为会开放这些镜像,用户可以点击Install按钮进行下载。等本地模拟器发布时,我再写文章详细讲解。

     

     

    3. 改变了创建工程的方式

     

    新版IDE改变了创建工程方式,首先要求选择模板,如下图所示。

     

     

    在这个模板中增加了11个跨设备模板,如下所示。

     

     

    下一步,会要求选择模板适用的设备,如下图所示。根据选择模板的不同,下方会出现该模板适用的所有可选设备,如果不适用,就不会显示。

     

     

    4. 原子化服务

    上面窗口中大多数都是一些常规的设置。这里要提一下Project Type。这里有两个选项:Service和Application。其中Application就是普通的App,无需多介绍。而Service是原子化服务App。Service App安装后,在桌面上是没有图标的。而且app的尺寸要限制在10MB以内,上传华为应用市场,通过某些条件(如跨设备流转),会自动从华为应用市场下载并安装(用户完全无感知)。

     

    而且创建原子化服务,会自动创建一个卡片,如下图所示。

     

    如果选中最后的Show in Service Center复选框,就会在鸿蒙的服务中心显示。

    通过从手机屏幕左下角向右上方滑动进入服务中心。

    现在按下面的样式修改string.json文件。

     

     

    接下来在模拟器或手机上运行,然后进入服务中心,输入FirstAtomApp,就会看到这个程序,如下图所示。其实这就是App中的卡片。

     

     

    然后点击,会弹出与其关联的Ability,如下图所示。不过,Service类型的App是没有图标的,所以只能从服务中心搜索启动,或者满足某些条件才能启动,如数据流转,NFC等。

     

    5. 学习的好帮手:Samples

     

    鸿蒙有一个CodeLabs(看下面的页面),但里面的例子有点大,所以IDE提供了很多samples(相对较小)。

    CodeLabs地址:

    https://developer.harmonyos.com/cn/develop/codelabs/

    导入samples,有两种方式。

    方式1,在欢迎界面(如下图所示),点击Import HarmonyOS Sample。

     

     

    然后会弹出下面的窗口,选择其中一个,点击Next按钮,按提示操作即可导入特定的Sample。

     

     

    方式2:在IDE里,点击File > New > Import HarmonyOS Sample菜单项,也会弹出上的Import HarmonyOS Sample窗口。

     

     

    其实Samples并不是直接打开工程,而是从gitee(码云)拉的,这些案例也可以从下面的页面中获取。

    https://gitee.com/openharmony/app_samples/tree/master

    6. 应用自签名

     

    我们知道,HarmonyOS App在部署到真机上时需要签名,在以前,都需要到AppGallery Connect生成一些用于签名的配置文件,然后进入Project Structure窗口,完成如下图所示的配置。

     

     

    在新版的IDE中,提供了一个Automatically generate signing复选框,选中该复选框,并在AppGallery Connect上创建一个与当前工程相同包名的应用,就可以自动产生相关的签名文件,效果如下图所示。

     

    不过使用自动签名要注意如下2点:

    (1)必须有鸿蒙设备连接到PC(通过USB或远程连接都可以)

    (2)与PC连接的所有设备必须都是鸿蒙设备,不能有Android设备。当然,Apple设备没问题

    如果有Android设备同时连接到PC上,在自动签名时会抛出如下异常:

     

    出错的原因是系统会签名所有的物理设备,目前并没有判断是鸿蒙设备,还是Android设备。所以如果遇到Android设备,也会签名。Android设备当然无法成功对HarmonyOS App签名了,所以就会导致签名失败(只要有一台设备签名失败,所有的设备签名都会失败)。

    当然,新版IDE还有很多其他功能,后期我会写文章专门介绍,敬请期待!

     

    展开全文
  • 有关压缩的一些东西

    千次阅读 2008-06-14 21:19:00
    所以,应当根据的具体需求,选择不同的压缩技术:如果只需要压缩/解压缩数据,可以直接用zlib实现,如果需要生成gzip格式的文件或解压其他工具的压缩结果,就必须用gzip或zip等相关的类来处理了。...

    【zlib、gzip、zip的区别】

    zlib是一种数据压缩程序库,它的设计目标是处理单纯的数据(而不管数据的来源是什么)。

    gzip是一种文件压缩工具(或该压缩工具产生的压缩文件格式),它的设计目标是处理单个的文件。gzip在压缩文件中的数据时使用的就是zlib。为了保存与文件属性有关的信息,gzip需要在压缩文件(*.gz)中保存更多的头信息内容,而zlib不用考虑这一点。但gzip只适用于单个文件,所以我们在UNIX/Linux上经常看到的压缩包后缀都是*.tar.gz或*.tgz,也就是先用tar把多个文件打包成单个文件,再用gzip压缩的结果。

    zip是适用于压缩多个文件的格式(相应的工具有PkZip和WinZip等),因此,zip文件还要进一步包含文件目录结构的信息,比gzip的头信息更多。但需要注意,zip格式可采用多种压缩算法,我们常见的zip文件大多不是用zlib的算法压缩的,其压缩数据的格式与gzip大不一样。

    Java SDK提供了对上述三种压缩技术的支持:Inflater类和Deflater类直接用zlib库对数据压缩/解压缩,GZIPInputStream类和GZIPOutputStream类提供了对gzip格式的支持,ZipFile、ZipInputStream、ZipOutputStream则用于处理zip格式的文件。

    所以,你应当根据你的具体需求,选择不同的压缩技术:如果只需要压缩/解压缩数据,你可以直接用zlib实现,如果需要生成gzip格式的文件或解压其他工具的压缩结果,你就必须用gzip或zip等相关的类来处理了。

    【DEFLATE】

    DEFLATE 是同时使用了 LZ77 算法与哈夫曼编码的一个无损数据压缩算法。它最初是由 Phil Katz 为他的 PKZIP 归档工具第二版所定义的,后来定义在 RFC1951 规范中。

    人们普遍认为 DEFLATE 不受任何专利所制约,并且在 LZW(GIF 文件格式使用)相关的专利失效之前,这种格式除了在ZIP文件格式中得到应用之外也在 gzip 压缩文件以及 PNG 图像文件中得到了应用。

    DEFLATE 压缩与解压的源代码可以在自由、通用的压缩库 zlib 上找到。

    更高压缩率的 DEFLATE 是 7-zip 所实现的。AdvanceCOMP 也使用这种实现,它可以对 gzip、PNG、MNG 以及 ZIP 文件进行压缩从而得到比 zlib 更小的文件大小。在 Ken Silverman 的 KZIP 与 PNGOUT 中使用了一种更加高效同时要求更多用户输入的 DEFLATE 程序。

    【INFLATE】

    inflate是GZip, PNG等广泛使用的解压算法,linux也使用inflate对内核进行解压.inflate的解压算法使用的第3种快速解压法的一个子集,它不考虑LONG_CODE,同时把SAME_LENGTH合并到MEDIUM_CODE。而对于规则的SAME_LENGTH编码,比如length和distance编码,inflate则使用额外的base和extra表示。这是因为在构造一般的查找表时,虽然对于SAME_LENGTH前缀可以不构造副表,但我们需要另外一个表格来保存符号的顺序,而这个表格的空间可能更大。但对于length和distance编码,他们的顺序是递增的,所以无需额外的表格来保存符号的顺序。

    inflate使用root表示上述的b,查找表的数据结构为code.主表和副同时保存在inflate_state结构中的大数组codes[ENOUGH]中.表的构造函数位于inftrees.c文件的inflate_table中.

    【7z】

    7z 是一种新的压缩格式,它拥有目前最高的压缩比。

    7z 已公开了结构编辑功能,所以它可以支持任何一种新的压缩算法。到目前为止,下列压缩算法已被整合到了 7z 中:

    压缩算法  备注 LZMA  LZ77 改良和优化算法后的最新版本 PPMD  基于 Dmitry Shkarin 之上的算法 PPMdH 并加以优化 BCJ  32-位 x86 可执行文件转换程序 BCJ2  32-位 x86 可执行文件转换程序 BZip2  标准 BWT 算法 Deflate  标准 LZ77-based 算法

    展开全文
  • Android ROM制作教程,让你拥有自己喜欢的ROM

    万次阅读 多人点赞 2018-09-20 20:40:18
    作者斯文是我 关键词:java环境配置 制作工具 update-编写美化 集成 编译反编译 一. ...帮助那些需要帮助的朋友(说不定有人喜欢制作的ROM) 二. 制作原理: 1. 安卓基础知识普及: Andro...

    文章转载自:http://bbs.xiaomi.cn/t-13336185

    作者斯文是我

    关键词:java环境配置
    制作工具 update-编写美化 集成 编译反编译

    一.
    制作目的:

    1.
    培养个人兴趣,感受动手动脑的快乐。

    2.
    学习手机基本知识,最终动手制作自己的ROM。

    3.
    帮助那些需要帮助的朋友(说不定有人喜欢你制作的ROM)

    二.
    制作原理:

    1.
    安卓基础知识普及:

    Android一词的本义指“机器人”,同时也是Google于2007年11月5日宣布的基于Linux平台的开源手机操作系统的名称,该平台由操作系统、中间件、用户界面和应用软件组成,号称是首个为移动终端打造的真正开放和完整的移动软件。目前,最新版本为Android 2.4Gingerbread和Android 3.0Honeycomb。


    底包
    :官方的系统包,相当于我们的Windows的操作系统,事实上它相当于一个纯净版或者内核版的系统包,是最底层的东西。扩展名为sbf,底包通常是官方发布的,ROM作者直接拿来用的,可以选择的版本不会太多,通常更新也不会频繁。底包通常使用PC端刷机工具(RSD)配合Bootloader的工程模式完成刷入。


    升级包
    (镜像包):广大玩家制作的底包增强包,通常表现为一个update.zip文件。升级包是对底包的扩展和增强,包含一系列的辅助工具和服务,没有中文的底包通过升级包可以实现中文。当然,很多功能也是通过升级包来实现的。可以说,在刷新了底包后,配合刷新相应的升级包,这样才形成一个完整系统。升级包通常通过Recovery工具,从SD卡读取刷入。


    Bootloader  :相当于电脑里面的bios(基本输入输出系统),手机一开机,控制手机的就是Bootloader。我们通常所说的进入Bootloader,实际上是指进入Bootloader的工程模式,既是刷机模式,在此模式下可以将moto的sbf文件(底包)刷到机器里面。


    Recovery : Moto 手机内置的一个独立备份恢复工具,类似电脑上的一些一键还原系统,既是在系统出现问题的时候仍然可以打开的一个模式。Moto 的 Recovery 主要提供了WIPE(硬启,清除数据,恢复出厂设置)和Update(通常用于安装升级包,update.zip)功能。 Recovery是不能直接刷新的底包的,通常它刷新的升级包(update.zip)的方式是:自动寻找SD卡上的特定文件,然后写入。


    基带(Baseband):是手机中的一块专门的代码,或者可以理解成为一个专门负责通讯的BIOS,负责完成移**络中无线信号的解调、解扰、解扩和解码工作。基带的不同会造成信号效果的不同。因为各地、各网络实际情况不同,需要大家自己选择适合自己的基带。


    WIPE :wipe后就恢复了出厂设置,包括联系人、短信、安装的软件等全部删除。俗称硬启,恢复出厂设置。注意,wipe后app2sd和root权限需要重新做。而且app2sd重要的分区步骤也要重新来过。某些说法提到在刷新底包或者升级包前需要进行WIPE操作,我对此操作的必要性不是很确定。


    OpenRecovery(简称OR) :由于MOTO很蛋疼的在update.zip上做了一些手脚,这些东西影响到了升级包的制作。于是高手们就搞出了一个OpenRecovery,这其实就一个第三方的增强版的Recovery工具,某些OpenRecovery已经发展成为一个具有很多功能的小系统了(类似WindowsPE),在这个OR中,可以完成很多东西,我们完全可以把OR想象成电脑上用的应急PE系统,在上面可以调整超频、基带、app2sd、更换启动画面、wipe、改变时区、调整键盘布局,甚至链接USB当读卡器等等,凡是recovery能做的,OR都可以做,recovery不能做到,OR可以做到。一般OpenRecovery在sd卡上有两个部分存在:update.zip和OpenRecovery目录,最新的GOT底包添加了新的一个OpenRecovery-CFG目录,用来存放各种个人文件。update.zip就是用来坑MOTO一个标准的的zip升级包,而真正的升级包要放在/sdcard/OpenRecovery/updates目录下。


    App2sd :说白了,其实很简单,就是把APK文件安装到sd卡上,android是Linux脱胎而来,App2sd的原理就是对SD卡进行分区,然后把SD上划分出来的某个分区合并到系统分区中去(听不懂,不要紧),划分出来的分区是Ext2格式,一般Windows不能识别,不要惊慌,正常现象。App2sd对sd卡要求比较高,如果感觉app2sd后比较慢,可以试试换一张C4的sd卡。因为在2.1的环境下,app2sd需要对sd进行分区,操作比较复杂,E文不好的小白或者电脑基础薄弱的小白容易失误。建议对Android非常熟悉了再做App2sd。


    Root :大家都知道android系统脱胎自Linux,也正是这个开源的内核让广大玩家可以自由发挥。Root是Linux系统下的系统级账号,拥有系统的全部权限,Android设计上的不开放这个用户的,目的是为了保护系统安全,但是这个保护似乎也带来很多不便。于是就一些工具和方法来开放这个账号。开放Root账号的方法似乎有很多,这里就不再细说。原理上分析,root的账号,应该通过在Android系统安装某个系统级别的服务,该服务具有root权限,然后其它需要root权限的程序再向这个服务请求root权限。WIPE、刷机都有可能会造成root权限失效,需要重新root权限。

    额外说明:


    从原理上分析,通常
    底包,Bootloader,Recovery,基带都是可以刷新替换的,升级包当然更可以。但是底包、Bootloader很少会有第三方开发或者修改的,一般都使用官方发布的。底包有时候会内置Bootloader、Recovery,这样的底包刷新时会连上述两者一起更新(推测结果,不确定)。更新这样的底包是有危险的,有可能会造成Bootloader损坏,这个东西损坏了,基本就是变砖了,真正的变砖,只能花钱去修了。只有这个东西没坏,就不是砖。②
    我们通常所说的刷机ROM实际是升级包,升级包是对应于特定的底包制作的,所以刷机时务必确保使用的底包和升级包版本上保持一致。③
    需要注意版本号的还有:Bootloader版本、基带版本、Recovery版本④
    目前有些OpenRecovery工具支持底包、升级包一起从SD卡读取刷入⑤
    似乎刷机前确保系统干净整洁是很重要的,很多教程提到要通过 WIPE - 刷底包的步骤来确保刷机前的干净,实际上如果底包版本没有变化,刷底包似乎、也许、大概、可能是不必要的。


    2.
    系统结构及文件简单剖析:

    一个常见的自制ROM根目录会有以下几个文件夹及文件:
    data,-IN,system,boot.img(锁了BL的可以无视这个,但制作时需要它,打包时把它拿出来。)
    系统目录说明
    ①应用程序安装目录
    1) 系统应用程序所在目录/system/app/*.apk
    2)用户安装应用程序所在目录/data/app/*.apk
    3) 注意:a)在模拟器中,每重启一次,/system/app/下的应用都会被还原,有时/data/app下也会被清除
    b)若在/system/app和/data/app下有重名的应用,不一定会启动哪一个,尤其是在adb install杀死正在运行的程序时,有时旧的就会被启动
    ②.用户数据所在目录
    /data/data/应用包名/shared_prefs配置文件
    /data/data/应用包名/databases/*库文件所在目录
    ③. SD卡对应目录/sdcard/
    而我们需要处理的只是两个文件夹里面的内容:
    data/app ——该文件夹里的文件可以全删,也可以自由添加自已所需安装的应用软件,刷机安装后可以自由删除。
    system/app ——在这个文件夹下的程序为系统默认的组件,可以看到都是以APK格式结尾的文件,但有些系统自带的ROM里面还有和APK文件名对应的odex文件。我们主要是针对该文件夹里的文件进行精简,如果有odex文件的,删除APK文件名时同时也删除与其对应的odex文件。虽然一般定制时只是对以上两个文件夹里的文件做相应的增减,但我们还是一起来了解system相应目录常见相应文件的用途吧。rom版本不同,里面的APK也会不一样,其它文件夹下需要改动的较少,或者不需要改动。但app文件下是制作时的重点,所以详细列出:
    \\system\\app
    \\system\\app\\AlarmClock.apk
    闹钟
    \\system\\app\\Browser.apk
    浏览器
    \\system\\app\\Bugreport.apk Bug报告
    \\system\\app\\Calculator.apk
    计算器
    \system\app\Calendar.apk
    日历
    \\system\\app\\CalendarProvider.apk
    日历提供
    \\system\\app\\Camera.apk
    照相机

    \\system\\app\\Contacts.apk
    联系人
    \\system\\app\\DownloadProvider.apk
    下载提供
    \\system\\app\\DrmProvider.apk DRM数字版权提供
    \\system\\app\\Email.apk
    电子邮件客户端
    \\system\\app\\FieldTest.apk
    测试程序
    \\system\\app\\GDataFeedsProvider.apk GoogleData提供
    \\system\\app\\Gmail.apk Gmail电子邮件
    \\system\\app\\GmailProvider.apk Gmail提供
    \\system\\app\\GoogleApps.apk
    谷歌程序包
    \\system\\app\\GoogleSearch.apk
    搜索工具
    \\system\\app\\gtalkservice.apk GTalk服务
    \\system\\app\\HTMLViewer.apk HTML查看器
    \\system\\app\\Htc**.apk
    集成**客户端PEEP
    \\system\\app\\IM.apk
    即使通讯组件包含MSN、yahoo通
    \\system\\app\\Launcher.apk
    启动加载器
    \\system\\app\\Maps.apk
    电子地图
    \\system\\app\\MediaProvider.apk
    多媒体播放提供
    \\system\\app\\Mms.apk
    短信、彩信
    \\system\\app\\Music.apk
    音乐播放器
    \\system\\app\\PackageInstaller.apk apk安装程序
    \\system\\app\\Phone.apk
    电话拨号器
    \\system\\app\\Settings.apk
    系统设置
    \\system\\app\\SettingsProvider.apk
    设置提供
    \\system\\app\\SetupWizard.apk
    设置向导
    \\system\\app\\SoundRecorder.apk
    录音工具
    \\system\\app\\Street.apk
    街景地图
    \\system\\app\\Sync.apk
    同步程序
    \\system\\app\\Talk.apk
    语音程序
    \\system\\app\\TelephonyProvider.apk
    电话提供
    \\system\\app\\Updater.apk
    更新程序
    \\system\\app\\***Services.apk ***服务
    \\system\\app\\Vending.apk
    制造商信息
    \\system\\app\\VoiceDialer.apk
    语音拨号器
    \\system\\app\\VoiceSearch.apk
    语音搜索
    app文件夹内放的就是内置软件,有不想要的,直接删除之。请在删除之前先弄清楚它能不能删除。有些官方内置的软件,删除了ROM就废了。当然,你也可以在没弄清楚的情况下乱删一气,只要在刷机完发现问题之后,把删除的软件,一个个放回去排查,刷个十遍八遍,大约也就搞定了。所以我们要佩服那么敢于探索的先驱,不容易啊。
    fonts文件夹放的是手机的字体,如果没有美术细胞的人就不要乱改,改字体有时候会死人的,刺眼、字形不协调、大小不一致等等诸如此类。要改也刷机完以后再改。具体方法要参见自己区的人发的帖子。
    lib文件夹顾名思义,是内置软件的库文件。有些软件需要动态库支持才能正常使用的,比如常见的输入法之类的。所以,如果你向一个原本可以正常使用的ROM中加入了新的软件之后,反而出现
    某程序意外关闭
    某程序意外结束的情况后,那么基本上就是你忘了把库文件给它移动过去。
    bin文件夹中放的是系统内置的工具,像什么busybox,su之类的都在里面,没事不要删除它,可以添加,但不要删除。
    etc文件夹中放置的是系统的设置,诸如无线、GPS、DHCP、拨号、APN列表之类的设置。这个目录中,如果你改了重要的CONF文件,则可能系统出问题。也可以改一部分不重要的东西(比如说APN列表)而不出现问题,但貌似APN列表没必要改。
    framework目录就是系统的UI了,想改界面的人应该改这个目录中的文件。。大约也就是替换一些什么图片,换掉界面框架什么的,改改字体颜色什么的?以达到改换界面的目的。   

    media目录是系统内置的媒体文件,如开机音乐,内置的通话铃声、信息铃声、闹钟铃声,可以改,但格式是OGG的,可以自己去搜索如何换格式。

    usr目录是系统的部分使用配置,包括键盘映射表什么的,没事不要改。。。

    xbin目录,好吧,这个目录可以放一些工具,而且貌似官方本身在里面放了一个tcpdump,是截获网络数据包的。没试过删除它,推荐有冒险精神的可以删除之,再将结果告诉我们。

          system:系统分区.我们刷机器一般就是刷的这个分区.

          userdata:数据分区.

          cache:缓存分区

          recovery:Recovery分区,相当于建立在hboot与android系统间的一个中间层,如名字一般,主要用于系统调试和恢复。.

          boot:存放内核和ramdisk的分区.

          hboot:这个是SPL所在的分区,即 bootloader

          splash1:这个就是开机第一屏幕了.

          radio:这个是无线所在的分区,即基带所在分区。

           misc:其他分区



    3.创建一个刷机包,update-脚本语法说明


    ①简单举例:创建一个update.zip文件是很简单的事情,你所需要做的就是将文件放置到与Android文件系统中相对应的文件夹中,然后编写一个用来复制这些文件到手机对应位置的update-, 文件。作为举例,比如安装Calculator.apk到system/app文件夹,复制libsec-ril.so文件到system/lib文件夹:新建一个空文件夹(本文例:G:\android)新建用来放置Calculator.apk的文件夹C:\android\system\app以及用来放置libsec-ril.so的文件夹G:\android\system\lib。创建用来放置update-文件的文件夹G:\android\-INF\com\google\android。


    创建一个名为updater-的文件,其内容如下:

    1.
    show_progress 0.1 0

    2.

    3.
    copy_dir PACKAGE:systemSYSTEM:

    4.

    5.
    show_progress 0.1 10

    6.

    行1和行5:显示进度条
    行3:复制刷机包中的system文件夹到Android的/system
    注意:你应该在文件的最末尾多添加一个空行(也就是行6)将C:\android压缩中的所有内容压缩为zip包(千万记住:是压缩android这个文件夹中的内容,不是android文件夹本身)为android.zip签名


    ②基础语法篇
    1.copy_dir
    语法:copy_dir 


    默认时区。在/system/default.prop中修改persist.sys.timezone(如果没有该项,则手动添加)的值为Asia/Shanghai(即东八区),即

    persist.sys.timezone=Asia/Shanghai

    注:如果没有/system/default.prop,也可以在/system/build.prop中修改或添加。

    ⑾锁了bl的同学,在修改时注意看运行时的语句,凡是涉及到的功能修改了boot.img,你就趁早删了update-相关语句重来吧,不然也不会出什么大事,就是手机卡在第一屏进不去,或者一直进入恢复模式。解决办法如果你先前备份了,那就还原一下。如果没备份,重刷底包吧。

    ⑿接下来就是打包签名,按照提示一步一步来就OK了。

     

    展开全文
  • 秒懂,Java 注解 (Annotation)可以这样学

    万次阅读 多人点赞 2017-06-27 21:48:30
    作为元数据,注解不直接影响的代码执行,但也有一些类型的注解实际上可以用于这一目的。Java 注解是从 Java5 开始添加到 Java 的。 这是大多数网站上对于 Java 注解,解释确实正确,但是说实在话,我第一次...

    文章开头先引入一处图片。

    这里写图片描述
    这处图片引自老罗的博客。为了避免不必要的麻烦,首先声明我个人比较尊敬老罗的。至于为什么放这张图,自然是为本篇博文服务,接下来我自会说明。好了,可以开始今天的博文了。

    Annotation 中文译过来就是注解、标释的意思,在 Java 中注解是一个很重要的知识点,但经常还是有点让新手不容易理解。

    我个人认为,比较糟糕的技术文档主要特征之一就是:用专业名词来介绍专业名词。

    比如:

    Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。Java 注解是从 Java5 开始添加到 Java 的。

    这是大多数网站上对于 Java 注解,解释确实正确,但是说实在话,我第一次学习的时候,头脑一片空白。这什么跟什么啊?听了像没有听一样。因为概念太过于抽象,所以初学者实在是比较吃力才能够理解,然后随着自己开发过程中不断地强化练习,才会慢慢对它形成正确的认识。

    我在写这篇文章的时候,我就在思考。如何让自己或者让读者能够比较直观地认识注解这个概念?是要去官方文档上翻译说明吗?我马上否定了这个答案。

    后来,我想到了一样东西————墨水,墨水可以挥发、可以有不同的颜色,用来解释注解正好。

    不过,我继续发散思维后,想到了一样东西能够更好地代替墨水,那就是印章。印章可以沾上不同的墨水或者印泥,可以定制印章的文字或者图案,如果愿意它也可以被戳到你任何想戳的物体表面。

    但是,我再继续发散思维后,又想到一样东西能够更好地代替印章,那就是标签。标签是一张便利纸,标签上的内容可以自由定义。常见的如货架上的商品价格标签、图书馆中的书本编码标签、实验室中化学材料的名称类别标签等等。

    并且,往抽象地说,标签并不一定是一张纸,它可以是对人和事物的属性评价。也就是说,标签具备对于抽象事物的解释。

    这里写图片描述

    所以,基于如此,我完成了自我的知识认知升级,我决定用标签来解释注解。

    注解如同标签

    回到博文开始的地方,之前某新闻客户端的评论有盖楼的习惯,于是 “乔布斯重新定义了手机、罗永浩重新定义了傻X” 就经常极为工整地出现在了评论楼层中,并且广大网友在相当长的一段时间内对于这种行为乐此不疲。这其实就是等同于贴标签的行为。

    在某些网友眼中,罗永浩就成了傻X的代名词。

    广大网友给罗永浩贴了一个名为“傻x”的标签,他们并不真正了解罗永浩,不知道他当教师、砸冰箱、办博客的壮举,但是因为“傻x”这样的标签存在,这有助于他们直接快速地对罗永浩这个人做出评价,然后基于此,罗永浩就可以成为茶余饭后的谈资,这就是标签的力量。

    而在网络的另一边,老罗靠他的人格魅力自然收获一大批忠实的拥泵,他们对于老罗贴的又是另一种标签。
    这里写图片描述

    老罗还是老罗,但是由于人们对于它贴上的标签不同,所以造成对于他的看法大相径庭,不喜欢他的人整天在网络上评论抨击嘲讽,而崇拜欣赏他的人则会愿意挣钱购买锤子手机的发布会门票。

    我无意于评价这两种行为,我再引个例子。

    《奇葩说》是近年网络上非常火热的辩论节目,其中辩手陈铭被另外一个辩手马薇薇攻击说是————“站在宇宙中心呼唤爱”,然后贴上了一个大大的标签————“鸡汤男”,自此以后,观众再看到陈铭的时候,首先映入脑海中便是“鸡汤男”三个大字,其实本身而言陈铭非常优秀,为人师表、作风正派、谈吐举止得体,但是在网络中,因为娱乐至上的环境所致,人们更愿意以娱乐的心态来认知一切,于是“鸡汤男”就如陈铭自己所说成了一个撕不了的标签。

    我们可以抽象概括一下,标签是对事物行为的某些角度的评价与解释。

    到这里,终于可以引出本文的主角注解了。

    初学者可以这样理解注解:想像代码具有生命,注解就是对于代码中某些鲜活个体的贴上去的一张标签。简化来讲,注解如同一张标签。

    在未开始学习任何注解具体语法而言,你可以把注解看成一张标签。这有助于你快速地理解它的大致作用。如果初学者在学习过程有大脑放空的时候,请不要慌张,对自己说:

    注解,标签。注解,标签。

    注解语法

    因为平常开发少见,相信有不少的人员会认为注解的地位不高。其实同 classs 和 interface 一样,注解也属于一种类型。它是在 Java SE 5.0 版本中开始引入的概念。

    注解的定义

    注解通过 @interface关键字进行定义。

    public @interface TestAnnotation {
    }
    

    它的形式跟接口很类似,不过前面多了一个 @ 符号。上面的代码就创建了一个名字为 TestAnnotaion 的注解。

    你可以简单理解为创建了一张名字为 TestAnnotation 的标签。

    注解的应用

    上面创建了一个注解,那么注解的的使用方法是什么呢。

    @TestAnnotation
    public class Test {
    }
    

    创建一个类 Test,然后在类定义的地方加上 @TestAnnotation 就可以用 TestAnnotation 注解这个类了。

    你可以简单理解为将 TestAnnotation 这张标签贴到 Test 这个类上面。

    不过,要想注解能够正常工作,还需要介绍一下一个新的概念那就是元注解。

    元注解

    元注解是什么意思呢?

    元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。

    如果难于理解的话,你可以这样理解。元注解也是一张标签,但是它是一张特殊的标签,它的作用和目的就是给其他普通的标签进行解释说明的。

    元标签有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。

    @Retention

    Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。

    它的取值如下:

    • RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
    • RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
    • RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

    我们可以这样的方式来加深理解,@Retention 去给一张标签解释的时候,它指定了这张标签张贴的时间。@Retention 相当于给一张标签上面盖了一张时间戳,时间戳指明了标签张贴的时间周期。

    @Retention(RetentionPolicy.RUNTIME)
    public @interface TestAnnotation {
    }
    

    上面的代码中,我们指定 TestAnnotation 可以在程序运行周期被获取到,因此它的生命周期非常的长。

    @Documented

    顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。

    @Target

    Target 是目标的意思,@Target 指定了注解运用的地方。

    你可以这样理解,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。

    类比到标签,原本标签是你想张贴到哪个地方就到哪个地方,但是因为 @Target 的存在,它张贴的地方就非常具体了,比如只能张贴到方法上、类上、方法参数上等等。@Target 有下面的取值

    • ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
    • ElementType.CONSTRUCTOR 可以给构造方法进行注解
    • ElementType.FIELD 可以给属性进行注解
    • ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
    • ElementType.METHOD 可以给方法进行注解
    • ElementType.PACKAGE 可以给一个包进行注解
    • ElementType.PARAMETER 可以给一个方法内的参数进行注解
    • ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

    @Inherited

    Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。
    说的比较抽象。代码来解释。

    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @interface Test {}
    
    
    @Test
    public class A {}
    
    
    public class B extends A {}
    
    

    注解 Test 被 @Inherited 修饰,之后类 A 被 Test 注解,类 B 继承 A,类 B 也拥有 Test 这个注解。

    可以这样理解:

    老子非常有钱,所以人们给他贴了一张标签叫做富豪。

    老子的儿子长大后,只要没有和老子断绝父子关系,虽然别人没有给他贴标签,但是他自然也是富豪。

    老子的孙子长大了,自然也是富豪。

    这就是人们口中戏称的富一代,富二代,富三代。虽然叫法不同,好像好多个标签,但其实事情的本质也就是他们有一张共同的标签,也就是老子身上的那张富豪的标签。

    @Repeatable

    Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。

    什么样的注解会多次应用呢?通常是注解的值可以同时取多个。

    举个例子,一个人他既是程序员又是产品经理,同时他还是个画家。

    
    @interface Persons {
    	Person[]  value();
    }
    
    
    @Repeatable(Persons.class)
    @interface Person{
    	String role default "";
    }
    
    
    @Person(role="artist")
    @Person(role="coder")
    @Person(role="PM")
    public class SuperMan{
    	
    }
    
    

    注意上面的代码,@Repeatable 注解了 Person。而 @Repeatable 后面括号中的类相当于一个容器注解。

    什么是容器注解呢?就是用来存放其它注解的地方。它本身也是一个注解。

    我们再看看代码中的相关容器注解。

    @interface Persons {
    	Person[]  value();
    }
    

    按照规定,它里面必须要有一个 value 的属性,属性类型是一个被 @Repeatable 注解过的注解数组,注意它是数组。

    如果不好理解的话,可以这样理解。Persons 是一张总的标签,上面贴满了 Person 这种同类型但内容不一样的标签。把 Persons 给一个 SuperMan 贴上,相当于同时给他贴了程序员、产品经理、画家的标签。

    我们可能对于 @Person(role=“PM”) 括号里面的内容感兴趣,它其实就是给 Person 这个注解的 role 属性赋值为 PM ,大家不明白正常,马上就讲到注解的属性这一块。

    注解的属性

    注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TestAnnotation {
    	
    	int id();
    	
    	String msg();
    
    }
    

    上面代码定义了 TestAnnotation 这个注解中拥有 id 和 msg 两个属性。在使用的时候,我们应该给它们进行赋值。

    赋值的方式是在注解的括号内以 value="" 形式,多个属性之前用 ,隔开。

    @TestAnnotation(id=3,msg="hello annotation")
    public class Test {
    
    }
    

    需要注意的是,在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组。

    注解中属性可以有默认值,默认值需要用 default 关键值指定。比如:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface TestAnnotation {
    	
    	public int id() default -1;
    	
    	public String msg() default "Hi";
    
    }
    
    

    TestAnnotation 中 id 属性默认值为 -1,msg 属性默认值为 Hi。
    它可以这样应用。

    @TestAnnotation()
    public class Test {}
    

    因为有默认值,所以无需要再在 @TestAnnotation 后面的括号里面进行赋值了,这一步可以省略。

    另外,还有一种情况。如果一个注解内仅仅只有一个名字为 value 的属性时,应用这个注解时可以直接接属性值填写到括号内。

    public @interface Check {
    	String value();
    }
    

    上面代码中,Check 这个注解只有 value 这个属性。所以可以这样应用。

    @Check("hi")
    int a;
    

    这和下面的效果是一样的

    @Check(value="hi")
    int a;
    

    最后,还需要注意的一种情况是一个注解没有任何属性。比如

    public @interface Perform {}
    
    

    那么在应用这个注解的时候,括号都可以省略。

    @Perform
    public void testMethod(){}
    

    Java 预置的注解

    学习了上面相关的知识,我们已经可以自己定义一个注解了。其实 Java 语言本身已经提供了几个现成的注解。

    @Deprecated

    这个元素是用来标记过时的元素,想必大家在日常开发中经常碰到。编译器在编译阶段遇到这个注解时会发出提醒警告,告诉开发者正在调用一个过时的元素比如过时的方法、过时的类、过时的成员变量。

    public class Hero {
    	
    	@Deprecated
    	public void say(){
    		System.out.println("Noting has to say!");
    	}
    	
    	
    	public void speak(){
    		System.out.println("I have a dream!");
    	}
    	
    
    }
    
    

    定义了一个 Hero 类,它有两个方法 say() 和 speak() ,其中 say() 被 @Deprecated 注解。然后我们在 IDE 中分别调用它们。
    这里写图片描述

    可以看到,say() 方法上面被一条直线划了一条,这其实就是编译器识别后的提醒效果。

    @Override

    这个大家应该很熟悉了,提示子类要复写父类中被 @Override 修饰的方法

    @SuppressWarnings

    阻止警告的意思。之前说过调用被 @Deprecated 注解的方法后,编译器会警告提醒,而有时候开发者会忽略这种警告,他们可以在调用的地方通过 @SuppressWarnings 达到目的。

    @SuppressWarnings("deprecation")
    public void test1(){
    	Hero hero = new Hero();
    	hero.say();
    	hero.speak();
    }
    

    @SafeVarargs

    参数安全类型注解。它的目的是提醒开发者不要用参数做一些不安全的操作,它的存在会阻止编译器产生 unchecked 这样的警告。它是在 Java 1.7 的版本中加入的。

    @SafeVarargs // Not actually safe!
    	static void m(List<String>... stringLists) {
    	Object[] array = stringLists;
    	List<Integer> tmpList = Arrays.asList(42);
    	array[0] = tmpList; // Semantically invalid, but compiles without warnings
    	String s = stringLists[0].get(0); // Oh no, ClassCastException at runtime!
    }
    

    上面的代码中,编译阶段不会报错,但是运行时会抛出 ClassCastException 这个异常,所以它虽然告诉开发者要妥善处理,但是开发者自己还是搞砸了。

    Java 官方文档说,未来的版本会授权编译器对这种不安全的操作产生错误警告。

    @FunctionalInterface

    函数式接口注解,这个是 Java 1.8 版本引入的新特性。函数式编程很火,所以 Java 8 也及时添加了这个特性。

    函数式接口 (Functional Interface) 就是一个具有一个方法的普通接口。

    比如

    @FunctionalInterface
    public interface Runnable {
        /**
         * When an object implementing interface <code>Runnable</code> is used
         * to create a thread, starting the thread causes the object's
         * <code>run</code> method to be called in that separately executing
         * thread.
         * <p>
         * The general contract of the method <code>run</code> is that it may
         * take any action whatsoever.
         *
         * @see     java.lang.Thread#run()
         */
        public abstract void run();
    }
    
    

    我们进行线程开发中常用的 Runnable 就是一个典型的函数式接口,上面源码可以看到它就被 @FunctionalInterface 注解。

    可能有人会疑惑,函数式接口标记有什么用,这个原因是函数式接口可以很容易转换为 Lambda 表达式。这是另外的主题了,有兴趣的同学请自己搜索相关知识点学习。

    注解的提取

    博文前面的部分讲了注解的基本语法,现在是时候检测我们所学的内容了。

    我通过用标签来比作注解,前面的内容是讲怎么写注解,然后贴到哪个地方去,而现在我们要做的工作就是检阅这些标签内容。 形象的比喻就是你把这些注解标签在合适的时候撕下来,然后检阅上面的内容信息。

    要想正确检阅注解,离不开一个手段,那就是反射。

    注解与反射。

    注解通过反射获取。首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解

    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
    
    

    然后通过 getAnnotation() 方法来获取 Annotation 对象。

     public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
    
    

    或者是 getAnnotations() 方法。

    
    public Annotation[] getAnnotations() {}
    

    前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的所有注解。

    如果获取到的 Annotation 如果不为 null,则就可以调用它们的属性方法了。比如

    @TestAnnotation()
    public class Test {
    	
    	public static void main(String[] args) {
    		
    		boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
    		
    		if ( hasAnnotation ) {
    			TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
    			
    			System.out.println("id:"+testAnnotation.id());
    			System.out.println("msg:"+testAnnotation.msg());
    		}
    
    	}
    
    }
    
    

    程序的运行结果是:

    id:-1
    msg:
    
    

    这个正是 TestAnnotation 中 id 和 msg 的默认值。

    上面的例子中,只是检阅出了注解在类上的注解,其实属性、方法上的注解照样是可以的。同样还是要假手于反射。

    @TestAnnotation(msg="hello")
    public class Test {
    	
    	@Check(value="hi")
    	int a;
    	
    	
    	@Perform
    	public void testMethod(){}
    	
    	
    	@SuppressWarnings("deprecation")
    	public void test1(){
    		Hero hero = new Hero();
    		hero.say();
    		hero.speak();
    	}
    
    
    	public static void main(String[] args) {
    		
    		boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
    		
    		if ( hasAnnotation ) {
    			TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
    			//获取类的注解
    			System.out.println("id:"+testAnnotation.id());
    			System.out.println("msg:"+testAnnotation.msg());
    		}
    		
    		
    		try {
    			Field a = Test.class.getDeclaredField("a");
    			a.setAccessible(true);
    			//获取一个成员变量上的注解
    			Check check = a.getAnnotation(Check.class);
    			
    			if ( check != null ) {
    				System.out.println("check value:"+check.value());
    			}
    			
    			Method testMethod = Test.class.getDeclaredMethod("testMethod");
    			
    			if ( testMethod != null ) {
    				// 获取方法中的注解
    				Annotation[] ans = testMethod.getAnnotations();
    				for( int i = 0;i < ans.length;i++) {
    					System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName());
    				}
    			}
    		} catch (NoSuchFieldException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    			System.out.println(e.getMessage());
    		} catch (SecurityException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    			System.out.println(e.getMessage());
    		} catch (NoSuchMethodException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    			System.out.println(e.getMessage());
    		}
    		
    		
    
    	}
    
    }
    
    

    它们的结果如下:

    id:-1
    msg:hello
    check value:hi
    method testMethod annotation:Perform
    
    

    需要注意的是,如果一个注解要在运行时被成功提取,那么 @Retention(RetentionPolicy.RUNTIME) 是必须的。

    注解的使用场景

    我相信博文讲到这里大家都很熟悉了注解,但是有不少同学肯定会问,注解到底有什么用呢?

    对啊注解到底有什么用?

    我们不妨将目光放到 Java 官方文档上来。

    文章开始的时候,我用标签来类比注解。但标签比喻只是我的手段,而不是目的。为的是让大家在初次学习注解时能够不被那些抽象的新概念搞懵。既然现在,我们已经对注解有所了解,我们不妨再仔细阅读官方最严谨的文档。

    注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分。注解对于代码的运行效果没有直接影响。

    注解有许多用处,主要如下:

    • 提供信息给编译器: 编译器可以利用注解来探测错误和警告信息
    • 编译阶段时的处理: 软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理。
    • 运行时的处理: 某些注解可以在程序运行的时候接受代码的提取

    值得注意的是,注解不是代码本身的一部分。

    如果难于理解,可以这样看。罗永浩还是罗永浩,不会因为某些人对于他“傻x”的评价而改变,标签只是某些人对于其他事物的评价,但是标签不会改变事物本身,标签只是特定人群的手段。所以,注解同样无法改变代码本身,注解只是某些工具的的工具。

    还是回到官方文档的解释上,注解主要针对的是编译器和其它工具软件(SoftWare tool)。

    当开发者使用了Annotation 修饰了类、方法、Field 等成员之后,这些 Annotation 不会自己生效,必须由开发者提供相应的代码来提取并处理 Annotation 信息。这些处理提取和处理 Annotation 的代码统称为 APT(Annotation Processing Tool)。

    现在,我们可以给自己答案了,注解有什么用?给谁用?给 编译器或者 APT 用的。

    如果,你还是没有搞清楚的话,我亲自写一个好了。

    亲手自定义注解完成某个目的

    我要写一个测试框架,测试程序员的代码有无明显的异常。

    —— 程序员 A : 我写了一个类,它的名字叫做 NoBug,因为它所有的方法都没有错误。
    —— 我:自信是好事,不过为了防止意外,让我测试一下如何?
    —— 程序员 A: 怎么测试?
    —— 我:把你写的代码的方法都加上 @Jiecha 这个注解就好了。
    —— 程序员 A: 好的。

    NoBug.java

    package ceshi;
    import ceshi.Jiecha;
    
    
    public class NoBug {
    	
    	@Jiecha
    	public void suanShu(){
    		System.out.println("1234567890");
    	}
    	@Jiecha
    	public void jiafa(){
    		System.out.println("1+1="+1+1);
    	}
    	@Jiecha
    	public void jiefa(){
    		System.out.println("1-1="+(1-1));
    	}
    	@Jiecha
    	public void chengfa(){
    		System.out.println("3 x 5="+ 3*5);
    	}
    	@Jiecha
    	public void chufa(){
    		System.out.println("6 / 0="+ 6 / 0);
    	}
    	
    	public void ziwojieshao(){
    		System.out.println("我写的程序没有 bug!");
    	}
    
    }
    

    上面的代码,有些方法上面运用了 @Jiecha 注解。

    这个注解是我写的测试软件框架中定义的注解。

    package ceshi;
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Jiecha {
    
    }
    

    然后,我再编写一个测试类 TestTool 就可以测试 NoBug 相应的方法了。

    package ceshi;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    
    
    public class TestTool {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		NoBug testobj = new NoBug();
    		
    		Class clazz = testobj.getClass();
    		
    		Method[] method = clazz.getDeclaredMethods();
    		//用来记录测试产生的 log 信息
    		StringBuilder log = new StringBuilder();
    		// 记录异常的次数
    		int errornum = 0;
    		
    		for ( Method m: method ) {
    			// 只有被 @Jiecha 标注过的方法才进行测试
    			if ( m.isAnnotationPresent( Jiecha.class )) {
    				try {
    					m.setAccessible(true);
    					m.invoke(testobj, null);
    				
    				} catch (Exception e) {
    					// TODO Auto-generated catch block
    					//e.printStackTrace();
    					errornum++;
    					log.append(m.getName());
    					log.append(" ");
    					log.append("has error:");
    					log.append("\n\r  caused by ");
    					//记录测试过程中,发生的异常的名称
    					log.append(e.getCause().getClass().getSimpleName());
    					log.append("\n\r");
    					//记录测试过程中,发生的异常的具体信息
    					log.append(e.getCause().getMessage());
    					log.append("\n\r");
    				} 
    			}
    		}
    		
    		
    		log.append(clazz.getSimpleName());
    		log.append(" has  ");
    		log.append(errornum);
    		log.append(" error.");
    		
    		// 生成测试报告
    		System.out.println(log.toString());
    
    	}
    
    }
    
    

    测试的结果是:

    1234567890
    1+1=11
    1-1=0
    3 x 5=15
    chufa has error:
    
      caused by ArithmeticException
    
    / by zero
    
    NoBug has  1 error.
    
    

    提示 NoBug 类中的 chufa() 这个方法有异常,这个异常名称叫做 ArithmeticException,原因是运算过程中进行了除 0 的操作。

    所以,NoBug 这个类有 Bug。

    这样,通过注解我完成了我自己的目的,那就是对别人的代码进行测试。

    所以,再问我注解什么时候用?我只能告诉你,这取决于你想利用它干什么用。

    注解应用实例

    注解运用的地方太多了,因为我是 Android 开发者,所以我接触到的具体例子有下:

    JUnit

    JUnit 这个是一个测试框架,典型使用方法如下:

    public class ExampleUnitTest {
        @Test
        public void addition_isCorrect() throws Exception {
            assertEquals(4, 2 + 2);
        }
    }
    

    @Test 标记了要进行测试的方法 addition_isCorrect().

    ButterKnife

    ButterKnife 是 Android 开发中大名鼎鼎的 IOC 框架,它减少了大量重复的代码。

    public class MainActivity extends AppCompatActivity {
    
        @BindView(R.id.tv_test)
        TextView mTv;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            ButterKnife.bind(this);
        }
    }
    
    

    Dagger2

    也是一个很有名的依赖注入框架。

    Retrofit

    很牛逼的 Http 网络访问框架

    public interface GitHubService {
      @GET("users/{user}/repos")
      Call<List<Repo>> listRepos(@Path("user") String user);
    }
    
    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .build();
    
    GitHubService service = retrofit.create(GitHubService.class);
    
    

    当然,还有许多注解应用的地方,这里不一一列举。

    总结

    1. 如果注解难于理解,你就把它类同于标签,标签为了解释事物,注解为了解释代码。
    2. 注解的基本语法,创建如同接口,但是多了个 @ 符号。
    3. 注解的元注解。
    4. 注解的属性。
    5. 注解主要给编译器及工具类型的软件用的。
    6. 注解的提取需要借助于 Java 的反射技术,反射比较慢,所以注解使用时也需要谨慎计较时间成本。

    Java 反射机制中另外一个比较重要的概念就是动态代理了,写下这篇文章后,我一鼓作气,又写了这篇 《轻松学,Java 中的代理模式及动态代理》,有兴趣的同学可以一并阅读一下。

    最后致敬老罗和陈铭,拿你们的事例为博文主题提供论点,只是基于技术视角,并没有一丝恶意和冒犯之心。

    读者们都在下面的二维码所示的免费的知识星球问我问题:
    在这里插入图片描述

    展开全文
  • 如何迅速秒杀掉:99%的海量数据处理面试题

    万次阅读 多人点赞 2012-03-22 12:51:07
    如何迅速秒杀掉:99%的海量数据处理面试题作者:July出处:结构之法算法之道blog前言 一般而言,标题含有“秒杀”,“99%”,“史上最全/最强”等词汇的往往都脱不了哗众取宠之嫌,但进一步来讲,如果读者读罢...
  • 它还预测,到 2022 年底,拥有人工智能特性的智能手机将占到全球出货量的 80%,而这一数字在 2017 年只有 10%。在 Gartner 看来,由于数据的处理和存储过程是在本地进行,因而人工智能设备的普及意味着数据安全性和...
  • 当你想了解一个框架,造个轮子,不妨试试搜索 xxx-like 或者 xxx-like framework,中文便是 仿 react 框架 或者 类 react。如我们在 Google 上搜索 react-like 就会搜索到 inferno。不过,按 GitHub 的尿性,要搜索...
  • 离开了公司,还有什么

    万次阅读 多人点赞 2017-02-20 06:57:52
    当你离开了工作,当你离开了那个位置,还有什么?可以有什么?怎样才能有这些什么?
  • Visual Studio技巧之打造拥有自己标识的代码模板

    万次阅读 热门讨论 2010-06-21 09:10:00
    可能经过很多博客的介绍,大家都知道代码段的使用,使用代码段可以很方便地生成一些常用的代码格式,确实对我们开发很方便。在团队开发中或者在某些情况下我们经常可能还会希望使用Visual Studio生成的代码自动带有...
  • 手把手教写专利申请书/如何申请专利

    万次阅读 多人点赞 2008-12-10 10:46:00
    手把手教写专利申请书·如何申请专利   摘要 小前言 (一)申请前的准备工作  1、申请前查询  2、其他方面的考虑  3、申请文件准备 (二)填写专利申请系列文档  1、实际操作步骤  2、具体操作  3、经验...
  • 大家都知道,在Android项目当中,drawable文件夹都是用来放置图片资源的,不管是jpg、png、还是9.png,都可以放在这里。...但是如果现在使用Android Studio来新建一个项目,会发现有如下的目录结构:
  • 首先是一个人,然后才是程序员。

    万次阅读 多人点赞 2017-03-23 11:47:26
     看完这个,LZ忍不住乐了,过后还拿着手机忍不住给某璐璐炫耀了一番,“看,现在知道老公帅了吧,别人都问我如何保养皮肤了,说明我皮肤好啊。媳妇儿啊,说我怎么回答他呢?真有点不好意思呢,嘻嘻。”...
  • [转]关于寻路算法的一些思考

    千次阅读 2016-10-21 14:19:08
    关于寻路算法的一些思考
  • 一些感悟

    千次阅读 多人点赞 2021-01-16 14:11:15
    真正有才能的人一定是脚踏实地,有工匠精神,同时又敢于突破,不拘泥于自己世界的人。 真正NB的人是一个历尽千帆归来仍是少年。真正伟大的人是他拥有了我们平常人看来的一切物质的情况下,仍能保持那份初心的人。 ...
  • 发现新大陆!什么是图数据库以及简单入门!

    万次阅读 多人点赞 2018-01-17 21:16:24
    一、关系型数据库的不适性 在众多不同的数据模型里,关系数据模型自20世纪80年代就处于统治地位,而且出现了不少巨头,如Oracle、MySQL,它们也被称为:关系数据库管理...同时,互联网发展也产生了一些新的趋势变化:
  • MySQL安全不知道的事

    万次阅读 多人点赞 2020-11-30 11:35:49
    多得是,不知道的事
  • 写Android网络框架之请求配置与Response缓存

    千次阅读 多人点赞 2015-01-27 14:21:03
    在教写Android网络框架的前三篇文章中,我们从基本结构到代码实现,剖析了一个简单的网络框架应该是怎样运作的,以及在面对各式各样的需求时应该如何对代码做出处理,在深入了解网络框架的同时学习到一些简单的...
  • 如果也23岁

    万次阅读 多人点赞 2014-10-15 14:01:21
    23 岁那年正处在哪个状态?现在呢?  我,23岁,应届毕业生。生活,工作,爱情都处于人生的低谷,一穷二白,一无所有,一事无成。 分享一下成长的建议吧。 匿名用户 23岁那年...就是去年......  在22岁的时候...
  • 本文所讲的代币是使用以太坊智能合约创建,阅读本文前,应该对以太坊、智能合约有所了解,如果还不了解,建议先看以太坊是什么 代币Token 如果不那么追求精确的定义,代币就是数字货币,比特币、以太币...
  • 请自己确实有需要的时候再去买,或者是像答主这样real很喜欢把东西贴在墙上或者窗户上提醒自己的 girl~~ 8.  Muji 卸妆棉签 一边尖头一边圆头, 且含有足量的卸妆液。 我当年化眼线总手抖的年代,它...
  • 区块链:一个故事告诉比特币的原理及运作机制

    万次阅读 多人点赞 2017-04-12 11:26:54
    一个故事告诉比特币的原理及运作机制推荐:《人工智能:法国浪漫之都的人工智能时代》《 花非花,物非物,AI岂是池中物(人工智能篇)》《致我们的青春,一个敬礼》周末花时间看了一些比特币原理相关的资料,虽然不...
  • Web Components 是个什么样的东西

    万次阅读 2016-08-31 11:01:33
    React 的components 等等,无一不是前端组件化的一种实现和探索,但是提上议程的 Web Components 标准是个怎样的东西,相关的一些框架或者类库,如 React,Angular2,甚至是 x-tag,polymer 现在实
  • 轻松学,听说还没有搞懂 Dagger2

    万次阅读 多人点赞 2017-07-20 22:14:00
    本文的目的尝试用比较容易理解的角度去解释 Dagger2 这样东西。 Dagger2 是有门槛的,这样不同水平能力的开发者去学习这一块的时候,感受到的压力是不一样的。 我个人总结了大家在学习 Dagger2 时,为什么感觉...
  • 正则表达式到底是什么东西??

    万次阅读 多人点赞 2012-07-02 14:01:12
    30分钟内让明白正则表达式是什么,并对它有一些基本的了解,让可以在自己的程序或网页里使用它。 如何使用本教程 最重要的是——请给我30分钟,如果没有使用正则表达式的经验,请不要试图在30秒内...
  • 一个应用程序当中通常都会包含很多个Activity,每个Activity都应该设计成为一个具有特定的功能,并且可以让用户进行操作的组件。...打个比方,如果的应用希望去发送一封邮件,就可以定义一个具有"send"动作
  • 动画制作只需要拥有这几款工具! 原创Amazing10业余码农 目录 大公开!动画制作只需要拥有这几款工具! 1PPT /Keynote 2Synifg Studio 3Adobe Animate 4FlipaClip 53DSMax / Maya / C4D / Blender 6总结 ...
  • 对LSTM和BLSTM的一些理解

    万次阅读 多人点赞 2018-07-01 14:49:58
    Recurrent Neural Networks 我们思考一件事情的时候,我们不会将所有以前的东西都全部丢弃,然后用空白的大脑进行思考,人类的思想拥有持久性。考虑这样一个问题,我们与他人交谈时,我们想要预知这个人接下来...
  • 漫谈程序员系列:的幸运女神呢

    千次阅读 多人点赞 2015-03-09 07:37:45
    程序员的转运宝典,幸运女神倚门盼来……
  • 网上找的好东西

    万次阅读 2010-05-21 13:30:00
    copy 路径/文件名1 路径/文件名2 /y 复制文件1到指定的目录为文件2,用参数/y就同时取消确认要改写一份现存目录文件 copy c:/srv.exe //ip/***$ 复制本地c:/srv.exe到对方的***下 cppy 1st.jpg/b+2st.txt...
  • 真的需要掌握多种编程语言吗?

    万次阅读 多人点赞 2016-08-17 16:25:11
    总有一些东西值得学习;有时候,这意味着要更深入地学习一种语言。 大多数情况下,专家能提更高的薪资要求,因为人们更愿意为专家支付更多的薪水。John Sonmez 在其视频《 I’m Not Sure I Want To Be A ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 222,612
精华内容 89,044
关键字:

当你拥有一些东西的同时