劲舞团情书怎么写屏蔽二级密码怎么写?哪位大神帮忙请用逻辑型的方法写出来参考一下

如何摆脱“写出来东西自己都不想看”尴尬境地? - 简书
如何摆脱“写出来东西自己都不想看”尴尬境地?
用“东西”形容写出来的文章,虽然我也不想但真的有些嫌弃。虽然热爱可以带来坚持的动力,虽然从来不曾想过半途而废,但看到群里小伙伴一个个登上简书首页获得赞同无数,心里还是会有挫败感。昨天在群里看到萱萱说要调整方法,将以往的文章尽力修改到满意,我突然灵光一闪。是啊,两个月来我一直在写写写,却没有停下来好好思考怎么写才能进步,是时候寻找差距产生的原因了。想要寻找差距,就得先看看优秀的人都是怎么写的。大量阅读群里广受好评几位同学的文章,我将文章按写作手法归为三类:逻辑类这一类文章结构清楚,论点论据充分,一般是为了阐述观点或讲解方法采用的文章类型,和高中时期的议论文很像。发现问题——提出观点——多面论证——得出结论——(解决方法),优秀的文章条理清晰极具导向性,读者会跟着作者的思路往下走,读完后恍然大悟或学到解决办法。群里这一类作者代表有萱萱、安心等人,读她们的文章,往往如鱼得水流畅自然,不存在思维发散或阻碍的情况。往往文章读完了,她们的观点和意见都懂了并很有启发。我简单粗暴的将鸡汤文都归到这一类。表达类虽然写文章都是在表达,但这里说的表达是指将事件、感受通过叙述的方式向大家娓娓道来,就像在和你面对面讲故事一样。这一类文章不像逻辑类框架那么明显但同样条理清晰,对文字的运用能力尤其强,字字句句都会在脑海中形成画面引领读者感同身受。群里公子布、惠子的文章多属于这一类,他们不用引经据典说明某个观点,准确入微的表述就吸引人无法自拔。专业类以叙彤和阿伊泰为代表的专业知识类文章,是经过工作的沉淀、积累与自己的思考形成的文章。这类知识以分享工作中遇到的问题、工作内容为重点,拓展了小伙伴的知识面与专业素质,带来思想丰富外的意外收获。在对优秀的文章进行内容拆解后,审视自己写作过程中遇到的问题寻找差距,一般有两种:1.不知道写什么虽然从一开始写千字都觉得很为难,到经过对别人文章内容的分析能多角度表述丰富自己的文章,但时不时还会发生没有选题或选题后素材不足的情况。2.觉得自己写的差思维混乱、内容单薄、没深度、语言缺乏说服力。。。太多问题的存在使我的文章成为了我自己都不愿意多读的“东西”。这两个问题往往是相互影响的,上一周写作时我就陷入了“觉得自己写什么都差→
没什么写→
勉强写出来更差”的消极循环中。我想写逻辑类,但觉得自己思想、建议都太幼稚;我想写表达类,可是文笔又不到家;专业类就更不用说了,根本分享不出来什么干货。这样把三种类型都排除后,就只能风格散漫的写一些随笔了。但是惠子说过这样一段话,“写文章应该有目的性,应该能给别人带去些什么,而不是自嗨”(大意)。深以为然,既然目的不是写日记,文章就应该给自己或他人一些启发。观察群里各路代表的文章会发现,他们的文章往往会让人觉得干货满满,读后如享受饕鬄盛宴般满足。我们怎样达到这样的水平呢?解决不知道写什么的方法1.观察生活。这是安心和灌头鱼给我的启发,她们总是通过身边随时发生的小事、现象展开思考,经过整理观点、丰富论据后呈现一篇有力度的文章。2.大量输入。大量输入是常常提到的一个词,最主要的就是大量阅读书籍、专栏等自己不了解的内容。在这个过程中有两个步骤要跟上:a.记笔记。感悟、启发、灵感......所有大脑的波动都要记下来,想的多了选题就有了。b.内容关联。阅读时遇到不同作者对同一个问题不同的表述,要能够将他们关联起来,比较他们观点的异同,试着产生自己的看法,这样,丰富的素材也就有了。这个过程推荐使用印象笔记分组记录,还能形成自己的知识库。通过以上这两种方法,你会发现想要知道写什么,最重要的还是多思考。很多事情发生在身边我们却熟视无睹,看了很多书却连概括大意都做不到,脑子不动,无话可说。解决写的差的方法从开始的三种写作手法来说,写的差不外乎“逻辑差、文笔差、干货少”。代表们写的好除了很少数人有天赋,大多数人还是靠思考、积累成长起来的。所以不要急,我们也可以。1.逻辑差思维混乱,典型表现是写文的时候思绪跳跃,什么都想写,结果最后不是跑题就是文章一团乱麻。针对这个毛病可以通过列大纲的方式梳理思路。写文前按照上文列举的逻辑类文章结构搭好框架,在这个过程中你会自发思考每段主题之间的关联性、论证角度,最后只需填充内容就可以了。
强烈推荐百度脑图
2.表达差这个没别的办法,就是写写写。写的时候注意两点:①多读优秀的文章,和自己的文章对比,寻找差距。相似的结构和观点借鉴人家的表现手法、思路,不断修改以前的文章。②无论是选定一个方向不断精进还是多方向尝试寻找擅长,坚持住。3.专业类这一类我没办法orz......我的高度还不够,但我觉得如果你工作有所成,不妨从分享工作心得、经验讲起,结构采用逻辑类即可。以上只是我关于写作的一些浅见,且是在没有阅读专业写作书籍情况下的想法,只能说是对加入写作群这两个多月写作过程的一些观察学习和反思总结。但这样的思考给我力量,知道自己哪里不足并且积极尝试改进才会成长不是吗?我相信我可以,你也可以。
17年开始潜心研究影评
1.容易影响心情。因为西藏行,有点精神恍惚,而且真的有点追求完美,不做完就不想放下,即使明天有很多事要做。
1.室友丢钱,急于摆脱自己的嫌疑,反而显得很有嫌疑。 2.情绪化。精神恍惚,影响打工,影响学习,影响工作。 3.要想成为朋...
成长记录-连载(三十六) ——我的第一篇五千字长文,说了什么,你一定想不到 并不是不想每天写公众号,而是之前思考怎么做,怎么做才有效。 因为李笑来的关于写东西一定要对别人有用,要简洁,是否对别人有用对我触动很大,是否对别人有用让我不敢肆无忌惮的写公众号,我害怕写出来的东西对...
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金相信有很多朋友...
用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你能获得这些料: 知道setContentView()之后发生了什么? ... Android 获取 View 宽高的常用正确方式,避免为零 - 掘金 相信有很多...
气象预报说台风“尼伯特”即将登陆,我问闺蜜要改行程不?她说不怕,她保护我。也行,那就按原计划回家吧~ 提前下班,打车,地铁,车站,等车,上车。 杭州的天因为G20的关系特别的蓝,我和闺密戏称G20蓝。可能是台风即将过境的关系,云层大片大片的,多且低,再配上蓝蓝的天空,特别的...
有时我在想,人是否就是一个矛盾到极致的生物。是不是凡是人,都有两种极端的情绪在内心中奔腾,进而迸发,还有本性中微存的一丝善良,在某个不经意的瞬间,像一朵最美丽的花,在心底徐徐开放,我不能一概而论。
是的,因为我也是这矛盾体。我也体会过人性的悲凉,以及那温暖如灯的...
补录而已。求哪位大神撒,把这个程序编写出来。。。。_百度知道
求哪位大神撒,把这个程序编写出来。。。。
谁能把这个编写出来咯,急事哈。。。
1. 银行的账户记录Account有账户的唯一性标识(11个长度的字符和数字的组合),用户的姓名,开户日期(Date),账户密码(六位的数字,可以用0开头),当前的余额。银行规定新开一个账户时,银行方面提供一个标识...
我有更好的答案
其余系统逻辑没什么..不过大神你得说明白用什么语言写啊 ..这你闹呢.? 这在数据库好实现 你非得手写..这不闹么..你这题也太笼统了......唯一标识用什么规则生成?11位不重复即可
为您推荐:
其他类似问题
程序编写的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。小站会根据您的关注,为您发现更多,
看到喜欢的小站就马上关注吧!
下一站,你会遇见谁的梦想?
浅谈阅读JDK源码对编程开发的好处
作为一名程序员,在闲暇是看一下jdk源码,有利于对自己日常的开发环境了解得更加深刻。一般的一个高级开发工程师,能阅读一些源码对自己的提升还是蛮大的。这里作个自己的小结。为什么要读源码?现在一个项目基本离不开jar包,第三方api,我们可以反编译去看一些大神们的源码,当然源码的水平也是有好有坏。都有哪些好处呢?&1、了解思想&程序员大部分开发中都是些增删查改,过的的业务的逻辑。比如一个需求 我们用了几十行代码写了。感觉没问题,但是别人可能用几行就搞定了,要学习别人的思路。&2、熟悉设计模式&包括24种设计模式,Java对象的三大特征,好的代码中都有体现。&3、提高自己的代码优雅性&我们代码可能更多是业务的需求, 但是源码大部分都比较优雅, 比如jdk 源码,非常精简。要学习源码的代码写法。&&4、知晓原理,提升面试能力&面试中经常闻到源码, 你是否读过源码,你觉得为什么这么写,举个例子, 之前面试碰到被别人问, jdk 7 和 jdk 8 的concurrentHashMap &的size()方法分别是怎么实现的,这个集合经常被问到。
5、让自己变得有耐心&我们知道, 阅读别人的代码是非常痛苦的事 ,尤其是一些比较差 的代码, 可读性非常差, 当然 jdk 源码 也比较头痛。举个例子, String ,这个 对象,它 的方法我们可能基本都用过了,但是它 的源码有多少人真正看完了呢?&我看了下, 它的源码有2000多行,一开始看起来非常枯燥 ,阅读源码, 让自己静下心来,程序员本身就是一份安静的工作。&6、让自己变得有格调&以前的一个资深开发每次跟我们聊天,说jdk源码都基本看过了,当然10个程序员有1个阅读源码就不错了,至少值得尊敬。当然,这个也不是说说就可以,水平的高低在实际工作中也能暴露出来。&7、提升自己代码严谨性&一个程序员,只要工作,就离不开bug ,jdk 的源码大部分都是专家写的,代码严谨性非常强,我们看了代码,改变自己平时错误的编码习惯,包括最基本的判空啊。再比如,一个类里面的常量到底是用private 修饰,还是protect修饰,还是public修饰,bug越多,越让别人鄙视。&
简析Java中的强引用、软引用、弱引用与虚引用
& & &对于Java中的垃圾回收机制来说,对象是否被回收的标准在于该对象是否被引用。因此,引用也是JVM进行内存管理的一个重要概念。众所周知,java中是JVM负责内存的分配和回收,这是它的优点(使用方便,程序不用再像使用c那样担心内存),但同时也是它的缺点(不够灵活)。为了解决内存操作不灵活这个问题,可以采用软引用等方法。&
& & &在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及状态,程序才能使用它。这就像在日常生活中,从商店购买了某样物品后,如果有用,就一直保留它,否则就把它扔到垃圾箱,由清洁工人收走。一般说来,如果物品已经被扔到垃圾箱,想再 把它捡回来使用就不可能了。& & 但有时候情况并不这么简单,你可能会遇到类似鸡肋一样的物品,食之无味,弃之可惜。这种物品现在已经无用了,保留它会占空间,但是立刻扔掉它也不划算,因为也许将来还会派用场。对于这样的可有可无的物品,一种折衷的处理办法是:如果家里空间足够,就先把它保留在家里,如果家里空间不够,即使把家里所有的垃圾清除,还是无法容纳那些必不可少的生活用品,那么再扔掉这些可有可无的物品。& & 从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。1.强引用&& & &以前我们使用的大部分引用实际上都是强引用,这是使用最普遍的引用。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。2.软引用(SoftReference)& & 如果一个对象只具有软引用,那就类似于可有可物的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。& &软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,JAVA虚拟机就会把这个软引用加入到与之关联的引用队列中。3.弱引用(WeakReference)& & 如果一个对象只具有弱引用,那就类似于可有可物的生活用品。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。&& & 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。4.虚引用(PhantomReference)& & "虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。& & 虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃 圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是 否已经加入了虚引用,来了解& & 被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。&& & 特别注意,在世纪程序设计中一般很少使用弱引用与虚引用,使用软用的情况较多,这是因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生。& & 以下是软引用的代码:[c-sharp] view plain copyimport java.lang.ref.SoftR &public class Test { && & &&& & public static void main(String[] args){ && & & & System.out.println("开始"); && & & & &&& & & & A a = new A(); && & & & &&& & & & SoftReference&A& sr = new SoftReference&A&(a); && & & & a = && & & & if(sr!=null){ && & & & & & a = sr.get(); && & & & } && & & & else{ && & & & & & a = new A(); && & & & & & sr = new SoftReference&A&(a); && & & & } && & & & &&& & & & System.out.println("结束"); & &&& & } && & &&& & &&} &&&class A{ && & int[] && & public A(){ && & & & a = new int[]; && & } &} &&
浅谈Java对象的初始化顺序
当一个类使用new关键字来创建新的对象的时候,比如Person per = new Person();JVM根据Person()寻找匹配的类,然后找到这个类相匹配的构造方法,这里是无参构造,如果程序中没有给出任何构造方法,则JVM默认会给出一个无参构造。当创建一个对象的时候一定对调用该类的构造方法,构造方法就是为了对对象的数据进行初始化。JVM会对给这个对象分配内存空间,也就是对类的成员变量进行分配内存空间,如果类中在定义成员变量就赋值的话,就按初始值进行运算,如果只是声明没有赋初始值的话,JVM会按照规则自动进行初始化赋值。而成员方法是在对象调用这个方法的时候才会从方法区中加载到栈内存中,用完就立即释放内存空间。&笔者认为学到类与对象时的一个关键点:初始化顺序。&先假设一个类,如图中一样各组成都有,那么他的初始化顺序是&1、初始化类变量(即static修饰的成员变量),并未赋值。不管写的位置在哪里,只要是类变量,系统总会先找到它进行变量初始化。2、执行静态代码块和类变量定义式,两者根据写的位置来决定先后,先写先执行。其实从某种角度上看,可以把类变量定义赋值视为两部分:一部分是定义变量,一部分赋值。而这个赋值部分可以看做是一个静态代码块。两个静态代码块的执行顺序自然是看写的位置的先后了。3、初始化实例变量(即未被static修饰的成员变量),并未赋值。同样的,不管写的位置在哪里,在创建对象时执行到这步时,系统总会找到它进行变量初始化。4、执行构造代码块和实例变量定义赋值式,两者同样根据写的位置先后来决定执行顺序先后,同样可以按2中所写来理解。但是,这里要注意的就是构造代码块是可以调用静态变量的,实例变量定义赋值式可以看做是只对实例变量进行赋值的构造代码块。5、执行构造函数。构造函数同样可以调用静态变量和实例变量。&初始化结束。&
这里说明一点:这是初始化顺序,不等同于语句程序的执行过程(毕老师的视频里有个很详细的例子讲这个执行过程,不知道的一定要去看)。因此在上面的初始化顺序里没有成员函数(静态或者非静态都没有),这是因为成员函数都是调用了才执行,虽然静态函数已经被加载进了方法区,但初始化过程中并没有执行过。&关于这个初始化顺序,其实一句话可以概括:&先初始化类变量然后赋值,再初始化实例变量然后赋值。&由于静态代码块可以调用静态变量,构造代码块和构造函数可以调用实例变量和静态变量,这块很容易来个看似复杂的代码,将一个变量变来变去的,弄明白这个初始化顺序就会解决很快了。&&接下来,看几个例子来验证下:&&第一个:&public class JustForTest {& & public static void main(String[] args) {& & & & Car c=new Car();& & & & sop("i="+c.i);& & }& & &static void sop(Object obj){& & & & System.out.println(obj);& & }}&class Car{& & static int i=1; & //定义赋值& & static { & & & & &//静态代码块& & & & i=4;& & } &&}运行结果为:i=4.&只改写Car的内部,让静态代码块和静态变量的定义赋值互换位置,其他保持不变:&class Car{& & static { & & & & &//静态代码块& & & & i=4;& & }& & static int i=1; & //定义赋值 & &}运行结果为:i=1.&最后来个综合点的,把Car再改写一下:&class Car{& static int i=1; & & //静态变量定义赋值& Car(){ & & & & & & //构造函数& i=2;& }& static { & & & & &//静态代码块& & & & i=4;& & }& & { & & & & & //构造代码块& & & &i=3;& & }}运行结果是:i=2.&按初始化顺序,构造函数是最后初始化的。&
浅谈OpenJDK 与JDK的差异
使用过LINUX的人都应该知道,在大多数LINUX发行版本里,内置或者通过软件源安装JDK的话,都是安装的openjdk,那么到底什么是openjdk,它与sun jdk有什么关系和区别呢?&历史上的原因是,openjdk是jdk的开放原始码版本,以GPL协议的形式放出。在JDK7的时候,openjdk已经成为jdk7的主干开发,sun jdk7是在openjdk7的基础上发布的,其大部分原始码都相同,只有少部分原始码被替换掉。使用JRL(JavaResearch License,Java研究授权协议)发布。&至于openjdk6则更是有其复杂的一面,首先是openjdk6是jdk7的一个分支,并且尽量去除Java SE7的新特性,使其尽量的符合Java6的标准。&
关于JDK和OpenJDK的区别,可以归纳为以下几点:&授权协议的不同:&openjdk采用GPL V2协议放出,而JDK则采用JRL放出。两者协议虽然都是开放源代码的,但是在使用上的不同在于GPL V2允许在商业上使用,而JRL只允许个人研究使用。&OpenJDK不包含Deployment(部署)功能:&部署的功能包括:Browser Plugin、Java Web Start、以及Java控制面板,这些功能在Openjdk中是找不到的。&OpenJDK源代码不完整:&这个很容易想到,在采用GPL协议的Openjdk中,sun jdk的一部分源代码因为产权的问题无法开放openjdk使用,其中最主要的部份就是JMX中的可选元件SNMP部份的代码。因此这些不能开放的源代码将它作成plug,以供OpenJDK编译时使用,你也可以选择不要使用plug。而Icedtea则为这些不完整的部分开发了相同功能的源代码(OpenJDK6),促使OpenJDK更加完整。&部分源代码用开源代码替换:&由于产权的问题,很多产权不是SUN的源代码被替换成一些功能相同的开源代码,比如说字体栅格化引擎,使用Free Type代替。&openjdk只包含最精简的JDK:&OpenJDK不包含其他的软件包,比如Rhino Java DB JAXP&&,并且可以分离的软件包也都是尽量的分离,但是这大多数都是自由软件,你可以自己下载加入。&不能使用Java商标:&这个很容易理解,在安装openjdk的机器上,输入&java -version&显示的是openjdk,但是如果是使用Icedtea补丁的openjdk,显示的是java。&
浅谈Hibernate与Jpa的区别与联系
在讨论Hibernate与Jpa的关系是,首先要明确Jpa的用途。JPA全称为Java Persistence API ,Java持久化API是Sun公司在Java EE 5规范中提出的Java持久化接口。JPA吸取了目前Java持久化技术的优点,旨在规范、简化Java对象的持久化工作。使用JPA持久化对象,并不是依赖于某一个ORM框架。与Jpa相关的就是这个ORM技术,ORM 是Object-Relation-Mapping,即对象关系影射技术,是对象持久化的核心。ORM是对JDBC的封装,从而解决了JDBC的各种存在问题:&a) 繁琐的代码问题用JDBC的API编程访问数据库,代码量较大,特别是访问字段较多的表的时候,代码显得繁琐、累赘,容易出错。ORM则建立了Java对象与数据库对象之间的影射关系,程序员不需要编写复杂的SQL语句,直接操作Java对象即可,从而大大降低了代码量,也使程序员更加专注于业务逻辑的实现。&b) 数据库对象连接问题关系数据对象之间,存在各种关系,包括1对1、1对多、多对1、多对多、级联等。在数据库对象更新的时候,采用JDBC编程,必须十分小心处理这些关系,以保证维持这些关系不会出现错误,而这个过程是一个很费时费力的过程。ORM建立Java对象与数据库对象关系影射的同时,也自动根据数据库对象之间的关系创建Java对象的关系,并且提供了维持这些关系完整、有效的机制。&c) 系统架构问题JDBC属于数据访问层,但是使用JDBC编程时,必须知道后台是用什么数据库、有哪些表、各个表有有哪些字段、各个字段的类型是什么、表与表之间什么关系、创建了什么索引等等与后台数据库相关的详细信息。使用ORM技术,可以将数据库层完全隐蔽,呈献给程序员的只有Java的对象,程序员只需要根据业务逻辑的需要调用Java对象的Getter和 Setter方法,即可实现对后台数据库的操作,程序员不必知道后台采用什么数据库、有哪些表、有什么字段、表与表之间有什么关系。&d) 性能问题采用JDBC编程,在很多时候存在效率低下的问题。&&pstmt =conn.prepareStatement("insert into user_info values(?,?)");& & & &for (int i=0; i&1000; i++) {& & & & & pstmt.setInt(1,i);& & & & & pstmt.setString(2,"User"+i.toString());& & & & & pstmt.executeUpdate();& & & &}&&以上程序将向后台数据库发送1000次SQL语句执行请求,运行效率较低。采用ORM技术,ORM框架将根据具体数据库操作需要,会自动延迟向后台数据库发送SQL请求,ORM也可以根据实际情况,将数据库访问操作合成,尽量减少不必要的数据库操作请求。知道Jpa是一种规范,而Hibernate是它的一种实现。除了Hibernate,还有EclipseLink(曾经的toplink),OpenJPA等可供选择,所以使用Jpa的一个好处是,可以更换实现而不必改动太多代码。在play中定义Model时,使用的是jpa的annotations,比如javax.persistence.Entity, Table, Column, OneToMany等等。但它们提供的功能基础,有时候想定义的更细一些,难免会用到Hibernate本身的annotation。我当时想,jpa这 么弱还要用它干什么,为什么不直接使用hibernate的?反正我又不会换成别的实现。因为我很快决定不再使用hibernate,这个问题就一直放下了。直到我现在在新公司,做项目要用到Hibernate。我想抛开jpa,直接使用hibernate的注解来定义Model,很快发现了几个问题:jpa中有Entity, Table,hibernate中也有,但是内容不同;jpa中有Column,OneToMany等,Hibernate中没有,也没有替代品;我原以为hibernate对jpa的支持,是另提供了一套专用于jpa的注解,但现在看起来似乎不是。一些重要的注解如Column, OneToMany等,hibernate没有提供,这说明jpa的注解已经是hibernate的核心,hibernate只提供了一些补充,而不是两 套注解。要是这样,hibernate对jpa的支持还真够足量,我们要使用hibernate注解就必定要使用jpa。&
成为一名优秀的程序员需要具备的特质
优秀的程序员往往具备一些共有的特质,下面笔者也分享几点:&1:团队精神和协作能力 把它作为基本素质,并不是不重要,恰恰相反,这是程序员应该具备的最基本的,也是最重要的安身立命之本。任何个人的力量都是有限的,即便如linus这样的 天才,也需要通过组成强大的团队来创造奇迹,那些遍布全球的为linux写核心的高手们,没有协作精神是不可想象的。一旦进入系统的研发团队,进入商业化和产品化的开发任务,缺乏这种素质的人是不合格的。&2:文档习惯 说高水平程序员从来不写文档的肯定是乳臭未干的毛孩子,良好的文档是正规研发流程中非常重要的环节,作为代码程序员,30%的工作时间写技术文档是很正常的,而作为高级程序员和系统分析员,这个比例还要 高很多。缺乏文档,一个软件系统就缺乏生命力,在未来的查错,升级以及模块的复用时就都会遇到极大的麻烦。&&3:规范化,标准化的代码编写习惯 代码的变量命名,代码内注释格式,甚至嵌套中行缩进的长度和函数间的空行数字都有明确规定,良好的编写习惯,不但有助于代码的移植和纠错,也有助于不同技术 人员之间的协作。有些codingfans叫嚣高水平程序员写的代码旁人从来看不懂,这种叫嚣只能证明他们自己?根不配自称程序员。代码具有良好的可读性,是程序员基本的素质需求。没有规范化和标准化的代码习惯,研发之间的协作是绝对不可想的。
4:需求理解能力 程序员需要理解一个模块的需求,很多程序员写程序往往只关注一个功能需求,他们把性能指标全部归结到硬件,操作系统和开发环境上,而忽视了本身代码的性能考 虑,性能需求指标中,稳定性,并访支撑能力以及安全性都很重要,作为程序员需要评估该模块在系统运营中所处的环境,将要受到的负荷压力以及各种潜在的危险 和恶意攻击的可能性。就这一点,一个成熟的程序员至少需要2到3年的项目研发和跟踪经验才有可能有心得。&5:复用性,模块化思维能力 经常可以听到一些程序员有这样的抱怨,写了几年程序,变成了熟练工,每天都是重复写一些没有任何新意的代码,这其实是中国软件人才最大浪费的地方,一些重复性工作变成了熟练程序员的主要工作,而这些,其实是完全可以避免的。 复用性设计,模块化思维就是要程序员在完成任何一个功能模块或函数的时候,要多想一些,不要局限在完成当前任务的简单思路上,想想看该模块是否可以脱离这个 系统存在,是否可以通过简单的修改参数的方式在其他系统和应用环境下直接引用,这样就能极大避免重复性的开发工作,如果一个软件研发单位和工作组能够在每 一次研发过程中都考虑到这些问题,那么程序员就不会在重复性的工作中耽误太多时间,就会有更多时间和精力投入到创新的代码工作中去。 一些好的程序模块代码,即便是70年代写成的,拿到现在放到一些系统里面作为功能模块都能适合的很好,而现在很多软件一升级或改进就动辄全部代码重写,大部分重复性工作无谓的浪费了时间和精力,这是我们应当刻意克服的弊病。&6:测试习惯 作为一些正规化的开发而言,专职的测试工程师是不可少的,但是并不是说有了专职的测试工程师程序员就可以不进行自测;软件研发作为一项工程而言,一个很重要 的特点就是问题发现的越早,解决的代价就越低,程序员在每段代码,每个子模块完成后进行认真的测试,就可以尽量将一些潜在的问题最早的发现和解决,这样对 整体系统建设的效率和可靠性就有了最大的保证。 测试工作实际上需要考虑两方面,一方面是正常调用的测试,也就是看程序是否能在正常调用下完成基本功能,这是最基本的测试职责,可惜在很多公司这成了唯一的测试任务,实际上还差的远那;第二方面就是异常调用的测试,比如高压力负荷下的稳定 性测试,用户潜在的异常输入情况下的测试,整体系统局部故障情况下该模块受影响状况的测试,频发的异常请求阻塞资源时的模块稳定测试等等。 当然并不是程序员要对自己的每段代码都需要进行这种完整测试,但是程序员必须清醒认识自己的代码任务在整体项目中的地位和各种性能需求,有针对性的进行相关测试并尽早发现和解决问题,当然这需要上面提到的需求理解能力。&7:学习和总结的能力&程序员是人才很容易被淘汰,很容易落伍的职业,因为一种技术可能仅仅在三两年内具有领先性,程序员如果想安身立命,就必须不断跟进新的技术,学习新的技能。善于学习,对于任何职业而言,都是前进所必需的动力,对于程序员,这种要求就更加高了。&但是学习也要找对目标,善于总结,也是学习能力的一种体现,每次完成一个研发任务,完成一段代码,都应当有目的的跟踪该程序的应用状况和用户反馈,随时总结,找到自己的不足,这样逐步提高,一个程序员才可能成长起来。&
Java虚拟机的原理是怎样的?学习一下吧
Java虚拟机是一个可以执行Java字节码的虚拟机进程。Java源文件被编译成能被Java虚拟机执行的字节码文件。Java是平台无关的语言是指用Java写的应用程序不用修改就可在不同的软硬件平台上运行。平台无关有两种:源代码级和目标代码级。C和C++具有一定程度的源代码级平台无关,表明用C或C++写的应用程序不用修改只需重新编译就可以在不同平台上运行。&Java主要靠Java虚拟机(JVM)在目标码级实现平台无关性。JVM是一种抽象机器,它附着在具体操作系统之上,本身具有一套虚机器指令,并有自己的栈、寄存器组等。但JVM通常是在软件上而不是在硬件上实现。(目前,SUN系统公司已经设计实现了Java芯片,主要使用在网络计算机NC上。另外,Java芯片的出现也会使Java更容易嵌入到家用电器中。)JVM是Java平台无关的基础,在JVM上,有一个Java解释器用来解释Java编译器编译后的程序。Java编程人员在编写完软件后,通过Java编译器将Java源程序编译为JVM的字节代码。任何一台机器只要配备了Java解释器,就可以运行这个程序,而不管这种字节码是在何种平台上生成的。另外,Java采用的是基于IEEE标准的数据类型。通过JVM保证数据类型的一致性,也确保了Java的平台无关性。
Java虚拟机通过调用某个指定类的方法main启动,传递给main一个字符串数组参数,使指定的类被装载,同时链接该类所使用的其它的类型,并且初始化它们。例如对于程序:&public class HelloApp {public static void main(String[] args){System.out.println("Hello World!");for (int i = 0; i & args. i++ ) {System.out.println(args);}}}编译后在命令行模式下键入:java HelloApp run virtual machine&将通过调用HelloApp的方法main来启动java虚拟机,传递给main一个包含三个字符串"run"、"virtual"、"machine"的数组。现在我们略述虚拟机在执行HelloApp时可能采取的步骤。&
简析Java中return和break的区别
break语句的使用场合主要是switch语句和循环结构。在循环结构中使用break语句,如果执行了break语句,那么就退出循环,接着执行循环结构下面的第一条语句。如果在多重嵌套循环中使用break语句,当执行break语句的时候,退出的是它所在的循环结构,对外层循环没有任何影响。如果循环结构里有switch语句,并且在switch语句中使用了break语句,当执行switch语句中的break语句时,仅退出switch语句,不会退出外面的循环结构。continue语句是这5种结束循环的方式中最特殊的,因为它并没有真的退出循环,而是只结束本次循环体的执行,所以在使用continue的时候要注意这一点。如果在程序中遇到return语句,那么代码就退出该函数的执行,返回到函数的调用处,如果是main()函数,那么结束整个程序的运行。下面就对三者的区别通过案例来简要说明:1、breakbreak :跳出当前循环;但是如果是嵌套循环,则只能跳出当前的这一层循环,只有逐层break才能跳出所有循环;&for (int i = 0; i & 10; i++) { && & & & & & if (i == 6) {&& & & & & & & & && & & & & & & &// 在执行i==6时强制终止循环,i==6不会被执行 && & & & & & & & }& & & & & & System.out.println(i); && & & & } &输出结果为0 1 2 3 4 5 ;6以后的都不会输出&
2、continuecontinue:终止当前循环,但是不跳出循环(在循环中continue后面的语句是不会执行了),继续往下根据循环条件执行循环。&for (int i = 0; i & 10; i++) { && & if (i == 6) &{& & & & && & & // i==6不会被执行,而是被中断了 & && & & &}&& & & &System.out.println(i); && &}输出结果为0 1 2 3 4 5 7 8 9;只有6没有输出&3、return(1).return 从当前的方法中退出,返回到该调用的方法的语句处,继续执行。 & & &(2).return 返回一个值给调用该方法的语句,返回值的数据类型必须与方法的声明中的返回值的类型一致。 & & &(3). return后面也可以不带参数,不带参数就是返回空,其实主要目的就是用于想中断函数执行,返回调用函数处。&特别注意:返回值为void的方法,从某个判断中跳出,必须用return.&下面再详细辨析一下return和break语句作用的区别&return 语句的作用(1) return 从当前的方法中退出,返回到该调用的方法的语句处,继续执行。(2) return 返回一个值给调用该方法的语句,返回值的数据类型必须与方法的声明中的返回值的类型一致。(3) return后面也可以不带参数,不带参数就是返回空,其实主要目的就是用于想中断函数执行,返回调用函数处。break语句的作用(1)break在循环体内,强行结束循环的执行,也就是结束整个循环过程,不在判断执行循环的条件是否成立,直接转向循环语句下面的语句。(2)当break出现在循环体中的switch语句体内时,其作用只是跳出该switch语句体。&
Servlet技术过时了吗?看了这个就会明白
Servlet 是Java Servlet的简称,是一种服务连接器,也是Java语言实现的一个借口类。支持Java的应用服务器都可以实现。Servlet可以相应任何类型的请求,至今在服务器开发领域仍然有比较广泛的使用。为了可以更加清晰直观的认识Servlet,我们可以将其和JSP加以对比。Jsp优点:一次编写,到处运行。除了系统之外,代码不用做任何更改。系统的多平台支持。基本上可以在所有平台上的任意环境中开发,在任意环境中进行系统部署,在任意环境中扩展。相比ASP的局限性JSP的优势是显而易见的。强大的可伸缩性。从只有一个小的Jar文件就可以运行Servlet/JSP,到由多台服务器进行集群和负载均衡,到多台Application进行事务处理,消息处理,一台服务器到无数台服务器,Java显示了一个巨大的生命力。多样化和功能强大的开发工具支持。这一点与ASP很像,Java已经有了许多非常优秀的开发工具,而且许多可以免费得到,并且其中许多已经可以顺利的运行于多种平台之下。支持服务器端组件。web应用需要强大的服务器端组件来支持,开发人员需要利用其他工具设计实现复杂功能的组件供web页面调用,以增强系统性能。JSP可以使用成熟的JAVA BEANS 组件来实现复杂商务功能。
缺点:与ASP也一样,Java的一些优势正是它致命的问题所在。正是由于为了跨平台的功能,为了极度的伸缩能力,所以极大的增加了产品的复杂性。Java的运行速度是用class常驻内存来完成的,所以它在一些情况下所使用的内存比起用户数量来说确实是&最低性能价格比&了。Servlet优点:方便  Servlet提供了大量的实用工具例程,例如自动地解析和解码HTML表单数据、读取和设置HTTP头、处理Cookie、跟踪会话状态等。功能强大在Servlet中,许多使用传统CGI程序很难完成的任务都可以轻松地完成。例如,Servlet能够直接和Web服务器交互,而普通的CGI程序不能。Servlet还能够在各个程序之间共享数据,使得数据库连接池之类的功能很容易实现。可移植性好Servlet用Java编写,Servlet API具有完善的标准。因此,为IPlanet Enterprise Server写的Servlet无需任何实质上的改动即可移植到Apache、Microsoft IIS或者WebStar。几乎所有的主流服务器都直接或通过插件支持Servlet。节省投资  不仅有许多廉价甚至免费的Web服务器可供个人或小规模网站使用,而且对于现有的服务器,如果它不支持Servlet的话,要加上这部分功能也往往是免费的(或只需要极少的投资)。缺点:Servlet 没有图形界面,运行在服务器端。Servlet是一个早期的不完善的产品,写business layer很好,写presentation layer就不太理想,并且两层混杂。总之,Servlet在今后的长时间内还会被广泛使用,所以不会过时。&
用Xcode7调试 Openjdk7的方法
笔者目前使用的Mac版本是10.10,配置好必要信息以后就开始编辑,结果错误满屏。简单看过之后发现是编译C文件的时候参数有误,于是查了一下,才知道是LLVM版本太新,不兼容低版本的一些编译参数。照着上面改了点代码,但是依旧编译不过。既然高版本不行,就装个低版本的呗。由于最新的OS X不能装低版本的Xcode(装了Xcode才能装LLVM),所以去下了一个10.8的OS X装在虚拟机里,然后再装个Xcode4.4。装好Xcode以后,要手动下载LLVM安装。打开Xcode,随便建立一个空项目,然后打开Preferences,找到如下所示的地方开始安装,接下来就可以逐步安装JDK7了。&1要安装JDK7,当然是要有JDK的二进制文件,可直接在ORACLE的官网中下载就可以拉出来 。PS:要注意系统版本的选择,我就是在折腾了许久的X64版本的JDK后,才发现我的系统是X86的。2接着就是解压tar.gz的文件了。tar -xzf jdk-7-linux-i586.tar.gz&3接着就是解压出来的文件夹移动到/usr/lib/jvm的目录下&在这之前当然需要你拥有root的权限 su -l 再输入root账户的密码,同时也需要你在/usr/lib目录下新建一个文件夹 mkdir /usr/lib/jvm。&做好这些准备之后,我们就可以吧jdk的文件移动我们想要的位置了。&mv jdk1.7.0 /usr/lib/jvm&为了方便配置环境变量,我们把jdk的文件改名一下,网上普遍把jdk的文件改名为jdk-7-sun。&
mv /usr/lib/jvm/jdk1.7.0 /usr/lib/jvm/java-7-sun&4配置环境变量&如果你机子上面有安装vim的话,请运行vim ~/.bashrc&如果没有的话可以用gedit打开, 请运行gedit ~/.bashrc&在环境变量中添加进以下内容:&export JAVA_HOME=/usr/lib/jvm/java-7-sun&export JRE_HOME=${JAVA_HOME}/jre&export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib&export PATH=${JAVA_HOME}/bin:$PATH&5保存环境变量,退出编辑器,然后输入以下命令使环境变量生效&source ~/.bashrc&可以用env命令来查看设置的环境变量是否成功。&6配置默认的程序&sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/java-7-sun/bin/java 300&sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/java-7-sun/bin/javac 300&sudo update-alternatives --config java&sudo update-alternatives --config javac如果你的系统中安装了其他的jdk,系统会提示出来,选择jdk7即&7测试以下jdk的版本,在终端中输入以下命令&java -version&javac -version&如果你看的结果和下面的一样的话,那你的jdk7配置就基本上完成了。&java version "1.7.0" Java(TM) SE Runtime Environment (build 1.7.0-b147) Java HotSpot(TM) Server VM (build 21.0-b17, mixed mode)&
浅谈ServletContext 与application的异同
servletContext接口是Servlet中最大的一个接口,呈现了web应用的Servlet视图。ServletContext实例是通过 getServletContext()方法获得的,由于HttpServlet继承Servlet的关系GenericServlet类和HttpServlet类同时具有该方法。条件:假设说我们有一个WEB应用,这个WEB应用中有10个SERVLET&在这里,这个WEB应用就拥有一个它自己的仓库-ServletContext,而这10个Servlet则共享这个大仓库,并且各自拥有属于他们自己的小仓库-ServletConfig。&ServletContext就是一个全局的概念,它属于应用,但我们有时候不想让某些参数被其他Servlet应用,仅仅想在自己的Servlet中被共享,这时候就需要把它保存在ServletConfig中,换句话说,从一个Servlet来看,ServletConfig是它的全局,而从一个Servlet集合(Web应用)来看,ServletContext是它的全局。&假设现在要运行一个应用。&&1.Tomcat启动&读入xml文件&2.容器为这个应用建立一个新的ServletContext实例,应用的所有部分都共享这个上下文&3.如果xml中有定义上下文的初始参数,则容器首先创建初始参数实例(应该就像一个Bean一样)&4.把初始化参数实例的引用交给ServletContext&5.容器建立一个新的servlet,这时建立一个新的ServletConfig对象,并且为这个ServletConfig对象提供一个ServletContext的引用&6.调用servlet的init()方法初始化servlet&
由第5步可以看出,每个servlet中都有一个上下文(ServletContext)的引用,因此,servlet都知道这个上下文。&但是ServletContext的实例比Servlet先诞生,所以ServletContext诞生的时候并不知道Servlet的存在。&&在JAVA EE API文档中&ServlectContext拥有获得Servlet的方法&例如:Servlet getServlet(String name)&但是,这一类的方法已经废弃了,从注释中可以看出,原先的这些方法返回的值是null,也就是无法获得servlet&因此,ServlectContext诞生的时候并不知道Servlet的存在,它的诞生仅仅是因为容器诞生了笔者觉得,ServletContext中并没有Servlet的信息,相反,每个Servlet中都持有ServletContext的引用。在HeadFirstJSP中有一个说法我觉得不错,ServletContext就像一块布告栏,你可以往上贴布告,走过的人都可以看到它!servlet上下文,是针对servletconfig而提出来的,因为容器在配置文件中提取的初始化参数保存在了servletconfig对象中,但由于初始化参数只针对某个具体的servlet而言,别的servlet是访问不到这个参数的,所以为了提供一个可以供全体servlet使用的对象--这个对象也可以从配置文件中获取参数,哪个老外就弄出了一个servletcontext对象,并把它称为上下文或者应用上下文,其实就这么简单。只不过大家现在所听到的所看到的上下文被形态化了,经典话了而已。追起本质,还是很好理解的。&ServletContext 与application的异同&&相同:其实servletContext和application 是一样的,就相当于一个类创建了两个不同名称的变量。在servlet中ServletContext就是application对象。大家只要打开jsp编译过后生成的Servlet中的_jspService()方法就可以看到如下的声明:& & & & & & ServletContextapplication =& & & & & & application= pageContext.getServletContext();&不同:两者的区别就是application用在jsp中,servletContext用在servlet中。application和page && & & requestsession 都是JSP中的内置对象,在后台用ServletContext存储的属性数据可以用 && & & application对象获得。& &而且application的作用域是整个Tomcat启动的过程。例如:ServletContext.setAttribute("username",username);则在JSP网页中可以使用 &application.getAttribute("username");来得到这个用户名。&
怎样在多台Web服务器上共享Session
在多台web服务器上共享session的问题,我们可以举一些案例来说明。比如:现在有三台php服务器,且实现了负载均衡,如何让这三台web服务器共享session数据?session数据默认是以文件的形式保存在web服务器的磁盘上,一般都是用户登录成功的时候,保存session数据。同一个用户登录后,就会将session保存在某个web服务器上,假设是保存在服务器A上,该用户访问网站的其他页面时,可能请求的就是服务器B或服务器C,但服务器B或服务器C上并没有该用户的session文件,这样,就会导致网站误认为该用户未登录,用户的登录状态丢失的问题。归根结底,就是要解决多台web服务器共享session的问题,尚学堂陈老师为我们简要总结了三种方法:&一、将本该保存在web服务器磁盘上的session数据保存到cookie中即用cookie会话机制替代session会话机制,将session数据保存到客户端浏览器的cookie中,这样同一个用户访问同一网站时,无论负载均衡到哪台web服务器,都不用再去服务器请求session数据,而直接获取客户端cookie中的session数据。如此,同一个用户的登录状态就不会丢失了。但这样做,有三大弊端:把session数据放到客户端的cookie中,一般都是重要数据(如用户id、昵称等),会存在安全问题,但可以将session数据加密后,再存放到cookie中,来降低安全风险。浏览器对单个cookie的数据量大小限制为4K左右,因此会存在数据量的限制问题。影响带宽性能,降低了页面的访问速度。在高访问量的情况下,用户每次请求时,都要将客户端cookie中的session数据发送到服务器,要占用较多的带宽,进而影响访问速度,服务器带宽成本增高。&二、将本该保存在web服务器磁盘上的session数据保存到MySQL数据库中sessionid还是利用cookie机制存储到客户端,但session数据却存放在MySQL服务器上。(需要建立sessionid和session数据行的对应关系)但这样做,只适合访问量比较小的网站。如果网站的访问量比较大,对MySQL服务器会造成很大压力。因为每次用户请求页面(即使是刷新页面)都要查询MySQL数据库中的session数据表,进而判断用户的登录状态和读取用户相关信息,势必会对数据库服务器造成很大压力,这样就会降低服务器的响应速度,影响用户体验。&三、将本该保存在web服务器磁盘上的session数据保存到内存数据库(memcache或redis)中memcache或redis是基于内存存储数据的,性能很高,尤其是高并发的情况下尤为合适。主要是因为从内存中读取数据要比从磁盘读取数据快很多。内存数据库还支持数据过期失效的机制,正好与session的过期机制对应,推荐使用redis内存数据库,因为它比memcache支持更多的数据类型,且支持内存数据备份到磁盘。&这里简单说一下,后面两种方法的注意要点:如果多台web服务器对应的是不同的域名,为了保证cookie的唯一(同一个cookie在各个域名有效),需要修改php.ini文件中的session.cookie_domain由于后面两种方法,属于用户自定义的方式管理session,而非默认的文件处理方式,故需修改php.ini中的session.save_handler=user在开启session之前(即调用session_start()之前),需要先调用session_set_save_handler,关于session_set_save_handler的具体用法,请参考php手册。&
浅析内存泄漏和内存溢出的区别
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。memory leak会最终会导致out of memory!内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。&&内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出!比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出。以发生的方式来分类,内存泄漏可以分为4类:&1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。&2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。&3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。&4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。&从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。&
Hotpot Java虚拟机Class对象是在方法区还是堆中
Class对象是存放在堆区的,不是方法区,这点很多人容易犯错。类的元数据(元数据并不是类的Class对象。Class对象是加载的最终产品,类的方法代码,变量名,方法名,访问权限,返回值等等都是在方法区的)才是存在方法区的。方法区&在一个JVM实例的内部,类型信息被存储在一个称为方法区的内存逻辑区中。类型信息是由类加载器在类加载时从类文件中提取出来的。类(静态)变量也存储在方法区中。JVM实现的设计者决定了类型信息的内部表现形式。如,多字节变量在类文件是以big-endian存储的,但在加载到方法区后,其存放形式由jvm根据不同的平台来具体定义。JVM在运行应用时要大量使用存储在方法区中的类型信息。在类型信息的表示上,设计者除了要尽可能提高应用的运行效率外,还要考虑空间问题。根据不同的需求,JVM的实现者可以在时间和空间上追求一种平衡。因为方法区是被所有线程共享的,所以必须考虑数据的线程安全。假如两个线程都在试图找lava的类,在lava类还没有被加载的情况下,只应该有一个线程去加载,而另一个线程等待。方法区的大小不必是固定的,jvm可以根据应用的需要动态调整。同样方法区也不必是连续的。方法区可以在堆(甚至是虚拟机自己的堆)中分配。jvm可以允许用户和程序指定方法区的初始大小,最小和最大尺寸。方法区同样存在垃圾收集,因为通过用户定义的类加载器可以动态扩展java程序,一些类也会成为垃圾。jvm可以回收一个未被引用类所占的空间,以使方法区的空间最小。&类型信息&对每个加载的类型,jvm必须在方法区中存储以下类型信息:&一 这个类型的完整有效名&二 这个类型直接父类的完整有效名(除非这个类型是interface或是&java.lang.Object,两种情况下都没有父类)&三 这个类型的修饰符(public,abstract, final的某个子集)&四 这个类型直接接口的一个有序列表&类型名称在java类文件和jvm中都以完整有效名出现。在java源代码中,完整有效名由类的所属包名称加一个&.&,再加上类名&组成。例如,类Object的所属包为java.lang,那它的完整名称为java.lang.Object,但在类文件里,所有的&.&都被&斜杠&/&代替,就成为java/lang/Object。完整有效名在方法区中的表示根据不同的实现而不同。&除了以上的基本信息外,jvm还要为每个类型保存以下信息:&类型的常量池( constant pool)&域(Field)信息&方法(Method)信息&除了常量外的所有静态(static)变量&常量池&jvm为每个已加载的类型都维护一个常量池。常量池就是这个类型用到的常量的一个有序集合,包括实际的常量(string,&integer, 和floating point常量)和对类型,域和方法的符号引用。池中的数据项象数组项一样,是通过索引访问的。&因为常量池存储了一个类型所使用到的所有类型,域和方法的符号引用,所以它在java程序的动态链接中起了核心的作用。&域信息&jvm必须在方法区中保存类型的所有域的相关信息以及域的声明顺序,&域的相关信息包括:&域名&域类型&域修饰符(public, private, protected,static,final volatile, transient的某个子集)方法信息&jvm必须保存所有方法的以下信息,同样域信息一样包括声明顺序&方法名&方法的返回类型(或 void)&方法参数的数量和类型(有序的)&方法的修饰符(public, private, protected, static, final, synchronized, native, abstract的一个子集)除了abstract和native方法外,其他方法还有保存方法的字节码(bytecodes)操作数栈和方法栈帧的局部变量区的大小&异常表类变量( Class Variables 译者:就是类的静态变量,它只与类相关,所以称为类变量 )&类变量被类的所有实例共享,即使没有类实例时你也可以访问它。这些变量只与类相关,所以在方法区中,它们成为类数据在逻辑上的一部分。在jvm使用一个类之前,它必须在方法区中为每个non-final类变量分配空间。常量(被声明为final的类变量)的处理方法则不同,每个常量都会在常量池中有一个拷贝。non-final类变量被存储在声明它的&类信息内,而final类被存储在所有使用它的类信息内。对类加载器的引用&jvm必须知道一个类型是由启动加载器加载的还是由用户类加载器加载的。如果一个类型是由用户类加载器加载的,那么jvm会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中。jvm在动态链接的时候需要这个信息。当解析一个类型到另一个类型的引用的时候,jvm需要保证这两个类型的类加载器是相同的。这对jvm区分名字空间的方式是至关重要的。对Class类的引用&jvm为每个加载的类型(译者:包括类和接口)都创建一个java.lang.Class的实例。而jvm必须以某种方式把Class的这个实例和存储在方法区中的类型数据联系起来。你可以通过Class类的一个静态方法得到这个实例的引用// A method declared in class java.lang.Class:&public static Class forName(String className);假如你调用forName(&java.lang.Object&),你会得到与java.lang.Object对应的类对象。你甚至可以通过这个函数 得到任何包中的任何已加载的类引用,只要这个类能够被加载到当前的名字空间。如果jvm不能把类加载到当前名字空间,forName就会抛出ClassNotFoundException。&(译者:熟悉COM的朋友一定会想到,在COM中也有一个称为 类对象(Class Object)的东东,这个类对象主要 是实现一种工厂模式,而java由于有了jvm这个中间 层,类对象可以很方便的提供更多的信息。这两种类对象 都是Singleton的)也可以通过任一对象的getClass()函数得到类对象的引用,getClass被声明在Object类中:&// A method declared in class java.lang.Object:&public final Class getClass();&例如,假如你有一个java.lang.Integer的对象引用,可以激活getClass()得到对应的类引用。通过类对象的引用,你可以在运行中获得相应类存储在方法区中的类型信息,下面是一些Class类提供的方法:&// Some of the methods declared in class java.lang.Class:&public String getName();&public Class getSuperClass();&public boolean isInterface();&public Class[] getInterfaces();&public ClassLoader getClassLoader();&这些方法仅能返回已加载类的信息。getName()返回类的完整名,getSuperClass()返回父类的类对象,isInterface()判断是否是接口。getInterfaces()返回一组类对象,每个类对象对应一个直接父接口。如果没有,则返回一个长度为零的数组。&getClassLoader()返回类加载器的引用,如果是由启动类加载器加载的则返回null。所有的这些信息都直接从方法区中获得。&方法表&为了提高访问效率,必须仔细的设计存储在方法区中的数据信息结构。除了以上讨论的结构,jvm的实现者还可以添加一些其他的数据结构,如方法表。jvm对每个加载的非虚拟类的类型信息中都添加了一个方法表,方法表是一组对类实例方法的直接引用(包括从父类继承的方法)。jvm可以通过方法表快速激活实例方法。(译者:这里的方法表与C++中的虚拟函数表一样,但java方法全都 是virtual的,自然也不用虚拟二字了。正像java宣称没有 指针了,其实java里全是指针。更安全只是加了更完备的检查机制,但这都是以牺牲效率为代价的,个人认为java的设计者 始终是把安全放在效率之上的,所有java才更适合于网络开发)&举一个例子&为了显示jvm如何使用方法区中的信息,我们据一个例子,我们&看下面这个类:&class Lava {&private int speed = 5; // 5 kilometers per hour&void flow() {&}&}&class Volcano {&public static void main(String[] args) {&Lava lava = new Lava();&lava.flow();&}&}&下面我们描述一下main()方法的第一条指令的字节码是如何被执行的。不同的jvm实现的差别很大,这里只是其中之一。&为了运行这个程序,你以某种方式把&Volcano&传给了jvm。有了这个名字,jvm找到了这个类文件(Volcano.class)并读入,它从类文件提取了类型信息并放在了方法区中,通过解析存在方法区中的字节码,jvm激活了main()方法,在执行时,jvm保持了一个指向当前类(Volcano)常量池的指针。注意jvm在还没有加载Lava类的时候就已经开始执行了。正像大多数的jvm一样,不会等所有类都加载了以后才开始执行,它只会在需要的时候才加载。main()的第一条指令告知jvm为列在常量池第一项的类分配足够的内存。jvm使用指向Volcano常量池的指针找到第一项,发现是一个对Lava类的符号引用,然后它就检查方法区看lava是否已经被加载了。这个符号引用仅仅是类lava的完整有效名&lava&。这里我们看到为了jvm能尽快从一个名称找到一个类,一个良好的数据结构是多么重要。这里jvm的实现者可以采用各种方法,如hash表,查找树等等。同样的算法可以用于Class类的forName()的实现。当jvm发现还没有加载过一个称为&Lava&的类,它就开始查找并加载类文件&Lava.class&。它从类文件中抽取类型信息并放在了方法区中。jvm于是以一个直接指向方法区lava类的指针替换了常量池第一项的符号引用。以后就可以用这个指针快速的找到lava类了。而这个替换过程称为常量池解析(constant pool resolution)。在这里我们替换的是一个native指针。jvm终于开始为新的lava对象分配空间了。这次,jvm仍然需要方法区中的信息。它使用指向lava数据的指针(刚才指向volcano常量池第一项的指针)找到一个lava对象究竟需要多少空间。jvm总能够从存储在方法区中的类型信息知道某类型对象需要的空间。但一个对象在不同的jvm中可能需要不同的空间,而且它的空间分布也是不同的。(译者:这与在C++中,不同的编译器也有不同的对象模型是一个道理)一旦jvm知道了一个Lava对象所要的空间,它就在堆上分配这个空间并把这个实例的变量speed初始化为缺省值0。假如lava的父对象也有实例变量,则也会初始化。当把新生成的lava对象的引用压到栈中,第一条指令也结束了。下面的指令利用这个引用激活java代码把speed变量设为初始值,5。另外一条指令会用这个引用激活Lava对象的flow()方法。&
浅析Mybatis与Hibernate的区别与用途
有很长一段时间对mybatis是比较陌生的,只知道与Hibernate一样是个orm数据库框架。随着使用熟练度的增加,发现它与Hibernate区别是非常大的,应当结合不同的情况分析选用。结合至今为止的经验,总结出以下几点:1. hibernate是全自动,而mybatis是半自动hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql。而mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。2. hibernate数据库移植性远大于mybatishibernate通过它强大的映射结构和hql语言,大大降低了对象与数据库(oracle、mysql等)的耦合性,而mybatis由于需要手写sql,因此与数据库的耦合性直接取决于程序员写sql的方法,如果sql不具通用性而用了很多某数据库特性的sql语句的话,移植性也会随之降低很多,成本很高。3. hibernate拥有完整的日志系统,mybatis则欠缺一些hibernate日志系统非常健全,涉及广泛,包括:sql记录、关系异常、优化警告、缓存提示、脏数据警告等;而mybatis则除了基本记录功能外,功能薄弱很多。4. mybatis相比hibernate需要关心很多细节hibernate配置要比mybatis复杂的多,学习成本也比mybatis高。但也正因为mybatis使用简单,才导致它要比hibernate关心很多技术细节。mybatis由于不用考虑很多细节,开发模式上与传统jdbc区别很小,因此很容易上手并开发项目,但忽略细节会导致项目前期bug较多,因而开发出相对稳定的软件很慢,而开发出软件却很快。hibernate则正好与之相反。但是如果使用hibernate很熟练的话,实际上开发效率丝毫不差于甚至超越mybatis。5. sql直接优化上,mybatis要比hibernate方便很多由于mybatis的sql都是写在xml里,因此优化sql比hibernate方便很多。而hibernate的sql很多都是自动生成的,无法直接维护sql;虽有hql,但功能还是不及sql强大,见到报表等变态需求时,hql也歇菜,也就是说hql是有局限的;hibernate虽然也支持原生sql,但开发模式上却与orm不同,需要转换思维,因此使用上不是非常方便。总之写sql的灵活度上hibernate不及mybatis。&随着使用情况的不断增多,我又做了进一步的总结总结:mybatis:小巧、方便、高效、简单、直接、半自动hibernate:强大、方便、高效、复杂、绕弯子、全自动&mybatis:1. 入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。2. 可以进行更为细致的SQL优化,可以减少查询字段。3. 缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。4. 二级缓存机制不佳。hibernate:1. 功能强大,数据库无关性好,O/R映射能力强,如果你对Hibernate相当精通,而且对Hibernate进行了适当的封装,那么你的项目整个持久层代码会相当简单,需要写的代码很少,开发速度很快,非常爽。2. 有更好的二级缓存机制,可以使用第三方缓存。3. 缺点就是学习门槛不低,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行。举个形象的比喻:mybatis:机械工具,使用方便,拿来就用,但工作还是要自己来作,不过工具是活的,怎么使由我决定。hibernate:智能机器人,但研发它(学习、熟练度)的成本很高,工作都可以摆脱他了,但仅限于它能做的事。&
浅谈Web开发中forward与redirect的区别
Forward和Redirect代表了两种请求转发方式:直接转发和间接转发。直接转发就是由控制器来控制请求应该转发给那个信息资源。然后由这些信息资源处理请求,处理完以后还可能转发给另外的信息资源来返回给用户,这个过程就是经典的MVC模式;而间接转发有时也叫做重定向,它一般用于避免用户的非正常访问。区别在于:&1.从地址栏显示来说&forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器。浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址。redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址。所以地址栏显示的是新的URL。&2.从数据共享来说&forward:转发页面和转发到的页面可以共享request里面的数据。redirect:不能共享数据。&3.从运用地方来说&forward:一般用于用户登陆的时候,根据角色转发到相应的模块。redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等。&4.从效率来说&forward:高。redirect:低。&关于两者的本质区别,有以下几种解释:&解释一  &一句话,转发是服务器行为,重定向是客户端行为。为什么这样说呢,这就要看两个动作的工作流程:&转发过程:客户浏览器发送http请求&&web服务器接受此请求&&调用内部的一个方法在容器内部完成请求处理和转发动作&&将目标资源。发送给客户;在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客 户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。重定向过程:客户浏览器发送http请求&&web服务器接受后发送302状态码响应及对应新的location给客户浏览器&&客户浏览器发现 是302响应,则自动再发送一个新的http请求,请求url是新的location地址&&服务器根据此请求寻找资源并发送给客户。在这里 location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的 路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。&&解释二&重定向,其实是两次request:第一次,客户端request A,服务器响应,并response回来,告诉浏览器,你应该去B。这个时候IE可以看到地址变了,而且历史的回退按钮也亮了。重定向可以访问自己web应用以外的资源。在重定向的过程中,传输的信息会被丢失。&&例子:&请求转发是服务器内部把对一个request/response的处理权,移交给另外一个,对于客户端而言,它只知道自己最早请求的那个A,而不知道中间的B,甚至C、D。 传输的信息不会丢失。&
解释三&假设你去办理某个执照, 重定向:你先去了A局,A局的人说:&这个事情不归我们管,去B局&,然后,你就从A退了出来,自己乘车去了B局。 转发:你先去了A局,A局看了以后,知道这个事情其实应该B局来管,但是他没有把你退回来,而是让你坐一会儿,自己到后面办公室联系了B的人,让他们办好后,送了过来。&&请求重定向与请求转发的比较:&尽管HttpServletResponse.sendRedirect方法和RequestDispatcher.forward方法都可以让浏览器获 得另外一个URL所指向的资源,但两者的内部运行机制有着很大的区别。下面是HttpServletResponse.sendRedirect方法实现 的请求重定向与RequestDispatcher.forward方法实现的请求转发的总结比较:&&(1)RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件;而 HttpServletResponse.sendRedirect 方法不仅可以重定向到当前应用程序中的其他资源,还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。如果传递给HttpServletResponse.sendRedirect 方法的相对URL以&/&开头,它是相对于整个WEB站点的根目录;如果创建RequestDispatcher对象时指定的相对URL以&/&开头,它 是相对于当前WEB应用程序的根目录。&&(2)调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初 始的URL地址变成重定向的目标URL;而调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。&&(3)HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一 个URL的 访问请求,这个过程好比有个绰号叫&浏览器&的人写信找张三借钱,张三回信说没有钱,让&浏览器&去找李四借,并将李四现在的通信地址告诉给了&浏览 器&。于是,&浏览器&又按张三提供通信地址给李四写信借钱,李四收到信后就把钱汇给了&浏览器&。可见,&浏览器&一共发出了两封信和收到了两次回复, &浏览器&也知道他借到的钱出自李四之手。RequestDispatcher.forward方 法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。这个过程好比绰号叫&浏 览器&的人写信找张三借钱,张三没有钱,于是张三找李四借了一些钱,甚至还可以加上自己的一些钱,然后再将这些钱汇给了&浏览器&。可见,&浏览器&只发 出了一封信和收到了一次回复,他只知道从张三那里借到了钱,并不知道有一部分钱出自李四之手。&&(4)RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同 一个访问请求和响应过程;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和 response对象,它们属于两个独立的访问请求和响应过程。对于同一个WEB应用程序的内部资源之间的跳转,特别是跳转之前要对请求进行一些前期预处 理,并要使用HttpServletRequest.setAttribute方法传递预处理结果,那就应该使用 RequestDispatcher.forward方法。不同WEB应用程序之间的重定向,特别是要重定向到另外一个WEB站点上的资源的情况,都应该 使用HttpServletResponse.sendRedirect方法。&&(5)无论是RequestDispatcher.forward方法,还是HttpServletResponse.sendRedirect方法,在调用它们之前,都不能有内容已经被实际输出到了客户端。如果缓冲区中已经有了一些内容,这些内容将被从缓冲区中清除。&
浅谈Java中JSON的序列化问题
在Java Web开发的过程中,时常会遇到与自己预期不一样的情况。有的时候静下心来自己去研究一番内在的原因还是很有趣的。这两天在写java web的时候,碰到了一个对象序列化的问题,问题大概是这样的:&public class AjaxJson {& & pri& & private S& & private O& & private Map&String, Object&&& & //getter and setter&& & public String getJsonStr() {& & & & JSONObject obj = new JSONObject();& & & & obj.put("success", this.isSuccess());& & & & obj.put("msg", this.getMsg());& & & & obj.put("obj", this.obj);& & & & obj.put("attributes", this.attributes);& & & & return obj.toJSONString();& & }}&&上面是一个接口类,我们需要把这个类的对象序列化成json返回。那么在springmvc中,一般是这样操作的。&@RequestMapping(params = "/get")@ResponseBodypublic AjaxJson del(HttpServletRequest request) {& & AjaxJson json = new AjaxJson();& & //省略业务操作& &}默认的话,返回ResponseBody,对象会直接序列化成json。这个时候,我们可以看一下返回的json。&{& & "success": "true",& & "Msg":"1",& & "obj":{& & & & ...& & },& & "attributes": null,& & "jsonStr":"{"success": "true","Msg":"1","obj":{...},"attributes": null,}"}显然,和我们预期想的不太一样,多了一个jsonstr字段。这个时候我在想,是不是springmvc的问题。结果仔细一想,springnvc之所以可以直接将对象序列化成json,其实是我们添加的配置文件在起作用,真正参与序列化工作的是jackson这个库。于是,我单独使用了jackson,结果返回的json字符串和之前是相同的,这下就可以肯定是,jackson这个库本身的设计问题了。&深入探讨&带着这份好奇,我把java中常用的json序列化的库都试了一下,看看是否都是这样。主流的库有jackson、fastjson和gson。&经过测试发现,jackson和阿里的fastjson返回的json字符串都带有一个jsonstr字段,唯独google的gson返回了我们预期的结果&&只序列化对象的field。&&于是我找了下这几个库的序列化原理:&jackson和fastjson&在序列化的时候,先利用反射找到对象类的所有get方法,接下来去get,然后小写化,作为json的每个key值,而get方法的返回值作为value。接下来再反射field,添加到json中。&gson&没有找到通俗的讲法,不过感觉应该就和getter方法无关吧。&所以,可以看大我们的AjaxJson类中存在这样一个getJsonStr,因此,jsonStr就作为key,序列化到json中了。&当然在jackson中,提供了相应的annotation,可以把这类方法忽略掉。在方法前加上@JsonIgnore 即可。&对此问题的理解&遇到问题的时候,千万不要忽略一些简单的地方,例如getter和setter方法。用getXXX的地方,可以用fetch等替代。&有时我们会在类中定义例如private int mAge的变量,而getter的方法是getAge()。显然我们希望在序列化的时候得到的key为age而非mAge,那么反射getter方法也就有它存在的意义了。&
浅谈Java中的ThreadLocal的多线程应用问题
什么是ThreadLocal?首先要说明的一点是ThreadLocal并不是一个Thread,而是Thread的局部变量。在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。下面我们就来看看ThreadLocal的初步内容:
多线程安全性解决方案&①进行同步控制synchronized &效率降低 & 并发变同步(串行)&②使用ThreadLocal 本地线程 &每个线程一个变量副本(各不相干)&两种线程安全方案的差异概括起来说,对于多线程资源共享的问题,同步机制采用了&以时间换空间&的方式,而 & & & &ThreadLocal采用了&以空间换时间&的方式。前者仅提供一份变量,让不同的线程排队 & & & &访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。&扩展问题我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中, 绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、 TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用 ThreadLocal进行处理,让它们也成为线程安全的状态,因为有状态的Bean就可以在多线程中共享了。&综上所述:两种解决方案,ThreadLocal占用内存较大,但是速度快,而线程同步相对内存占用小,但是速度慢。如果在内存比较充足的情况,对并发部分的执行效率要求很高的话,那么就是ThreadLocal登场的时候了。一般情况下用同步机制还是居多的。&
三分钟读懂Java与JavaScript的区别,让小白摘帽
Java跟JavaScript虽然在名称上有些许相似,但其实是两种完全不同的语言。Java是一种程序设计语言,JavaScript是客户端的脚本语言,把这两样东西放在一起比较在科学上其实并不严谨。但它们唯一相同的地方可能就是名字中都有Java。JavaScript为什么有Java这个词呢,是因为它里面借鉴了Java的对象的概念,所以才有了这个具有&迷惑性&的名称。鉴于有同学在学习的时候容易混肴,所以笔者还是将其加以区别:&一、javascript与Java是由不同的公司开发的不同产品。javascript是Netscape公司的产品,其目的是为了扩展Netscape Navigator功能,而开发的一种可以嵌入Web页面中的基于对象和事件驱动的解释性语言;而Java是SUN Microsystems公司推出的新一代面向对象的程序设计语言,特别适合于Internet应用程序开发。实际上,javascript最初的名字并不是javascript,而是LiveScript,名字中的&Java&是经过SUN Microsystems公司授权的。&二、javascript是基于对象的,它是一种脚本语言,是一种基于对象和事件驱动的编程语言,因而它本身提供了非常丰富的内部对象供设计人员使用。而Java是面向对象的,即Java是一种真正的面向对象的语言,即使是开发简单的程序也必须设计对象。 &&三、javascript与Java嵌入方式不一样。在HTML文档中,两种编程语言的标识不同,&四、javascript与Java在浏览器中所执行的方式不一样。javascript是一种解释性编程语言,其源代码在发往客户端执行之前不需经过编译,而是将文本格式的字符代码发送给客户,即javascript语句本身随Web页面一起下载下来,由浏览器解释执行。而Java的源代码在传递到客户端执行之前,必须经过编译,因而客户端上必须具有相应平台上的仿真器或解释器,它可以通过编译器或解释器实现独立于某个特定的平台编译代码。 &&五、javascript与Java代码格式不一样。javascript的代码是一种谋咀址格式,可以直接嵌入HTML文档中,并且可动态装载,编写HTML文档就像编辑文本文件一样方便,其独立文件的格式为*.js。Java是一种与HTML无关的格式,必须通过像HTML中引用外媒体那么进行装载,其代码以字节代码的形式保存在独立的文档中,其独立文件的格式为*.class。 &&六、javascript与Java所采取的变量是不一样的。&javascript中的变量声明采用弱类型,即变量在使用前不需作声明,而是解释器在运行时检查其数据类型。Java采用强类型变量检查,即所有变量在编译之前必须作声明。 &&七、javascript采用动态联编,即javascript的对象引用在运行时进行检查。Java采用静态联编,即Java的对象引用必须在编译时的进行,以使编译器能够实现强类型检查。 &&八、javascript不直接对文本和图形进行操作,它在Web页面中与HTML元素组合一起发挥作用,但它可以控制浏览器,让浏览器直接对文本和图形进行处理。而Java则可以直接对文本和图形进行操作。&
简单比较Spring和Mybatis,帮你更好地选择和使用
Spring和Mybatis是目前依然还比较流行的两大框架,比较一下两者的优缺点就会了解其中的原因,主要还是对开发者或所开发的项目提供什么便利的原因。下面简要介绍一下两者的优缺点,方便大家来比较。&Mybatis的优缺点:&优点:1.易于上手和掌握。2.SQL写在xml里,便于统一管理和优化。3.解除SQL与程序代码的耦合。4.提供映射标签,支持对象与数据库的orm字段关系映射5.提供对象关系映射标签,支持对象关系组建维护6.提供xml标签,支持编写动态sql。&缺点:1. sql工作量很大,尤其是字段多、关联表多时,更是如此。2. sql依赖于数据库,导致数据库移植性差。3.由于xml里标签id必须唯一,导致DAO中方法不支持方法重载。4.字段映射标签和对象关系映射标签仅仅是对映射关系的描述,具体实现仍然依赖于sql。(比如配置了一对多Collection标签,如果sql里没有join子表或查询子表的话,查询后返回的对象是不具备对象关系的,即Collection的对象为null)5. DAO层过于简单,对象组装的工作量较大。6.不支持级联更新、级联删除。7.编写动态sql时,不方便调试,尤其逻辑复杂时。8.提供的写动态sql的xml标签功能简单(连struts都比不上),编写动态sql仍然受限,且可读性低。9.使用不当,容易导致N+1的sql性能问题。10.使用不当,关联查询时容易产生分页bug。11.若不查询主键字段,容易造成查询出的对象有&覆盖&现象。12.参数的数据类型支持不完善。(如参数为Date类型时,容易报没有get、set方法,需在参数上加@param)13.多参数时,使用不方便,功能不够强大。(目前支持的方法有map、对象、注解@param以及默认采用012索引位的方式)14.缓存使用不当,容易产生脏数据。&总结:mybatis的优点其实也是mybatis的缺点,正因为mybatis使用简单,数据的可靠性、完整性的瓶颈便更多依赖于程序员对sql的使用水平上了。sql写在xml里,虽然方便了修改、优化和统一浏览,但可读性很低,调试也非常困难,也非常受限,无法像jdbc那样在代码里根据逻辑实现复杂动态sql拼接。mybatis简单看就是提供了字段映射和对象关系映射的jdbc,省去了数据赋值到对象的步骤而已,除此以外并无太多作为,不要把它想象成hibernate那样强大,简单小巧易用上手,方便浏览修改sql就是它最大的优点了。mybatis适用于小型且程序员能力较低的项目和人群使用,对于中大型项目来说我并不推荐使用,如果觉得hibernate效率低的话(实际上也是使用不当所致,hibernate是实际上是不适用于拥有高负载的工程项目),还不如直接用spring提供的jdbc简单框架(Template),同样支持对象映射。&&spring的优缺点:&优点:a.Spring能有效地组织你的中间层对象,不管你是否选择使用了EJB。如果你仅仅使用了Struts或其他为J2EE的 API特制的framework。Spring致力于解决剩下的问题。b.Spring能消除在许多工程中常见的对Singleton的过多使用。根据我的经验,这是一个很大的问题,它降低了系统的可测试性和面向对象的程度。c.通过一种在不同应用程序和项目间一致的方法来处理配置文件,Spring能消除各种各样自定义格式的属性文件的需要。曾经对某个类要寻找的是哪个魔法般的属性项或系统属性感到不解,为此不得不去读Javadoc甚至源编码?有了Spring,你仅仅需要看看类的JavaBean属性。Inversion of Control的使用(在下面讨论)帮助完成了这种简化。d.通过把对接口编程而不是对类编程的代价几乎减少到没有,Spring能够促进养成好的编程习惯。e.Spring被设计为让使用它创建的应用尽可能少的依赖于他的APIs。在Spring应用中的大多数业务对象没有依赖于Spring。f.使用Spring构建的应用程序易于单元测试。g.Spring能使EJB的使用成为一个实现选择,而不是应用架构的必然选择。你能选择用POJOs或local EJBs来实现业务接口,却不会影响调用代码。h.Spring帮助你解决许多问题而无需使用EJB。Spring能提供一种EJB的替换物,它们适用于许多web应用。例如,Spring能使用AOP提供声明性事务管理而不通过EJB容器,如果你仅仅需要与单个数据库打交道,甚至不需要一个JTA实现。i.Spring为数据存取提供了一个一致的框架,不论是使用的是JDBC还是O/R mapping产品(如Hibernate)。Spring确实使你能通过最简单可行的解决办法来解决你的问题。而这是有有很大价值的。缺点:使用人数不多、jsp中要写很多代码、控制器过于灵活,缺少一个公用控制器。&
站长在关注}

我要回帖

更多关于 劲舞团修改密码 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信