java游戏设计教程中判断按键精灵颜色判断语句是否在屏幕中

java可以不可以像按键精灵一样,将一个程序的窗口移动到指定屏幕的坐标?如果可以,求关键代码。_百度知道
java可以不可以像按键精灵一样,将一个程序的窗口移动到指定屏幕的坐标?如果可以,求关键代码。
游戏点得累,脚本大师取色判断用不好,想试试java
提问者采纳
2 标准扩展,则 X-Window系统会抛出异常,其中是这样介绍的。例如,那么试图构造 Robot 对象时将抛出AWTException。如果当前平台配置不允许使用输入控件,请查看Java的API。出于自测试之外的目的而使用 Robot 的应用程序应妥善处理这些错误条件、自运行演示程序和其他需要控制鼠标和键盘的应用程序生成本机系统输入事件。注意,而不是只生成鼠标移动事件,某些平台需要特定权限或扩展来访问低级输入控件,Robot。Robot 的主要目的是便于 Java 平台实现自动测试。例如,有一个类叫做Robot:事件是在平台的本机输入队列中生成的。使用该类生成输入事件与将事件发送到 AWT 事件队列或 AWT组件的区别在于:public class Robotextends Object此类用于为测试自动化,我只能提供一条路子这个的话,如果 X 服务器不支持(或没有启用)XTEST 2。从以下版本开始.mouseMove将实际移动鼠标光标
提问者评价
来自团队:
其他类似问题
为您推荐:
按键精灵的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁当前访客身份:游客 [
主职打羽毛球,平时无聊写写代码~~~
:确实有效,非常感谢分享
:不支持乘方肿么破...
:那么后续的连接就会从线程池里取(或创建)。那么...
:restlet 怎么获取客户端的IP啊?大神帮帮忙吧!...
:Map显性指定, Map mm=new HashMap&Integer, Int...
:运行的时候 restlet一直无法响应,为什么?
:这事因为什么呢\?libevent配置的路径不对吗?...
今日访问:5
昨日访问:45
本周访问:97
本月访问:523
所有访问:191156
列表模式: |
什么是JIT?
JIT是just in time,即时编译技术。使用该技术,能够加速java程序的执行速度。下面,就对该技术做个简单的讲解。
首先,我们大家都知道,通常javac将程序源代码编译,转换成java字节码,JVM通过解释字节码将其翻译成对应的机器指令,逐条读入,逐条解释翻译。很显然,经过解释执行,其执行速度必然会比可执行的二进制字节码程序慢。为了提高执行速度,引入了JIT技术。
在运行时JIT会把翻译过的机器码保存起来,已备下次使用,因此从理论上来说,采用该JIT技术可以,可以接近以前纯编译技术。下面我看看,JIT的工作过程。
JIT 编译过程
当JIT编译启用时(默认是启用的),JVM读入.class文件解释后,将其发给JIT编译器。JIT编译器将字节码编译成本机机器代码,下图展示了该过程。
什么是JIT?
JIT是just in time,即时编译技术。使用该技术,能够加速java程序的执行速度。下面,就对该技术做个简单的讲解。
首先,我们大家都知道,通常javac将程序源代码编译,转换成java字节码,JVM通过解释字节码将其翻译成对应的机器指令,逐条读入,逐条解释翻译。很显然,经过解释执行,其执行速度必然会比可执行的二进制字节码程序慢。为了提高执行速度,引入了JIT技术。
在运行时JIT会把翻译过的机器码保存起来,已备下次使用,因此从理论上来说,采用该JIT技术可以,可以接近以前纯编译技术。下面我看看,JIT的工作过程。
JIT 编译过程
当JIT编译启用时(默认是启用的),JVM读入.class文件解释后,将其发给JIT编译器。JIT编译器将字节码编译成本机机器代码,下图展示了该过程。
通过上面的解释,我们了解了JIT的工作原理及过程,同样也发现了个问题,由于JIT对每条字节码都进行编译,造成了编译过程负担过重。为了避免这种情况,当前的JIT只对经常执行的字节码进行编译,如循环等。
需要说明的是,JIT并不总是奏效,不能期望JIT一定能够加速你代码执行的速度,更糟糕的是她有可能降低代码的执行速度。这取决于你的代码结构,当然很多情况下我们还是能够如愿以偿的。
发布于 6年前,
阅读(614) | 评论(0) |
投票(0) | 收藏(0)
重要神仙表
> 盘古氏-又称元始天王,一名,浮黎元始天尊。
> 元始天尊
> 灵宝天尊 又名太上道君
> 道德天尊 又名太上老君(西游记里也称为太上道祖)
> 中央玉皇大帝 妻:王母娘娘,又称为 西王母
> 北方北极中天紫微大帝
> 南方南极长生大帝,又名玉清真王,为元始天王九子。
> 东方东极青华大帝太乙救苦天尊
> 西方太极天皇大帝 (手下:八大元帅,五极战神(天空战神,大地战神,人中战神,
> 北极战神和南极战神))
> 大地之母:承天效法后土皇地祗
> 五方五老:
> 南方南极观音
> 东方崇恩圣帝
> 三岛十洲仙翁东华大帝君(即东王公,名”金蝉氏”,号木公)
> 北方北极玄灵斗姆元君(佛教中二十诸天的摩利支天)
> 中央黄极黄角大仙
> 中央天宫仙位表
> 千里眼 | 顺风耳 | 金童 | 玉女 | 雷公 | 电母(金光圣母) | 风伯 | 雨师 | 游奕灵官 | 翊圣真君 | 大力鬼王 | 七仙女 | 太白金星 | 赤脚大仙 | 广寒仙子(姮娥仙子)嫦娥 | 玉兔 | 玉蟾 | 吴刚 | 天蓬元帅 | 天佑元帅 | 九天玄女 | 十二金钗 | 九曜星 | 日游神 | 夜游神 | 太阴星君 | 太阳星君 | 武德星君 | 佑圣真君 | 托塔天王李靖 | 金吒 | 木吒(行者惠岸) | 三坛海会大神哪吒 | 巨灵神 | 月老 | 左辅右弼 | 二郎神杨戬 | 太乙雷声应化天尊王善王灵官 | 萨真人 | 紫阳真人(张伯端) | 文昌帝君 | 天聋 | 地哑
> 三官大帝: 天官 | 地官 | 水官
> 四大天王: 增长天王、持国天王、多闻天王与广目天王
> 四值功曹: 值年神李丙 | 值月神黄承乙 | 值日神周登 | 值时神刘洪
> 四大天师: 张道陵、许逊(字敬之,号许旌阳)、邱弘济、葛洪
> 四方神: 青龙孟章神君、白虎监兵神君、朱雀陵光神君、玄武执明神君。
> 四渎龙神: 黄河 | 长江 | 淮河 | 济水河神
> 马赵温关四大元帅:
> 马元帅 又名马天君,又称华光天王、华光大帝
> 赵元帅 即武财神赵公明,又名赵玄坛
> 温元帅 温琼,东岳大帝部将
> 关元帅 关羽。
> 五方谒谛:金光揭谛、银头揭谛、波罗揭谛、波罗僧揭谛、摩诃揭谛
> 五炁真君:东方岁星木德真君 | 南方荧惑火德真君 | 西方太白金德真君 | 北方辰星水德真君 | 中央镇星土德真君
> 五岳 :东岳泰山天齐仁圣大帝 南岳衡山司天昭圣大帝 中岳嵩山中天崇圣大帝 北岳恒山安天玄圣大帝 西岳华山金天愿圣大帝 (五岳帝君:东岳帝君,名金虹氏,东华帝君弟。其它四岳帝君为东华帝君的四个儿子。) 及 碧霞元君
> 五斗星君: 东斗星君 | 西斗星君 | 中斗星君 | 南斗星君 | 北斗星君
> 六丁六甲: 六丁为阴神玉女 | 丁卯神司马卿 | 丁已神崔巨卿 | 丁未神石叔通 | 丁酉神臧文公 丁亥神张文通 | 丁丑神赵子玉 | 六甲为阳神玉男 | 甲子神王文卿 | 甲戌神展子江 | 甲申神扈文长 | 甲午神卫玉卿 | 甲辰神孟非卿 | 甲寅神明文章
> 南斗六星君
> 第一天府宫:司命星君
> 第二天相宫:司禄星君
> 第三天梁宫:延寿星君
> 第四天同宫:益算星君
> 第五天枢宫:度厄星君
> 第六天机宫:上生星君
> 北斗七星君:(《狮驼国》中的北天七皇)
> 北斗第一阳明贪狼星君
> 北斗第二阴精巨门星君
> 北斗第三真人禄存星君
> 北斗第四玄冥文曲星君
> 北斗第五丹元廉贞星君
> 北斗第六北极武曲星君
> 北斗第七天关破军星君
> (《狮驼国》中的北斗七星君为北斗星君的另一个称号:天枢、天璇、天玑、天权、玉衡、开阳、摇光。”天枢、天璇、天玑、天权”合起来又称为”斗魁”或”璇”,后三星组成斗柄,称”杓”
> 八仙: 铁拐李、汉钟离、吕洞宾、何仙姑、蓝采和、韩湘子、曹国舅、张果老
> 增长天王手下八将:庞刘荀毕、邓辛张陶,其全名为刘俊、荀雷吉、庞煜、毕宗远;邓伯温、辛汉臣、张元伯、陶元信(四目)
> 九曜星 金星 | 木星 | 水星 | 火星 | 土星 | 罗睺(蚀星) | 计都星 | 紫炁星 | 月孛星
> 十二元辰 子丑寅卯等
> 二十八星宿 :亢金龙、女土蝠、房日兔、心月狐、尾火虎、箕水豹、斗木獬、 牛金牛、氐土貉、虚日鼠、危月燕、室火猪、壁水獝、奎木狼、 娄金狗、胃土彘、昴日鸡、毕月乌、觜火猴、参水猿、井木犴、 鬼金羊、柳土獐、星日马、张月鹿、翼火蛇、轸水蚓。
> 三十六天将
> 蒋光 | 钟英 | 金游 | 殷郊 | 庞煜 | 刘吉 | 关羽 | 马胜 | 温琼 | 王善 | 康应 | 朱彦 | 吕魁 | 方角 | 耿通 | 邓伯温 | 辛汉臣 | 张元伯 | 陶元信 | 荀雷吉 | 毕宗远 | 赵公明 | 吴明远 | 李青天 | 梅天顺 | 熊光显 | 石远信 | 孔雷结 | 陈元远 | 林大华 | 周青远 | 纪雷刚 | 崔志旭 | 江飞捷 | 贺天祥 | 高克 (三十六天将的版本是最多,以上仅供参考)
> 地上天仙表
> 姜子牙(亦为东华帝君,估计是木公> 的接班人)
> 蓬莱三仙:
> 福禄寿三星,福神天官大帝,另一说是西汉杨成,又一说中是唐阳城;财神赵公明、(一说比干范蠡为文财神);寿星南极仙翁,女寿星:麻姑
> 真武大帝,又名九天降魔祖师、玄武元帅。
> 龟蛇二将(又名太玄水精黑灵尊神、太玄火精赤灵尊神)
> 小张太子与五大神龙
> 黎山****、镇元子
> 龙王:东海龙王敖广 | 南海龙王敖钦 | 西海龙王敖闰 | 北海龙王敖顺 | 井海王
> 神霄派诸神
> 紫微北极大帝
> 玉清真王(南极长生大帝)--元始天王第九子
> 神霄八帝(多为道教虚构),玉清真王与神霄八帝合起来又称为神霄九宸大帝
> 东极青华大帝、九天应元雷声普化天尊(黄帝)、九天雷祖大帝等。
> (太乙天帝、六天洞渊大帝、六波天主帝君、可韩真君、采访真君)
> 九司三省与北极四圣
> 九司:玉府判府真君、玉府左右待中、玉府左右仆谢、天雷上相、玉枢使相、
> 斗枢上相、上清司命玉府右卿、五雷院使君、雷霆都司元命真君
> 三省:雷霆泰省、雷霆玄省、雷霆都省
> 北极四圣: 天蓬元帅(猪八戒) 手下天罡大圣、九天杀童大将(北斗第八星,又称天杀大神)、
> 雷使者等。
> 天佑(猷)元帅
> 翊圣元帅
> 玄武元帅 真武大帝
> 另有:五方雷王、五方雷霆大帝
> 阴曹地府
> 北阴酆都大帝
> 五方鬼帝:
> 东方鬼帝蔡郁垒、神荼,治\”桃止山-:special:1:- 鬼门关
> 西方鬼帝赵文和,王真人,治-:special:1:-嶓冢山-:special:1:-
> 北方鬼帝张衡、杨云,治罗酆山;
> 南方鬼帝杜子仁,治罗浮山;
> 中央鬼帝周乞、稽康,治-:special:1:-抱犊山-:special:1:-
> 罗酆六天以下为宫名,六天为守宫神)
> 纣绝阴天宫、泰煞谅事宗天宫、明晨耐犯武城天宫、
> 恬昭罪气天宫、宗灵七非天宫、敢司连宛屡天宫
> 地藏菩萨
> 十殿阎王:秦广王、楚江王、宋帝王、仵官王、阎罗王、
> 平等王、泰山王、都市王、卞城王、转轮王
> 其这将、臣:
>   首席判官崔府君、钟魁、黑白无常、牛头马面、孟婆神、
> 上古神话诸神
> 混沌天神--较正式的说法,盘古为开天辟地之始神,但仍有部分传说中,混沌早于盘古
> 天吴、毕方、据比、竖亥、烛阴、女娲
> 上古四方天帝与辅神:
> 太阳神炎帝与火神祝融共同治理天南一万二千里的地方
> 少昊与水神共工建立天西一万二千里的地方
> 颛顼与海神禺强(又名冬神玄冥)治理天北一万二千里的地方
> 青帝伏羲与九河神女华胥氏及属神句芒治理天东一万二千里的地方
> 黄帝时代的诸神
> 陆吾、英招、离珠、金甲神(此神应是其它神的一种化身说,根据他我虚拟了狮驼国中的金甲雷神)
> 蚩尤、风伯雨师、赤松子、力牧、神皇、风后、应龙、魃、夸父、大力神夸娥氏、大庭氏、五龙氏
> 炎帝,又称为神农氏
> 炎帝的女儿
> 女娃(后化身精卫鸟)
> 瑶姬,在《狮驼国》中又名婉华仙子。
> 还有一个小女儿,其名不可考,(拙著《狮驼国》中为炎天圣母)
> 少昊母为皇娥、长子春神句芒、次子秋神蓐收
> 颛顼的后代
> 四子:虐鬼、魍魉、送穷鬼、梼杌
> 后代:老童、太子长琴、黎、重、彭祖(孙)
> 天上妻子:羲和、常羲
> 人间妻子(省略)
> 女丑、羿
> 鲧 妻:女喜。
> 尧 又名:放勋, 妻女皇;
> 舜 姓姚,名重华,妻娥皇,女英;
> 禹,父鲧,妻”女娇”,又名涂山氏,系九尾白狐精
> 指天地人三皇,分别是伏羲、神农与女娲。
> 通常指 黄帝 | 颛顼 | 帝喾 | 尧 | 舜
> 其它--后天著名仙真表
> 房中之祖--彭祖 | 纵横始祖--鬼谷子 | 文始真人--尹喜 | 南华真人--庄子 | 求仙使者--徐福 | 茅山仙祖--三茅真君 | 万古丹王--魏伯阳 | 太极真人--刘安 | 诙谐岁星--东方朔 | 太平教主--于吉 | 役使鬼神--费长房 | 竹林狂士--嵇康 | 水府仙伯--郭璞 | 净明教主--许逊 | 蓬莱(都)水监--陶弘景 | 天师--寇谦之
> 情仙--裴航 | 扶摇子--陈抟 | 显化真人--张三丰 | 王重阳与全真七子(长春子丘处机、玉阳子王处一、广宁子郝大通、 清净散人孙不二、长生子刘处玄、长真子谭处端、丹阳子马钰)
> 其它--民间神灵不完全列表
> 天妃娘娘 | 城隍 | 土地神 | 门神 秦叔宝、尉迟敬德 | 床神(又分床公床母,前者又称-:special:1:-九天监生明素真君-:special:1:-,后者又称-:special:1:-九天卫房圣母天君-:special:1:-)| 喜神 | 厕神紫姑 | 石敢当 | 小儿神项橐 | 朱天大帝崇帧 | 茶神陆羽 | 花神 | 染织二圣梅、葛 | 酒神杜康 | 土工祖师神鲁班 | 纺织神黄道婆 | 蚕神马头娘(山海经载为西陵氏,嫘祖) | 狱神皋陶 | 梨园神唐明皇 | 马神 | 青蛙神白玉蟾 | 驱蝗神刘猛(取猛将军之意) | 蛇王施相公(施全) | 痘神张帅 | 农神后稷 |
> 瘟神:又称五鬼或五方力士,人间又有称五瘟,其中春瘟张元伯、夏瘟刘元达、秋瘟赵公明、冬瘟钟士贵、总管中瘟史文业。 | 窑神太上老君 | 贼神时迁 | 穷神 | **神管仲 | 武穆> 王岳飞 | 周公、桃花女 | 欢喜神和合二仙寒山、拾得
> 纯本书虚构主要仙魔表
> 太古猿君 | 魔佛老人 | 千面天妖 | 地心古龙 | 圣手仙王 | 圣手文王 | 天罗王(道教中为三清的一种化身) |乾坤大仙 | 颠倒老祖 | 穹天老祖 | 先天老祖 | 无极老祖 | 无为老祖 | 霹雳老祖 | 藤祖 | 幻仙子 | 清弥天诸神 | 阴阳法王 |毒龙山千毒沼沼底---蟒神(有双翼)| 南海深处一千里以下的---海皇(章鱼怪);
> 兽帝(九蛇头加龟背)(九婴与相柳借天地交合之气所造怪物)
> 霸王(长白山天池的箭恐龙) | 天子梼杌(颛顼之子,住在北方玄冰宫)| 不坏林王狻猊(住在南方热带密林中,身坚胜铁,刀枪不入)
> 平天大圣牛魔王 | 覆海大圣蛟魔王 | 移山大圣狮驼王 | 驱神大圣野象王 | 浑天大圣鹏魔王 | 通风大圣弥猴王 | 齐天大圣美猴王
> 西天灵山仙佛表
> 三世佛:南无过去、现在、未来 注:通常三世佛分横三世佛与竖三世佛。
> 竖三世佛:
> 过去佛的燃灯上古佛,加上现在世的释迦佛(原名:悉达多),以及未来
> 世的弥勒佛
> 横三世佛:
> 中间是释迦牟尼佛,右有文殊菩萨,左立普贤菩萨;
> 右边是西方极乐世界的阿弥陀佛,两旁是观世音菩萨和大势至菩萨;
> 左边为东方净琉璃世界的药师佛,两旁日光菩萨和月光菩萨。
> (因都有如来在,所以本文中就不增加三世佛这个名词.西游原著里,提
> 及了南无过去现在未来佛,本书中称之为三世佛。)
> 四大金刚:
> 五台山秘魔岩神通广大泼法金刚
> 峨眉山淸凉洞法力无量胜至金刚
> 须弥山摩耳崖毗卢沙门大力金刚
> 昆仑山金雫岭不坏尊王永住金刚
> 东方不动(身)佛;南方宝生佛;中央毗卢遮那佛;西方阿弥陀佛;北方不空成就佛。
> 八菩萨:
> 观音菩萨、普贤菩萨、文殊菩萨、地藏王菩萨、灵吉菩萨、大势至菩萨、日光菩萨、月光菩萨
> 十大弟子:
>   舍利弗智慧第一 | 目犍连神通第一 | 阿难陀多闻第一 | 优波离持戒第一
>   阿那律天眼第一 | 大迦叶头陀第一 | 富楼那说法第一 | 迦旃延论议第一
>   罗睺罗密行第一 | 须菩提解空第一
> 十八罗汉:
> 托塔罗汉 | 探手罗汉 | 过江罗汉 | 芭蕉罗汉 | 静座罗汉 | 骑象罗汉 | 看门罗汉 | 降龙罗汉 | 举钵罗汉 | 布袋罗汉 | 长眉罗汉 | 开心罗汉 | 喜庆罗汉 | 挖耳罗汉 | 笑狮罗汉 | 伏虎罗汉 | 沉思罗汉 | 骑鹿罗汉 |
> 十八伽蓝
> 美音 | 梵音 | 天鼓 | 叹妙 | 叹美 | 摩妙 | 雷音 | 师子 | 妙叹
> 梵响 | 人音 | 佛奴 | 颂德 | 广目 | 妙眼 | 彻听 | 彻视 | 遍视
> 二十诸天:
> 日天(又名日宫天子)| 大梵天 | 多闻天 | 金刚密迹 | 鬼子母神;
> 月天 (又名月宫天子) | 帝释天 | 持国天 | 大自在天 | 摩利支天;
> (大)辩才天 | (大)功德天 | 增长天 | 散脂大将 | 婆竭龙王;
> 韦驮天(战神塞犍陀) | 坚牢地神 | 广目天 | 菩提树神 | 阎摩罗王。
> 金顶大仙、阿傩、伽叶。
> 婆罗门教诸神
> 佛祖摩诃婆罗佛与婆罗三世佛(此四佛全部为虚构、以下人名为与如来有关的仙、人)
> 频婆娑、阿罗蓝、郁陀、提婆达多
> 主要大神:大梵天、湿婆楼陀罗、雪山女神杜尔迦、群主
> 婆罗八部(婆罗门天龙八部)-(婆罗八部为虚构,以下诸神为印度创世诸神)
>   水神伐楼那 | 土神陀湿多 | 风神伐由 | 日神苏里耶 | 天帝因陀罗
> 道神普善 | 保护神毗湿奴 | 阿修罗:底提耶与檀那婆 | 火神婆由
为了你的电脑安全,请只打开来源可靠的网址。打开网址 取消
此链接转自手机浏览器,可能无法打开。打开网址 取消
发布于 6年前,
阅读(630) | 评论(2) |
投票(0) | 收藏(3)
我们平时所玩的很多游戏都有着非常绚丽的动画效果,尤其是像ACT、RPG等类型的游戏,必须拥有华丽的魔法和攻击效果才能吸引玩家的眼球。本文将主要介绍如何使用OPhone API以及动画编辑器类的工具来编辑、绘制和处理精灵的动画,整个程序的运行效果如下图所示:
图1 游戏最终效果
我们都看过动画片,看过电影,玩过游戏,里面都有各种绚丽的动画,实际上动画的绘制机制概括说来就是以一定的速度连续播放静态的图片,这样人眼就能识别出动画。一般我们人眼能够分辨的动画速度为10——20帧/秒,我们称之为FPS(Frame Per Second),低于10帧就会变得很卡,高于20就会变成快动作,因此,控制好这个数值对游戏整体的流畅度至关重要。
那么总结起来,要想在游戏中绘制动画需要具备以下几个必要元素:
1. 动画的原始图片
2.动画序列数据
3.动画刷新机制(下一帧)
常规的动画播放方法
1.实现第一步(动画的原始图片)
常规的播放2D动画方法的方法实际就是对上述过程的一个分解:在游戏中,精灵的图片经常是被放置到一张图片上,下图就是一个典型的2D游戏精灵图片:
图2 角色原始图片
2.实现第二步(设定动画序列)
有了原始图片之后,我们就可以把这些图片按照一定的尺寸进行分割,切割成的每个块我们称之为“帧”,同时为每一帧进行编号,为每帧分配唯一的索引号,索引号可以从任意数字开始,可连续也可以随机,但要注意不能有重复的索引号,分配好的索引号可参照下图所示:
表1 游戏帧序列
有了这个索引,我们就可以为每个动画设定动画序列了,比如,我们可以分别定义精灵的上、下、左、右行走的动画序列,每个动画的序列如下面代码所示:
final static int ACTION_UP[]={0,1,2};
final static int ACTION_DOWN[]={6,7,8};
final static int ACTION_LEFT[]={9,10,11};
final static int ACTION_RIGHT[]={3,4,5};
final static int ACTION_STAND[]={7};
数组中的每个元素值就是上面表格中的数值。
3.实现第三步(切换并播放动画)
 由于所有的图片块都被放置到了一个数组中保存起来,因此有个动画数据之后,我们就可以把数据所对应的图片绘制到屏幕上了,然后,通过线程来控制一帧一帧的切换,这就是游戏中动画处理的一般过程。
上面这种播放动画的方式的优点是开发简单,便于切换和控制,但是也有如下的一些缺点:
  1.存在重复的图片资源
我们可以从原始图片上看到,如果要实现精灵向下走的动画,需要使用4帧图片,但是这4帧图片中只有精灵脚步的图片存在差异,剩下的都大致相同,这就是一种图片上的浪费。而我们的手机内存目前还比较小,因此这种浪费应该是要尽量避免的。
  2.动画数据直接存在于代码中
上面的例子中,我们直接把动画的序列以数组的形式保存到了代码中,也就是说,把对动画数据的处理交给了程序员来完成,而程序员的主要工作应该是处理游戏中的算法逻辑,因此,比较好的解决方法是把动画的处理交给美工和策划来完成。因此,上面这种方法也存在缺点。
  3.帧图片要求规整
如果采用上面的方法绘制动画,要求每一帧必须按照指定的长度和宽度进行分割,否则就是出现绘制错误,这在一定程度上也限制了程序的灵活性。
  4. 难易实现复杂的动画效果
由于帧的尺寸人为的被限定,同时每一个动作就必须要一帧进行显示,如果要想实现复杂的动画序列就意味着要存在大量的帧序列,而原始图片势必要随之变得很大,进而增加了对内存的占用,而在这种情况下,帧数越多,重复的内容也会随之不断增多,显然这也不适合手机这种资源有限的设备的特点。
上面说了这些缺点,那么该如何解决呢?下面就为你介绍一下目前比较流行的一种动画处理方式,也是本文的重点——使用动画编辑工具。
李建,乐成数字通信学院 高级讲师。层就职于国内数家SP,CP公司,具有丰富的软件、游戏开发经验。并从事多年教学工作,具有丰富的教学经验。目前主要从事OPhone、J2ME开发和教学方面的工作。
动画编辑器的原理
动画编辑器就是一种软件工具,它的作用就是通过软件对原始图片进行切割,然后在软件中把切割好的图片块拼成一帧一帧的图片,再选择相应的图片来组成动画序列,最后将数据导出以文件。
动画编辑器的使用
目前,很多的手机游戏公司都在使用动画编辑器来制作动画,而不同的公司使用的工具也不尽相同,下图为一个功能比较强大且使用很广泛的动画编辑工具,界面如下图所示:
图3 动画编辑器界面
接下来我将一步一步的演示如何使用这个工具来制作动画:
首先要建立一个工程,这个同时点击“”按钮引入一张图片,如下图:
图4 角色原始图片
从图中我们看到,原始图片不再是规则的帧序列,精灵图片被一块块的分解了。
下面我们要对图片进行分割了,选中左边栏的“”,然后在图片上进行切割,把乌龟的各个零部件都用方块圈出来,最后的效果如下图:
图5 分割原始图片
接下来就可以用这些“零件”拼图了。首先我们在右上方的窗口中点击“”按钮,接下来就可以看到右侧窗口变成如下图所示的界面:
图6 frame窗口
接下来双击上图中的“1-Frame”,就会出现如下图所示界面:
图7 拼图界面
接下来你就可以在左边的窗口中按住鼠标左键选择你要的乌龟的零部件图片并将其拖入右边窗口的坐标系中,一般将其放置到第一象限,一个拼好的帧图片如下图所示:
图8 帧的拼图
在拼图中,你可以使用左边的一些按钮来实现各个图块的位置和对齐,如图:
图9 布局排列按钮
可以点击“”来回到帧列表界面,同时可以使用“”按键增加新的帧。按照上述方法可以拼出乌龟的上、下、左、右行走等各个帧序列,拼好的效果如下图:
图10 拼好的各个帧
有了帧图片就可以利用它们来组成动画了,方法如下:
菜单中选择“Action——Edit”,效果如下图:
图11 增加动画
图12 动画编辑界面
接下来在“Action Edit”窗口中通过“”按钮增加一个动画,然后就可以从Frame列表中选择相应的帧来组成相应动画了,如下图所示:
图13 设置动画
这样我们就制作好了一个乌龟向下行走的动画,同时你可以点击“”按钮来观察这个动画,并根据效果对动画进行调整,非常方便。
现在我们已经完成了整个动画的制作过程,下面就要将数据进行导出,过程如下图所示:
图14 导出数据
上面介绍了如何使用动画编辑器来设定动画,相信你已经掌握了这个工具的使用了。但是,用这个工具制作的动画并不能直接显示到手机屏幕上,还需要我们通过代码的方式来对其进行处理。下面来介绍一下如何通过代码来绘制响应的动画。
动画播放类——Animation的实现:
要想实现对动画的播放必须要有一个动画的解析类,也就是需要对“.sprite”数据文件进行解析,这里我们将这个类命名为SpriteX,这个类的作用是解析数据文件并提供动画的绘制方法,因该类内容较多,此处没有贴出源代码,请参考附件。
精灵类——Role的实现
每个精灵类都需要有个SpriteX类的对象用来处理该精灵的动画,因此需要在这个类中定义如下属性:
精灵类的构造方法如下:
public Role(GameView view)
spx=new SpriteX("s.sprite",R.drawable.a2,view);
这里面的“view”为视图类的对象,稍后会有介绍。
注意:精灵图片需要放置到“res/drawable”文件夹,动画数据要放到“assets”文件夹下面。
精灵类的绘制方法如下:
public void paint(Canvas g)
spx.paint(g,100,100);
spx.nextFrame();
设计屏幕类
定义好精灵类只是实现了这个项目的第一步,我们还不能在屏幕上看到精灵的动画,我们需要一个视图来把精灵显示出来,接下来我们定义视图类,在这里我们自定义一个类GameView来实现这个功能。作为一个自定义的视图类,这个类需要继承View,关于这个类请参考api文档。这个类用来处理精灵的绘制,按键处理等功能。其构造方法如下:
public GameView(Context view)
super(view);
gamePaint = new Paint();
player=new Role(this);
// 建立线程
Thread t = new Thread(this);
t.start();
精灵对象创建完毕后,我们就可以将其绘制到屏幕上了,这里需要重写View类中的onDraw()方法,此方法会在该类对象被Activity调用时自动调用,其方法如下:
protected void onDraw(Canvas g)
role.draw(gamePaint);
动画的刷新
在GameView类中需要处理动画的刷新,也就是每隔一段时间来播放动画的下一帧,因此我们用线程来实现这个功能,线程的run方法如下所示:
public void run()
while (true)
// 放慢速度
long bm = System.currentTimeMillis();
// 更新屏幕
postInvalidate();
long cm = System.currentTimeMillis();
if (cm - bm & SPLASH_RATE)
Thread.sleep(SPLASH_RATE - (cm - bm));
} catch (InterruptedException e)
e.printStackTrace();
在这里要注意给线程适当的休眠时间,用来控制FPS,这样有利于得到更好的游戏体验。
注意:SPLASH_RATE就是每个线程的间隔时间
定义Activity
最后我们定义一个Activity的子类用来运行该游戏,在Activitiy中我们需要创一个GameView对象,然后通过setContentView()方法进行设定,代码如下:
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
view=new GameView(this);
setContentView(view);
到此,我们已经完成了所有的功能,你可以运行模拟器并观察其效果了。
使用动画编辑工具的方法可以非常方便的开发复杂的动画效果,尽可能的节约有限的内存资源并且使程序员和策划、美工的工作相分离,是现在手机端2D游戏开发普遍采用的一种高效、方便的方法。
发布于 6年前,
阅读(1346) | 评论(0) |
投票(0) | 收藏(2)
在开源面向对象数据库
系列文章的第 1 部分: 中,作者介绍了 db4o 的历史和现状,应用领域,以及和 ORM 等的比较; 在第 2 部分:中, 作者介绍了 db4o 的三种不同的查询方式:QBE、SODA 以及 Native Queries,并分别通过这三种不同的途径实现了两个关联对象的查询。
前面我们已经介绍了如何在 db4o 中查询以及添加对象,在本文中我们将会向您介绍在 db4o 中如何对对象进行更新以及删除操作。
我们来设想这样的场景:一位名叫“张三”的人买了车,并上好了牌照(如本系列第二部分之代码),而他基本信息的地址并不详细,只写了“成都市”,在一次主管部门检查此人信息的时候,发现了这个问题,并立即着手修改。
在 db4o 中,我们这样来实现对这个用户信息的修改():
& & & & & & & & & & & & & & & &
import bo.P
import com.db4o.Db4o;
import com.db4o.ObjectC
import com.db4o.ObjectS
import com.db4o.query.P
public class DB4OTest{
& & & & public static void main([] args){
& & & & & & & & //打开数据库
& & & & & & & & ObjectContainer db = Db4o.openFile(&auto.yap&);
& & & & & & & & try{
& & & & & & & & & & & & ObjectSet&People& result = db.query(new Predicate&People&() {
& & & & & & & & & & & & & & public boolean match(People people) {
& & & & & & & & & & & & & & & & return people.getName().equals(&张三&);
& & & & & & & & & & & & & & }
& & & & & & & & & & & & });
& & & & & & & & & & & & People people = result.next();
& & & & & & & & & & & & //修改地址
& & & & & & & & & & & & people.setAddress(&成都市金牛区xxx号&);
& & & & & & & & & & & & db.set(people);
& & & & & & & & }finally{
& & & & & & & & & & & & //关闭连接
& & & & & & & & & & & & db.close();
& & & & & & & & }
& & & & }
修改数据是如此的简单,通过 NQ 查询出 People 对象,接着修改其地址,最后保存即可。现在我们来看看修改是否成功, 打开 ObjectManager ,如 所示,我们可以看到数据库里的用户数据已经更新了。
与本系列文章第二部分不同的是,我们利用 ObjectSet&People& result 来获取返回结果,而不是 List&People& list。查阅 ObjectSet 的 API 我们发现 ObjectSet 实际上继承了 java.util.List 和 java.util.Iterator。为什么要继承两个接口?这是由于 db4o 为了方便开发者而有意这样设计的,db4o 的设计目标就是轻量级,这样的继承方式为 ObjectSet 提供了多种特性,而无需开发者在多个集合接口之间转换。
让我们考虑下面这个场景:
由于工作原因,“张三”要离开省会去其他城市发展,他的汽车也要在那里使用,为了方便,他还是决定重新更换为本地牌照。
这次我们几乎和场景一采用同样的代码,但结果却不同():
& & & & & & & & & & & & & & & &
import bo.P
import com.db4o.Db4o;
import com.db4o.ObjectC
import com.db4o.ObjectS
import com.db4o.query.P
public class DB4OTest{
& & & & public static void main([] args){
& & & & & & & & //打开数据库
& & & & & & & & ObjectContainer db = Db4o.openFile(&auto.yap&);
& & & & & & & & try{
& & & & & & & & & & & & ObjectSet&People& result = db.query(new Predicate&People&() {
& & & & & & & & & & & & & & public boolean match(People people) {
& & & & & & & & & & & & & & & & return people.getName().equals(&张三&);
& & & & & & & & & & & & & & }
& & & & & & & & & & & & });
& & & & & & & & & & & & People people = result.next();
& & & & & & & & & & & & //修改地址
& & & & & & & & & & & & people.setAddress(&绵阳市xx区xxx号&);
& & & & & & & & & & & & //修改车牌号
& & & & & & & & & & & & people.getAutoInfoList().get(0).setLicensePlate(&川B00000&);
& & & & & & & & & & & & db.set(people);
& & & & & & & & }finally{
& & & & & & & & & & & & //关闭连接
& & & & & & & & & & & & db.close();
& & & & & & & & }
& & & & }
想必应该保存成功了吧,只是多加入了设置车牌的代码。打开 ObjectManager,如 所示。很奇怪,地址保存成功了,而车牌却根本没变化。
其实这也是 db4o 的有意安排。设想一个复杂对象有很多成员,并且这些成员又有自己的成员。当更新该对象,db4o 将不得不更新其所有的关联对象、关联对象的关联对象,等等。这将引起严重的性能惩罚,而且在大部分的情况下是没有必要这样的。
db4o 引入了“更新深度(update depth)”这一概念来控制被更新的对象成员树深度。默认的更新深度是 1,这就意味着只有基本类型和 String 类型的成员变量可以被更新,而修改对象成员将得不到任何反映,例如本例中修改 People 对象的 _autoInfoList 成员。
为了能更新成员对象,ob4o 提供了 cascadeOnUpdate() 方法,该方法必须在每次开启数据库之前设置:
& & & & & & & & & & & & & & & &
import bo.P
import com.db4o.Db4o;
import com.db4o.ObjectC
import com.db4o.ObjectS
import com.db4o.query.P
public class DB4OTest{
& & & & public static void main([] args){
& & & & //级联设置
& & & & & & & & Db4o.configure().objectClass(&bo.People&)
& & & & .cascadeOnUpdate(true);
& & & & & & & & //打开数据库
& & & & & & & & ObjectContainer db = Db4o.openFile(&auto.yap&);
& & & & & & & & try{
& & & & & & & & & & & & ObjectSet&People& result = db.query(new Predicate&People&() {
& & & & & & & & & & & & & & public boolean match(People people) {
& & & & & & & & & & & & & & & & return people.getName().equals(&张三&);
& & & & & & & & & & & & & & }
& & & & & & & & & & & & });
& & & & & & & & & & & & People people = result.next();
& & & & & & & & & & & & //修改地址
& & & & & & & & & & & & people.setAddress(&绵阳市xx区xxx号&);
& & & & & & & & & & & & //修改车牌号
& & & & & & & & & & & & people.getAutoInfoList().get(0).setLicensePlate(&川B00000&);
& & & & & & & & & & & & db.set(people);
& & & & & & & & }finally{
& & & & & & & & & & & & //关闭连接
& & & & & & & & & & & & db.close();
& & & & & & & & }
& & & & }
这下终于如愿以偿,如 所示。其实 db4o 为开发者想得很周到,关键是如何用好这些特性。
“张三”换了工作后,事业发展很快,准备把车卖了换新的,于是他去交管部门办理移交手续,删除关联的车辆信息:
& & & & & & & & & & & & & & & &
import bo.AutoI
import com.db4o.Db4o;
import com.db4o.ObjectC
import com.db4o.ObjectS
import com.db4o.query.P
public class DB4OTest{
& & & & public static void main([] args){
& & & & & & & & //打开数据库
& & & & & & & & ObjectContainer db = Db4o.openFile(&auto.yap&);
& & & & & & & & try{
& & & & & & & & & & & & ObjectSet&AutoInfo& result = db.query(new Predicate&AutoInfo&() {
& & & & & & & & & & & & & & public boolean match(AutoInfo ai) {
& & & & & & & & & & & & & & & & //匹配姓名和车牌号
& & & & & & & & & & & & & & & & return ai.getLicensePlate().equals(&川B00000&)
& & & & & & & & & & & & & & & & & & & & & &&& ai.getOwnerNo().getName().equals(&张三&);
& & & & & & & & & & & & & & }
& & & & & & & & & & & & });
& & & & & & & & & & & & AutoInfo ai = result.next();
& & & & & & & & & & & & //删除车辆信息
& & & & & & & & & & & & db.delete(ai);
& & & & & & & & }finally{
& & & & & & & & & & & & //关闭连接
& & & & & & & & & & & & db.close();
& & & & & & & & }
& & & & }
如 所示,所关联的车辆信息已被删除了。
在场景三的基础上修改一下,设想“张三”由于工作不顺,导致最后维护汽车的开支都困难,他不得不退出有车一族的行列:
& & & & & & & & & & & & & & & &
import bo.P
import com.db4o.Db4o;
import com.db4o.ObjectC
import com.db4o.ObjectS
import com.db4o.query.P
public class DB4OTest{
& & & & public static void main([] args){
& & & & //级联设置
& & & & & & & & Db4o.configure().objectClass(&bo.People&)
& & & & .cascadeOnDelete(true);
& & & & & & & & //打开数据库
& & & & & & & & ObjectContainer db = Db4o.openFile(&auto.yap&);
& & & & & & & & try{
& & & & & & & & & & & & ObjectSet&People& result = db.query(new Predicate&People&() {
& & & & & & & & & & & & & & public boolean match(People people) {
& & & & & & & & & & & & & & & & //匹配姓名
& & & & & & & & & & & & & & & & return people.getName().equals(&张三&);
& & & & & & & & & & & & & & }
& & & & & & & & & & & & });
& & & & & & & & & & & & People people = result.next();
& & & & & & & & & & & & //删除车主以及关联的车辆信息
& & & & & & & & & & & & db.delete(people);
& & & & & & & & }finally{
& & & & & & & & & & & & //关闭连接
& & & & & & & & & & & & db.close();
& & & & & & & & }
& & & & }
用过 Hibernate 的开发者都知道,它的级联删除让人留下了深刻印象,第一次使用的时候都会为之振奋。db4o 也为开发者提供了级联删除,和场景二的级联更新一样, cascadeOnDelete() 是专门为删除准备的,基本概念和 cascadeOnUpdate() 一致。打开 ObjectManager 我们会发现数据库已经清空了,张三的购车经历到此结束。
通过本系列文章,db4o 的优势已经体现得淋漓尽致,它的添加、更新、删除是如此的简单,正如 db4o 的口号那样——“仅需一行代码就能存储复杂结构对象,极大的降低了开发时间和成本,提供高效的性能,无需 DBA 干预”。
如本文有不详尽之处,大家可以参考官方的《用户指南》或访问 ,db4o 中文社区正在火热成长!
:查看此系列文章完整列表。
:了解 ODMG 技术。
:数百篇关于 Java 编程各个方面的文章。
获得产品和技术
db4o :讨论 db4o 技术。
:学习 Java 技术。
Rosen Jiang 来自成都,是 db4o 和 OO 的忠实 fans,是 2005 年 db4o 的 dvp 获得者之一。他正在 J2me 应用中使用 db4o,你可以通过
和他联系。
Chris 来自香港,热爱开源和 db4o。他创办了中国最火热的 Java 和开源社区 Matrix(http://www.), 你可以通过
和他联系。
张黄瞩,热爱开源软件,熟悉 Java/C/C++ 编程语言,对数据库技术网络技术均感兴趣。你可以通过
发布于 6年前,
阅读(378) | 评论(0) |
投票(0) | 收藏(1)
系列文章的第一部分: 中,作者介绍了 db4o 的历史和现状,应用领域,以及和 ORM 等的比较。在这篇文章中,作者将会介绍 db4o 的安装、启动以及三种不同的查询方式:QBE(Query by Example)、SODA(Simple Object Database Access) 以及 NQ(Native Queries),并分别通过这三种不同的途径实现了两个关联对象的查询。本文还示范了开发中最经常用到的几个典型功能的 db4o 实现。
db4o 所有最新的版本都可以直接在官方网站上下载,进入 db4o 的,我们可以看到最新的 for Java 稳定版本是 5.5,包括 JAR、源代码、入门文档、API 等内容的完整的打包文件只有 6 MB,db4o 还有一个对象数据库管理工具 ObjectManager,目前版本是 1.8(请在参考资源中)。
接着在 Eclipse 中新建 Java 项目,把 db4o 对象数据库引擎包 db4o-5.5-java5.jar 导入进项目。由于 db4o 支持多种版本的 JDK,除了 for JDK 5.0 的 db4o-5.5-java5.jar 外,还有 for JDK 1.1、1.2-1.4 的 JAR 包,以适应多种环境。与 Hibernate、iBATIS SQL Maps 相比,db4o 更加自然,无需过多地引用第三方支持库。
db4o 怎样进行对象持久化呢?通过浏览目录可以发现,与传统的 RDBMS 一样,db4o 也有自己的数据库文件, 在 db4o 中数据库文件的后缀名是“*.yap”。让我们先来了解一下 db4o 对象数据库引擎的主要包结构:
com.db4o 包含了使用 db4o 时最经常用到的功能。两个最重要的接口是 com.db4o.Db4o 和 com.db4o.ObjectContainer。com.db4o.Db4o 工厂是运行 db4o 的起点,这个类中的静态方法可以开启数据库文件、启动服务器或连接一个已经存在的服务器,还可以在开启数据库之前进行 db4o 环境配置。com.db4o.ObjectContainer 接口很重要,开发过程中 99% 的时间都会用到它,ObjectContainer 可在单用户模式下作为数据库实例,也可作为 db4o 服务器的客户端。每个 ObjectContainer 实例都有自己的事务。所有的操作都有事务保证。当打开 ObjectContainer,就已经进入事务了,commit() 或 rollback() 时,下一个事务立即启动。每个 ObjectContainer 实例维护它自己所管理的已存储和已实例化对象,在需要 ObjectContainer 的时候,它会一直保持开启状态,一旦关闭,内存中数据库所引用的对象将被丢弃。
com.db4o.ext
你也许想知道为什么在 ObjectContainer 中只能看见很少的方法,原因如下:db4o 接口提供了两个途径,分别在 com.db4o 和 com.db4o.ext 包中。这样做首先是为了让开发者能快速上手;其次为了让其他产品能更容易的复制基本的 db4o 接口;开发者从这一点上也能看出 db4o 是相当轻量级的。每个 com.db4o.ObjectContainer 对象也是 com.db4o.ext.ExtObjectContainer 对象。可以转换成 ExtObjectContainer 获得更多高级特性。
com.db4o.config
com.db4o.config 包含了所有配置 db4o 所需的类。
com.db4o.query
com.db4o.query 包包含了构造“原生查询, NQ(Native Queries)”所需的 Predicate 类。NQ 是 db4o 最主要的查询接口。
db4o 提供两种运行模式,分别是本地模式和服务器模式。本地模式是指直接在程序里打开 db4o 数据库文件进行操作:
ObjectContainer db = Db4o.openFile("auto.yap");
而服务器模式则是客户端通过 IP 地址、端口以及授权口令来访问服务器:
服务器端:
ObjectServer server=Db4o.openServer(&auto.yap&,1212);
server.grantAccess(&admin&,&123456&);
ObjectContainer db=Db4o.openClient(&192.168.0.10&,1212,&admin&,&123456&);
两种方式都可以得到 ObjectContainer 实例,就目前 Java EE 应用环境来看,服务器模式更有现实意义;而本地模式更适合于嵌入式应用。为了简化演示,本文在下面的例子都将采用本地模式。
在下面的例子里,我们都会用到下面两个对象: People 和 AutoInfo 对象。
People 对象:
清单1. People 对象
public class People {
& & & & private java.lang. _
& & & & private java.lang. _
& & & & private java.lang. _
& & & & private java.util.List&AutoInfo& _autoInfoL
& & & & public java.lang. getId() {
& & & & & & & & return _
& & & & }
& & & & public void setId(java.lang. _id) {
& & & & & & & & this._id = _
& & & & }
& & & & public java.lang. getName() {
& & & & & & & & return _
& & & & }
& & & & public void setName(java.lang. _name) {
& & & & & & & & this._name = _
& & & & }
& & & & public java.lang. getAddress() {
& & & & & & & & return _
& & & & }
& & & & public void setAddress(java.lang. _address) {
& & & & & & & & this._address = _
& & & & }
& & & & public java.util.List&AutoInfo& getAutoInfoList() {
& & & & & & & & return this._autoInfoL
& & & & }
& & & & public void addAutoInfo(AutoInfo _autoInfoList) {
& & & & & & & & if (null == this._autoInfoList)
& & & & & & & & & & & & this._autoInfoList = new java.util.ArrayList&AutoInfo&();
& & & & & & & & this._autoInfoList.add(_autoInfoList);
& & & & }
AutoInfo 对象:
清单2. AutoInfo 对象
public class AutoInfo{
& & & & private java.lang. _
& & & & private java.lang. _licenseP
& & & & private bo.People _ownerNo;
& & & & public java.lang. getId () {
& & & & & & & & return _
& & & & }
& & & & public void setId (java.lang. _id) {
& & & & & & & & this._id = _
& & & & }
& & & & public java.lang. getLicensePlate () {
& & & & & & & & return _licenseP
& & & & }
& & & & public void setLicensePlate (java.lang. _licensePlate) {
& & & & & & & & this._licensePlate = _licenseP
& & & & }
& & & & public bo.People getOwnerNo () {
& & & & & & & & return this._ownerNo;
& & & & }
& & & & public void setOwnerNo (bo.People _ownerNo) {
& & & & & & & & this._ownerNo = _ownerNo;
& & & & }
利用 set 方法把新对象存入 ObjectContainer,而对 ObjectContainer 中已有对象进行 set 操作则是更新该对象。db4o 保存数据库很简单,下面就是一个段完整的保存对象的代码:
AutoInfo 对象:
import bo.AutoI
import bo.P
import com.db4o.Db4o;
import com.db4o.ObjectC
public class DB4OTest{
& & & & public static void main([] args){
& & & & & & & & //打开数据库
& & & & & & & & ObjectContainer db = Db4o.openFile(&auto.yap&);
& & & & & & & & try{
& & & & & & & & & & & & //构造 People 对象
& & & & & & & & & & & & People peo = new People();
& & & & & & & & & & & & peo.setId(1);
& & & & & & & & & & & & peo.setAddress(&成都市&);
& & & & & & & & & & & & peo.setName(&张三&);
& & & & & & & & & & & & //构造 AutoInfo 对象
& & & & & & & & & & & & AutoInfo ai = new AutoInfo();
& & & & & & & & & & & & ai.setId(1);
& & & & & & & & & & & & ai.setLicensePlate(&川A00000&);
& & & & & & & & & & & & //设置 People 和 AutoInfo 的关系
& & & & & & & & & & & & ai.setOwnerNo(peo);
& & & & & & & & & & & & peo.addAutoInfo(ai);
& & & & & & & & & & & & //保存对象
& & & & & & & & & & & & db.set(peo);
& & & & & & & & }finally{
& & & & & & & & & & & & //关闭连接
& & & & & & & & & & & & db.close();
& & & & & & & & }
& & & & }
当我们运行上述代码,db4o 会自动创建“auto.yap”文件。让我们来看看到底保存成功没有,打开 ObjectManager 工具,所示。
图1. 对象数据库管理工具
“File”-&“Open File”-&选择刚才我们保存的“auto.yap”文件(“auto.yap”文件可在项目的根目录下找到),最新的 ObjectManager 1.8 版本为我们提供了“Read Only”方式读取数据库文件,避免 ObjectManager 占用数据库文件所导致的程序异常。
打开之后,所示,刚才存贮的 People 对象已经在数据库中了,并且还可以很直观的看到 AutoInfo 对象也放入了 ArrayList 中。这种可视化的对象关系有利于我们对数据的理解,是传统 RDBMS 无法比拟的。有些开发者会说 ObjectManager 工具略显简单,这点我想随着 db4o 的不断发展会加入更多的特性。在这个工具中,我们意外的发现了 Java 集合对象的踪影,db4o 把与 ArrayList 有直接关系的所有接口和父类都保存了,这样显得更直观。
在此,我保留了 _id 属性,这是因为通常在 Java EE 环境中,DAO 第一次不是把整个对象都返回到表现层,而是只返回了“标题”、“发布时间”这些信息(并隐式的返回id),接着 DAO 与数据库断开;要查看详情(比如文章内容)就需要进行 findById 操作,这时 DAO 要再次与数据库交互,只有唯一标识符才能正确地找到对象。这种懒加载方式也是很多书籍所推荐的。
回到本文的范例程序中,这个 _id 属性可由人工编码实现的“序列”进行赋值,当然 db4o 也提供了内部标识符 Internal IDs,中的 id=1669;以及 UUIDs。
图2. 对象结构
img src=”/i/v14/rules/blue_rule.gif” alt=”" width=&#%” height=+ /&
查询数据库
和 RDBMS 一样,db4o 也有自己的查询语言,分别是 QBE(Query by Example)、NQ(Native Queries)、SODA(Simple Object Database Access),db4o 更推荐使用 NQ 进行查询。NQ 方式提供了非常强大的查询功能,支持原生语言,也就意味着你可以使用 Java 来判断该对象是否符合条件,这是其他数据库查询语言无法比拟的。在某些情况下, db4o 核心会将 NQ 翻译成 SODA 以获得更高的性能。下面详细介绍一下这三种查询语言。
QBE(Query by Example)
QBE 规范可在。QBE 最初由 IBM 提出,同时业界也有许多和 QBE 兼容的接口,包括著名的 Paradox。有些系统,比如微软的 Access,它的基于表单的查询也是受到了部分 QBE 思想的启发。在 db4o 中,用户可借用 QBE 快速上手,可以很容易适应 db4o 存取数据的方式。
当利用 QBE 为 db4o 提供模板(example)对象时,db4o 将返回所有和非默认值字段匹配的全部对象。内部是通过反射所有的字段和构造查询表达式(所有非默认值字段结合”AND”表达式)来实现。
例如,利用 QBE 查找到车牌号为“川A00000”的车主姓名,这是一个级联查询。:
import java.util.L
import bo.AutoI
import com.db4o.Db4o;
import com.db4o.ObjectC
public class DB4OTest{
& & & & public static void main([] args){
& & & & & & & & //打开数据库
& & & & & & & & ObjectContainer db = Db4o.openFile(&auto.yap&);
& & & & & & & & try{
& & & & & & & & & & & & //构造模板对象
& & & & & & & & & & & & AutoInfo ai = new AutoInfo();
& & & & & & & & & & & & ai.setLicensePlate(&川A00000&);
& & & & & & & & & & & & //查询对象
& & & & & & & & & & & & List&AutoInfo& list = db.get(ai);
& & & & & & & & for(int x = 0; x & list.size(); x++){
& & & & & & & & & & & & .out.println(&车主姓名:&+list.get(x).getOwnerNo().getName());
& & & & & & & & & & & & }
& & & & & & & & }finally{
& & & & & & & & & & & & //关闭连接
& & & & & & & & & & & & db.close();
& & & & & & & & }
& & & & }
但是 QBE 也有明显的限制:db4o 必须反射模板(example)对象的所有成员;无法执行更进一步的查询表达式(例如 AND、OR、NOT 等等);不能约束 0(整型)、””(空字符串)或者 null(对象),因为这些都被认为是不受约束的。要绕过这些限制,db4o 提供了 NQ(Native Queries)。
SODA ,简单对象数据库访问,请查看,其中一位主要维护者是 Carl Rosenberger,Carl 正是 db4o 首席架构师。
SODA 就是一种与数据库通讯的对象 API。最终的目标是实现类型安全、对象复用、最小的字符串使用、与编程语言无关等特性。SODA 是 db4o 最底层的查询 API,目前 SODA 中使用字符串来定义字段,这样将不能实现类型安全也无法在编译时检查代码,而且写起来较麻烦,当然要达到设计目标这个阶段是必须的。大部分情况下 NQ(Native Queries)是很好的查询接口,不过遇到动态生成查询的时候 SODA 就大有作为了。
通过 SODA 查找到车牌号为“川A00000”的车主姓名。:
import java.util.L
import bo.AutoI
import com.db4o.Db4o;
import com.db4o.ObjectC
import com.db4o.query.Q
public class DB4OTest{
& & & & public static void main([] args){
& & & & & & & & //打开数据库
& & & & & & & & ObjectContainer db = Db4o.openFile(&auto.yap&);
& & & & & & & & try{
& & & & & & & & & & & & //构造查询对象
& & & & & & & & & & & & Query query=db.query();
& & & & & & & & & & & & //设置被约束实例
& & & & & & & & & & & & query.constrain(AutoInfo.class);
& & & & & & & & & & & & //设置被约束实例的字段和约束条件
& & & & & & & & & & & & query.descend(&_licensePlate&).constrain(&川A00000&);
& & & & & & & & & & & & //查询对象
& & & & & & & & & & & & List&AutoInfo& list = query.execute();
& & & & & & & & for(int x = 0; x & list.size(); x++){
& & & & & & & & & & & & .out.println(&车主姓名:&+list.get(x).getOwnerNo().getName());
& & & & & & & & & & & & }
& & & & & & & & }finally{
& & & & & & & & & & & & //关闭连接
& & & & & & & & & & & & db.close();
& & & & & & & & }
& & & & }
通过 API,发现 Query 实例增加了 sortBy 按字段排序方法和 orderAscending正序、orderDescending 倒序排列方法,SODA 比 QBE 更进了一步。
精彩总是在最后出场,NQ 才是 db4o 查询方式中最精彩的地方!有没有想过用你熟悉的的编程语言进行数据库查询呢?要是这样,你的查询代码将是 100% 的类型安全、100% 的编译时检查以及 100% 的可重构,很奇妙吧?NQ 可以做到这些。
有两篇论文专门讲解了 NQ 的基本概念和设计思路,分别是
和 《Cook/Rai,Safe Query Objects: Statically Typed Objects as Remotely Executable Queries》。作为结果集的一部分,NQ 表达式必须返回 true 值来标记特定实例。如果可能的话 db4o 将尝试优化 NQ 表达式,并依赖索引来运行表达式。
通过 NQ 查找到车牌号为“川A00000”的车主姓名。:
import java.util.L
import bo.AutoI
import com.db4o.Db4o;
import com.db4o.ObjectC
import com.db4o.query.P
public class DB4OTest{
& & & & public static void main([] args){
& & & & & & & & //打开数据库
& & & & & & & & ObjectContainer db = Db4o.openFile(&auto.yap&);
& & & & & & & & try{
& & & & & & & & & & & &
&AutoInfo& list = db.query(new Predicate&AutoInfo&() {
& & & & & & & & & & & & & & & & public boolean match(AutoInfo ai) {
& & & & & & & & & & & & & & & & //这样才是类型安全的
& & & & & & & & & & & & & & & & return ai.getLicensePlate().equals(&川A00000&);
& & & & & & & & & & & & & & }
& & & & & & & & & & & & });
& & & & & & & & for(int x = 0; x & list.size(); x++){
& & & & & & & & & & & & .out.println(list.get(x).getOwnerNo().getName());
& & & & & & & & & & & & }
& & & & & & & & }finally{
& & & & & & & & & & & & //关闭连接
& & & & & & & & & & & & db.close();
& & & & & & & & }
& & & & }
必须指出 NQ 的一个的问题是:在内部,db4o 设法把 NQ 转换成 SODA。但并不是所有的查询表达式都可以成功转换。有些查询表达式的流向图(flowgraph)非常难于分析。这种情况下,db4o 将不得不实例化一些持久对象来真实地运行 NQ 表达式。
正在开发中的 NQ 查询优化器就可以化解这个障碍,它将分析 NQ 表达式的每个部分,以确保最少量的实例化对象,以此提高性能。当然,优化器的不是灵丹妙药,关键还需要自己多优化代码。
开发 Java EE 项目经常会用到分页,怎样用 NQ 实现呢?向数据库写入六条记录。:
import java.util.L
import bo.AutoI
import com.db4o.Db4o;
import com.db4o.ObjectC
import com.db4o.query.P
public class DB4OTest{
& & & & public static void main([] args){
& & & & & & & & //打开数据库
& & & & & & & & ObjectContainer db = Db4o.openFile(&auto.yap&);
& & & & & & & & try{
& & & & & & & & & & & & List&AutoInfo& list = db.query(new Predicate&AutoInfo&() {
& & & & & & & & & & & & & & & & public boolean match(AutoInfo ai) {
& & & & & & & & & & & & & & & & return true;
& & & & & & & & & & & & & & }
& & & & & & & & & & & & });
& & & & & & & & & & & & //记录总数
& & & & & & & & & & & &
count = list.size();
& & & & & & & & & & & & //每页两条,分三页
& & & & & & & & for(int x = 0; x & 3; x++){
& & & & & & & & & & & & .out.println(&第&+x+&页:&+list.get(x*2).getLicensePlate());
& & & & & & & & & & & & .out.println(&第&+x+&页:&+list.get(x*2+1).getLicensePlate());
& & & & & & & & & & & & }
& & & & & & & & }finally{
& & & & & & & & & & & & //关闭连接
& & & & & & & & & & & & db.close();
& & & & & & & & }
& & & & }
我们发现,在进行 NQ 查询时并没有加入任何条件(无条件返回 true),是不是相当于遍历了整个数据库?db4o 的设计者早就想到了这个问题,当 db.query() 执行完毕返回 list 实例的时候,db4o 只是与数据库同步取出内部 IDs 而已,并没有把所有的 AutoInfo 对象全部取出,只有在 list.get(x*2).getLicensePlate() 之后才会去根据 IDs 取出记录。所以不必担心性能问题。
db4o 为开发者提供了多种查询方式,这些方式都很灵活。要引起大家注意的是:灵活在带来便利的同时也对开发者自身素质提出了更高的要求,(比如排序,既可以用 SODA 也可以用 Java 集合对象实现)在开发过程中一定要形成某种统一的开发模式,这样 db4o 才能最高效能地为我所用。
:查看此系列文章完整列表。
:了解 ODMG 技术。
:数百篇关于 Java 编程各个方面的文章。
获得产品和技术
发布于 6年前,
阅读(413) | 评论(1) |
投票(0) | 收藏(0)
前些天使用jetty作为我程序的钳入式http和servlet服务器模块,后来为了方便管现程序的内存数据和停止服务器,那么我就写了一个jsp来调用相关的stop()方法
问题就来了,我通过jsp调用stop方法时发现我启动服务器时附的静态变量值居然为null,怪事 大家先来看看代码:
private static S
public static void startHttp(int prot) { server = new Server(); }
public static void stop(){ System.out.println(&server=&+server); server.stop(); }
代码大约就是这样,正在百思不得其解的时候,我突然有一个想法,会不会是这个类被重新初始化了呢,于是我又加多了一个代码,一个final变量,如下:
private static final int i=Random.nextInt();
这个变量作为一个随机数,首先在starthttp()方法里打印出来,然后在stop里再打印一次,你会惊奇的发现,二个数不一样!!!
这时问题就好清楚了,就是这个类被初始化了二次,为什么呢,于是我分别在startHttp方法和stop方法里再加多一句打印语句
System.out.println(HttpServer.class.getClassloader());
果然,不一样!!!!
一个是sun的,一个是jetty自己实现的类
这时问题终于搞明白了,因为我启动服务器是通过java的命令的,当然这时classloader就是sun自带的loader,当我停止服务器时 因为是通过jsp的,要通过jetty的jsp解释器,jetty为了方便管理和实现自动加载等,把这个loader自己扩展了。
解决方法,把jetty的loader设为sun的loader
在jetty的WebAppContext类,可以设置这个应用的loader的,把他设成自己的就行了 webapp.setClassLoader(HttpServer.class.getClassLoader());
这里引一个问题出来:我们可以不可通过方法得到现在系统里的所有classloader呢????
发布于 6年前,
阅读(976) | 评论(0) |
投票(0) | 收藏(2)
代码非常简单,,要引入tool.jar这个包
com.sun.tools.javac.Main javac = new Main();
File file =new File("E:/work/JavaGGDS/bin/Test.java");// new File("Test",".java", );
if(file.exists())file.delete();
FileWriter fw=new FileWriter(file);
fw.write("public class "+file.getName().substring(0,file.getName().lastIndexOf("."))+" { public static void a(){System.out.println(\"dddddddd\");}}");
fw.flush();
fw.close();//
String[] arg0=new String[]{"-d",System.getProperty("user.dir"),file.getName()};
String[] arg0=new String[]{"-d","E:/work/JavaGGDS/bin/","E:/work/JavaGGDS/bin/"+"Test.java"};
int pile(arg0);
System.out.println(status);
Class cls = Class.forName(file.getName().substring(0,file.getName().lastIndexOf(".")));
cls.getMethod("a").invoke(null);
这样就可以了,大家基本看得明白吧
发布于 6年前,
阅读(875) | 评论(0) |
投票(0) | 收藏(1)
一:树节点的定义(TreeNode.java)import java.util.Limport java.util.ArrayLimport java.io.S
public class TreeNode implements Serializable{ private int parentId;private int selfId;protected String nodeNprotected Oprotected TreeNode parentNprotected List childLpublic TreeNode(){ initChildList();}public TreeNode(TreeNode parentNode){this.getParentNode();initChildList();}public boolean isLeaf(){if(childList==null){}else{if(childList.isEmpty()){}else {}}}/*插入一个child节点到当前节点中*/public void addChildNode(TreeNode treeNode){initChildList();childList.add(treeNode);}public void initChildList(){if(childList==null)childList=new ArrayList();}public boolean isValidTree(){}/*返回当前节点的父辈节点集合*/public List getElders(){List elderList=new ArrayList();TreeNode parentNode=this.getParentNode();if(parentNode==null){return elderL}else{elderList.add(parentNode);elderList.addAll(parentNode.getElders()); return elderL} }/*返回当前节点的晚辈集合*/public List getJuniors(){List juniorList=new ArrayList();List childList=this.getChildList();if(childList==null){return juniorL}else{int childNumber=childList.size();for(int i=0;i<childNi++){TreeNode junior=childList.get(i);juniorList.add(junior);juniorList.addAll(junior.getJuniors()); }return juniorL} }/*返回当前节点的孩子集合*/public List getChildList() {return childL}/*删除节点和它下面的晚辈*/public void deleteNode(){TreeNode parentNode=this.getParentNode();int id=this.getSelfId();if(parentNode!=null){parentNode.deleteChildNode(id);}}/*删除当前节点的某个子节点*/public void deleteChildNode(int childId){List childList=this.getChildList();int childNumber=childList.size();for(int i= 0 ; i < childNi++){TreeNode child=childList.get(i);if(child.getSelfId()==childId){childList.remove(i);}}}/*动态的插入一个新的节点到当前树中*/public boolean insertJuniorNode(TreeNode treeNode){int juniorParentId=treeNode.getParentId();if(this.parentId==juniorParentId){addChildNode(treeNode);}else{List childList=this.getChildList();int childNumber=childList.size();boolean insertFfor(int i=0;i<childNi++){TreeNode childNode= childList.get(i);insertFlag=childNode.insertJuniorNode(treeNode);if(insertFlag==true)}}}/*找到一颗树中某个节点*/public TreeNode findTreeNodeById(int id){ if(this.selfId==id)if(childList.isEmpty() || childList==null){}else{int childNumber=childList.size(); for(int i= 0 ; i < childNi++){TreeNode child=childList.get(i); TreeNode resultNode=child.findTreeNodeById(id);if(resultNode!=null){return resultN}}}}/*遍历一棵树,层次遍历*/public void traverse(){if(selfId<0)print(this.selfId);if(childList==null || childList.isEmpty())int childNumber=childList.size();for(int i= 0 ; i < childNi++){TreeNode child=childList.get(i); child.traverse();} }public void print(String content){System.out.println(content);}public void print(int content){System.out.println(String.valueOf(content));}public void setChildList(List childList) {this.childList = childL}public int getParentId() {return parentId;}public void setParentId(int parentId) {this.parentId = parentId;}public int getSelfId() {return selfId;}public void setSelfId(int selfId) {this.selfId = selfId;}
public TreeNode getParentNode() {return parentN}
public void setParentNode(TreeNode parentNode) {this.parentNode = parentN}
public String getNodeName() {return nodeN}
public void setNodeName(String nodeName) {this.nodeName = nodeN}
public Object getObj() {}
public void setObj(Object obj) {this.obj =}}二:TreeHelper.javaimport java.util.Limport java.util.Iimport java.util.ArrayLimport java.util.HashMpublic class TreeHelper {private TreeNprivate List tempNodeLprivate boolean isValidTree=public TreeHelper(){ } public TreeHelper(List treeNodeList){ tempNodeList=treeNodeLgenerateTree();}public static TreeNode getTreeNodeById(TreeNode tree,int id){if(tree==null)TreeNode treeNtreeNode=tree.findTreeNodeById(id);return treeN}/** generate a tree from the given treeNode or entity list*/public void generateTree(){HashMap nodeMap = putNodesIntoMap(); putChildIntoParent(nodeMap);}/** put all the treeNodes into a hash table by its id as the key*@return hashmap that contains the treenodes*/protected HashMap putNodesIntoMap(){int maxId=Integer.MAX_VALUE;HashMap nodeMap=new HashMap();Iterator it=tempNodeList.iterator();while(it.hasNext()){TreeNode treeNode=(TreeNode)it.next();int id=treeNode.getSelfId();if(id<maxId){maxId=this.root=treeN}String keyId=String.valueOf(id); nodeMap.put(keyId,treeNode); //System.out.println("keyId: " +keyId);} return nodeM}/** set the parent nodes point to the child nodes *@param nodeMap a hashmap that contains all the treenodes by its id as the key */protected void putChildIntoParent(HashMap nodeMap){Iterator it=nodeMap.values().iterator();while(it.hasNext()){TreeNode treeNode=(TreeNode)it.next(); int parentId=treeNode.getParentId();String parentKeyId=String.valueOf(parentId);if(nodeMap.containsKey(parentKeyId)){TreeNode parentNode=(TreeNode)nodeMap.get(parentKeyId);if(parentNode==null){this.isValidTree=}else{parentNode.addChildNode(treeNode);//System.out.println("childId: " +treeNode.getSelfId()+" parentId: "+parentNode.getSelfId());} }} }/**initialize the tempNodeList property */protected void initTempNodeList(){if(this.tempNodeList==null){this.tempNodeList=new ArrayList();}}/** add a tree node to the tempNodeList*/public void addTreeNode(TreeNode treeNode){initTempNodeList();this.tempNodeList.add(treeNode);}/** insert a tree node to the tree generated already* @return show the insert operation is ok or not */public boolean insertTreeNode(TreeNode treeNode) {boolean insertFlag= root.insertJuniorNode(treeNode);return insertF}/** adapt the entities to the corresponding treeNode*@param entityList list that contains the entities*@return the list containg the corresponding treeNodes of the entities*/public static List changeEnititiesToTreeNodes(List entityList){OrganizationEntity orgEntity=new OrganizationEntity();List tempNodeList=new ArrayList();TreeNode treeNIterator it = entityList.iterator();while(it.hasNext()){ orgEntity= (OrganizationEntity)it.next(); treeNode=new TreeNode();treeNode.setObj(orgEntity);treeNode.setParentId(orgEntity.getParentId());treeNode.setSelfId(orgEntity.getOrgId());treeNode.setNodeName(orgEntity.getOrgName());tempNodeList.add(treeNode);}return tempNodeL}public boolean isValidTree(){return this.isValidT}
public TreeNode getRoot() {}
public void setRoot(TreeNode root) {this.root =}
public List getTempNodeList() {return tempNodeL}
public void setTempNodeList(List tempNodeList) {this.tempNodeList = tempNodeL} }
发布于 6年前,
阅读(998) | 评论(0) |
投票(0) | 收藏(3)
过年在武汉时,和 的朋友一起吃饭。 问,你在网易那么多年,说说网易的文化吧。
一时间,我不知道从何说起。网易从来没有一本如职培训教材上条条款款写明所谓公司文化的。也没有什么人认真总结过。我想,每个网易人心中都有一份网易文化的定义。
如果让我说,第一反应是,网易重视技术人员。通常在 IT 的创业小公司中,这种现象比较常见。网易已经不算是小公司了,坚持这样比较难得。这倒不是因为丁磊有技术背景,我想更多的是,网易在几个关键时期,都是技术人员起了重要的作用。公司善待技术人员,算是投桃报李了。这是公司的一种发展偏好吧。
网易在做重要决策时,往往显得谨慎小心。不够大气。往往比别人慢一拍,且少有破釜沉舟的投入。这是几个公司高层性格的体现,物以类聚,人以群分,所以这也影响了许多员工。这似乎成了公司的性格,因此,也有性格不合的人离开。
能称之为文化的是什么呢?我拿不太准。或许,追求“平等”,勉强算的上吧。
有些“平等”,是很容易做出来的。许多公司都一样。
没有特别多的层级、所谓扁平化管理。我听过许多抱怨,说网易的管理太有问题,全是干活的人,没几个管事的。一个头管了无数人,自己还要亲力亲为,怎么可能管的好。好几年前,公司也请了所谓管理咨询公司,不断的培养所谓“中层管理人员”。成效怎样?不敢妄断。可以肯定是的,一些期望公司变好,更像一个大公司的努力,和公司原有文化是发生了一定冲击的。
公司的 CXO 们,和新进来的普通员工在街边吃烧烤,似乎不是什么稀罕事。下了班,就不再分上下级,一律是同事。该玩还是一起玩儿。该聊天还是敞开了聊。从丁磊开始,他这些年就没改过习惯,兴致来了就打电话叫同事一起喝酒。遇见朋友,一律介绍,这是我的同事 XXX 。不过,现在和以前不同,和不熟的同事在一起时,他都抢着买单了。不过我倒是觉得,抢着买单倒是见外了。要说平等,即使不 AA ,随便谁买都一样。老板也不应该有买单的义务,再说,下了班就不是老板了。
网易主张敞开式的大开间办公。在很长一段时间里,没有人有独立的小办公室。高职位者也不过一张同样的桌子,坐在大家的中间,甚至不是更好的位置。
其实这些刻意去做都不难,难的是把“平等”二字写在心里。
01 年我刚进网易的时候,游戏部门刚刚成立,所有人都是临时拼凑起来的。我听闻了一则故事。有美术部门的同事之间争吵起来,大概是工作上的吧。最后谁也说不过谁,只好比起员工级别来了。网易的员工级别有 9 级,其实落到大部分员工上的级别很少。开发人员最低是 8 级,如果到 5 级,基本属于高级管理人员了,人数非常稀少。所以大部分人不是 7 级就是 8 级( 6 级属于中层管理人员,人数也不太多)。刚好吵架的人一个是 7 级,另一个是 8 级。这级别高的就用级别压人。
给我讲故事的这位老兄一脸的不屑。我们这又不是军队,没什么上下级的。他的想法代表了大部分网易老员工的观念:工作中具体东西的争议,不是靠级别高就可以说了算的。所谓特权的思想,在整个网易的文化中是受排斥的。
05 年,游戏部门中层管理人员开了次比较大的会议。讨论许多管理中出现的问题。其中有个议题争论的非常厉害。那就是中高层人员,有没有权利比普通员工晚来上班。这个议题的前提还是,几乎所有的中高层人员工作时间都长于普通员工,只是晚来晚走而已。但是,即使这样,要求别人 9 点上班打卡,而自己可以推迟到中午报道,已经让大多数人感觉到严重的不平等了。而开始的所有人还都是在享受这个特权的,并没有普通员工参加。
04 年,我和我的上司 dingdang 有过一次激烈的争吵。那是唯一的一次。谁都说服不了谁。最后 dingdang 逼急了,说,这次一定要听我的,我要为整个团队负责。一句话噎的我在旁边闷声不响。五分钟以后,dingdang 就跑过来向我道歉。或许,有人不会理解,为什么应该道歉?因为,无论你看的多远,想的更多,在讨论具体问题时,不能以自己的位置来压人。其实,这个位置不单单是指职位的高低,也包含有你的经验,你在行业内的权威,等等。
说起来容易,做起来其实很难。
在我们的办公室里,经常为一些不知为谓的问题,吵的面红耳赤。因为每个人随时都可以对别人在做的东西发表自己的意见。不论怎么吵,都不能搬出:我做这个已经很久了,我的“感觉”这样就是好的,这种理由来说事。做技术的人往往有这种感觉,有些东西凭自己的经验这么做就是对的,讲出道理来却很难。有些还是一些个人喜好甚至“信仰”的缘故。但是这种东西,在争论时,大家都有一种默契,不拿自己的“感觉”说事。因为涉及到“感觉”,就牵扯到每个人在各自领域的所谓“权威”。而“权威”最容易造成不平等的争论。
去“权威”化,是“平等”文化的一部分。即使在单纯的技术领域也是一样。讨论问题时,不应该有一个人站的更高。这样,人才能够放开心胸把自己的想法说出来,不至于每每到最后去“抬杠”,“钻牛角尖”。
都说,技术问题的争论是单纯的,只要对事不对人,没什么大不了。实际上,根本不是这样。大多数技术问题,都有截然不同的几个面。根本无法决定那种方案更好。单凭道理,很难说服“政见”不同的对方的。由于本不存在对错,所以争论的结果造成不欢而散的结果其实非常多见。单方面的让步,其实只是隐藏的问题,而并没有解决。许多人会觉得,管他谁对谁错,只管去做就是了。让事实说话?事实不是一个因对一个果的。
所以,把“平等”放在心中就变的重要起来。一切争论都需要有个结果。而这个结果是在平等的基础上,双方妥协让步的结果。虽然每个人都不爽,但是每个人都不得不接受。没有人允许说,“这次我说了算,我会考虑你的意见”。
为什么需要这样?的确,很多成功来至于独断专行。因为这样有最高的效率。但是,失败的概率比成功更高。只是因为样本空间足够大,让人们看见了那些偶然的成功者而已。而发挥每个人的智慧,即使引起了冲突,我们不得不妥协放弃更好的方案,但我们很少犯错。
每个人总有些权利,即使工作多年一事无成,也有权利向刚工作的新人倚老卖老。有多少人肯放弃这种权利呢?
追求平等,就要懂得放弃自己已有的东西。真正的平等是居高位者放弃自己的权利换来的。在没有权利时,抱怨不平等,又有什么意义呢?
转自:/2009/02/equality.html
发布于 6年前,
阅读(467) | 评论(0) |
投票(0) | 收藏(1)
再学习了haffman算法之后发现压缩算法很有意思,上网查了点资料,这是做好的一篇(主要是我能理解)。前面几种都能看懂,关键是那个LZ77算法。这个是很强大的压缩算法,zip,rar用得都是这种算法,让我们来感叹下两个犹太人的强大!!!
几个常见的压缩算法(转)(一) 字典算法字典算法是最为简单的压缩算法之一。它是把文本中出现频率比较多的单词或词汇组合做成一个对应的字典列表,并用特殊代码来表示这个单词或词汇。例如:有字典列表:00=Chinese01=People02=China源文本:I am a Chinese people,I am from China 压缩后的编码为:I am a 00 01,I am from 02。压缩编码后的长度显著缩小,这样的编码在SLG游戏等专有名词比较多的游戏中比较容易出现,比如《SD高达》。
(二) 固定位长算法(Fixed Bit Length Packing)这种算法是把文本用需要的最少的位来进行压缩编码。比 如八个十六进制数:1,2,3,4,5,6,7,8。转换为二进制为:000100, 001000。每个数只用到了低4位,而高4位没有用到(全为0),因此对低4位进行压缩编 码后得到:,,,。然后补充为字节得到:, 111000。所以原来的八个十六进制数缩短了一半,得到4个十六进制数:12,34,56,78。这也是比较常见的压缩算法之一。
(三) RLE算法这种压缩编码是一种变长的编码,RLE根据文本不同的具体情况会有不同的压缩编码变体与之相适应,以产生更大的压缩比率。
  变体1:重复次数+字符文本字符串:A A A B B B C C C C D D D D,编码后得到:3 A 3 B 4 C 4 D。
  变体2:特殊字符+重复次数+字符文本字符串:A A A A A B C C C C B C C C,编码后得到:B B 5 A B B 4 C B B 3 C。编码串的最开始说明特殊字符B,以后B后面跟着的数字就表示出重复的次数。
  变体3:把文本每个字节分组成块,每个字符最多重复 127 次。每个块以一个特殊字节开头。那个特殊字节的第 7 位如果被置位,那么剩下的7位数值就是后面的字符的重复次数。如果第 7 位没有被置位,那么剩下 7 位就是后面没有被压缩的字符的数量。例如:文本字符串:A A A A A B C D E F F F。编码后得到:85 A 4 B C D E 83 F(85H= B、4H= B、83H= B)
  以上3种不RLE变体是最常用的几种,其他还有很多很多变体算法,这些算法在Winzip Winrar这些软件中也是经常用到的。
(四) LZ77算法LZ77算法是由 Lempel-Ziv 在1977发明的,也是GBA内置的压缩算法。LZ77算法有许多派生算法(这里面包括 LZSS算法)。它们的算法原理上基本都相同,无论是哪种派生算法,LZ77算法总会包含一个动态窗口(Sliding Window)和一个预读缓冲器(Read Ahead Buffer)。动态窗口是个历史缓冲器,它被用来存放输入流的前n个字节的有关信息。一个动态窗口的数据范围可以从 0K 到 64K,而LZSS算法使用了一个4K的动态窗口。预读缓冲器是与动态窗口相对应的,它被用来存放输入流的前n个字节,预读缓冲器的大小通常在0 – 258 之间。这个算法就是基于这些建立的。用下n个字节填充预读缓存器(这里的n是预读缓存器的大小)。在动态窗口中寻找与预读缓冲器中的最匹配的数据,如果匹 配的数据长度大于最小匹配长度 (通常取决于编码器,以及动态窗口的大小,比如一个4K的动态窗口,它的最小匹配长度就是2),那么就输出一对〈长度(length),距离 (distance)〉数组。长度(length)是匹配的数据长度,而距离(distance)说明了在输入流中向后多少字节这个匹配数据可以被找到。
  例如:(假设一个 10个字节的动态窗口, 以及一个5个字节的预读缓冲器)文本:A A A A A A A A A A A B A B A A A A A--------------------- =========动态窗口 预读缓存器动 态窗口中包含10个A ,这就是最后读取的10个字节。预读缓冲器包含了 B A B A A。编码的第一步就是寻找动态窗口与预读缓存器相似长度大于2的字节部分。在动态窗口中找不到B A B A A,所以B就被按照字面输出。然后动态窗口滑过1个字节,现在暂时输出了一个B。第二步:A A A A A A A A A A A B A B A A A A A--------------------- =========动态窗口 预读缓存器现 在预读缓冲器包含A B A A A,然后再和动态窗口进行比较。这时,在动态窗口找到了相似长度为2的A B,因此一对〈长度, 距离〉就被输出了。长度(length)是2 并且向后距离也是2,所以输出为,然后动态窗口滑过2个字节。现在已经输出了B 。第三步:A A A A A A A A A A A B A B A A A A A--------------------- =========动态窗口 预读缓存器继续上面的方法得到输出结果。现在已经输出了B
。最终的编码结果是:A A A A A A A A A A A B
。但 数组是无法直接用二进制来表示的,LZ77会把编码每八个数分成一组,每组前用一个前缀标示来说明这八个数的属性。比如数据流:A B A C A C B A C A按照LZ77的算法编码为:A B A C ,刚好八个数。按照LZ77的规则,用“0”表示原文输出,“1”表示数组输出。所以这段编码就表示为:B(等于 0FH),因此得到完整的压缩编码表示:F A B A C 2 2 4 5。虽然表面上只缩短了1个字节的空间,但当数据流很长的时候就会突出它的优势,这种算法在zip格式中是经常用到。
  除此之外还有很多压缩算法,像霍夫曼编码(Huffman Encoding)等等。这些编码也是非常的著名而且压缩效率极高,不过这些编码的算法相对比较繁琐,规则也很复杂,由于篇幅就不逐一介绍了。如果大家对这方面感兴趣可以到网站相关网站查询资料。
发布于 6年前,
阅读(1053) | 评论(0) |
投票(0) | 收藏(2)

我要回帖

更多关于 按键精灵时间判断 的文章

 

随机推荐