长夜降至,劳累了一天的你是否感到疲惫,是否感到欣慰?
今天这一天无疑是痛苦的,长时间近乎变态的加班不仅导致生活节奏完全被打乱,下午的时候眼睛和大脑也是叫嚣着要罢工 。 不管怎样,现在的我感觉很好,对得起自己的付出。 想起来以前初中的时候,成绩很好,天赋很好各种好那种。 总是不愿在人前表露出自己很努力的样子,一是怕努力得不到效果被嘲笑,二是为了可笑的优越感,认为自己就是那样不用努力就能取得别人怎么努力也不能轻易得到的成绩。
随着年龄的增长,自然是知道了:一份耕耘一份收获,不要总是羡慕别人人前的风光,殊不知别人背后花了多少的精力,费了多少的功夫。 除了自己脸皮还是有一点放不开以外,其他的想法倒是完全变了。 感慨一番,回归正题!
之前看源码的时候,总想追根溯源,从最基础的地方了解起走,这样才能彻底弄透彻,于是逛各种技术贴,自己debug。 发现每次追到rt.jar包,也就是java的一些核心类库时,里面出现了 native关键字。 这在以前时没有见过的,而且没有实现方法,不报错。 还有一个比较有意思的命名方式: 比如 java方法为 sayHello(); 则其如果为native的实现的话,一般叫做 sayHello0();
后来也是了解到了,原来这个东东叫 JNI,是java用来弥补自身效率缺陷的,因为java是采用的伪代码解释运行的方法,依赖jvm,对有一些高效率的操作不及c。
动手实践的步骤大致如下:
由于时间关系以及自己的时间安排,就懒得贴图和详细写了
1. 为了自己的更好理解,建议不用ide,自己用记事本,才能更好的理解。 新建一个java源代码文件,写上你要调用的方法,前面加一个native 关键字,注意这个类里面要有一个 静态块,用来加载动态链接库文件,因为静态块会在类加载的时候就运行。 其方法为: System.loadLibrary();
2. javac 编译为class;
3.javah 将java字节码文件编译为c头文件,(以前没见过,其实这里面主要按照 javah程序定义的规则生成了一个关于 native类的声明和方法声明,最主要的是回去加载jni.h文件,该文件位于 jdk/inlude中)。
4.写自己的c文件,其实就是native的实现方法,在程序开头引用javah 编译好的 头文件。
5.运行 也就是 java 你的class文件。
=====这其中有一些插曲: 首先我的系统是windows,网上的很多教程都是基于linux的,这难免得自己尝试。 windows下我不得不用ide,vs 2015,vs2017,vs绿色版,还好我电脑之前有。 但是由于之前没怎么用过这些编辑器,也不是很熟,也不知道怎么配置jni的路径,始终编译不成功。 网上的教程又都是基于命令行的,我就想说 将 cy.exe(用于编译c的),配置一下,然后采用命令行的模式进行启动,后来权衡了一下,认为是可行的,但是却要花很多的时间跟精力,因为中途会碰到很多没见过的问题,然后一路前行。 这是不值得的。 最后果断曲线救国,上传git,用老式的linux电脑,一番折腾,最后终于ok了。 还有一个问题就是,java 运行我们的类文件时,需要指定库文件的地址才能执行成功的, 方法有三,一是在编译时指定,即在 静态块中 调用: System.load("动态库的全路径"),这个我尝试了一下失败了,但是碍于时间原因没有再试,暂且记下;二是 设置环境变量,可以设置永久的,也可以在命令行设置临时的,linux和windows各自都有自己的方法; 三是 在运行java -Ojava.library.path = "动态库的全路径";指定,注意-O为大写。 ======
感悟就是: 我们在学习新的知识的途中,会碰到很多的问题。 我们要对碰到的问题进行一个权衡,采用发散的方式去解决所碰到的问题固然是好事,我们在途中也能学习到一些额外的知识,但是于此同时我们便失去了针对性,失去了自己的主要目标。 所以有时候碰到问题,在时间允许以及符合自己的标准的情况下进行思维的发散处理,否则,一律才用直达目标的手段,待有时间与精力时在回过头来解决。
接下来进行第二个问题的总结:
java中集合都有一个扩容因子,第一次听是在一个学长那儿。之前没接触过,怪自己急功近利吧,基础不行。
今天偶然看到了同学写的一个关于List集合的add()方法的介绍,里面有介绍扩容。 索性我就来了解一下。
其他的就懒得写了,上结论:
ArrayList的扩容因子为0.5,其实现方法为:oldCapacity+(oldCapacity>>1)。 这里 oldCapacity采用了位运算,右移以为,缩小为原来的1/2。
HashMap的扩容因子为0.75 其实现方法: if((oldCap <<1)<.....) oldCap<<1...。 这里,oldCap进行两次向左的位运算,并且第二次是在第一次的基础上进行。0.5+0.5*0.5 = 0.75;
Vector,若不考虑扩容因子,Vector将增长为原来的2倍。
StringBuilder,StringBuffer扩容机制都是将原来的大小*2+2。 (注意: StringBuilder是非线程安全的,但是效率更高,StringBuffer是线程安全的)。
我们在使用时可以手动设置初始大小,减少因扩容带来的性能问题。
这里顺便记录一个,记得之前调试的时候,一个类中用来向控制台输出一句话的指令,即 :System.out.pringln("hello,world!"); 其首次编译执行花的时间大致在3到5秒钟,运行时候访问堆栈,也就是指令条数(不知道这样理解对不对)在 10万条左右。具体多少不记得了,因为最高的变量访问次数就有8万多,应该会位于12万到15万之间吧。
嗯就这样,晚安好梦!