Subscriber: yeming
Subscription Code: lLR7ZL-655444-54516456213945437
注意注册时千万别上网,否则你就重装吧!
正常:
Subscriber:Administra×
Subscription Code:NLR8ZC-855550-6552685393219112
6.0的:
Subscriber: www.1cn.biz
Subscriber Code: jLR8ZC-655355-5450765457039125
或者
Subscriber: www.1cn.biz
Subscriber Code: jLR7ZL-655355-5450755330522962
MyEclipse 6.0.1 注册码
Subscriber: administra×
Subscription Code: nLR7ZL-655342-54657656405281154注册后:
Subscriber: administra×
Product ID: E2MY (MyEclipse Standard Subscription)
License version: 1.0
Full Maintenance Included
Subscription expiration date (YYYYMMDD): 20091021
Number of licenses: 897
下面把 6.0GA / M1 和 5.5GA 版本的“注册信息”“注册码”“破解”给大家:
Subscriber: www.1cn.biz
Subscriber Code: jLR8ZC-655355-5450765457039125
或者
Subscriber: www.1cn.biz
Subscriber Code: jLR7ZL-655355-5450755330522962适用于早期的 5.5 M2 版本的:
Subscriber: www.1cn.biz
Subscriber Code: jLR8ZC-956-55-5467865833584547适用于早期的 5.1.1 GA 和 5.5 M1 版本的:
Subscriber: www.1cn.biz
Subscriber Code: jLR8ZC-444-55-4467865481680090注册成功后会发现:
Subscriber: www.1cn.biz
Product ID: E3MP (MyEclipse Professional Subscription)
License version: x.x
Full Maintenance Included
Subscription expiration date (YYYYMMDD): 20090520
Number of licenses: 800
Posted in 1 | No Comments »
mysql忘记root密码的解决
如果忘记了MySQL的root密码,可以用以下方法重新设置:
- KILL掉系统里的MySQL进程(千万不敢用下面的方式关闭,你会发现你的数据表损坏);
killall -TERM mysqld(错误)
service mysql stop(正确)
用以下命令启动MySQL,以不检查权限的方式启动;
/usr/local/mysql/bin/mysqld_safe –skip-grant-tables &
然后用空密码方式使用root用户登录 MySQL;
/usr/local/mysql/bin/mysql -uroot -p
修改root用户的密码;
mysql> update mysql.user set password=password(”123456″) where user=”root”;
mysql> flush privileges;
mysql> quit
以正常模式启动mysql
service mysql stop
service mysql start
重新启动MySQL后,就可以使用新密码登录了。
Posted in 1 | No Comments »
天地伟业的二面结束了,怎么说呢,表现不太好,还有很多有待提高的地方。写下来供以后参考。
面试过程
2008年10月29日,上午11点钟的时候心想天地伟业的二面通知应该出结果了吧?可是一直没有得到通知。然后自己主动给天地伟业hr部门打了个电话,问二面是不是通知完了,天地伟业的hr部门小姐说“是”。难道居然被天地伟业鄙视了吗?心中颇感郁闷……到了1点40分,突然接到022开头的电话,对!是天地伟业。接到电话得知通知的时候把我给落下了,要我2:20到大活门口等去他们那儿的车,过去面试。赶紧把一身行头穿上,领带打上,不错,自我感觉良好。感到大活,看到一群和我一样西装革履的小伙子还有一个MM,估计是一起去的,交流了一会儿,得知好几个人也和我一样是第一次,其中有两个小硕。闲话不多说,面试前大家先在天地伟业3层的一个小型会议室等着,一个一个的过去面试。我们8个人,4个非技术+4个技术的。前两个人面的时间都很短,不到5分钟就回来了,说根本没问他们多少东西,第四个轮到我了,心里还是有点紧张。
三个面试官,中间的是技术部门的老大,左青龙右白虎。左边的是hr部门的,右边的不清楚。
首先简单介绍一下自己吧,有点紧张,介绍完了基本情况之后突然感觉没什么可说的了,总不用把简历背一遍吧,所以我就说了一下自己的优点并表达了对以后工作的期望。
然后中间的老大开始发彪了:
先是问我的社团工作,主要负责那些工作,我把自己在学生社团中的工作和地位说了一下,感觉很拖沓,不够简洁,但表达还算清楚吧。
然后问我Java和C++语言的区别,我先从历史的角度说了一下,然后说了在指针、垃圾回收和多重继承方面他们的区别,说Java给程序开发人员更多的自由而C++把很多危险的内存分配和回收工作交给程序员自己,说C++是developer’s language,Java是manager’s language,那大哥头也不抬,不知道他什么反应。
然后他问我都有没有做过兼职之类的工作,实话实说“没有”。
接着他问我都做过那些项目。我说做过天津大学IBM学生俱乐部的成员管理网站和短学期实习的网上考试系统。他又问:会员管理网站是用什么数据库做的?我说是用MySql做的。他又问:为什么用MySql。我说主要考虑两方面原因,首先会员人数不多,经常登录的人也不是很多,所以选择MySql这种轻量级的数据库而没有选择Oracle和MS Sqlserver;其次当时正在学web开发这门课,正是以MySql为背景讲的。
接下来他又问对C++库和Java开源框架有多少了解。我跟本就对C++接触不深,大一时候学的呢?前些天才重新捡起来的,还没复习完呢。实话是说吧,我说自己对C++库不太了解,把原因说了一下。Java开源框架,我说对struts框架有些了解。
然后右边的同学终于张口了,问我当时用struts使用的哪个版本。我记得以前查过,我说3.0,然而貌似这位大哥对struts还是有些了解的,他说你们用的真的是3.0?我的信心遭到动摇,好像确实不是3.0哈?瞧我这记性,接着我说好像记错了。目前的最新版本是3.0,当时好像用的是1.x。
中间的老大又接管了比赛,问我C++里面是怎么清理指针占用的内存的。当时真是有点儿答非所问,我一个劲儿回答对象是怎么清理的,什么析构函数呀,什么遇到右括号自动清理局部变量分配的内存呀……真是有点答非所问,这大哥受委屈了。他说不对,我说您可以告诉我吗?他说回去自己查查资料吧。
左边的大姐说话了,说在这么多的竞争者中你觉得自己有什么优势吗?我不了解别人,还是从自身的性格特点说吧:说自己不断制定目标并向目标不断努力;在进入一个新环境的时候总是把自己定位的很低,然后不断学习,最终成为one of the best!如果有幸能被贵公司录用一定会努力学习,向自己的目标前进的,并未企业带来效益的增加。
最后,要我问他们一些问题。我问了公司的发展战略问题和企业文化方面的问题。
然后参观了他们的办公环境,感觉还蛮不错的。企业文化也很好,很多绿色植物,基础设施也挺不错的。据说明年要搬新家了,环境应该更好一点吧!
面试总结
不足一 面试时候语言表达有待提升,逻辑性还不够强。回答的时候应该先针对性的回答问题,然后再根据时间和考官反应进行一定的扩展。
不足二 面试时候的语气应该进一步好好把握。这两次面试回答问题的时候都是语气没有拿捏好,有点生硬,没有抑扬顿挫的感觉。
不足三 没有好好准备自我介绍,二面的时候开始要简短地做个自我介绍。感觉自己做得马马虎虎,肯定不是很出彩。
不足四 有些基础知识掌握的不好,问关于项目的问题的时候卡住了。没办法,再复习吧,尽力就好了。至于项目这个问题,自己也是真地没做什么像样的项目,有点没底气。以后面试之前一定要好好看看这些做过的项目。
估计明后天就会有结果了吧,不知道会是什么结果。不过照目前来看今年工作好像是挺难找的,各方面原因吧。天地伟业也是挺有发展前景的,基础设施也可以,企业文化也可以,也比较适合自己的水平。不过感觉自己对他的业务领域不太感兴趣,对安防也不太了解。不管了,再说吧!这两天把Thinking in C++第一卷完整的看完,再看看数据结构,毕竟十一月还有一波儿呢。
Posted in 1 | No Comments »
这些天感觉很疲惫,真的。身体疲惫?No,是心里的疲惫。
从九月下旬开始找工作到现在一个月了,才只有一次面试,两次笔试。当然中途从十月一号到十月十四号,一直在忙比赛的事儿,也没太在工作上花功夫。反正不管怎么说,我还是没有找到我想要的,求职的路还有多远?不得而知。
经过这么多天的折腾,心里的那一点点儿锐气和傲气已经消失殆尽了。现在有时想起自己曾经去tencent,去baidu的想法还是有点不现实,反映了自己心理的幼稚。江总书记说:“too simple, sometimes naive” 就是现在我对一个月前的自己的概括。进入这些所谓的名企,所谓的巨头真是太难了,除去研究生大军的竞争,客观的说自己的实力也是没有达名企的标。百度笔试即遭鄙视,腾讯根本没有得到笔试的机会,网易没有去,联发博动错过了,校内错过了......终于熬到今天,现在正在准备天津的天地伟业的二面。过去不代表将来,继续努力,毕竟日子还要一天一天的过嘛!
好友小龙已经签了,还不错。国企“北方重工”,销售,实习期间一个月3000+,转正式之后一个月4000+。对于他这个机械专业的已经是非常好了(估计他的很多同学都会去工厂做蓝领呢),签了之后把他兴奋的马上给我打了电话聊了十多分钟。这小子rp真是没的说,而且听说他是连着忽悠面试官和hr经理两个半天才感动了上天的,忽悠+实力+运气=很好的工作!
小侯姐也好几次面试了(都被鄙视了),相比之下我的面试经验就显得太少了,昨天晚上在QQ上她还特意给我上了一堂应对面试的培训课。她投的多不是技术类的!看来非技术类的面试机会要比技术类的大很多呀。有时候真的怀疑自己的选择,技术真的适合自己吗?说不定把方向定为销售或其它早都已经面试了或者签了。老爸、老妈很少帮我做决定,但还是给了我很多意见参考,听大姨的话“工作之后,什么都不参和,踏踏实实的搞技术,稳稳当当的积累人脉”,这样以后转行腰杆儿也硬,而且可以避免很多不必要的事情。既然选择了就义无反顾了。
算了,想这么多太累了,估计这也是最近为什么这么累的原因吧!虽然不能说是“世上本无事”,但有时我也是有点“庸人自扰之”了。把心放宽,继续努力。相信上帝对每个人都是公平的。
老妈,我爱你。谢谢这么长时间里您给我的支持。谢谢所有我爱的人。
Posted in 生活点滴 | No Comments »
<
p>内存分配方式有三种:
(1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的
整个运行期间都存在。例如全局变量,static 变量。
(2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函
数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集
中,效率很高,但是分配的内存容量有限。
(3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意
多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存
期由我们决定,使用非常灵活,但问题也最多。
内存分配方法:C++内存分配的五种方法的不
同
疯狂代码 http://www.CrazyCoder.cn/ ĵ:http:/www.CrazyCoder.cn/VC/Article13759.html
在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是
局部变量、函数参数等。
堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个
new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生
命的。
全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始
化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当
手段也可以修改,而且方法很多,在《const的思考》一文中,我给出了6种方法)
明确区分堆与栈
在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清的,所以
我决定拿他第一个开刀。
首先,我们举一个例子:
void f() { int* p=new int[5]; }
这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针
p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。在程
序会先确定在堆中分配内存的大小,然后调用opera× new分配内存,然后返回这块内存的首地址,放入栈中
,他在VC6下的汇编代码如下:
00401028 push 14h
0040102A call opera× new (00401060)
0040102F add esp,4
00401032 mov dword ptr [ebp-8],eax
00401035 mov eax,dword ptr [ebp-8]
00401038 mov dword ptr [ebp-4],eax
这里,我们为了简单并没有释放内存,那么该怎么去释放呢?是delete p么?澳,错了,应该是delete
[]p,这是为了告诉编译器:我删除的是一个数组,VC6就会根据相应的Cookie信息去进行释放内存的工作。
好了,我们回到我们的主题:堆和栈究竟有什么区别?
主要的区别由以下几点:
1、管理方式不同;
2、空间大小不同;
3、能否产生碎片不同;
4、生长方向不同;
5、分配方式不同;
6、分配效率不同;
管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制
,容易产生memory leak。
空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限
制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M(好像是
,记不清楚了)。当然,我们可以修改:
打开工程,依次操作菜单如下:Project->Setting->Link,在Category 中选中Output,然后在
Reserve中设定堆栈的最大值和commit。
注意:reserve最小值为4Byte;commit是保留在虚拟内存的页文件里面,它设置的较大会使栈开辟较大
的值,可能增加内存的开销和启动时间。
碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序
效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永
远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参
考数据结构,这里我们就不再一一讨论了。
生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方
向是向下的,是向着内存地址减小的方向增长。
分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是
编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他
的动态分配是由编译器进行释放,无需我们手工实现。
分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地
址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很
复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内
存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统
功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈
要低得多。
从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专
门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在
程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部
变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。
虽然栈有如此众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,还是用堆好一
些。
无论是堆还是栈,都要防止越界现象的发生(除非你是故意使其越界),因为越界的结果要么是程序崩溃
,要么是摧毁程序的堆、栈结构,产生以想不到的结果,就算是在你的程序运行过程中,没有发生上面的问题
,你还是要小心,说不定什么时候就崩掉,那时候debug可是相当困难的。 2008-9-25 0:53:57
疯狂代码 http://www.CrazyCoder.cn/
Posted in 1 | No Comments »
Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。例如,使用它能获得 Java 类中各成员的名称并显示出来。
Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。
JavaBean 是 reflection 的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过 reflection 动态的载入并取得 Java 组件(类) 的属性。
1. 一个简单的例子
考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。
import java.lang.reflect.;
public class DumpMethods {
public static void main(String args[]) {
try {
Class c = Class.forName(args[0]);
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
} catch (Throwable e) {
System.err.println(e);
}
}
}
按如下语句执行:
java DumpMethods java.util.Stack
它的结果输出为:
public java.lang.Object java.util.Stack.push(java.lang.Object)
public synchronized java.lang.Object java.util.Stack.pop()
public synchronized java.lang.Object java.util.Stack.peek()
public boolean java.util.Stack.empty()
public synchronized int java.util.Stack.search(java.lang.Object)
这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。
这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。
2.开始使用 Reflection
用于 reflection 的类,如 Method,可以在 java.lang.relfect 包中找到。使用这些类的时候必须要遵循三个步骤:第一步是获得你想操作的类的 java.lang.Class 对象。在运行中的 Java 程序中,用 java.lang.Class 类来描述类和接口等。
下面就是获得一个 Class 对象的方法之一:
Class c = Class.forName(”java.lang.String”);
这条语句得到一个 String 类的类对象。还有另一种方法,如下面的语句:
Class c = int.class;
或者
Class c = Integer.TYPE;
它们可获得基本类型的类信息。其中后一种方法中访问的是基本类型的封装类 (如 Integer) 中预先定义好的 TYPE 字段。
第二步是调用诸如 getDeclaredMethods 的方法,以取得该类中定义的所有方法的列表。
一旦取得这个信息,就可以进行第三步了——使用 reflection API 来操作这些信息,如下面这段代码:
Class c = Class.forName(”java.lang.String”);
Method m[] = c.getDeclaredMethods();
System.out.println(m[0].toString());
它将以文本方式打印出 String 中定义的第一个方法的原型。
在下面的例子中,这三个步骤将为使用 reflection 处理特殊应用程序提供例证。
模拟 instanceof 操作符
得到类信息之后,通常下一个步骤就是解决关于 Class 对象的一些基本的问题。例如,Class.isInstance 方法可以用于模拟 instanceof 操作符:
class A {
}
public class instance1 {
public static void main(String args[]) {
try {
Class cls = Class.forName(”A”);
boolean b1 = cls.isInstance(new Integer(37));
System.out.println(b1);
boolean b2 = cls.isInstance(new A());
System.out.println(b2);
} catch (Throwable e) {
System.err.println(e);
}
}
}
在这个例子中创建了一个 A 类的 Class 对象,然后检查一些对象是否是 A 的实例。Integer(37) 不是,但 new A() 是。
3.找出类的方法
找出一个类中定义了些什么方法,这是一个非常有价值也非常基础的 reflection 用法。下面的代码就实现了这一用法:
import java.lang.reflect.;
public class method1 {
private int f1(Object p, int x) throws NullPointerException {
if (p == null)
throw new NullPointerException();
return x;
}
public static void main(String args[]) {
try {
Class cls = Class.forName(”method1″);
Method methlist[] = cls.getDeclaredMethods();
for (int i = 0; i < methlist.length; i++) {
Method m = methlist[i];
System.out.println(”name = ” + m.getName());
System.out.println(”decl class = ” + m.getDeclaringClass());
Class pvec[] = m.getParameterTypes();
for (int j = 0; j < pvec.length; j++)
System.out.println(”param #” + j + ” ” + pvec[j]);
Class evec[] = m.getExceptionTypes();
for (int j = 0; j < evec.length; j++)
System.out.println(”exc #” + j + ” ” + evec[j]);
System.out.println(”return type = ” + m.getReturnType());
System.out.println(”—–”);
}
} catch (Throwable e) {
System.err.println(e);
}
}
}
这个程序首先取得 method1 类的描述,然后调用 getDeclaredMethods 来获取一系列的 Method 对象,它们分别描述了定义在类中的每一个方法,包括 public 方法、protected 方法、package 方法和 private 方法等。如果你在程序中使用 getMethods 来代替 getDeclaredMethods,你还能获得继承来的各个方法的信息。
取得了 Method 对象列表之后,要显示这些方法的参数类型、异常类型和返回值类型等就不难了。这些类型是基本类型还是类类型,都可以由描述类的对象按顺序给出。
4.获取构造器信息
获取类构造器的用法与上述获取方法的用法类似,如:
import java.lang.reflect.;
public class construc×1 {
public construc×1() {
}
protected construc×1(int i, double d) {
}
public static void main(String args[]) {
try {
Class cls = Class.forName(”construc×1″);
Construc× c×list[] = cls.getDeclaredConstruc×s();
for (int i = 0; i < c×list.length; i++) {
Construc× ct = c×list[i];
System.out.println(”name = ” + ct.getName());
System.out.println(”decl class = ” + ct.getDeclaringClass());
Class pvec[] = ct.getParameterTypes();
for (int j = 0; j < pvec.length; j++)
System.out.println(”param #” + j + ” ” + pvec[j]);
Class evec[] = ct.getExceptionTypes();
for (int j = 0; j < evec.length; j++)
System.out.println(”exc #” + j + ” ” + evec[j]);
System.out.println(”—–”);
}
} catch (Throwable e) {
System.err.println(e);
}
}
}
这个例子中没能获得返回类型的相关信息,那是因为构造器没有返回类型。
5.获取类的字段(域)
找出一个类中定义了哪些数据字段也是可能的,下面的代码就在干这个事情:
import java.lang.reflect.;
public class field1 {
private double d;
public static final int i = 37;
String s = “testing”;
public static void main(String args[]) {
try {
Class cls = Class.forName(”field1″);
Field fieldlist[] = cls.getDeclaredFields();
for (int i = 0; i < fieldlist.length; i++) {
Field fld = fieldlist[i];
System.out.println(”name = ” + fld.getName());
System.out.println(”decl class = ” + fld.getDeclaringClass());
System.out.println(”type = ” + fld.getType());
int mod = fld.getModifiers();
System.out.println(”modifiers = ” + Modifier.toString(mod));
System.out.println(”—–”);
}
} catch (Throwable e) {
System.err.println(e);
}
}
}
这个例子和前面那个例子非常相似。例中使用了一个新东西 Modifier,它也是一个 reflection 类,用来描述字段成员的修饰语,如“private int”。这些修饰语自身由整数描述,而且使用 Modifier.toString 来返回以“官方”顺序排列的字符串描述 (如“static”在“final”之前)。
和获取方法的情况一下,获取字段的时候也可以只取得在当前类中申明了的字段信息 (getDeclaredFields),或者也可以取得父类中定义的字段 (getFields) 。
6.根据方法的名称来执行方法
文本到这里,所举的例子无一例外都与如何获取类的信息有关。我们也可以用 reflection 来做一些其它的事情,比如执行一个指定了名称的方法。下面的示例演示了这一操作:
import java.lang.reflect.;
public class method2 {
public int add(int a, int b) {
return a + b;
}
public static void main(String args[]) {
try {
Class cls = Class.forName(”method2″);
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Method meth = cls.getMethod(”add”, partypes);
method2 methobj = new method2();
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj = meth.invoke(methobj, arglist);
Integer retval = (Integer) retobj;
System.out.println(retval.intvalue());
} catch (Throwable e) {
System.err.println(e);
}
}
}
假如一个程序在执行的某处的时候才知道需要执行某个方法,这个方法的名称是在程序的运行过程中指定的 (例如,JavaBean 开发环境中就会做这样的事),那么上面的程序演示了如何做到。
上例中,getMethod 用于查找一个具有两个整型参数且名为 add 的方法。找到该方法并创建了相应的 Method 对象之后,在正确的对象实例中执行它。执行该方法的时候,需要提供一个参数列表,这在上例中是分别包装了整数 37 和 47 的两个 Integer 对象。执行方法的返回的同样是一个 Integer 对象,它封装了返回值 84。
7.创建新的对象
对于构造器,则不能像执行方法那样进行,因为执行一个构造器就意味着创建了一个新的对象 (准确的说,创建一个对象的过程包括分配内存和构造对象)。所以,与上例最相似的例子如下:
import java.lang.reflect.;
public class construc×2 {
public construc×2() {
}
public construc×2(int a, int b) {
System.out.println(”a = ” + a + ” b = ” + b);
}
public static void main(String args[]) {
try {
Class cls = Class.forName(”construc×2″);
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Construc× ct = cls.getConstruc×(partypes);
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj = ct.newInstance(arglist);
} catch (Throwable e) {
System.err.println(e);
}
}
}
根据指定的参数类型找到相应的构造函数并执行它,以创建一个新的对象实例。使用这种方法可以在程序运行时动态地创建对象,而不是在编译的时候创建对象,这一点非常有价值。
8.改变字段(域)的值
reflection 的还有一个用处就是改变对象数据字段的值。reflection 可以从正在运行的程序中根据名称找到对象的字段并改变它,下面的例子可以说明这一点:
import java.lang.reflect.;
public class field2 {
public double d;
public static void main(String args[]) {
try {
Class cls = Class.forName(”field2″);
Field fld = cls.getField(”d”);
field2 f2obj = new field2();
System.out.println(”d = ” + f2obj.d);
fld.setDouble(f2obj, 12.34);
System.out.println(”d = ” + f2obj.d);
} catch (Throwable e) {
System.err.println(e);
}
}
}
这个例子中,字段 d 的值被变为了 12.34。
9.使用数组
本文介绍的 reflection 的最后一种用法是创建的操作数组。数组在 Java 语言中是一种特殊的类类型,一个数组的引用可以赋给 Object 引用。观察下面的例子看看数组是怎么工作的:
import java.lang.reflect.;
public class array1 {
public static void main(String args[]) {
try {
Class cls = Class.forName(”java.lang.String”);
Object arr = Array.newInstance(cls, 10);
Array.set(arr, 5, “this is a test”);
String s = (String) Array.get(arr, 5);
System.out.println(s);
} catch (Throwable e) {
System.err.println(e);
}
}
}
例中创建了 10 个单位长度的 String 数组,为第 5 个位置的字符串赋了值,最后将这个字符串从数组中取得并打印了出来。
下面这段代码提供了一个更复杂的例子:
import java.lang.reflect.*;
public class array2 {
public static void main(String args[]) {
int dims[] = new int[]{5, 10, 15};
Object arr = Array.newInstance(Integer.TYPE, dims);
Object arrobj = Array.get(arr, 3);
Class cls = arrobj.getClass().getComponentType();
System.out.println(cls);
arrobj = Array.get(arrobj, 5);
Array.setInt(arrobj, 10, 37);
int arrcast[][][] = (int[][][]) arr;
System.out.println(arrcast[3][5][10]);
}
}
例中创建了一个 5 x 10 x 15 的整型数组,并为处于 [3][5][10] 的元素赋了值为 37。注意,多维数组实际上就是数组的数组,例如,第一个 Array.get 之后,arrobj 是一个 10 x 15 的数组。进而取得其中的一个元素,即长度为 15 的数组,并使用 Array.setInt 为它的第 10 个元素赋值。
注意创建数组时的类型是动态的,在编译时并不知道其类型。
Posted in 技术文章收藏夹 | 1 Comment »
在C语言里堆(heap)和栈(stack)里的区别
简单的可以理解为:
heap:是由malloc之类函数分配的空间所在地。地址是由低向高增长的。
stack:是自动分配变量,以及函数调用的时候所使用的一些空间。地址是由高向低减少的。
一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表
在Java语言里堆(heap)和栈(stack)里的区别
1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共 享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要 在运行时动态分配内存,存取速度较慢。
3. Java中的数据类型有两种。
一种是基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char(注意,并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的,称为自动变量。值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出 后,字段值就消失了),出于追求速度的原因,就存在于栈中。
另外,栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义
int a = 3;
int b = 3;
编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处 理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。
特别注意的是,这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状 态,那么另一个对象引用变量也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例, 我们定义完a与 b的值后,再令a=4;那么,b不会等于4,还是等于3。在编译器内部,遇到a=4;时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存 放4的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。
另一种是包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中,Java用new()语句来显示地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。
4. String是一个特殊的包装类数据。即可以用String str = new String(”abc”);的形式来创建,也可以用String str = “abc”;的形式来创建(作为对比,在JDK 5.0之前,你从未见过Integer i = 3;的表达式,因为类与字面值是不能通用的,除了String。而在JDK 5.0中,这种表达式是可以的!因为编译器在后台进行Integer i = new Integer(3)的转换)。前者是规范的类的创建过程,即在Java中,一切都是对象,而对象是类的实例,全部通过new()的形式来创建。Java 中的有些类,如DateFormat类,可以通过该类的getInstance()方法来返回一个新创建的类,似乎违反了此原则。其实不然。该类运用了单 例模式来返回类的实例,只不过这个实例是在该类内部通过new()来创建的,而getInstance()向外部隐藏了此细节。那为什么在String str = “abc”;中,并没有通过new()来创建实例,是不是违反了上述原则?其实没有。
5. 关于String str = “abc”的内部工作。Java内部将此语句转化为以下几个步骤:
(1)先定义一个名为str的对String类的对象引用变量:String str;
(2)在栈中查找有没有存放值为”abc”的地址,如果没有,则开辟一个存放字面值为”abc”的地址,接着创建一个新的String类的对 象o,并将o 的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为”abc”的地址,则查找对象o,并返回o的地址。
(3)将str指向对象o的地址。
值得注意的是,一般String类中字符串值都是直接存值的。但像String str = “abc”;这种场合下,其字符串值却是保存了一个指向存在栈中数据的引用!
为了更好地说明这个问题,我们可以通过以下的几个代码进行验证。
String str1 = “abc”;
String str2 = “abc”;
System.out.println(str1==str2); //true
注意,我们这里并不用str1.equals(str2);的方式,因为这将比较两个字符串的值是否相等。==号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是,str1与str2是否都指向了同一个对象。
结果说明,JVM创建了两个引用str1和str2,但只创建了一个对象,而且两个引用都指向了这个对象。
我们再来更进一步,将以上代码改成:
String str1 = “abc”;
String str2 = “abc”;
str1 = “bcd”;
System.out.println(str1 + “,” + str2); //bcd, abc
System.out.println(str1==str2); //false
这就是说,赋值的变化导致了类对象引用的变化,str1指向了另外一个新对象!而str2仍旧指向原来的对象。上例中,当我们将str1的值改为”bcd”时,JVM发现在栈中没有存放该值的地址,便开辟了这个地址,并创建了一个新的对象,其字符串的值指向这个地址。
事实上,String类被设计成为不可改变(immutable)的类。如果你要改变其值,可以,但JVM在运行时根据新值悄悄创建了一个新 对象,然后将这个对象的地址返回给原来类的引用。这个创建过程虽说是完全自动进行的,但它毕竟占用了更多的时间。在对时间要求比较敏感的环境中,会带有一 定的不良影响。
再修改原来代码:
String str1 = “abc”;
String str2 = “abc”;
str1 = “bcd”;
String str3 = str1;
System.out.println(str3); //bcd
String str4 = “bcd”;
System.out.println(str1 == str4); //true
str3 这个对象的引用直接指向str1所指向的对象(注意,str3并没有创建新对象)。当str1改完其值后,再创建一个String的引用str4,并指向 因str1修改值而创建的新的对象。可以发现,这回str4也没有创建新的对象,从而再次实现栈中数据的共享。
我们再接着看以下的代码。
String str1 = new String(”abc”);
String str2 = “abc”;
System.out.println(str1==str2); //false
创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。
String str1 = “abc”;
String str2 = new String(”abc”);
System.out.println(str1==str2); //false
创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。
以上两段代码说明,只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。
6. 数据类型包装类的值不可修改。不仅仅是String类的值不可修改,所有的数据类型包装类都不能更改其内部的值。
7. 结论与建议:
(1)我们在使用诸如String str = “abc”;的格式定义类时,总是想当然地认为,我们创建了String类的对象str。担心陷阱!对象可能并没有被创建!唯一可以肯定的是,指向 String类的引用被创建了。至于这个引用到底是否指向了一个新的对象,必须根据上下文来考虑,除非你通过new()方法来显要地创建一个新的对象。因 此,更为准确的说法是,我们创建了一个指向String类的对象的引用变量str,这个对象引用变量指向了某个值为”abc”的String类。清醒地认 识到这一点对排除程序中难以发现的bug是很有帮助的。
(2)使用String str = “abc”;的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String(”abc”);的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。这个思想应该是 享元模式的思想,但JDK的内部在这里实现是否应用了这个模式,不得而知。
(3)当比较包装类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==。
(4)由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。
Posted in 技术文章收藏夹 | No Comments »
A Skeleton in the Cupboard.(橱中骷髅)是国外的谚语,我们经常在小说里读到,一个外表看起来很受人尊敬的人或家庭,多年来一直隐藏着一些不为人知的可怕的秘密。 在故事的某个戏剧性时刻,这种骇人听闻的秘密--即“橱中骷髅”让人识破了,于是便名誉扫地。
现常常指每个人或每个家庭都有不可告人的秘密。
Posted in 百家杂谈收藏家 | No Comments »
Be thankful for what you have and you will have more.
If you always concentrate on what you do not have you will never ever have enough.
by Oprah Winfrey
何必总是对自己得不到的耿耿于怀,其实现在身边的一切更值得珍惜。
人在大四,发现自己比以前更成熟了,也更懂得珍惜了。
有 时候自己努力回想大学以前的生活,其实和现在一样,也是一点一点的从眼皮底下、从指缝中间流走的,可是在我的脑海里留下的记忆却很少,感觉自己的从前就像 是空白一片。以前自己对一切都过于苛求,总是想着前面的事情,希望有个好的前景,却从没有回头看看走过的路,没有珍惜身边的人。
有句广告 词说得好“人生就像一场旅行,不必在乎目的,要在乎的沿途的风景和看风景的心情。” 一个人即使取得再大的成功,登到不胜寒的高处,但是如果他回首这一路行程心里却没有一点儿情感的积淀和沿途风景的轮廓,可以说这趟旅行是不成功的。人生的 确就像一趟旅行,A one way trip,没有回头的路,失去的就是失去了,永远的失去了。
前天晚上,给妈妈打了个电话。这种主动 给家里打电话的行为平时是很少在我身上发生的,以前每次要往家里打电话的时候总是感觉还有其它事情要做而最终搁浅了,甚至老妈打电话过来的时候我也总是想 早点结束,感觉“就那点儿事儿,也没什么说的”。现在的感觉不一样了,我总是想给家里打电话,想对他们说“我爱你”,记得补英语口语的时候,Sandy说 过“Say it before it’s too late”。这就是人生,Any chance could be the last chance.
对拥有的一切心存感恩,对想要拥有的好好准备、努力争取。希望能在品味成功之余,品味生活的精彩!
Posted in 生活点滴 | No Comments »
会永远记住今天的!不仅在游泳上有了很大的进步(呵呵,I‘m a rookie @_@,两位师傅走了之后,自己又游了一个来回,哈哈,对”rebuild my upper body”非常有信心了),而且了却了一桩心事。挺不错的!哈哈。
人与人之间有很多误会,我认为没有人真正了解其他人。一个人可能在某些人眼里就是个纯粹的人渣,但是谁又真正了解这个人渣呢?就连和他最亲近的人,我想,也不敢打百分之百的保票,说“我非常了解这个人”。
所以,我对自己说:“不管自己在别人眼里什么形象,做好真正的自己!为自己活着,为真正爱你的人快乐、伤心,其它的,谁管呢?”
呵呵,每天多一些笑容,去爱身边的这个世界。Time doesn’t lie to any body.
感谢身边的每一个人,珍惜自己所拥有的一切!
ps:
TOMaster JBer 和 Master B,谢谢!
Posted in 生活点滴 | No Comments »