2008年7月31日星期四

这个视频太有爱了……

我不说了,自己看去
http://222.243.146.200/plus/view.php?aid=4658
 

这是人民的胜利!

今天下午3时,维基百科中文站被解除封锁,这到底是GOV终于想通了,还是因为OG将近,GOV为了“外国记者”的方便而搞的应急措施呢,或者是GFW的硬件系统出现致命错误呢?让我们拭目以待吧!
》》经过多方证明,是第二种猜测……TMD。

2008年7月27日星期日

爷爷,走好。

爷爷昨天的这个时候永远的离我而去了……这一天某熊的感觉可以用度日如年来形容。下面就发点儿牢骚和感慨,寄托对老爷子的思念之情。
一:失去了才学会珍惜
爷爷走之前说的最后一句话是:“宝宝(我),秀清(奶奶),谢谢你们。”我从小就在爷爷奶奶家长大,可以说是爷爷奶奶用工资养活了我的爸爸,大爷,姑姑等。然后用退休金养活了我。记得小时候生病的时候最喜欢吃的是爷爷做的面片汤,面片很薄,吃起来很好吃。小时候经常让爷爷给我做着做那的……比如想吃雪糕了,爷爷去买……想出去玩了,爷爷陪着去。奶奶的身体一直不好。家里有什么活都是老爷子的工作。今年过年回家,爷爷还特别有精神。4月份好像是摔坏了腰,脊椎出现了一些裂缝。后来在住院期间查出了肺癌……但是据说当时爷爷还是很能吃,后来家里决定让他去做伽玛刀,爷爷虽然不愿意,但是还是做了,这一做就是一个月,7月14号,我从桂林放假回家时路过北京,就顺便去看了看爷爷,那时的爷爷已经是大不如前了,身体上的脂肪几乎都没有了,可以直接摸到骨头的感觉。但是他就吃饭吃不香,说话也没有了底气。我回家2天以后。爷爷也做完伽玛刀回家了。回来以后一直不好好吃饭。而且经常出冷汗。一直到26日,爷爷的病情加重了,终于在医院抢救无效后,离开了我们。
二:危机处理不能慌
26日中午,爷爷的病情已经到了不能自己站立的情况了。 当时我就发现他的身体很凉,但是由于爷爷有糖尿病,我怀疑是他的血糖过低了。经过测试以后,血糖水平是21.6,不但不低,反而偏高不少。由于爷爷的心脏机能一直不错,我也没有想到是心脏的问题。等到我突然发现他的症状是典型的心脏病发作时,爷爷已经失去意识了。假如我当时及早的给他含几片速效救心丸,可能结果就完全不会是现在的样子了……现在想起来我真想狠狠的抽我自己几下子……家里有老人的,本熊在这里提醒一下子,遇到这种事千万不能慌张,不然可能会留下一生的遗憾。
三:精神准备和物质准备
听到爷爷已经停止一切生命活动以后,在场最镇定的人反而是奶奶。奶奶说:他们俩早就为彼此的先走一步走好了思想准备。所以她不遗憾,该做的我们都做了,天命不饶人。
--未完待续--
附:某熊的爷爷,享年73岁,于2008年7月26日下午死于肺癌和心力衰竭。

2008年7月23日星期三

我发现我爱上nio了

Java从1.4版本以后提供的新特性:nio我以前一直没用过。写网络程序时一直喜欢用Socket+Stream的阻塞IO。但是这回接的任务要求很高并发和性能的网络交互处理……用原来的阻塞IO肯定不行(总不能一个链接就用一个专用线程处理吧……就是用线程池也架不住好几千的线程一起运行吧= =||,所以用了一下nio的非阻塞io模型,起初发现nio很麻烦,什么事情都要求手动同步,并且很容易出bug...经常是出了bug都不知道从哪里下手(因为程序逻辑和同步顺序的原因)……而且经常出现调用某个函数,必须使用某个特定 的线程的情况,处理异常不得不使用大量的回掉函数……
总之,吧某熊搞的是精疲力竭的……
不过自打用上了Mina,情况改变了(怎么感觉像托儿= =||)。Mian吧nio进行了包装,并对网络IO处理进行了分层处理,采用了事件化的io模型。感觉就和用vb的winsock控件一样,而且比winsock的要简单且功能丰富。再也不用为了大量的同步,回掉和异常处理而操心了,oh,yeah~
Mian是apache的开源项目,网站是http://mina.apache.org 有兴趣的不妨看看~

2008年7月22日星期二

多线程环境下的性能杀手:日志记录

今天晚上做了一个性能测试,发现在同等条件下,使用日志的处理速度比关闭所有日志慢了接近10被。
我的应用是一个基于Mian的多线程服务器程序,在打开日志时进行压力测试,发现Profiler的Thread图表基本上是万里河山一片红:
根据图例,红色代表线程正在等待某个监视器。但是我的事务代码基本上没有什么使用同步的东西啊……数据库连接也用ThreadLocal了,不应该出现这种情况啊。
经过检查,发现拖慢处理速度的就是平时经常使用的日志。因为Logger的方法都是同步的(或者从根本上说,System.out和System.err就是一个同步的输出流)所以造成线程在处理时不得不停下来等待其他线程完成日志输出。就算不用Logger,用System.out.println()也是一样的道理。
编辑日志属性,关闭所有日志以后,性能有了极大的提高,每秒能处理的请求数量提升了13倍左右。

暴强的RP学3定律

今天DB提到的,一Google还真的有唉……真的囧到我了~~


人品学基本定律


“人品既不能被创生,也不能被消灭。只能从一个人转移到另一个人,从一个层面转化到另一个层面,而在转移和转化的过程当中,人品的总和保持不变。至此引出人品学(Characterics)三定律:


第一定律:即人品守恒定律,在任何过程中,宇宙中人品总量保持为常数。(也就是说,做好事增加人品做坏事损人品,遇到好事是以前积攒的人品起了作用,而要使你连自己系开的必修课都没选上,那你真的要多扶扶老奶奶过马路了)


第二定律:不可能把人品从一个人品低的人传到一个人品高的人,而不引起其它变化。(也就是说,人品低的想获得人品需要付出一定的代价,而请客吃饭等就是其最简单易行的途径。)


第三定律:不能用有限的步骤使一个人的人品完全消耗。(也就是说,你再怎么霉,也还是会有点人品存量的,所以永远不要灰心丧气。)请大家看一个范例:「塞翁的马丢了,他说“没事,攒人品”,当他丢失的马带回来一群马,别人羡慕不已,他则暗叹“不妙,人品消耗的太多”,果然他的儿子因为骑马而摔断了腿后,他摇摇头说“继续攒人品”,等到战争时别人家的孩子被征兵战死沙场,只有他的儿子因为腿断了而幸免,这时他激动地说“人品爆发了啊”......」


而现在的人品学家们在人品学理论的微观研究上已取得了革命性突破,在量子力学、大一统论、超弦理论大旗号召下的今天,让我们一起走进量子人品学(Quantum Characterics)的新纪元!


又发现的另外一种表述:


  1)RP第一定律------RP守恒定律


  RP是不能用科学原理和自然规律解释的一种非物质存在形式,一切不能用上述机理解释的问题,全部归类于RP问题。RP不能凭空生成,也不会凭空消失。它在自然界的总和一定。在一定时期,某个静态有机体所含有的RP一定。消耗RP,RP值降低,积攒RP,RP值升高。


  2)RP第二定律------RP传递定律


  RP只能自发地从RP高的物体传到RP低的物体,反之不成立。如果要使上述情况成立,必须消耗好人卡,公式:


  RP = Num.好人卡/ 客观条件 + 机遇。


  3)RP第三定律------RP数值定律


  RP最小值为零,最大值正无穷, 物理意义上不存在负RP.

   
  [人品的定义]:
从广义上说,但凡科学无法确定的的,不在科学所能接受范畴之内的现象均可用人品来给出解释,即人品是涵盖宏观和微观世界的客观存在;从狭义上说,人品也称为运势,通过个体衍生至全部,从而影响整个宇宙的发展。


  [人品的性质]:
  人品是客观存在的,不以人的意志为转移;人品是无处不在,无所不能的;人品是绝对的,不受任何外力的影响。


  [人品守恒定律]:
  宇宙的总人品是恒定的,有些人人品值高了,另一些人的人品值便会相应降低;个人的总人品在某一时间段内是恒定的,今天人品值低了,改天便会相应增高,但没有固定的期限。


  [人品转移定律]:
  人品是可以相互转移的,但这种转移必须通过必要的手段,譬如烧香,祈祷,诅咒等,以及相应的媒介,譬如遭遇高僧或者超级霉人。


[人品统计定律]:
对于个体事件,人品是极不确定的,或不可量度的;然而对于大量的事件而言,人品会体现一定的统计规律。


人品与获得满足的关系:


导论:


人品作为一般等价物,为满足日常需要,需投入一定的人品,以投入人品与获得的效用的数据构建图像,可以得到基数人品论(cardinal characterics)的边际人品-效用图。后来,有学者提出人品不可测量,只可比较,由此发展了序数人品论(ordinal characterics),目前比较成熟完善的是基数人品论。


基数人品论的一些观点:


1.为提高享受,需不断追加人品消耗,而享受的提高因随追加人品的增加而递减,享受提高为零时,投入人品就应停止,如再增加,则成为负数。即“人品效率递减定律”。表达式:dU/dRP<0


2.人品等分配定律:当面临多种消耗人品的活动时,应使得花费在所有活动的最后一单位人品边际效用相等。这样能将给定的人品转化出最大效用。表达式:dUk/dRPk=dU(k+1)/dRP(k+1),k∈N。


3.在原有人品消费已满足的前提下,要想用人品换取更多的好处,只有发展新人品消费项目和扩充原有人品消费项目。


规模人品:


消费人品的活动,必须根据它的特点,确立一个起始人品投入规模/最小人品投入规模或称“最小有效规模”,投入低于这一规模,就会导致回报为零。超过这一规模,即进入一个“合理规模”区间,在这一区间内,追加人品投入都会得到回报。


人品爆发:


一定条件下,存在以单位最小人品投入量获得最大单位的收益的点,称为“人品爆发点”。
但这种事件的发生时间、场所等往往难以确定。


由人品等分配定律可得,单位最小人品投入量获得最大单位的收益的点就是起始点。“人品爆发点”与之矛盾,如何解释呢?后经科学家赵明毅(?-2007)研究,人品爆发原因是他的故土--锑星星球有重要关系。锑星特有物质磷化卤(R?P),理化特性由于赵明毅的离奇失踪(?)而流失。其独特的的反重力性(探佚专家自《大锑赵明毅》相关章节推出)使得部分游离态磷化卤会脱离锑星,被喷射出去,从而对人品分布产生干扰,导致部分时间与场人品运行机理扭曲。由于历史原因,人品爆发常被归结于行善,现在这个概念已由国际人品研究协会(International Characteric Research Association,ICRA)规范化,形成了目前的通用表述与解释。

2008年7月17日星期四

附送本本照片一张


纯属无聊,发上来玩玩

写代码一定要小心

今天写程序时遇到一个问题,调试了半天没头绪,结果最后发现是一个非常脑残的问题:
问题代码如下:
        PreparedStatement ps = conn.prepareStatement(
                "INSERT INTO certs"/* +
                "   [CertData] ," +
                "   [PK_DUMP] ," +
                "   [PK_N],"+
                "   [PK_E],"+
                "   [Signature] ," +
                "   [Version] ," +
                "   [SigAlgName] ," +
                "   [SigAlgOID] ," +
                "   [SigAlgParams] ," +
                "   [SubjectDN] ," +
                "   [IssuerDN] ," +
                "   [CertDump] ," +
                "   [ServerName]) "*/ +
                "VALUES (null , ? , ? , ? ,? , ? , ? , ? , ? , ? , ? , ? , ? , ?)");
        ps.setBytes(1, cert.getTBSCertificate());
        System.out.println(cert.getTBSCertificate().length);
        if (goodPk) {
            ps.setBytes(2, pk.getEncoded());
            System.out.println(pk.getEncoded().length);
        } else {
            ps.setBytes(2, null);
        }
        if (rsapk != null) {
            ps.setBytes(3, rsapk.getModulus().toByteArray());
            ps.setBytes(4, rsapk.getPublicExponent().toByteArray());
        } else {
            ps.setBytes(3, null);
            ps.setBytes(4, null);
        }
        ps.setBytes(5, cert.getSignature());
        System.out.println(cert.getSignature().length);
        ps.setInt(6, cert.getVersion());
        ps.setString(7, cert.getSigAlgName());
        System.out.println(cert.getSigAlgName().length());
        ps.setString(8, cert.getSigAlgOID());
        System.out.println(cert.getSigAlgOID().length());
        if (cert.getSigAlgParams() != null) {
            ps.setBytes(9, cert.getSigAlgParams());
            System.out.println(cert.getSigAlgParams().length);
        } else {
            ps.setBytes(9, null);
        }
        ps.setString(10, cert.getSubjectDN().toString());
        System.out.println(cert.getSubjectDN().toString().length());
        ps.setString(11, cert.getIssuerDN().toString());
        System.out.println(cert.getIssuerDN().toString().length());
        ps.setString(12, cert.toString());
        ps.setString(13, serverName);
        return ps.executeUpdate();
你能看出这段代码有什么问题么?无论怎么改,总是提示我SQL语法出错=,=
看出来了么?问题在这里:
        PreparedStatement ps = conn.prepareStatement(
                "INSERT INTO certs"/* +
                "   [CertData] ," +
                "   [PK_DUMP] ," +
                ...
                "   [ServerName]) "*/ +
                "VALUES (null , ? , ? , ? ,? , ? , ? , ? , ? , ? , ? , ? , ? , ?)");
吧列名注释掉以后,表名和VALUES关键字后面少了一个空格!,所以无论如何都会出错……
所以遇到什么奇怪的问题时不妨仔细看看代码……不要像我今天这么脑残~~

2008年7月15日星期二

到北京啦!

昨天晚上10:30到北京西站。今天下午15:30在北京站做另一趟回家的火车。
从桂林到北京一共花了27小时30分(晚点40分)。一上车发现车上有电源插座,很高兴。结果插上变压器一试=,=没有电 = =||
然后听到广播说:车上的设施多么多么好,有空调,热水****,无线上网!?
听到以后马上掏出本本链接,果然提示说发现无线网络,而且是无加密的,信号质量是80%,大喜,链接之,遂提示:以链接到无线局域网- -||
怎么是局域网?打开浏览器,找不到服务器,再ping一下google,域名解析失败=,=
等乘务员来了一问,说"这个无线啊,摆设来的,不能用” 某熊擦汗中……
三个小时以后,电源耗尽,开始冬眠……车上空调开的挺大,有点冷……
然后顺利抵京。
PS附送登录界面一张


2008年7月13日星期日

一切就绪,准备出发

这次某熊回家的行李有:
活熊一只(- -||)
本本一台
硬盘两块
键盘一块
鼠标两只
包包两个
手机一台
电池两块
充电器一个
其他杂碎物品若干
PLMM:0只=_=b
一起就绪, Ready~Go!

收拾东西准备回家咯~

今天下午7:00的火车,现在开始收拾一下东西。不过这次回家没什么好拿的,一人、一本、一包足以~~床上乱堆的书和光盘要处理一下……而且经常发现在大堆的书和CD中混进了奇怪的东西= =||要好好整理一下才行。
这次回家基本没什么时间上网的,找不到人不要奇怪。

发现一个好玩的东西

┏━┯━┯━┯━┯━┯━┯━┯━┯━┯━┓
┃ │ │ │墙│,│我│帖│中│错│刚┃
┃ │ │ │鼓│伟│们│吐│国│,│发┃
┃ │ │ │掌│大│再│槽│特│蛮│现┃
┃ │ │ │吧│的│次│的│色│好│这┃
┃ │ │ │!│政│为│必│的│玩│个┃
┃ │ │ │ │府│了│备│互│的│东┃
┃ │ │ │ │和│伟│之│联│。│西┃
┃ │ │ │ │伟│大│物│网│是│M┃
┃ │ │ │ │大│的│。│上│在│S┃
┃ │ │ │ │的│党│让│发│有│不┃
┗━┷━┷━┷━┷━┷━┷━┷━┷━┷━┛
此古书式竖文格式由 http://www.cshbl.com/shuwen.html 在线竖文转换器生成

2008年7月10日星期四

考完高数的郁闷和听说RSA破解理论的惊奇

今天某熊考高数啊……2个星期以前就结课,一直没看……结果自然是……郁闷。
回来以后遇到一位来自德国的仁兄,问我那个SSL证书的事情,但是他要求的目的很奇怪:不要求验证证书的有效性,而且还要收集证书。
某熊好奇的问了一句收集证书做什么用。得到了一个意想不到的回答:通过大量的收集SSL证书,然后根据某个理论,找出可能出错的那个证书,从而逆退出根ca的私钥?
某熊不是搞加密的,也不是很懂。这位仁兄的原话在这里:

***** 22:51:57
我收集证书用来探测其中RSA算法的漏洞
***** 22:52:43
虽然其概率很小,但是可能比如一万份里或者十万份里会有一个带着错误RSA算法的证书
***** 22:53:20
根据他里面的错误的签名,就可以破解整个CA的私钥
***** 22:54:09
理论基础是中国剩余定理,RSA是基于这个方法制作签名的。
IcyBear 22:54:06
根据签名和明文逆推私钥么?
***** 22:55:19
对,是的。前提是,RSA是基于中国剩余定理,并在特定的环境,比如温度高或者磁场因素等等,会偶然的生成错误的签名
***** 22:55:35
那这个签名就是攻破整个CA系统的钥匙
IcyBear 22:56:01
祝你成功~~
IcyBear 22:56:16
这样需要的运算量大么?
开放式互联 22:57:12
呵呵,谢谢,现在才是万里长征的第一步,运算量蛮大的,但首先须收集到足够的证书,及错误的签名

具体是不是真的可行,我就不知道了。作为位仁兄给出了一个参考资料的地址,有兴趣的童鞋们可以去看看,英文的哦。
http://www.geocities.com/marcjoye/papers/chinese99.pdf

2008年7月9日星期三

囧:《新世纪鹡鸰战士》

说实话,我是冲着这个名字才点击去看的……好吧,我承认这个名字起的囧了一点= =|||
片子下载了一集,没什么感觉,属于卖肉系的=,= 某熊不控这一系,丢掉。
====华丽的囧吧的分割线====
中文名称:新世纪鹡鸰战士
英文名称:Sekirei
版本:[空间字幕组][2008.07番][MKV+RMVB][1280X720][01]
发行时间:2008年07月
地区:日本
语言:日语
简介


【片名】Sekirei-新世纪鹡鸰战士
【字幕】空间字幕组
【格式】MKV+RMVB

【内容介绍】

第二次应考失败的主角碰上了寻找各自的主人的苇牙女主后为了参加迷之计划“鹡

鸰计划”的故事


【STAFF】

监督:草川启造
脚本:吉冈たかを 
角色设计:友冈新平
美术监督:东润一 
美术设定:泉寛 
色彩设计:甲斐けいこ 篠原爱子 
撮影监督:中山敦史 
编集:布施由美子 野尻由纪子(ウィンズ) 
音楽:佐野広明 
音响监督:明田川仁(マジックカプセル) 
効果:高梨絵美(eNa) 
音响制作:グロービジョン 
动画制作:セブン アークス 
制作:アニプレックス、セブン アークス、ムービック


【CAST】

佐桥皆人:立花慎之介
结:早见沙织(川澄绫子)
月海:井上麻里奈(田中理惠)
草野:花泽香菜(田村ゆかり)
松:远藤綾(松冈由贵)
浅间美哉:大原さやか
焔/篝:甲斐田ゆき(平田宏美)
瀬尾:小西克幸(中井和哉)
光:甲斐田裕子
响:根谷美智子
鈿女:生天目仁美(小林ゆう)
佐桥ユカリ:阿澄佳奈
椎菜:石塚さより
秋津:小林ゆう
蜜羽:矢作纱友里

2008年7月7日星期一

买到车票,可以回家啦

经过两个多小时的漫长排队,终于买到了7月13日会北京的车票。本来打算11号就回去的,结果11号的车票已经卖完,12号只有上铺。只能买13号的票了。华丽的花了300大洋=,=|||

2008年7月6日星期日

某人的作业,有用的拿走

今天下午五分钟给某人赶制的作业一份,有需要的拿走。
关键字:java socket tcp 文件传输


import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.Socket;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;

/*
* Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
* Release under GNU/GPL Version 2.
*/
/**
*
* @author Bearice
*/
public class FileTransport {

public static void send(String args[]) throws Exception {
String host = args[1];
int port = Integer.parseInt(args[2]);
System.out.printf("Connecting to %s:%d\n", host, port);
Socket socket = SocketFactory.getDefault().createSocket(host, port);
FileInputStream fis = new FileInputStream(args[3]);
int b;
System.out.println("Sending...");
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
while ((b = fis.read()) != -1) {
bos.write(b);
}
bos.close();
}

public static void recv(String args[]) throws Exception {
int port = Integer.parseInt(args[1]);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(args[2]));
System.out.printf("Listening on port %d\n", port);
Socket socket = ServerSocketFactory.getDefault().createServerSocket(port).accept();
int b;
InputStream is = socket.getInputStream();
System.out.println("Recving...");
while ((b = is.read()) != -1) {
bos.write(b);
}
bos.close();
}

public static void main(String[] args) throws Exception {
if (args.length == 4 && args[0].equalsIgnoreCase("send")) {
send(args);
} else if (args.length == 3 && args[0].equalsIgnoreCase("recv")) {
recv(args);
} else {
System.out.println("Usage:");
System.out.println("FileTransport [recv|send <host>] <port> <file>");
}
}
}

2008年7月5日星期六

使用Java进行双向认证的SSL链接以及使用OpenSSL生产证书链

这几天被SSL和证书搞得头昏脑胀的。不过还好终于把这个SSL搞定了。

用SSL进行双向身份验证意思就是在客户机连接服务器时,链接双方都要对彼此的数字证书进行验证,保证这是经过授权的才能够连接(我们链接一般的SSL时采用的是单向验证,客户机只验证服务器的证书,服务器不验证客户机的证书。而连接网上银行时使用的U盾就是用来存储进行双向验证所需要的客户端证书的)。

JDK里面内置了一个数字证书生产工具:keytool。但是这个工具只能生成自签名的数字证书。所谓自签名就是指证书只能保证自己是完整的,没有经过非法修改的。但是无法保证这个证书是属于谁的。其实用这种自签名的证书也是可以进行双向验证的(用keytool生成的自签名证书进行双向验证请看这里,向这位仁兄致意~:http://www.blogjava.net/stone2083/archive/2007/12/20/169015.html),但是这种验证有一个缺点:对于每一个要链接的服务器,都要保存一个证书的验证副本。而且一旦服务器更换证书,所有客户端就需要重新部署这些副本。对于比较大型的应用来说,这一点是不可接受的。所以就需要证书链进行双向认证。证书链是指对证书的签名又一个预先部署的,众所周知的签名方签名完成,这样每次需要验证证书时只要用这个公用的签名方的公钥进行验证就可以了。比如我们使用的浏览器就保存了几个常用的CA_ROOT。每次连接到网站时只要这个网站的证书是经过这些CA_ROOT签名过的。就可以通过验证了。

但是这些共用的CA_ROOT的服务不是免费的。而且价格不菲。所以我们有必要自己生成一个CA_ROOT的密钥对,然后部署应用时,只要把这个CA_ROOT的私钥部署在所有节点就可以完成验证了。要进行CA_ROOT的生成,需要OpenSSL(http://www.openssl.org/)。你也可以在http://www.slproweb.com/products/Win32OpenSSL.html找到Windows下的版本

安装好OpenSSL以后就可以生成证书链了,我写了一个BAT解决这些东西:



@echo off
:OpenSSL配置文件路径(如果出现“The organizationName field needed to be the same in the”之类的错误,请编辑此文件,修改CA_default节中的policy = policy_match为policy = policy_anything
set CONFIG="D:\OpenSSL\bin\openssl.cfg"
:服务器证书库密码
set PWD_SERVER_KS=serverks
:服务器证书密码
set PWD_SERVER_KEY=serverkey
:客户端证书库密码
set PWD_CLIENT_KS=clientks
:客户端证书密码
set PWD_CLIENT_KEY=clientkey
:有效期(天)
set VALIDITY=365
:服务器证书名
set SERVER_CERT_NAME=logon_server_private_key
:客户端证书名
set CLIENT_CERT_NAME=ipclient_private_key
:服务器证书库文件名
set SERVER_KEYSTORE_NAME=server.keystore
:客户端证书库文件名
set CLIENT_KEYSTORE_NAME=client.keystore

if not exist DemoCA (
mkdir DemoCA
mkdir DemoCA\certs
mkdir DemoCA\newcerts
echo CAFEBABE>DemoCA\serial
copy nul DemoCA\index.txt
)

if not exist ca.key (
echo Generating a ca root key file...
openssl req -new -x509 -keyout ca.key -out ca.crt -config %CONFIG%
) else (
echo ca.key already exists...
)

if not exist server.keystore (
echo Generating server's private key...
keytool -genkey -alias %SERVER_CERT_NAME% -validity %VALIDITY% -keyalg RSA -keysize 1024 -keystore %SERVER_KEYSTORE_NAME% -keypass %PWD_SERVER_KEY% -storepass %PWD_SERVER_KS%
) else (
echo server.keystore already exits...
)

if not exist client.keystore (
echo Generating client's private key...
keytool -genkey -alias %CLIENT_CERT_NAME% -validity %VALIDITY% -keyalg RSA -keysize 1024 -keystore %CLIENT_KEYSTORE_NAME% -keypass %PWD_CLIENT_KEY% -storepass %PWD_CLIENT_KS%
) else (
echo client.keystore already exits...
)

echo ========Finished key generation=========

if not exist %SERVER_CERT_NAME%.csr (
echo Generating server's singature request file...
keytool -certreq -alias %SERVER_CERT_NAME% -sigalg MD5withRSA -file %SERVER_CERT_NAME%.csr -keypass %PWD_SERVER_KEY% -storepass %PWD_SERVER_KS% -keystore %SERVER_KEYSTORE_NAME%
) else (
echo %SERVER_CERT_NAME%.csr already exits...
)

if not exist %CLIENT_CERT_NAME%.csr (
echo Generating client's singature request file...
keytool -certreq -alias %CLIENT_CERT_NAME% -sigalg MD5withRSA -file %CLIENT_CERT_NAME%.csr -keypass %PWD_CLIENT_KEY% -storepass %PWD_CLIENT_KS% -keystore %CLIENT_KEYSTORE_NAME%
) else (
echo %CLIENT_CERT_NAME%.csr already exits...
)

if not exist %SERVER_CERT_NAME%.crt (
openssl ca -in %SERVER_CERT_NAME%.csr -out %SERVER_CERT_NAME%.crt -cert ca.crt -keyfile ca.key -notext -config %CONFIG%
) else (
echo %SERVER_CERT_NAME%.crt already exits...
)

if not exist %CLIENT_CERT_NAME%.crt (
openssl ca -in %CLIENT_CERT_NAME%.csr -out %CLIENT_CERT_NAME%.crt -cert ca.crt -keyfile ca.key -notext -config %CONFIG%
) else (
echo %CLIENT_CERT_NAME%.crt already exits...
)

echo =========Finished ca root signaturing==========

echo Importing ca root certs into keystore...

keytool -import -v -trustcacerts -alias ca_root -file ca.crt -storepass %PWD_SERVER_KS% -keystore %SERVER_KEYSTORE_NAME%

keytool -import -v -trustcacerts -alias ca_root -file ca.crt -storepass %PWD_CLIENT_KS% -keystore %CLIENT_KEYSTORE_NAME%

echo Importing signatured keys...

keytool -import -v -alias %SERVER_CERT_NAME% -file %SERVER_CERT_NAME%.crt -keypass %PWD_SERVER_KEY% -storepass %PWD_SERVER_KS% -keystore %SERVER_KEYSTORE_NAME%

keytool -import -v -alias %CLIENT_CERT_NAME% -file %CLIENT_CERT_NAME%.crt -keypass %PWD_CLIENT_KEY% -storepass %PWD_CLIENT_KS% -keystore %CLIENT_KEYSTORE_NAME%

echo All done!

运行这个批处理,期间需要回答一些问题,然后就可以得到一些文件其中client.keystore是需要在客户端部署的,server.keystore是在服务器部署的。ca.*是root_ca的密钥文件。
然后可以用下面的代码测试:

/*
* Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
* Release under GNU/GPL Version 2.
*/

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

/**
*
* @author Bearice
*/
public class NewClass extends Thread {

@Override
public void run() {
try {
sleep(100);
SSLContext ctx = SSLContext.getInstance("SSL");

KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

KeyStore ks = KeyStore.getInstance("JKS");
//KeyStore tks = KeyStore.getInstance("JKS");

ks.load(new FileInputStream("e:/certs/client.keystore"), "clientks".toCharArray());
//tks.load(new FileInputStream("e:/certs/tclient.keystore"), "clientks".toCharArray());

kmf.init(ks, "clientkey".toCharArray());
tmf.init(ks);

ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLSocketFactory factory = ctx.getSocketFactory();

SSLSocket socket = (SSLSocket) factory.createSocket("127.0.0.1", 4433);

showCerts(socket.getSession());

PrintWriter pw = new PrintWriter(socket.getOutputStream());
pw.println("GET /index.html HTTP/1.0");
pw.println("Server: mail.google.com");
pw.println("Connection: close");
pw.println();
pw.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String ln;
while ((ln = in.readLine()) != null) {
System.err.println(ln);
}
} catch (Exception ex) {
Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
}
}

public static void showCerts(SSLSession session) {
X509Certificate cert = null;
try {
cert = (X509Certificate) session.getPeerCertificates()[0];
} catch (SSLPeerUnverifiedException e) {
e.printStackTrace();
System.err.println(session.getPeerHost() + " did not present a valid certificate");
//System.exit(1);
return;
}
System.out.println(session.getPeerHost() + " has presented a certificate belonging to" + "[" + cert.getSubjectDN() + "]\n" + "The certificate was issued by: \t" + "[" + cert.getIssuerDN() + "]");

}

public static void main(String[] args) throws Exception {
SSLContext ctx = SSLContext.getInstance("SSL");

KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

KeyStore ks = KeyStore.getInstance("JKS");
//KeyStore tks = KeyStore.getInstance("JKS");

ks.load(new FileInputStream("e:/certs/server.keystore"), "serverks".toCharArray());
//tks.load(new FileInputStream("e:/certs/tserver.keystore"), "serverks".toCharArray());

kmf.init(ks, "serverkey".toCharArray());
tmf.init(ks);

ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

SSLServerSocketFactory factory = ctx.getServerSocketFactory();
SSLServerSocket serverSocket = (SSLServerSocket) factory.createServerSocket(4433);

serverSocket.setNeedClientAuth(true);

new NewClass().start();

SSLSocket socket = (SSLSocket) serverSocket.accept();
try {
socket.startHandshake();
} catch (Exception ex) {
System.out.println("Handshake failed: " + ex);
}

showCerts(socket.getSession());
socket.startHandshake();
PrintWriter out = new PrintWriter(socket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String ln;
while ((ln = in.readLine()) != null) {
System.out.println(ln);
if (ln.equals("")) {
break;
}
}
out.println("HTTP/1.1 200 OK");
out.println("Cache-Control: no-cache");
out.println("Pragma: no-cache");
out.println("Expires: Fri, 01 Jan 1990 00:00:00 GMT");
out.println("Content-Type: text/html; charset=UTF-8");
out.println("Date: Tue, 01 Jul 2008 11:56:42 GMT");
out.println("Server: BWS");
out.println("X-Powered-By: BWS");
out.println();
out.println("

hello world

");
out.close();
socket.close();
}
}


其他参考链接:
SSL-用Keytool和OpenSSL生成和签发数字证书
为高级 JSSE 开发人员定制 SSL

法×功分子们偶尔也做一点好事嘛

ma~那些家伙们虽然做了不少坏事,但是就一件事来是,是绝对值得肯定的: 提供了反GFW的软件。这年头GFW被滥用的厉害,前两天连SourceForge都被墙了,政府那帮白痴吃饱了撑的啊。前两天大树说GFW让他想起了Q朝的文字狱,这该死的GFW果然就是文字狱的网络版(传说中的文字狱.net么?GF是不是收了M4什么好处啊……)。
牢骚暂停(因为还有很多很多,懒得吐槽了)最后大喊一声:

F**K GFW!!!

2008年7月3日星期四

大家都俯卧撑了,我也俯一下好了

受神秘诅咒美军昨夜从伊拉克紧急撤军
文章提交者:评评灌灌
转载自http://yang1965888.blog.163.com/blog/static/58064872008638372220/
(此链接已经被HX,多亏Google快照)


  美军昨夜从伊拉克紧急撤军

   C&K巴格达讯(记者:评评灌灌):7月2日凌晨2点,平静已久的伊拉克突然陷入混乱,大街上随处可见仓皇逃窜的美军士兵,城中到处充斥着带着 美式英语腔调的哀嚎声,人们惊奇地发现,身上仅穿一条四角内裤的驻伊美军司令彼得雷乌斯将军也在奔跑的人群当中,惊慌失措的他脚上连一双鞋都没有,尽管光 着脚丫,但是他奔跑的速度并没有受到丝毫的影响。

  在巴格达街上,随处可见美军士兵丢弃的武器。一只无主宠物犬的嘴里竟然叼着一颗美军 士兵丢弃的手雷。宠物犬走到哪里,哪里的人群便四处逃窜。记者拦住一位身上没有携带任何武器的跑得上气不接下气的美军士兵询问,那位美军士兵哭着警告记 者:快跑,俯、俯卧撑。话没说完,那位美军就撇开记者跑得不见了身影。

  经过多方了解,原来从北京时间7月1日17点40分以后,巴格达城中出现了三名能发出驴叫一样声音的神秘人,这三名神秘人一见到美军士兵就趴在地上做俯卧撑,一做就是三个,不多也不少。美军士兵见了以后就像中了邪一样纷纷跳入底格里斯河自杀, 由于自杀人数众多,底格里斯河河岸上挤满了焦急地等候自杀的美军士兵。美军士兵们在自杀前都不约而同地说着同样的一句话:“跳河死了算了,如果死不成就好 好活下去”。一些实在等不及跳河的美军士兵则纷纷开枪自杀或者互相开枪对射。底格里斯河在不到一个小时的时间内就被鲜血染红。

  “神秘 人俯卧撑”带来的恐慌由巴格达迅速蔓延到了伊拉克全境所有的驻伊美军当中,大批美军在没有任何命令的情况下擅自向伊拉克边境逃离,部分还没有见到神秘人的 驻伊美军由于担心自己不能及时逃离伊拉克,在极度恐慌的情况下纷纷用军用匕首戳瞎了自己的双眼,想藉此逃避神秘人的“俯卧撑诅咒”。一些没有匕首的美军文 职军官则用自己的双手抠瞎了自己的双眼。一位名叫詹姆斯·黔李的女军官用手指夹着自己的两个刚刚抠出的眼球幸福地说到:“看你俯卧撑快还是我抠眼珠子 快!”

  截至今晨北京时间9点30分,巴格达街头的美军士兵所剩无几,剩下的均是双眼失明的美军士兵,他们互相搀扶着,迈着坚定的步伐要离开伊拉克。

   据了解,美军逃离巴格达的事件发生后,美军紧急召开参谋长联席会议研究对策。经过多方调查和求助,一名香港某报的口吃记者向美国军方提供了一个令人匪夷 所思的对策,该名口吃记者向美国军方表示:美军士兵一旦发现有人在自己面前做俯卧撑,只要没有看到对手连续做三个俯卧撑就没事,一个、两个或者三个以上的 俯卧撑对美军士兵没有生命威胁。该名口吃记者在向美国军方陈述这种解决方法时由于口吃过于严重,导致现场的六名焦急的美军高层人士心脏病发作,其中4人由于抢救无效死亡。

  尽管找到了解决方法,但是蔓延在驻伊美军中的恐慌并没有消除。据知情人透露,基地组织目前对“俯卧撑诅咒”的杀伤力非常感兴趣,正计划不惜一切代价想把“俯卧撑诅咒”这种超自然战术武器据为己有。

Java在处理SSL时证书无效的问题,以及解决方法

Java内置了对HTTPS和SSL的支持,但是我在写客户端时遇到了一些问题,比如最大的问题就是在连接的服务器没有一个有效的(也就是经过根CA认证的)SSL证书时会报错。Google了一下,说有两种方式:一种是事先把目标证书导入Java的证书管理器里,另一种是强制忽略证书合法性检查。第一种方法不用对代码进行什么更改,只要运行一个命令就行了,但是缺点是每次服务器更换证书都要进行一次导入。
第二种方法需要更改一下代码,优点是可以应用于任何SSL证书,而且不用重复导入,缺点也很明显,降低了系统的安全性。
下面是第二钟方法的实例代码


try {
final SSLContext sslContext = SSLContext.getInstance("TLSv1");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {

public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
}

public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
//这里进行有效性检查,不抛出异常就算检查成功
}

public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
}, null);
sleep(100);
SSLSocketFactory factory = sslContext.getSocketFactory();
final SSLSocket socket = (SSLSocket) factory.createSocket("127.0.0.1", 4433);
SSLSession session = socket.getSession();
X509Certificate cert = null;
try {
cert = (X509Certificate) session.getPeerCertificates()[0];
} catch (SSLPeerUnverifiedException e) {
e.printStackTrace();
System.err.println(session.getPeerHost() + " did not present a valid certificate");
return;
}
System.out.println(session.getPeerHost() + " has presented a certificate belonging to" + "[" + cert.getSubjectDN() + "]\n" + "The certificate was issued by: \t" + "[" + cert.getIssuerDN() + "]");
PrintWriter pw = new PrintWriter(socket.getOutputStream());
pw.println("GET /index.html HTTP/1.0");
pw.println("Server: mail.google.com");
pw.println("Connection: close");
pw.println();
pw.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String ln;
while ((ln = in.readLine()) != null) {
System.err.println(ln);
}
} catch (Exception ex) {
Logger.getLogger(ServerLauncher.class.getName()).log(Level.SEVERE, null, ex);
}

浅析Java内部类与嵌套类

浅析Java内部类与嵌套类

Abstraction:

本文描述了Java语言的嵌入类、内部类的具体分类和行为表现。

1 概述

我们知道,Java是一种完全的面向对象的语言,作为对象的灵魂,类的种类是多种多样的。类大致可以分外部类和内部类两种,外部类就是我们通常使用的类,而内部类的使用要比外部类少的多,最常见的是GUI事件侦听器。内部类的应用虽然不多,但是如果能够有效的使用内部类,能达到事半功倍的效果。废话不多说,下面开始:

2 内部类和嵌套类

要讨论内部类和嵌套类,首先要分清他们两者的区别于联系。

首先,内部类(Inner Classes)和嵌套类(Nested Classes)是指在一个类里面定义的另一个类。其次无论是内部类还是嵌套类,在编译时都被当作一个独立的整体。对于访问他们的其他对象来说(假如他们对这个类来说是可见的)他们的使用和我们通常用的类是一样的。

但是,内部类和嵌套类的区别在于:

1. 嵌套类是静态的,而内部类不是,也就是说嵌套类的实例化不需要外部类的实例。但是内部类是需要这个实例的。

2. 嵌套类可以任意声明静态成员,内部类不允许声明除了编译时常量以外的任何静态成员。这一限制也适用于静态初始化函数。

3. 嵌套类都是命名的,匿名的类声明不能声明运行时静态成员(不管声明是不是静态的)。

注意:类内部声明的接口都属于嵌入类。

下面我们来分别讨论一下他们的具体行为表现。

3 内部类

内部类是指在一个类里面以非静态形式声明的另一个类。内部类的实例化需要外部实例的存在。一个类可以拥有多个内部类,一个外部实例可以拥有多个内部类的实例。但是内部类有且只有一个外部实例,并且在实例化时就已经指定,无法更改。

3.1 内部类的分类

内部类根据访问权限不同可以分为以下一种类型:普通内部类局部内部类

普通内部类和局部内部类主要的区别在于作用域和访问权限的不同,普通内部类可以被所有人访问(只要访问控制符允许),而局部内部类的作用域更像一个变量,只能在定义它的函数内部被使用,其他人是无法使用这个类的。而且局部类可以访问定义它的函数中的final变量。

根据声明方式不同又可以分为:命名内部类匿名内部类。命名内部类和匿名内部类的区别在于:

首先,命名类可以抽象的。匿名类不能为抽象,事实上,匿名内部类在编译时被隐形的声明为最终的(final)

其次,命名类声明可以继承一个父类并实现多个接口,匿名类只能有一个父类(或者接口)。

再次,命名类可以被多次实例化,而匿名类只能在定义时被实例化一次。

最后,命名类可以声明多个构造函数并控制访问哪一个父类的构造函数,匿名类无法声明构造函数。

下面分别描述这些区别:

3.2 普通内部类

普通内部类是指在类成员定义中定义的类,这些类可以拥有访问控制符(public, private)。如果访问控释符允许,则这些类可以被外面直接应用。普通命名内部类可以声明为一个接口,或者是抽象的。嵌入类其实是特殊的普通内部类,但由于其特殊性,故在下面独立讨论。

3.2.1 声明

3.2.1.1 命名类

class OuterClass{

//Outer class deflation
class InnerNamedClass{
//Inner class definition

}
}

3.2.1.2 匿名类

声明匿名类时,可以使用一个类或者接口作为他的父类。

class OuterClass{
//Outer class deflation
Object unnamedObject = new Object(){
//Inner class definition
}
}

3.2.2 实例化:

3.2.2.1 命名类

外部或静态方法

OuterClass outerObject = new OuterClass();
OuterClass.InnerNamedClass innerObject = outerObject.new InnerNamedClass();

内部

InnerNamedClass innerObject = new InnerNamedClass();

3.2.2.2 匿名类

定义时即完成实例化

3.2.3 访问权限:

3.2.3.1 内部实例对外部实例的访问权限为:

外部类定义或继承的所有字段

3.2.3.2 外部实例对内部实例的访问权限为:

内部类定义或继承的所有字段

3.2.3.3 其他对象对内部实例的访问权限为:

若内部类不可见,则只能访问其超类定义的字段

若内部类可见,则可访问内部实例的非私有字段,具体情况与通常的类类似

3.2.4 备注:

内部类的外部实例是在构造时作为参数传给构造函数的,在SUN JDK中,保存外部实例的字段通常被声明为:

final OutterClass this$0;

3.3 局部内部类

局部内部类,是指在函数体内声明的类,这种类是局域性的,只在函数内声明后有效,他最大的特点是:可以访问定义它的函数中的final变量。

3.3.1 声明:

3.3.1.1 命名类:

class OuterClass{
//Outer class deflation
void aMethod(){
class InnerNamedClass{
//Inner class definition
}
}
}

3.3.1.2 匿名类:

class OuterClass{
//Outer class deflation
void aMethod(){
Object unnamedObject = new Object(){
//Inner class definition
}
}
}

3.3.2 实例化:

3.3.2.1 命名类:

局部类的作用域仅限定义该类的方法中,无法在外部实例化或访问,实例化方法与通常类相同

3.3.2.2 匿名类:

定义时即完成实例化

3.3.3 访问权限:

3.3.3.1 内部实例对外部实例的访问权限为:

外部类定义或继承的所有字段

定义该内部类的方法在定义类之前所定义的所有final变量

3.3.3.2 外部实例对内部实例的访问权限为:

在定义该内部类的方法中可以访问内部类定义或继承的所有字段

在外部实例的其他字段中只能访问其超类定义的字段

3.3.3.3 其他对象对内部实例的访问权限为:

只能访问其超类定义的字段

3.3.4 备注:

当试图访问一个final变量时,编译器实际上把该变量的值赋值给内部类的一个隐含字段中。编译器会自动的在构造函数中添加相应的参数。在SUN JDK中,这个隐含字段通常被命名为:val$varname

3.4 使用内部类的注意事项:

本节包括了一些使用内部类时需要注意的事项,这些事项对所有内部类都适用。

3.4.1 静态成员

首先需要注意的是,内部类不能非常量声明静态成员,任何静态成员的声明都会被当成编译错误,例如:

InnerClasses.java:12: 内部类不能有静态声明

static String a;

^

1 错误

先要了解更加详细的信息,请参考附录A

3.4.2 访问外部实例

要在一个内部实例中访问外部实例,请使用:

OuterClass.this

3.4.3 字段覆盖

在内部类中声明的与外部类同签名的字段将覆盖外部字段,要访问外部字段请使用外部实例对象前缀。

OuterClass.this.field

OuterClass.this.Method();

4 嵌套类

嵌套类(Nested Classes)其实是普通内部类的一种特殊形式,首先它的声明是静态的,这就表示了这个类不需要外部实例。也表示了他不能访问外部类的实例字段。但是相应的,嵌套类可以拥有非常量静态成员。事实上,JDK通常把嵌套类当成一个具有特殊名字的独立类。

另外,嵌套类还拥有一种特殊形式:匿名嵌套类。前面说过,匿名类都是内部类,但是匿名嵌套类是一个特例,从理论上讲,他既不属于嵌套类,也不属于内部类。匿名嵌套类 不允许拥有非常量静态成员,但是他也没有外部实例供访问。

4.1 声明:

4.1.1 命名类:

class OuterClass{

//Outer class deflation
static class StaticInnerNamedClass{
//Inner class definition

}
}

4.1.2 匿名类:

class OuterClass{
//Outer class deflation
static Object unnamedObject = new Object(){
//Inner class definition
}
}

4.2 实例化

4.2.1 内部

StaticInnerNamedClass staticInnerNamedObject = new StaticInnerNamedClass();

4.2.2 外部

OuterClass.StaticInnerNamedClass staticInnerNamedObject = new OuterClass.StaticInnerNamedClass();

4.3 访问权限:

4.3.1 内部实例对外部实例的访问权限为:

外部类定义或继承的所有静态字段

4.3.2 外部实例对内部实例的访问权限为:

与通常内部类相同

4.3.3 其他对象对内部实例的访问权限为:

与通常内部类相同

A. 附录(Appendix

A) 为什么内部类不能声明静态成员?

关于这个问题,MS JLS没有给出一个明确的答案(还是我没找到么?)。后来我在Usenet的新闻组上发贴子问了一下,结果大概是这样的:

1) 匿名类使用非常量静态成员是不必要的,因为匿名类只有一个实例

2) 命名内部类如果允许使用静态 的话会使内部类显得过分独立,应该尽量使用外部类的设施。

(原帖见https://groups.google.com/group/comp.lang.java.programmer/browse_thread/thread/0f109738f2f089d9?hl=en#d61250f96cf8e96e

Why inner classes can not have static members?

bearice@gmail.com

Feb 4, 10:15 pm

as title.

Lew

Feb 4, 11:07 pm

> bear...@gmail.com wrote:

> as title.

Cultural note: It's considered polite to repeat the question inside the body of the post to facilitate others' ability to read the conversation.

Inner classes can have static members, provided such members are compile-time constants.

Asking "why" the language specifies something is an exercise in telepathy, unless the language designers left some notes or blog entries or white papers behind explaining the rational, which they might have done. GIYF.

I know that static members of inner classes would confuse me. Would such a member only be static within the context of the immediately enclosing instance of some instances of the inner class, or would it apply to all instances of the inner class?

The problem is that inner classes are (generally) instantiated within an instance of their enclosing class. Inner classes are not "static" enough on their own for me to be comfortable with a "static" that operates across all enclosing instance contexts. I suppose I could get used to it if Java were defined that way, but it isn't. It's defined to make inner classes very dependent on their enclosing instances.

If you want static members, use non-inner nested classes, or avoid nested classes altogether.

Why is a static member of an inner class necessary for you? Why is an alternative idiom not acceptable?

Lew

Markus Tazl

Feb 4, 11:18 pm

wrote:

> As title.

Wow, a question in shorthand? :-)

Anyway, Sun's Docs are your friend. Explained here in detail:

http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html, see

Topic: "Inner classes" at the end of the page

Best regards

Markus Tazl

bearice@gmail.com

Feb 5, 4:53 am

- Quoted text -

I see, sorry for my impolite way of asking. And thank all of you for answering me.

I'm not really need a static member in an inner class. just very curious about it when the complier tells me it is an error.

Thanks again.

Lew

Feb 5, 8:38 am

Well, the simple answer is because that's the way it's defined for the language. The rules explicitly allow only compile-time constants to be static members of inner classes. Non-inner nested classes do not have this restriction.

> Inner classes may not declare static initializers (§8.7) or member interfaces.

> Inner classes may not declare static members, unless they are compile-time constant fields (§15.28). ...

> Nested classes that are not inner classes may declare static members freely, in accordance with the usual rules of the Java programming language.

In practice the restriction causes no difficulties. If anything, it makes inner classes easier to deal with, as one can conceptualize the inner class as "belonging" entirely to the enclosing instances that instantiate it without wondering if static members should differ between different enclosing instances.

Language designers always face interesting decisions like this, such as what the value of the remainder operator '%' should be when the denominator is negative. Sometimes they get it wrong, as many feel Java did by not (yet) making generics reifiable. I have never encountered an authoritative explanation for why inner classes in Java cannot have non-compile-time-constant static members; OTOH I've never encountered a situation where the restriction caused trouble.

Inner classes are an odd duck anyway. They're useful for sure, because having a class than can access the members (even private ones) of its enclosing class instance sure helps out - it mitigates the lack of closures, for example.

However, one should always consider using a non-inner nested class or non-public top-level class before creating an inner class that does not need such access.

--

Lew

da...@dagon.net

Feb 5, 9:01 am

bear...@gmail.com wrote:

>Why inner classes can not have static members?

Lew wrote:

>Inner classes can have static members, provided such members are compile-time constants.

Static inner classes can have static members without such a restriction. This is legal:

class Test {

static class Foo {

static int a;

public static void setA(int newA) {

a = newA;

}

}

}

The difference between a static and non-static inner class is important. A static inner class is a fairly normal class, and behaves very similarly to other outer classes. A non-static inner class has an implicit pointer to an instance of it's enclosing class, so doesn't really have a static context to execute in.

Note: anonymous inner classes are always non-static.

--

Lew

Daniel Pitts

Feb 5, 9:57 am

Mark Rafn wrote:

The difference between a static and non-static inner class is important. A static inner class is a fairly normal class, and behaves very similarly to other outer classes. A non-static inner class has an implicit pointer to an instance of it's enclosing class, so doesn't really have a static context to execute in

Note: anonymous inner classes are always non-static.

I actually believe that's called a nested class and has different semantics.

Lew

Feb 5, 11:19 am

Daniel Pitts wrote:

> I actually believe that's called a nested class and has different semantics.

"Static inner class" is a contradiction. Inner classes are never static, in that they are *defined* as nested classes that do not use the "static" keyword.

Nested classes comprise both inner classes and static nested classes.

The relevant section of the JLS is linked up thread.

--

Lew

B) 内部类与嵌套类的命名规则

内部类和嵌套类在编译时被分开成独立的类,编译器对这些独立的类有相应的命名规则,下面就来描述一下这些规则:

B.1匿名类的命名规则

所有的匿名类统一按下列规则重命名:

$

其中,ID是这个匿名类在外部类中出现的位置,例如第一个匿名类就是1,第二个就是2

B.2 命名类的命名规则

命名类重命名规则为:

$

其中InnerClass为内部类的类名

B.3 局部命名类的命名规则

局部命名类的命名规则为:

$

其中,ID是同名的局部类在外部类中出现的位置,例如第一个就是1,第二个就是2InnerClass为内部类的类名

C) 一个完整的例子

interface PublicPrint{
void pubPrint();
}
class OuterClass{
public static final void print(String str){System.out.println(str);}
public String pubStr = "public string";
private String prvStr = "private string";
public static String staPubStr = "static public string";
private static String staPrvStr = "static private string";
//命名内部类 OuterClass$InnerNamedClass
public class InnerNamedClass implements PublicPrint{
public void pubPrint(){
print(getClass().getName());
print(pubStr);
print(prvStr);
print(staPubStr);
print(staPrvStr);
}
}
//匿名内部类 OuterClass$1
public PublicPrint innerUnnamedObject = new PublicPrint(){
public void pubPrint(){
print(getClass().getName());
print(pubStr);
print(prvStr);
print(staPubStr);
print(staPrvStr);
}
};
//命名嵌套 OuterClass$StaticInnerNamedClass
public static class StaticInnerNamedClass implements PublicPrint{
public void pubPrint(){
print(getClass().getName());
print(staPubStr);
print(staPrvStr);
}
}
//匿名嵌套 OuterClass$2
public static PublicPrint staticInnerUnnamedObject = new PublicPrint(){
public void pubPrint(){
print(getClass().getName());
print(staPubStr);
print(staPrvStr);
}
};
public PublicPrint defineNamedEmbedClass(final String arg){
//命名局部 OuterClass$1InnerEmbedNamedClass
class InnerEmbedNamedClass implements PublicPrint{
public void pubPrint(){
print(getClass().getName());
print(pubStr);
print(prvStr);
print(staPubStr);
print(staPrvStr);
print(arg);
}
}
PublicPrint innerEmbedNamedObject = new InnerEmbedNamedClass();
//innerEmbedNamedObject.pubPrint();
return innerEmbedNamedObject;
}
public PublicPrint defineUnnamedEmbedClass(final String arg){
//匿名局部 OuterClass$3
PublicPrint innerEmbedUnnamedObject = new PublicPrint(){
public void pubPrint(){
print(getClass().getName());
print(pubStr);
print(prvStr);
print(staPubStr);
print(staPrvStr);
print(arg);
}
};
//innerEmbedNamedObject.pubPrint();
return innerEmbedUnnamedObject;
}
}
class Runner{
public static void main(String[] args){
//外部实例
OuterClass outerObject = new OuterClass();
//命名内部类
OuterClass.InnerNamedClass innerObject = outerObject.new InnerNamedClass();
innerObject.pubPrint();
//匿名内部类
outerObject.innerUnnamedObject.pubPrint();
//命名嵌入
OuterClass.StaticInnerNamedClass staticInnerNamedObject = new OuterClass.StaticInnerNamedClass();
staticInnerNamedObject.pubPrint();
//匿名嵌入
OuterClass.staticInnerUnnamedObject.pubPrint();
//命名局部
PublicPrint innerEmbedNamedObject = outerObject.defineNamedEmbedClass("Hello");
innerEmbedNamedObject.pubPrint();
//匿名局部
PublicPrint innerEmbedUnnamedObject = outerObject.defineUnnamedEmbedClass("World");
innerEmbedUnnamedObject.pubPrint();
}
}

D) 参考文档

JLS: <>

HCJ: <>

E) 版权声明

Mails referenced in Appendix A belong to their authors.

Java TM, Sun, are trade mark of Sun Microsystems Corp.

This document is released under CDDL.

Copy rights © 2008 Bearice [MDSA Group]