4.java学习总结文章

想来学习Java也有两个年头了,永远不敢说多么精通,但也想谈谈自己的感受,写给软件学院的同仁们,帮助大家在技术的道路上少一点弯路。说得伟大一点是希望大家为软件学院争气,其实最主要的还是大家自身的进步提升??

1. 关于动态加载机制??
学习Java比C++更容易理解OOP的思想,毕竟C++还混合了不少面向过程的成分。很多人都能背出来Java语言的特点,所谓的动态加载机制等等。当然概念往往是先记住而后消化的,可有多少人真正去体会过动态加载的机制,试图去寻找过其中的细节呢? 提供大家一个方法:
在命令行窗口运行Java程序的时候,加上这个很有用的参数:

java -verbose *.class

这样会清晰的打印出被加载的类文件,大部分是jdk自身运行需要的,最后几行会明显的看到自己用到的那几个类文件被加载进来的顺序。即使你声明了一个类对象,不实例化也不会加载,说明只有真正用到那个类的实例即对象的时候,才会执行加载。这样是不是大家稍微能明白一点动态加载了呢?^_^

2. 关于寻找class文件原理??
建议大家在入门的时候在命令行窗口编译和运行,不要借助JCreator或者Eclipse等IDE去帮助做那些事情。尝试自己这样做:
javac -classpath yourpath *.java
java -classpath yourpath *.class
也许很多人都能看懂,设置classpath的目的就是告诉编译器去哪里寻找你的class文件. 不过至少笔者今日才弄懂JVM去查询类的原理,编译器加载类要依靠classloader, 而classloader有3个级别,从高到低分别是BootClassLoader(名字可能不准确) , ExtClassLoader, AppClassLoader.

这3个加载器分别对应着编译器去寻找类文件的优先级别和不同的路径:BootClassLoader对应jre/classes路径,是编译器最优先寻找class的地方
ExtClassLoader对应jre/lib/ext路径,是编译器次优先寻找class的地方
AppClassLoader对应当前路径,所以也是编译器默认找class的地方

其实大家可以自己写个程序简单的测试,对任何class,例如A,
调用new A().getClass().getClassLoader().toString() 打印出来就可以看到,把class文件放在不同的路径下再次执行,就会看到区别。特别注意的是如果打印出来是null就表示到了最高级 BootClassLoader, 因为它是C++编写的,不存在Java对应的类加载器的名字。

寻找的顺序是一种向上迂回的思想,即如果本级别找不到,就只能去本级别之上的找,不会向下寻找。不过似乎从Jdk1.4到Jdk1.6这一特点又有改变,没有找到详细资料。所以就不举例子了。告诉大家设计这种体系的是Sun公司曾经的技术核心宫力先生,一个纯种华人哦!^_^

这样希望大家不至于迷惑为什么总报错找不到类文件,不管是自己写的还是导入的第三方的jar文件(J2ee中经常需要导入的)。

3. 关于jdk和jre??
大家肯定在安装JDK的时候会有选择是否安装单独的jre,一般都会一起安装,我也建议大家这样做。因为这样更能帮助大家弄清楚它们的区别:

Jre 是java runtime environment, 是java程序的运行环境。既然是运行,当然要包含jvm,也就是大家熟悉的虚拟机啦, 还有所有java类库的class文件,都在lib目录下打包成了jar。大家可以自己验证。至于在windows上的虚拟机是哪个文件呢? 学过MFC的都知道什么是dll文件吧,那么大家看看jre/bin/client里面是不是有一个jvm.dll呢?那就是虚拟机。

Jdk 是java development kit,是java的开发工具包,里面包含了各种类库和工具。当然也包括了另外一个Jre. 那么为什么要包括另外一个Jre呢?而且jdk/jre/bin同时有client和server两个文件夹下都包含一个jvm.dll。 说明是有两个虚拟机的。这一点不知道大家是否注意到了呢?

相信大家都知道jdk的bin下有各种java程序需要用到的命令,与jre的bin目录最明显的区别就是jdk下才有javac,这一点很好理解,因为 jre只是一个运行环境而已。与开发无关,正因为如此,具备开发功能的jdk自己的jre下才会同时有client性质的jvm和server性质的 jvm, 而仅仅作为运行环境的jre下只需要client性质的jvm.dll就够了。

记得在环境变量path中设置jdk/bin路径麽?这应该是大家学习Java的第一步吧, 老师会告诉大家不设置的话javac和java是用不了的。确实jdk/bin目录下包含了所有的命令。可是有没有人想过我们用的java命令并不是 jdk/bin目录下的而是jre/bin目录下的呢?不信可以做一个实验,大家可以把jdk/bin目录下的java.exe剪切到别的地方再运行 java程序,发现了什么?一切OK!

那么有人会问了?我明明没有设置jre/bin目录到环境变量中啊?

试想一下如果java为了提供给大多数人使用,他们是不需要jdk做开发的,只需要jre能让java程序跑起来就可以了,那么每个客户还需要手动去设置环境变量多麻烦啊?所以安装jre的时候安装程序自动帮你把jre的java.exe添加到了系统变量中,验证的方法很简单,大家看到了系统环境变量的 path最前面有“%SystemRoot%\system32;%SystemRoot%;”这样的配置,那么再去Windows/system32下面去看看吧,发现了什么?有一个java.exe。

如果强行能够把jdk/bin挪到system32变量前面,当然也可以迫使使用jdk/jre里面的java,不过除非有必要,我不建议大家这么做。使用单独的jre跑java程序也算是客户环境下的一种测试。

这下大家应该更清楚jdk和jre内部的一些联系和区别了吧?

PS: 其实还有满多感想可以总结的,一次写多了怕大家扔砖头砸死我,怪我太罗唆。大家应该更加踏实更加务实的去做一些研究并互相分享心得,大方向和太前沿的技术讨论是必要的但最好不要太多,毕竟自己基础都还没打好,什么都讲最新版本其实是进步的一大障碍!


Java 学习杂谈(二)
Java 学习杂谈(二)
鉴于上回写的一点感想大家不嫌弃,都鼓励小弟继续写下去,好不容易等到国庆黄金周,实习总算有一个休息的阶段,于是这就开始写第二篇了。希望这次写的仍然对志同道合的朋友们有所帮助。上回讲了Java动态加载机制、classLoader原理和关于jdk和jre三个问题。这次延续着讲一些具体的类库??

1. 关于集合框架类
相信学过Java的各位对这个名词并不陌生,对 java.util.*这个package肯定也不陌生。不知道大家查询API的时候怎么去审视或者分析其中的一个package,每个包最重要的两个部分就是interfaces和classes,接口代表了它能做什么,实现类则代表了它如何去做。关注实现类之前,我们应该先理解清楚它的来源接口,不管在j2se还是j2ee中,都应该是这样。那么我们先看这三个接口:List、Set、Map。
也许有些人不太熟悉这三个名字,但相信大部分人都熟悉ArrayList,LinkedList,TreeSet,HashSet,HashMap, Hashtable等实现类的名字。它们的区别也是满容易理解的,List放可以重复的对象集合,Set放不可重复的对象组合,而Map则放 这样的名值对, Key不可重复,Value可以。这里有几个容易混淆的问题:

到底Vector和ArrayList,Hashtable和HashMap有什么区别?
很多面试官喜欢问这个问题,其实更专业一点应该这样问:新集合框架和旧集合框架有哪些区别?新集合框架大家可以在这些包中找since jdk1.2的,之前的如vector和Hashtable都是旧的集合框架包括的类。那么区别是?
a. 新集合框架的命名更加科学合理。例如List下的ArrayList和LinkedList
b. 新集合框架下全部都是非线程安全的。建议去jdk里面包含的源代码里面自己去亲自看看vector和ArrayList的区别吧。当然如果是jdk5.0之后的会比较难看一点,因为又加入了泛型的语法,类似c++的template语法。

那么大家是否想过为什么要从旧集合框架默认全部加锁防止多线程访问更新到新集合框架全部取消锁,默认方式支持多线程?(当然需要的时候可以使用collections的静态方法加锁达到线程安全)
笔者的观点是任何技术的发展都未必是遵循它们的初衷的,很多重大改变是受到客观环境的影响的。大家知道Java的初衷是为什么而开发的麽?是为嵌入式程序开发的。记得上一篇讲到classLoader机制麽?那正是为了节约嵌入式开发环境下内存而设计的。而走到今天,Java成了人们心中为互联网诞生的语言。互联网意味着什么?多线程是必然的趋势。客观环境在变,Java技术也随着飞速发展,导致越来越脱离它的初衷。据说Sun公司其实主打的是J2se,结果又是由于客观环境影响,J2se几乎遗忘,留在大家谈论焦点的一直是j2ee。

技术的细节这里就不多说了,只有用了才能真正理解。解释这些正是为了帮助大家理解正在学的和将要学的任何技术。之后讲j2ee的时候还会再讨论。
多扯句题外话:几十年前的IT巨人是IBM,Mainframe市场无人可比。微软如何打败IBM?正是由于硬件飞速发展,对个人PC的需求这个客观环境,让微软通过OS称为了第二个巨人。下一个打败微软的呢?Google。如何做到的?如果微软并不和IBM争大型机,Google借着互联网飞速发展这个客观环境作为决定性因素,避开跟微软争OS,而是走搜索引擎这条路,称为第3个巨人。那么第4个巨人是谁呢?很多专家预言将在亚洲或者中国出现, Whatever,客观环境变化趋势才是决定大方向的关键。当然笔者也希望会出现在中国,^_^~~

2. 关于Java设计模式
身边的很多在看GOF的23种设计模式,似乎学习它无论在学校还是在职场,都成了一种流行风气。我不想列举解释这23种Design Pattern, 我写这些的初衷一直都是谈自己的经历和看法,希望能帮助大家理解。
首先我觉得设计模式只是对一类问题的一种通用解决办法,只要是面向对象的编程预言都可以用得上这23种。理解它们最好的方法就是亲自去写每一种,哪怕是一个简单的应用就足够了。如果代码实现也记不住的话,记忆它们对应的UML图会是一个比较好的办法,当然前提是必须了解UML。
同时最好能利用Java自身的类库帮助记忆,例如比较常用的观察者模式,在java.util.*有现成的Observer接口和Observable这个实现类,看看源代码相信就足够理解观察者模式了。再比如装饰器模式,大家只要写几个关于java.io.*的程序就可以完全理解什么是装饰器模式了。有很多人觉得刚入门的时候不该接触设计模式,比如图灵设计丛书系列很出名的那本《Java设计模式》,作者: Steven John Metsker,大部分例子老实说令现在的我也很迷惑。但我仍然不同意入门跟学习设计模式有任何冲突,只是我们需要知道每种模式的概念的和典型的应用,这样我们在第一次编写 FileOutputStream、BufferedReader、PrintWriter的时候就能感觉到原来设计模式离我们如此之近,而且并不是多么神秘的东西。

另外,在学习某些模式的同时,反而更能帮助我们理解java类库的某些特点。例如当你编写原型(Prototype)模式的时候,你必须了解的是 java.lang.Cloneable这个接口和所有类的基类Object的clone()这个方法。即深copy和浅copy的区别:
Object.clone()默认实现的是浅copy,也就是复制一份对象拷贝,但如果对象包含其他对象的引用,不会复制引用,所以原对象和拷贝共用那个引用的对象。
深copy当然就是包括对象的引用都一起复制啦。这样原对象和拷贝对象,都分别拥有一份引用对象。如果要实现深copy就必须首先实现 java.lang.Cloneable接口,然后重写clone()方法。因为在Object中的clone()方法是protected签名的,而 Cloneable接口的作用就是把protected放大到public,这样clone()才能被重写。

那么又有个问题了?如果引用的对象又引用了其他对象呢?这样一直判断并复制下去,是不是显得很麻烦?曾经有位前辈告诉我的方法是重写clone方法的时候直接把原对象序列化到磁盘上再反序列化回来,这样不用判断就可以得到一个深copy的结果。如果大家不了解序列化的作法建议看一看 ObjectOutputStream和ObjectInputStream

归根结底,模式只是思想上的东西,把它当成前人总结的经验其实一点都不为过。鼓励大家动手自己去写,例如代理模式,可以简单的写一个Child类, Adult类。Child要买任何东西由Adult来代理实现。简单来说就是Adult里的buy()内部实际调用的是Child的buy(),可是暴露在main函数的却是Adult.buy()。这样一个简单的程序就足够理解代理模式的基本含义了。

Java 杂谈(三)
Java 杂谈(三)
这已经笔者写的第三篇Java杂记了,庆幸前两篇一直得到论坛朋友们的支持鼓励,还望大家继续指正不足之处。笔者也一直渴望通过这样方式清醒的自审,来寻找自己技术上的不足之处,希望和共同爱好Java的同仁们一起提高。
前两次分别讲述了关于jvm、jdk、jre、collection、classLoader和一些Design Pattern的自我理解。这次仍然不准备开始过渡到j2ee中,因为觉得还有一些琐碎的j2se的问题没有总结完毕。

1. 关于Object类理解
大家都知道Object是所有Java类的基类, 意味着所有的Java类都会继承了Object的11个方法。建议大家去看看Object的 11个成员函数的源代码,就会知道默认的实现方式。比如equals方法,默认实现就是用"=="来比较,即直接比较内存地址,返回true 或者 false。而toString()方法,返回的串组成方式是??
"getClass().getName() + "@" + Integer.toHexString(hashCode())"
其实不用我过多的解释,大家都能看懂这个串的组成。接下来再看看hashCode():
public native int hashCode();

由于是native方法,跟OS的处理方式相关,源代码里仅仅有一个声明罢了。我们有兴趣的话完全可以去深究它的hashCode到底是由OS怎么样产生的呢?但笔者建议最重要的还是先记住使用它的几条原则吧!首先如果equals()方法相同的对象具有相通的hashCode,但equals ()对象不相通的时候并不保证hashCode()方法返回不同的整数。而且下一次运行同一个程序,同一个对象未必还是当初的那个hashCode() 哦。
其余的方法呢?nofigy()、notifyAll()、clone()、wait()都是native方法的,说明依赖于操作系统的实现。最后一个有趣的方法是finalize(),类似C++的析构函数,签名是protected,证明只有继承扩展了才能使用,方法体是空的,默示什么也不做。它的作用据笔者的了解仅仅是通知JVM此对象不再使用,随时可以被销毁,而实际的销毁权还是在于虚拟机手上。那么它真的什么也不做麽?未必,实际上如果是线程对象它会导致在一定范围内该线程的优先级别提高,导致更快的被销毁来节约内存提高性能。其实从常理来说,我们也可以大概这样猜测出jvm做法的目的。

2. 关于重载hashCode()与Collection框架的关系
笔者曾经听一位搞Java培训多年的前辈说在他看来hashCode方法没有任何意义,仅仅是为了配合证明具有同样的hashCode会导致equals 方法相等而存在的。连有的前辈都犯这样的错误,其实说明它还是满容易被忽略的。那么hashCode()方法到底做什么用?

学过数据结构的课程大家都会知道有一种结构叫hash table,目的是通过给每个对象分配一个唯一的索引来提高查询的效率。那么Java也不会肆意扭曲改变这个概念,所以hashCode唯一的作用就是为支持数据结构中的哈希表结构而存在的,换句话说,也就是只有用到集合框架的 Hashtable、HashMap、HashSet的时候,才需要重载hashCode()方法,
这样才能使得我们能人为的去控制在哈希结构中索引是否相等。笔者举一个例子:
曾经为了写一个求解类程序,需要随机列出1,2,3,4组成的不同排列组合,所以笔者写了一个数组类用int[]来存组合结果,然后把随机产生的组合加入一个HashSet中,就是想利用HashSet不包括重复元素的特点。可是HashSet怎么判断是不是重复的元素呢?当然是通过 hashCode()返回的结果是否相等来判断啦,可做一下这个实验:
int[] A = {1,2,3,4};
int[] B = {1,2,3,4};
System.out.println(A.hashCode());
System.out.println(B.hashCode());

这明明是同一种组合,却是不同的hashCode,加入Set的时候会被当成不同的对象。这个时候我们就需要自己来重写hashCode()方法了,如何写呢?其实也是基于原始的hashCode(),毕竟那是操作系统的实现, 找到相通对象唯一的标识,实现方式很多,笔者的实现方式是:
首先重写了toString()方法:
return A[0]“+” A[1]“+” A[2]“+” A[3]; //显示上比较直观
然后利用toString()来计算hashCode():
return this.toString().hashCode();
这样上述A和B返回的就都是”1234”,在测试toString().hashCode(),由于String在内存中的副本是一样的,”1234”.hashCode()返回的一定是相同的结果。

说到这,相信大家能理解得比我更好,今后千万不要再误解hashCode()方法的作用。

3. 关于Class类的成员函数与Java反射机制
很早刚接触Java就听很多老师说过Java的动态运行时机制、反射机制等。确实它们都是Java的显著特点,运行时加载笔者在第一篇介绍过了,现在想讲讲反射机制。在Java中,主要是通过java.lang包中的Class类和Method类来实现内存反射机制的。
熟悉C++的人一定知道下面这样在C++中是做不到的: 运行时以字符串参数传递一个类名,就可以得到这个类的所有信息,包括它所有的方法,和方法的详细信息。还可以实例化一个对象,并通过查到的方法名来调用该对象的任何方法。这是因为Java的类在内存中除了C++中也有的静态动态数据区之外,还包括一份对类自身的描述,也正是通过这描述中的信息,才能帮助我们才运行时读取里面的内容,得到需要加载目标类的所有信息,从而实现反射机制。大家有没有想过当我们需要得到一个JavaBean的实例的时候,怎么知道它有哪些属性呢?再明显简单不过的例子就是自己写一个JavaBean的解析器:

a. 通过Class.forName(“Bean的类名”)得到Class对象,例如叫ABeanClass
b. 通过ABeanClass的getMethods()方法,得到Method[]对象
c. 按照规范所有get方法名后的单词就代表着该Bean的一个属性
d. 当已经知道一个方法名,可以调用newInstance()得到一个实例,然后通过invoke()方法将方法的名字和方法需要用的参数传递进去,就可以动态调用此方法。

当然还有更复杂的应用,这里就不赘述,大家可以参考Class类和Method类的方法。

4. 坦言Synchronize的本质
Synchronize大家都知道是同步、加锁的意思,其实它的本质远没有大家想得那么复杂。声明Synchronize的方法被调用的时候,锁其实是加载对象上,当然如果是静态类则是加在类上的锁,调用结束锁被解除。它的实现原理很简单,仅仅是不让第二把锁再次被加在同一个对象或类上,仅此而已。一个简单的例子足以说明问题:
class A{
synchronized void f(){}
void g(){}
}

当A的一个对象a被第一个线程调用其f()方法的时候,第二个线程不能调用a的synchronized方法例如f(),因为那是在试图在对象上加第二把锁。但调用g()却是可以的,因为并没有在同一对象上加两把锁的行为产生。
这样大家能理解了麽?明白它的原理能更好的帮助大家设计同步机制,不要滥用加锁。

PS:下篇笔者计划开始对J2ee接触到的各个方面来进行总结,谈谈自己的经验和想法。希望大家还能一如既往的支持笔者写下去,指正不足之处。

Java杂谈(四)

不知不觉已经写到第四篇了,论坛里面不断的有朋友鼓励我写下去。坚持自己的作风,把一切迷惑不容易理清楚的知识讲出来,讲到大家都能听懂,那么自己就真的懂了。最近在公司实习的时候Trainer跟我讲了很多经典事迹,对还未毕业的我来说是笔不小的财富,我自己的信念是:人在逆境中成长的速度要远远快过顺境中,这样来看一切都能欣然接受了。
好了,闲话不说了,第三篇讲的是反射机制集合框架之类的,这次打算讲讲自己对反序列化和多线程的理解。希望能对大家学习Java起到帮助??

1.关于序列化和反序列化
应该大家都大概知道Java中序列化和反序列化的意思,序列化就是把一个Java对象转换成二进制进行磁盘上传输或者网络流的传输,反序列化的意思就是把这个接受到的二进制流重新组装成原来的对象逆过程。它们在Java中分别是通过ObjectInputStream和 ObjectInputStream这两个类来实现的(以下分别用ois和oos来简称)。

oos的writeObject()方法用来执行序列化的过程,ois的readObject()用来执行反序列化的过程,在传输二进制流之前,需要讲这两个高层流对象连接到同一个Channel上,这个Channel可以是磁盘文件,也可以是socket底层流。所以无论用哪种方式,底层流对象都是以构造函数参数的形式传递进oos和ois这两个高层流,连接完毕了才可以进行二进制数据传输的。例子:
可以是文件流通道
file = new File(“C:/data.dat”);
oos = new ObjectOutputStream(new FileOutputStream(file));
ois = new ObjectInputStream(new FileInputStream(file));

或者网络流通道
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());

不知道大家是否注意到oos总是在ois之前定义,这里不希望大家误解这个顺序是固定的么?回答是否定的,那么有顺序要求么?回答是肯定的。原则是什么呢?
原则是互相对接的输入/输出流之间必须是output流先初始化然后再input流初始化,否则就会抛异常。大家肯定会问为什么?只要稍微看一看这两个类的源代码文件就大概知道了,output流的任务很简单,只要把对象转换成二进制往通道中写就可以了,但input流需要做很多准备工作来接受并最终重组这个Object,所以ObjectInputStream的构造函数中就需要用到output初始化发送过来的header信息,这个方法叫做 readStreamHeader(),它将会去读两个Short值用于决定用多大的缓存来存放通道发送过来的二进制流,这个缓存的size因jre的版本不同是不一样的。所以output如果不先初始化,input的构造函数首先就无法正确运行。

对于上面两个例子,第一个顺序是严格的,第二个因为oos和ois连接的已经不是对方了,而是socket另外一端的流,需要严格按照另外一方对接的output流先于对接的input流打开才能顺利运行。

这个writeObject和readObject本身就是线程安全的,传输过程中是不允许被并发访问的。所以对象能一个一个接连不断的传过来,有很多人在运行的时候会碰到EOFException, 然后百思不得其解,去各种论坛问解决方案。其实笔者这里想说,这个异常不是必须声明的,也就是说它虽然是异常,但其实是正常运行结束的标志。EOF表示读到了文件尾,发送结束自然连接也就断开了。如果这影响到了你程序的正确性的话,请各位静下心来看看自己程序的业务逻辑,而不要把注意力狭隘的聚集在发送和接受的方法上。因为笔者也被这样的bug困扰了1整天,被很多论坛的帖子误解了很多次最后得出的教训。如果在while循环中去readObject,本质上是没有问题的,有对象数据来就会读,没有就自动阻塞。那么抛出EOFException一定是因为连接断了还在继续read,什么原因导致连接断了呢?一定是业务逻辑哪里存在错误,比如NullPoint、 ClassCaseException、ArrayOutofBound,即使程序较大也没关系,最多只要单步调适一次就能很快发现bug并且解决它。

难怪一位程序大师说过:解决问题90%靠经验,5%靠技术,剩下5%靠运气!真是金玉良言,笔者大概查阅过不下30篇讨论在while循环中使用 readObject抛出EOFExceptionde 的帖子,大家都盲目的去关注解释这个名词、反序列化的行为或反对这样写而没有一个人认为EOF是正确的行为,它其实很老实的在做它的事情。为什么大家都忽略了真正出错误的地方呢?两个字,经验!

2.关于Java的多线程编程
关于Java的线程,初学或者接触不深的大概也能知道一些基本概念,同时又会很迷惑线程到底是怎么回事?如果有人认为自己已经懂了不妨来回答下面的问题:
a. A对象实现Runnable接口,A.start()运行后所谓的线程对象是谁?是A么?
b. 线程的wait()、notify()方法到底是做什么时候用的,什么时候用?
c. 为什么线程的suspend方法会被标注过时,不推荐再使用,线程还能挂起么?
d. 为了同步我们会对线程方法声明Synchronized来加锁在对象上,那么如果父类的f()方法加了Synchronized,子类重写f()方法必须也加Synchronized么?如果子类的f()方法重写时声明Synchronized并调用super.f(),那么子类对象上到底有几把锁呢?会因为竞争产生死锁么?

呵呵,各位能回答上来几道呢?如果这些都能答上来,说明对线程的概念还是满清晰的,虽说还远远不能算精通。笔者这里一一做回答,碍于篇幅的原因,笔者尽量说得简介一点,如果大家有疑惑的欢迎一起讨论。

首先第一点,线程跟对象完全是两回事,虽然我们也常说线程对象。但当你用run()和start()来启动一个线程之后,线程其实跟这个继承了 Thread或实现了Runnable的对象已经没有关系了,对象只能算内存中可用资源而对象的方法只能算内存正文区可以执行的代码段而已。既然是资源和代码段,另外一个线程当然也可以去访问,main函数执行就至少会启动两个线程,一个我们称之为主线程,还一个是垃圾收集器的线程,主线程结束就意味着程序结束,可垃圾收集器线程很可能正在工作。

第二点,wait()和sleep()类似,都是让线程处于阻塞状态暂停一段时间,不同之处在于wait会释放当前线程占有的所有的锁,而 sleep不会。我们知道获得锁的唯一方法是进入了Synchronized保护代码段,所以大家会发现只有Synchronized方法中才会出现 wait,直接写会给警告没有获得当前对象的锁。所以notify跟wait配合使用,notify会重新把锁还给阻塞的线程重而使其继续执行,当有多个对象wait了,notify不能确定唤醒哪一个,必经锁只有一把,所以一般用notifyAll()来让它们自己根据优先级等竞争那唯一的一把锁,竞争到的线程执行,其他线程只要继续wait。

从前Java允许在一个线程之外把线程挂起,即调用suspend方法,这样的操作是极不安全的。根据面向对象的思想每个对象必须对自己的行为负责,而对自己的权力进行封装。如果任何外步对象都能使线程被挂起而阻塞的话,程序往往会出现混乱导致崩溃,所以这样的方法自然是被毙掉了啦。

最后一个问题比较有意思,首先回答的是子类重写f()方法可以加Synchronized也可以不加,如果加了而且还内部调用了super.f ()的话理论上是应该对同一对象加两把锁的,因为每次调用Synchronized方法都要加一把,调用子类的f首先就加了一把,进入方法内部调用父类的 f又要加一把,加两把不是互斥的么?那么调父类f加锁不就必须永远等待已经加的锁释放而造成死锁么?实际上是不会的,这个机制叫重进入,当父类的f方法试图在本对象上再加一把锁的时候,因为当前线程拥有这个对象的锁,也可以理解为开启它的钥匙,所以同一个线程在同一对象上还没释放之前加第二次锁是不会出问题的,这个锁其实根本就没有加,它有了钥匙,不管加几把还是可以进入锁保护的代码段,畅通无阻,所以叫重进入,我们可以简单认为第二把锁没有加上去。

总而言之,Synchronized的本质是不让其他线程在同一对象上再加一把锁。
Java杂谈(五)
Java杂谈(五)


本来预计J2se只讲了第四篇就收尾了,可是版主厚爱把帖子置顶长期让大家浏览让小弟倍感责任重大,务必追求最到更好,所以关于J2se一些没有提到的部分,决定再写几篇把常用的部分经验全部写出来供大家讨论切磋。这一篇准备讲一讲Xml解析包和Java Swing,然后下一篇再讲java.security包关于Java沙箱安全机制和RMI机制,再进入J2ee的部分,暂时就做这样的计划了。如果由于实习繁忙更新稍微慢了一些,希望各位见谅!

1. Java关于XML的解析
相信大家对XML都不陌生,含义是可扩展标记语言。本身它也就是一个数据的载体以树状表现形式出现。后来慢慢的数据变成了信息,区别是信息可以包括可变的状态从而针对程序硬编码的做法变革为针对统一接口硬编码而可变状态作为信息进入了XML中存储。这样改变状态实现扩展的唯一工作是在XML中添加一段文本信息就可以了,代码不需要改动也不需要重新编译。这个灵活性是XML诞生时候谁也没想到的。

当然,如果接口要能提取XML中配置的信息就需要程序能解析规范的XML文件,Java中当然要提高包对这个行为进行有利支持。笔者打算讲到的两个包是 org.w3c.dom和javax.xml.parsers和。(大家可以浏览一下这些包中间的接口和类定义)

Javax.xml.parsers包很简单,没有接口,两个工厂配两个解析器。显然解析XML是有两种方式的:DOM解析和SAX解析。本质上并没有谁好谁不好,只是实现的思想不一样罢了。给一个XML文件的例子:



A Cat



所谓DOM解析的思路是把整个树状图存入内存中,需要那个节点只需要在树上搜索就可以读到节点的属性,内容等,这样的好处是所有节点皆在内存可以反复搜索重复使用,缺点是需要消耗相应的内存空间。

自然SAX解析的思路就是为了克服DOM的缺点,以事件触发为基本思路,顺序的搜索下来,碰到了Element之前触发什么事件,碰到之后做什么动作。由于需要自己来写触发事件的处理方案,所以需要借助另外一个自定义的Handler,处于org.xml.sax.helpers包中。它的优点当然是不用整个包都读入内存,缺点也是只能顺序搜索,走完一遍就得重来。

大家很容易就能猜到,接触到的J2ee框架用的是哪一种,显然是DOM。因为类似Struts,Hibernate框架配置文件毕竟是很小的一部分配置信息,而且需要频繁搜索来读取,当然会采用DOM方式(其实SAX内部也是用DOM采用的结构来存储节点信息的)。现在无论用什么框架,还真难发现使用 SAX来解析XML的技术了,如果哪位仁兄知道,请让笔者也学习学习。

既然解析方式有了,那么就需要有解析的存储位置。不知道大家是否发现org.w3c.dom这个包是没有实现类全部都是接口的。这里笔者想说一下Java 如何对XML解析是Jdk应该考虑的事,是它的责任。而w3c组织是维护定义XML标准的组织,所以一个XML结构是怎么样的由w3c说了算,它不关心 Java如何去实现,于是乎规定了所有XML存储的结构应该遵循的规则,这就是org.w3c.dom里全部的接口目的所在。在笔者看来,简单理解接口的概念就是实现者必须遵守的原则。

整个XML对应的结构叫Document、子元素对应的叫做Element、还有节点相关的Node、NodeList、Text、Entity、 CharacterData、CDATASection等接口,它们都可以在XML的语法中间找到相对应的含义。由于这里不是讲解XML基本语法,就不多介绍了。如果大家感兴趣,笔者也可以专门写一篇关于XML的语法规则帖与大家分享一下。

2. Java Swing
Swing是一个让人又爱又恨的东西,可爱之处在于上手很容易,较AWT比起来Swing提供的界面功能更加强大,可恨之处在于编复杂的界面工作量实在是巨大。笔者写过超过3000行的Swing界面,感觉用户体验还不是那么优秀。最近又写过超过6000行的,由于功能模块多了,整体效果还只是一般般。体会最深的就一个字:累! 所以大家现在都陆续不怎么用Swing在真正开发的项目上了,太多界面技术可以取代它了。笔者去写也是迫于无奈组里面大家都没写过,我不入地域谁入?

尽管Swing慢慢的在被人忽略,特别是随着B/S慢慢的在淹没C/S,笔者倒是很愿意站出来为Swing正身。每一项技术的掌握绝不是为了流行时尚跟风。真正喜欢Java的朋友们还是应该好好体会一下Swing,相信在校的很多学生也很多在学习它。很可能从Jdk 1.1、1.2走过来的很多大学老师可能是最不熟悉它的。
Swing提供了一组轻组件统称为JComponent,它们与AWT组件的最大区别是JComponent全部都是Container,而 Container的特点是里面可以装载别的组件。在Swing组件中无论是JButton、JLabel、JPanel、JList等都可以再装入任何其他组件。好处是程序员可以对Swing组件实现“再开发”,针对特定需求构建自己的按钮、标签、画板、列表之类的特定组件。

有轻自然就有重,那么轻组件和重组件区别是?重组件表现出来的形态因操作系统不同而异,轻组件是Swing自己提供GUI,在跨平台的时候最大程度的保持一致。
那么在编程的时候要注意一些什么呢?笔者谈谈自己的几点经验:

a. 明确一个概念,只有Frame组件才可以单独显示的,也许有人会说JOptionPane里面的静态方法就实现了单独窗口出现,但追寻源代码会发现其实现实出来的Dialog也需要依托一个Frame窗体,如果没有指定就会默认产生一个然后装载这个Dialog显示出来。

b. JFrame是由这么几部分组成:
最底下一层JRootPane,上面是glassPane (一个JPanel)和layeredPane (一个JLayeredPane),而layeredPane又由contentPane(一个JPanel)和menuBar构成。我们的组件都是加在 contentPane上,而背景图片只能加在layeredPane上面。 至于glassPane是一个透明的覆盖了contentPane的一层,在特定效果中将被利用到来记录鼠标坐标或掩饰组件。

c. 为了增强用户体验,我们会在一些按钮上添加快捷键,但Swing里面通常只能识别键盘的Alt键,要加入其他的快捷键,必须自己实现一个ActionListener。

d. 通过setLayout(null)可以使得所有组件以setBounds()的四个参数来精确定位各自的大小、位置,但不推荐使用,因为好的编程风格不应该在Swing代码中硬编码具体数字,所有的数字应该以常数的形式统一存在一个静态无实例资源类文件中。这个静态无实例类统一负责Swing界面的风格,包括字体和颜色都应该包括进去。

e. 好的界面设计有一条Golden Rule: 用户不用任何手册通过少数尝试就能学会使用软件。所以尽量把按钮以菜单的形式(不管是右键菜单还是窗体自带顶部菜单)呈现给顾客,除非是频繁点击的按钮才有必要直接呈现在界面中。

其实Swing的功能是相当强大的,只是现在应用不广泛,专门去研究大概是要花不少时间的。笔者在各网站论坛浏览关于Swing的技巧文章还是比较可信的,自己所学非常有限,各人体会对Swing各个组件的掌握就是一个实践积累的过程。笔者只用到过以上这些,所以只能谈谈部分想法,还望大家见谅!
Java杂谈(六)
Java杂谈(六)


这篇是笔者打算写的J2se部分的最后一篇了,这篇结束之后,再写J2ee部分,不知道是否还合适写在这个版块?大家可以给点意见,谢谢大家对小弟这么鼓励一路写完前六篇Java杂谈的J2se部分。最后这篇打算谈一谈Java中的RMI机制和JVM沙箱安全框架。

1. Java中的RMI机制
RMI的全称是远程方法调用,相信不少朋友都听说过,基本的思路可以用一个经典比方来解释:A计算机想要计算一个两个数的加法,但A自己做不了,于是叫另外一台计算机B帮忙,B有计算加法的功能,A调用它就像调用这个功能是自己的一样方便。这个就叫做远程方法调用了。

远程方法调用是EJB实现的支柱,建立分布式应用的核心思想。这个很好理解,再拿上面的计算加法例子,A只知道去call计算机B的方法,自己并没有B的那些功能,所以A计算机端就无法看到B执行这段功能的过程和代码,因为看都看不到,所以既没有机会窃取也没有机会去改动方法代码。EJB正式基于这样的思想来完成它的任务的。当简单的加法变成复杂的数据库操作和电子商务交易应用的时候,这样的安全性和分布式应用的便利性就表现出来优势了。

好了,回到细节上,要如何实现远程方法调用呢?我希望大家学习任何技术的时候可以试着依赖自己的下意识判断,只要你的想法是合理健壮的,那么很可能实际上它就是这么做的,毕竟真理都蕴藏在平凡的生活细节中。这样只要带着一些薄弱的Java基础来思考RMI,其实也可以想出个大概来。

a) 需要有一个服务器角色,它拥有真正的功能代码方法。例如B,它提供加法服务
b) 如果想远程使用B的功能,需要知道B的IP地址
c) 如果想远程使用B的功能,还需要知道B中那个特定服务的名字

我们很自然可以想到这些,虽然不完善,但已经很接近正确的做法了。实际上RMI要得以实现还得意于Java一个很重要的特性,就是Java反射机制。我们需要知道服务的名字,但又必须隐藏实现的代码,如何去做呢?答案就是:接口!
举个例子:
public interface Person(){
public void sayHello();
}

Public class PersonImplA implements Person{
public PersonImplA(){}

public void sayHello(){ System.out.println(“Hello!”);}
}

Public class PersonImplB implements Person{
public PersonImplB(){}

public void sayHello(){ System.out.println(“Nice to meet you!”);}
}

客户端:Person p = Naming.lookup(“PersonService”);
p.sayHello();

就这几段代码就包含了几乎所有的实现技术,大家相信么?客户端请求一个say hello服务,服务器运行时接到这个请求,利用Java反射机制的Class.newInstance()返回一个对象,但客户端不知道服务器返回的是 ImplA还是ImplB,它接受用的参数签名是Person,它知道实现了Person接口的对象一定有sayHello()方法,这就意味着客户端并不知道服务器真正如何去实现的,但它通过了解Person接口明确了它要用的服务方法名字叫做sayHello()。

如此类推,服务器只需要暴露自己的接口出来供客户端,所有客户端就可以自己选择需要的服务。这就像餐馆只要拿出自己的菜单出来让客户选择,就可以在后台厨房一道道的按需做出来,它怎么做的通常是不让客户知道的!(祖传菜谱吧,^_^)

最后一点是我调用lookup,查找一个叫PersonService名字的对象,服务器只要看到这个名字,在自己的目录(相当于电话簿)中找到对应的对象名字提供服务就可以了,这个目录就叫做JNDI (Java命名与目录接口),相信大家也听过的。

有兴趣的朋友不妨自己做个RMI的应用,很多前辈的博客中有简单的例子。提示一下利用Jdk的bin目录中rmi.exe和 rmiregistry.exe两个命令就可以自己建起一个服务器,提供远程服务。因为例子很容易找,我就不自己举例子了!

2. JVM沙箱&框架
RMI罗唆得太多了,实在是尽力想把它说清楚,希望对大家有帮助。最后的最后,给大家简单讲一下JVM框架,我们叫做Java沙箱。Java沙箱的基本组件如下:
a) 类装载器结构
b) class文件检验器
c) 内置于Java虚拟机的安全特性
d) 安全管理器及Java API

其中类装载器在3个方面对Java沙箱起作用:
a. 它防止恶意代码去干涉善意的代码
b. 它守护了被信任的类库边界
c. 它将代码归入保护域,确定了代码可以进行哪些操作

虚拟机为不同的类加载器载入的类提供不同的命名空间,命名空间由一系列唯一的名称组成,每一个被装载的类将有一个名字,这个命名空间是由Java虚拟机为每一个类装载器维护的,它们互相之间甚至不可见。

我们常说的包(package)是在Java虚拟机第2版的规范第一次出现,正确定义是由同一个类装载器装载的、属于同一个包、多个类型的集合。类装载器采用的机制是双亲委派模式。具体的加载器框架我在Java杂谈(一)中已经解释过了,当时说最外层的加载器是AppClassLoader,其实算上网络层的话AppClassLoader也可以作为parent,还有更外层的加载器URLClassLoader。为了防止恶意攻击由URL加载进来的类文件我们当然需要分不同的访问命名空间,并且制定最安全的加载次序,简单来说就是两点:

a. 从最内层JVM自带类加载器开始加载,外层恶意同名类得不到先加载而无法使用
b. 由于严格通过包来区分了访问域,外层恶意的类通过内置代码也无法获得权限访问到内层类,破坏代码就自然无法生效。

附:关于Java的平台无关性,有一个例子可以很明显的说明这个特性:
一般来说,C或C++中的int占位宽度是根据目标平台的字长来决定的,这就意味着针对不同的平台编译同一个C++程序在运行时会有不同的行为。然而对于 Java中的int都是32位的二进制补码标识的有符号整数,而float都是遵守IEEE 754浮点标准的32位浮点数。

PS: 这个小弟最近也没时间继续研究下去了,只是想抛砖引玉的提供给大家一个初步认识JVM的印象。有机会了解一下JVM的内部结构对今后做Java开发是很有好处的。
Java杂谈(七)--接口& 组件、容器
Java杂谈(七)--接口& 组件、容器

终于又静下来继续写这个主题的续篇,前六篇主要讲了一些J2se方面的经验和感受, 眼下Java应用范围已经被J2ee占据了相当大的一块领域,有些人甚至声称Java被J2ee所取代了。不知道大家如何来理解所谓的J2ee (Java2 Enterprise Edition),也就是Java企业级应用?

笔者的观点是,技术的发展是顺应世界变化的趋势的,从C/S过渡到B/S模式,从客户端的角度考虑企业级应用或者说电子商务领域不在关心客户端维护问题,这个任务已经交给了任何一台PC都会有的浏览器去维护;从服务器端的角度考虑,以往C/S中的TCP/IP协议实现载体ServerSocket被Web Server Container所取代,例如大家都很熟悉的Tomcat、JBoss、WebLogic等等。总之一切的转变都是为了使得Java技术能更好的为人类生产生活所服务。

有人会问,直接去学J2ee跳过J2se行否?笔者是肯定不赞成的,实际上确实有人走这条路,但笔者自身体会是正是由于J2se的基础很牢固,才会导致在J2ee学习的道路上顺风顺水,知识点上不会有什么迷惑的地方。举个简单的例子吧:

笔者曾经跟大学同学讨论下面这两种写法的区别:
ArrayList list = new ArrayList(); //笔者不说反对,但至少不赞成
List list = new ArrayList(); //笔者支持
曾经笔者跟同学争论了几个小时,他非说第一种写法更科学,第二种完全没有必要。我无法完全说服他,但笔者认为良好的习惯和意识是任何时候都应该针对接口编程,以达到解耦合和可扩展性的目的。下面就以接口开始进入J2ee的世界吧:

1. J2ee与接口

每一个版本的J2ee都对应着一个确定版本的JDK,J2ee1.4对应Jdk1.4,现在比较新的是JDK5.0,自然也会有J2EE 5.0。其实笔者一直在用的是J2EE1.4,不过没什么关系,大家可以下任何一个版本的J2ee api来稍微浏览一下。笔者想先声明一个概念,J2ee也是源自Java,所以底层的操作依然调用到很多J2se的库,所以才建议大家先牢牢掌握J2se 的主流技术。

J2ee api有一个特点,大家比较熟悉的几个包java.jms、javax.servlet.http、javax.ejb等都以interface居多,实现类较少。其实大家真正在用的时候百分之六十以上都在反复的查着javax.servlet.http这个包下面几个实现类的api函数,其他的包很少问津。笔者建议在学习一种技术之前,对整体的框架有一个了解是很有必要的,J2ee旨在通过interface的声明来规范实现的行为,任何第三方的厂商想要提供自己品牌的实现前提也是遵循这些接口定义的规则。如果在从前J2se学习的道路上对接口的理解很好的话,这里的体会将是非常深刻的,举个简单的例子:

public interface Mp3{
public void play();
public void record();
public void stop();
}

如果我定义这个简单的接口,发布出去,规定任何第三方的公司想推出自己的名字为Mp3的产品都必须实现这个接口,也就是至少提供接口中方法的具体实现。这个意义已经远远不止是面向对象的多态了,只有厂商遵循J2ee的接口定义,世界上的J2ee程序员才能针对统一的接口进行程序设计,最终不用改变代码只是因为使用了不同厂商的实现类而有不同的特性罢了,本质上说,无论哪一种厂商实现都完成了职责范围内的工作。这个就是笔者想一直强调的,针对接口编程的思想。

接口到底有什么好处呢?我们这样设想,现在有AppleMp3、SonyMp3、SamsungMp3都实现了这个Mp3的接口,于是都有了play、 record、stop这三个功能。我们将Mp3产品座位一个组件的时候就不需要知道它的具体实现,只要看到接口定义知道这个对象有3个功能就可以使用了。那么类似下面这样的业务就完全可以在任何时间从3个品牌扩展到任意个品牌,开个玩笑的说,项目经理高高在上的写完10个接口里的方法声明,然后就丢给手下的程序员去写里面的细节,由于接口已经统一(即每个方法传入和传出的格式已经统一),经理只需关注全局的业务就可以天天端杯咖啡走来走去了,^_^:
public Mp3 create();
public void copy(Mp3 mp3);
public Mp3 getMp3();

最后用一个简单的例子说明接口:一个5号电池的手电筒,可以装入任何牌子的5号电池,只要它符合5号电池的规范,装入之后任何看不到是什么牌子,只能感受到手电筒在完成它的功能。那么生产手电筒的厂商和生产5号电池的厂商就可以完全解除依赖关系,可以各自自由开发自己的产品,因为它们都遵守5号电池应有的形状、正负极位置等约定。这下大家能对接口多一点体会了么?

2. 组件和容器
针对接口是笔者特意强调的J2ee学习之路必备的思想,另外一个就是比较常规的组件和容器的概念了。很多教材和专业网站都说J2EE的核心是一组规范与指南,强调J2ee的核心概念就是组件+容器,这确实是无可厚非的。随着越来越多的J2ee框架出现,相应的每种框架都一般有与之对应的容器。

容器,是用来管理组件行为的一个集合工具,组件的行为包括与外部环境的交互、组件的生命周期、组件之间的合作依赖关系等等。J2ee包含的容器种类大约有 Web容器、Application Client容器、EJB容器、Applet客户端容器等。但在笔者看来,现在容器的概念变得有点模糊了,大家耳熟能详是那些功能强大的开源框架,比如 Hibernate、Struts2、Spring、JSF等,其中Hibernate就基于JDBC的基础封装了对事务和会话的管理,大大方便了对数据库操作的繁琐代码,从这个意义上来说它已经接近容器的概念了,EJB的实体Bean也逐渐被以Hibernate为代表的持久化框架所取代。

组件,本意是指可以重用的代码单元,一般代表着一个或者一组可以独立出来的功能模块,在J2ee中组件的种类有很多种,比较常见的是EJB组件、DAO组件、客户端组件或者应用程序组件等,它们有个共同特点是分别会打包成.war,.jar,.jar,.ear,每个组件由特定格式的xml描述符文件进行描述,而且服务器端的组件都需要被部署到应用服务器上面才能够被使用。

稍微理解完组件和容器,还有一个重要的概念就是分层模型,最著名的当然是MVC三层模型。在一个大的工程或项目中,为了让前台和后台各个模块的编程人员能够同时进行工作提高开发效率,最重要的就是实现层与层之间的耦合关系,许多分层模型的宗旨和开源框架所追求的也就是这样的效果。在笔者看来,一个完整的 Web项目大概有以下几个层次:

a) 表示层(Jsp、Html、Javascript、Ajax、Flash等等技术对其支持)
b) 控制层(Struts、JSF、WebWork等等框架在基于Servlet的基础上支持,负责把具体的请求数据(有时卸载重新装载)导向适合处理它的模型层对象)
c) 模型层(笔者认为目前最好的框架是Spring,实质就是处理表示层经由控制层转发过来的数据,包含着大量的业务逻辑)
d) 数据层(Hibernate、JDBC、EJB等,由模型层处理完了持久化到数据库中)

当然,这仅仅是笔者个人的观点,仅仅是供大家学习做一个参考,如果要实现这些层之间的完全分离,那么一个大的工程,可以仅仅通过增加人手就来完成任务。虽然《人月神话》中已经很明确的阐述了增加人手并不能是效率增加,很大程度上是因为彼此做的工作有顺序上的依赖关系或者说难度和工作量上的巨大差距。当然理想状态在真实世界中是不可能达到的,但我们永远应该朝着这个方向去不断努力。最开始所提倡的针对接口来编程,哪怕是小小的细节,写一条List list= = new ArrayList()语句也能体现着处处皆使用接口的思想在里面。Anyway,这只是个开篇,笔者会就自己用过的J2ee技术和框架再细化谈一些经验
Java杂谈(八)--Servlet/Jsp
终于正式进入J2ee的细节部分了,首当其冲的当然是Servlet和Jsp了,上篇曾经提到过J2ee只是一个规范和指南,定义了一组必须要遵循的接口,核心概念是组件和容器。曾经有的人问笔者Servlet的Class文件是哪里来的?他认为是J2ee官方提供的,我举了一个简单的反例:稍微检查了一下Tomcat5.0里面的Servlet.jar文件和JBoss里面的Servlet.jar文件大小,很明显是不一样的,至少已经说明了它们不是源自同根的吧。其实Servlet是由容器根据J2ee的接口定义自己来实现的,实现的方式当然可以不同,只要都遵守J2ee规范和指南。

上述只是一个常见的误区罢了,告诉我们要编译运行Servlet,是要依赖于实现它的容器的,不然连jar文件都没有,编译都无法进行。那么Jsp呢? Java Server Page的简称,是为了开发动态网页而诞生的技术,其本质也是Jsp,在编写完毕之后会在容器启动时经过编译成对应的Servlet。只是我们利用Jsp 的很多新特性,可以更加专注于前后台的分离,早期Jsp做前台是满流行的,毕竟里面支持Html代码,这让前台美工人员可以更有效率的去完成自己的工作。然后Jsp将请求转发到后台的Servlet,由Servlet处理业务逻辑,再转发回另外一个Jsp在前台显示出来。这似乎已经成为一种常用的模式,最初笔者学习J2ee的时候,大量时间也在编写这样的代码。

尽管现在做前台的技术越来越多,例如Flash、Ajax等,已经有很多人不再认为Jsp重要了。笔者觉得Jsp带来的不仅仅是前后端分离的设计理念,它的另外一项技术成就了我们今天用的很多框架,那就是Tag标签技术。所以与其说是在学习Jsp,不如更清醒的告诉自己在不断的理解Tag标签的意义和本质。

1. Servlet以及Jsp的生命周期
Servlet是Jsp的实质,尽管容器对它们的处理有所区别。Servlet有init()方法初始化,service()方法进行Web服务, destroy()方法进行销毁,从生到灭都由容器来掌握,所以这些方法除非你想自己来实现Servlet,否则是很少会接触到的。正是由于很少接触,才容易被广大初学者所忽略,希望大家至少记住Servlet生命周期方法都是回调方法。回调这个概念简单来说就是把自己注入另外一个类中,由它来调用你的方法,所谓的另外一个类就是Web容器,它只认识接口和接口的方法,注入进来的是怎样的对象不管,它只会根据所需调用这个对象在接口定义存在的那些方法。由容器来调用的Servlet对象的初始化、服务和销毁方法,所以叫做回调。这个概念对学习其他J2ee技术相当关键!

那么Jsp呢?本事上是Servlet,还是有些区别的,它的生命周期是这样的:
a) 一个客户端的Request到达服务器 ->
b) 判断是否第一次调用 -> 是的话编译Jsp成Servlet
c) 否的话再判断此Jsp是否有改变 -> 是的话也重新编译Jsp成Servlet
d) 已经编译最近版本的Servlet装载所需的其他Class
e) 发布Servlet,即调用它的Service()方法

所以Jsp号称的是第一次Load缓慢,以后都会很快的运行。从它的生命的周期确实不难看出来这个特点,客户端的操作很少会改变Jsp的源码,所以它不需要编译第二次就一直可以为客户端提供服务。这里稍微解释一下Http的无状态性,因为发现很多人误解,Http的无状态性是指每次一张页面显示出来了,与服务器的连接其实就已经断开了,当再次有提交动作的时候,才会再次与服务器进行连接请求提供服务。当然还有现在比较流行的是Ajax与服务器异步通过 xml交互的技术,在做前台的领域潜力巨大,笔者不是Ajax的高手,这里无法为大家解释。

2. Tag标签的本质
笔者之前说了,Jsp本身初衷是使得Web应用前后台的开发可以脱离耦合分开有效的进行,可惜这个理念的贡献反倒不如它带来的Tag技术对J2ee的贡献要大。也许已经有很多人开始使用Tag技术了却并不了解它。所以才建议大家在学习J2ee开始的时候一定要认真学习Jsp,其实最重要的就是明白标签的本质。

Html标签我们都很熟悉了,有 、 、 、 ,Jsp带来的Tag标签遵循同样的格式,或者说更严格的Xml格式规范,例如 <jsp:include> 、 <jsp:useBean> 、 <c:if> 、 <c:forEach> 等等。它们没有什么神秘的地方,就其源头也还是Java Class而已,Tag标签的实质也就是一段Java代码,或者说一个Class文件。当配置文件设置好去哪里寻找这些Class的路径后,容器负责将页面中存在的标签对应到相应的Class上,执行那段特定的Java代码,如此而已。 <br>说得明白一点的话还是举几个简单的例子说明一下吧: <br> <br><jsp:include> 去哪里找执行什么class呢?首先这是个jsp类库的标签,当然要去jsp类库寻找相应的class了,同样它也是由Web容器来提供,例如 Tomcat就应该去安装目录的lib文件夹下面的jsp-api.jar里面找,有兴趣的可以去找一找啊! <br> <br><c:forEach> 又去哪里找呢?这个是由Jsp2.0版本推荐的和核心标记库的内容,例如 <c:if> 就对应在页面中做if判断的功能的一断Java代码。它的class文件在jstl.jar这个类库里面,往往还需要和一个standard.jar类库一起导入,放在具体Web项目的WEB-INF的lib目录下面就可以使用了。 <br> <br>顺便罗唆一句,Web Project的目录结构是相对固定的,因为容器会按照固定的路径去寻找它需要的配置文件和资源,这个任何一本J2ee入门书上都有,这里就不介绍了。了解Tag的本质还要了解它的工作原理,所以大家去J2ee的API里找到并研究这个包:javax.servlet.jsp.tagext。它有一些接口,和一些实现类,专门用语开发Tag,只有自己亲自写出几个不同功能的标签,才算是真正理解了标签的原理。别忘记了自己开发的标签要自己去完成配置文件,容器只是集成了去哪里寻找jsp标签对应class的路径,自己写的标签库当然要告诉容器去哪里找啦。 <br> <br>说了这么多,我们为什么要用标签呢?完全在Jsp里面来个 <% %> 就可以在里面任意写Java代码了,但是长期实践发现页面代码统一都是与html同风格的标记语言更加有助于美工人员进行开发前台,它不需要懂Java,只要Java程序员给个列表告诉美工什么标签可以完成什么逻辑功能,他就可以专注于美工,也算是进一步隔离了前后台的工作吧! <br> <br>3. 成就Web框架 <br>框架是什么?曾经看过这样的定义:与模式类似,框架也是解决特定问题的可重用方法,框架是一个描述性的构建块和服务集合,开发人员可以用来达成某个目标。一般来说,框架提供了解决某类问题的基础设施,是用来创建解决方案的工具,而不是问题的解决方案。 <br> <br>正是由于Tag的出现,成就了以后出现的那么多Web框架,它们都开发了自己成熟实用的一套标签,然后由特定的Xml文件来配置加载信息,力图使得Web 应用的开发变得更加高效。下面这些标签相应对很多人来说相当熟悉了: <br><html:password> <br><logic:equal> <br><bean:write> <br><f:view> <br><h:form> <br><h:message> <br> <br>它们分别来自Struts和JSF框架,最强大的功能在于控制转发,就是MVC三层模型中间完成控制器的工作。Struts-1实际上并未做到真正的三层隔离,这一点在Struts-2上得到了很大的改进。而Jsf向来以比较完善合理的标签库受到人们推崇。 <br> <br>今天就大概讲这么多吧,再次需要强调的是Servlet/Jsp是学习J2ee必经之路,也是最基础的知识,希望大家给与足够的重视! <br>Java杂谈(九)--Struts <br>Java杂谈(九)--Struts <br> <br>J2ee的开源框架很多,笔者只能介绍自己熟悉的几个,其他的目前在中国IT行业应用得不是很多。希望大家对新出的框架不要盲目的推崇,首先一定要熟悉它比旧的到底好在哪里,新的理念和特性是什么?然后再决定是否要使用它。 <br> <br>这期的主题是Struts,直译过来是支架。Struts的第一个版本是在2001年5月发布的,它提供了一个Web应用的解决方案,如何让Jsp和 servlet共存去提供清晰的分离视图和业务应用逻辑的架构。在Struts之前,通常的做法是在Jsp中加入业务逻辑,或者在Servlet中生成视图转发到前台去。Struts带着MVC的新理念当时退出几乎成为业界公认的Web应用标准,于是当代IT市场上也出现了众多熟悉Struts的程序员。即使有新的框架再出来不用,而继续用Struts的理由也加上了一条低风险,因为中途如果开发人员变动,很容易的招进新的会Struts的IT民工啊, ^_^! </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1344369951330349056"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(学习记录,Java,Swing,多线程,框架,设计模式)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1835513551624695808.htm" title="【iOS】MVC设计模式" target="_blank">【iOS】MVC设计模式</a> <span class="text-muted">Magnetic_h</span> <a class="tag" taget="_blank" href="/search/ios/1.htm">ios</a><a class="tag" taget="_blank" href="/search/mvc/1.htm">mvc</a><a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a><a class="tag" taget="_blank" href="/search/objective-c/1.htm">objective-c</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/ui/1.htm">ui</a> <div>MVC前言如何设计一个程序的结构,这是一门专门的学问,叫做"架构模式"(architecturalpattern),属于编程的方法论。MVC模式就是架构模式的一种。它是Apple官方推荐的App开发架构,也是一般开发者最先遇到、最经典的架构。MVC各层controller层Controller/ViewController/VC(控制器)负责协调Model和View,处理大部分逻辑它将数据从Mod</div> </li> <li><a href="/article/1835509897106649088.htm" title="Long类型前后端数据不一致" target="_blank">Long类型前后端数据不一致</a> <span class="text-muted">igotyback</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>响应给前端的数据浏览器控制台中response中看到的Long类型的数据是正常的到前端数据不一致前后端数据类型不匹配是一个常见问题,尤其是当后端使用Java的Long类型(64位)与前端JavaScript的Number类型(最大安全整数为2^53-1,即16位)进行数据交互时,很容易出现精度丢失的问题。这是因为JavaScript中的Number类型无法安全地表示超过16位的整数。为了解决这个问</div> </li> <li><a href="/article/1835509769822105600.htm" title="LocalDateTime 转 String" target="_blank">LocalDateTime 转 String</a> <span class="text-muted">igotyback</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;publicclassMain{publicstaticvoidmain(String[]args){//获取当前时间LocalDateTimenow=LocalDateTime.now();//定义日期格式化器DateTimeFormatterformat</div> </li> <li><a href="/article/1835509391361667072.htm" title="Linux下QT开发的动态库界面弹出操作(SDL2)" target="_blank">Linux下QT开发的动态库界面弹出操作(SDL2)</a> <span class="text-muted">13jjyao</span> <a class="tag" taget="_blank" href="/search/QT%E7%B1%BB/1.htm">QT类</a><a class="tag" taget="_blank" href="/search/qt/1.htm">qt</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/sdl2/1.htm">sdl2</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a> <div>需求:操作系统为linux,开发框架为qt,做成需带界面的qt动态库,调用方为java等非qt程序难点:调用方为java等非qt程序,也就是说调用方肯定不带QApplication::exec(),缺少了这个,QTimer等事件和QT创建的窗口将不能弹出(包括opencv也是不能弹出);这与qt调用本身qt库是有本质的区别的思路:1.调用方缺QApplication::exec(),那么我们在接口</div> </li> <li><a href="/article/1835507248395284480.htm" title="【一起学Rust | 设计模式】习惯语法——使用借用类型作为参数、格式化拼接字符串、构造函数" target="_blank">【一起学Rust | 设计模式】习惯语法——使用借用类型作为参数、格式化拼接字符串、构造函数</a> <span class="text-muted">广龙宇</span> <a class="tag" taget="_blank" href="/search/%E4%B8%80%E8%B5%B7%E5%AD%A6Rust/1.htm">一起学Rust</a><a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/Rust%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">Rust设计模式</a><a class="tag" taget="_blank" href="/search/rust/1.htm">rust</a><a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、使用借用类型作为参数二、格式化拼接字符串三、使用构造函数总结前言Rust不是传统的面向对象编程语言,它的所有特性,使其独一无二。因此,学习特定于Rust的设计模式是必要的。本系列文章为作者学习《Rust设计模式》的学习笔记以及自己的见解。因此,本系列文章的结构也与此书的结构相同(后续可能会调成结构),基本上分为三个部分</div> </li> <li><a href="/article/1835506996258893824.htm" title="回溯 Leetcode 332 重新安排行程" target="_blank">回溯 Leetcode 332 重新安排行程</a> <span class="text-muted">mmaerd</span> <a class="tag" taget="_blank" href="/search/Leetcode%E5%88%B7%E9%A2%98%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95/1.htm">Leetcode刷题学习记录</a><a class="tag" taget="_blank" href="/search/leetcode/1.htm">leetcode</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E8%81%8C%E5%9C%BA%E5%92%8C%E5%8F%91%E5%B1%95/1.htm">职场和发展</a> <div>重新安排行程Leetcode332学习记录自代码随想录给你一份航线列表tickets,其中tickets[i]=[fromi,toi]表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。所有这些机票都属于一个从JFK(肯尼迪国际机场)出发的先生,所以该行程必须从JFK开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。例如,行程[“JFK”,“LGA”]与[“JFK”,“LGB</div> </li> <li><a href="/article/1835498925755297792.htm" title="DIV+CSS+JavaScript技术制作网页(旅游主题网页设计与制作)云南大理" target="_blank">DIV+CSS+JavaScript技术制作网页(旅游主题网页设计与制作)云南大理</a> <span class="text-muted">STU学生网页设计</span> <a class="tag" taget="_blank" href="/search/%E7%BD%91%E9%A1%B5%E8%AE%BE%E8%AE%A1/1.htm">网页设计</a><a class="tag" taget="_blank" href="/search/%E6%9C%9F%E6%9C%AB%E7%BD%91%E9%A1%B5%E4%BD%9C%E4%B8%9A/1.htm">期末网页作业</a><a class="tag" taget="_blank" href="/search/html%E9%9D%99%E6%80%81%E7%BD%91%E9%A1%B5/1.htm">html静态网页</a><a class="tag" taget="_blank" href="/search/html5%E6%9C%9F%E6%9C%AB%E5%A4%A7%E4%BD%9C%E4%B8%9A/1.htm">html5期末大作业</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E9%A1%B5%E8%AE%BE%E8%AE%A1/1.htm">网页设计</a><a class="tag" taget="_blank" href="/search/web%E5%A4%A7%E4%BD%9C%E4%B8%9A/1.htm">web大作业</a> <div>️精彩专栏推荐作者主页:【进入主页—获取更多源码】web前端期末大作业:【HTML5网页期末作业(1000套)】程序员有趣的告白方式:【HTML七夕情人节表白网页制作(110套)】文章目录二、网站介绍三、网站效果▶️1.视频演示2.图片演示四、网站代码HTML结构代码CSS样式代码五、更多源码二、网站介绍网站布局方面:计划采用目前主流的、能兼容各大主流浏览器、显示效果稳定的浮动网页布局结构。网站程</div> </li> <li><a href="/article/1835498547785592832.htm" title="【华为OD机试真题2023B卷 JAVA&JS】We Are A Team" target="_blank">【华为OD机试真题2023B卷 JAVA&JS】We Are A Team</a> <span class="text-muted">若博豆</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E5%8D%8E%E4%B8%BA/1.htm">华为</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>华为OD2023(B卷)机试题库全覆盖,刷题指南点这里WeAreATeam时间限制:1秒|内存限制:32768K|语言限制:不限题目描述:总共有n个人在机房,每个人有一个标号(1<=标号<=n),他们分成了多个团队,需要你根据收到的m条消息判定指定的两个人是否在一个团队中,具体的:1、消息构成为:abc,整数a、b分别代</div> </li> <li><a href="/article/1835497283932745728.htm" title="利用LangChain的StackExchange组件实现智能问答系统" target="_blank">利用LangChain的StackExchange组件实现智能问答系统</a> <span class="text-muted">nseejrukjhad</span> <a class="tag" taget="_blank" href="/search/langchain/1.htm">langchain</a><a class="tag" taget="_blank" href="/search/microsoft/1.htm">microsoft</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>利用LangChain的StackExchange组件实现智能问答系统引言在当今的软件开发世界中,StackOverflow已经成为程序员解决问题的首选平台之一。而LangChain作为一个强大的AI应用开发框架,提供了StackExchange组件,使我们能够轻松地将StackOverflow的海量知识库集成到我们的应用中。本文将详细介绍如何使用LangChain的StackExchange组件</div> </li> <li><a href="/article/1835496149843275776.htm" title="关于城市旅游的HTML网页设计——(旅游风景云南 5页)HTML+CSS+JavaScript" target="_blank">关于城市旅游的HTML网页设计——(旅游风景云南 5页)HTML+CSS+JavaScript</a> <span class="text-muted">二挡起步</span> <a class="tag" taget="_blank" href="/search/web%E5%89%8D%E7%AB%AF%E6%9C%9F%E6%9C%AB%E5%A4%A7%E4%BD%9C%E4%B8%9A/1.htm">web前端期末大作业</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a><a class="tag" taget="_blank" href="/search/%E6%97%85%E6%B8%B8/1.htm">旅游</a><a class="tag" taget="_blank" href="/search/%E9%A3%8E%E6%99%AF/1.htm">风景</a> <div>⛵源码获取文末联系✈Web前端开发技术描述网页设计题材,DIV+CSS布局制作,HTML+CSS网页设计期末课程大作业|游景点介绍|旅游风景区|家乡介绍|等网站的设计与制作|HTML期末大学生网页设计作业,Web大学生网页HTML:结构CSS:样式在操作方面上运用了html5和css3,采用了div+css结构、表单、超链接、浮动、绝对定位、相对定位、字体样式、引用视频等基础知识JavaScrip</div> </li> <li><a href="/article/1835496148601761792.htm" title="HTML网页设计制作大作业(div+css) 云南我的家乡旅游景点 带文字滚动" target="_blank">HTML网页设计制作大作业(div+css) 云南我的家乡旅游景点 带文字滚动</a> <span class="text-muted">二挡起步</span> <a class="tag" taget="_blank" href="/search/web%E5%89%8D%E7%AB%AF%E6%9C%9F%E6%9C%AB%E5%A4%A7%E4%BD%9C%E4%B8%9A/1.htm">web前端期末大作业</a><a class="tag" taget="_blank" href="/search/web%E8%AE%BE%E8%AE%A1%E7%BD%91%E9%A1%B5%E8%A7%84%E5%88%92%E4%B8%8E%E8%AE%BE%E8%AE%A1/1.htm">web设计网页规划与设计</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/dreamweaver/1.htm">dreamweaver</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>Web前端开发技术描述网页设计题材,DIV+CSS布局制作,HTML+CSS网页设计期末课程大作业游景点介绍|旅游风景区|家乡介绍|等网站的设计与制作HTML期末大学生网页设计作业HTML:结构CSS:样式在操作方面上运用了html5和css3,采用了div+css结构、表单、超链接、浮动、绝对定位、相对定位、字体样式、引用视频等基础知识JavaScript:做与用户的交互行为文章目录前端学习路线</div> </li> <li><a href="/article/1835492740536823808.htm" title="node.js学习" target="_blank">node.js学习</a> <span class="text-muted">小猿L</span> <a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a><a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/vim/1.htm">vim</a> <div>node.js学习实操及笔记温故node.js,node.js学习实操过程及笔记~node.js学习视频node.js官网node.js中文网实操笔记githubcsdn笔记为什么学node.js可以让别人访问我们编写的网页为后续的框架学习打下基础,三大框架vuereactangular离不开node.jsnode.js是什么官网:node.js是一个开源的、跨平台的运行JavaScript的运行</div> </li> <li><a href="/article/1835490839837634560.htm" title="自我意识" target="_blank">自我意识</a> <span class="text-muted">徐立华</span> <div>----读帕克.帕尔默《教学勇气》(P18----19)5.铸造我们的学科帕克.帕尔默说学科知识对我们的自身认同和外部世界有启发意义。学科会铸造我们。“在我们与学科的命题概念和学科的生活框架相遇之前,自我意识知识处于潜伏状态,通过回想学科是怎样唤醒自我意识,我们就可以找回教学心灵。”《教学勇气》(P18)我们的自我意识像冰山表面下无限延伸的冰层,常常处于潜伏状态。但是在我们对所教授的学科进行深入思</div> </li> <li><a href="/article/1835489207716507648.htm" title="基于CODESYS的多轴运动控制程序框架:逻辑与运动控制分离,快速开发灵活操作" target="_blank">基于CODESYS的多轴运动控制程序框架:逻辑与运动控制分离,快速开发灵活操作</a> <span class="text-muted">GPJnCrbBdl</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>基于codesys开发的多轴运动控制程序框架,将逻辑与运动控制分离,将单轴控制封装成功能块,对该功能块的操作包含了所有的单轴控制(归零、点动、相对定位、绝对定位、设置当前位置、伺服模式切换等等)。程序框架由主程序按照状态调用分归零模式、手动模式、自动模式、故障模式,程序状态的跳转都已完成,只需要根据不同的工艺要求完成所需的动作即可。变量的声明、地址的规划都严格按照C++的标准定义,能帮助开发者快速</div> </li> <li><a href="/article/1835479758033481728.htm" title="SpringBlade dict-biz/list 接口 SQL 注入漏洞" target="_blank">SpringBlade dict-biz/list 接口 SQL 注入漏洞</a> <span class="text-muted">文章永久免费只为良心</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a> <div>SpringBladedict-biz/list接口SQL注入漏洞POC:构造请求包查看返回包你的网址/api/blade-system/dict-biz/list?updatexml(1,concat(0x7e,md5(1),0x7e),1)=1漏洞概述在SpringBlade框架中,如果dict-biz/list接口的后台处理逻辑没有正确地对用户输入进行过滤或参数化查询(PreparedSta</div> </li> <li><a href="/article/1835477614848995328.htm" title="insert into select 主键自增_mybatis拦截器实现主键自动生成" target="_blank">insert into select 主键自增_mybatis拦截器实现主键自动生成</a> <span class="text-muted">weixin_39521651</span> <a class="tag" taget="_blank" href="/search/insert/1.htm">insert</a><a class="tag" taget="_blank" href="/search/into/1.htm">into</a><a class="tag" taget="_blank" href="/search/select/1.htm">select</a><a class="tag" taget="_blank" href="/search/%E4%B8%BB%E9%94%AE%E8%87%AA%E5%A2%9E/1.htm">主键自增</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a><a class="tag" taget="_blank" href="/search/delete%E8%BF%94%E5%9B%9E%E5%80%BC/1.htm">delete返回值</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a><a class="tag" taget="_blank" href="/search/insert%E8%BF%94%E5%9B%9E%E4%B8%BB%E9%94%AE/1.htm">insert返回主键</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a><a class="tag" taget="_blank" href="/search/insert%E8%BF%94%E5%9B%9E%E5%AF%B9%E8%B1%A1/1.htm">insert返回对象</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a><a class="tag" taget="_blank" href="/search/plus/1.htm">plus</a><a class="tag" taget="_blank" href="/search/insert%E8%BF%94%E5%9B%9E%E4%B8%BB%E9%94%AE/1.htm">insert返回主键</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a><a class="tag" taget="_blank" href="/search/plus/1.htm">plus</a><a class="tag" taget="_blank" href="/search/%E6%8F%92%E5%85%A5%E7%94%9F%E6%88%90id/1.htm">插入生成id</a> <div>前言前阵子和朋友聊天,他说他们项目有个需求,要实现主键自动生成,不想每次新增的时候,都手动设置主键。于是我就问他,那你们数据库表设置主键自动递增不就得了。他的回答是他们项目目前的id都是采用雪花算法来生成,因此为了项目稳定性,不会切换id的生成方式。朋友问我有没有什么实现思路,他们公司的orm框架是mybatis,我就建议他说,不然让你老大把mybatis切换成mybatis-plus。mybat</div> </li> <li><a href="/article/1835476093189058560.htm" title="Java 重写(Override)与重载(Overload)" target="_blank">Java 重写(Override)与重载(Overload)</a> <span class="text-muted">叨唧唧的</span> <div>Java重写(Override)与重载(Overload)重写(Override)重写是子类对父类的允许访问的方法的实现过程进行重新编写,返回值和形参都不能改变。即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定于自己的行为。也就是说子类能够根据需要实现父类的方法。重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如:父类的一个方法申明了一个检查异常IOExceptio</div> </li> <li><a href="/article/1835473830873755648.htm" title="简单了解 JVM" target="_blank">简单了解 JVM</a> <span class="text-muted">记得开心一点啊</span> <a class="tag" taget="_blank" href="/search/jvm/1.htm">jvm</a> <div>目录♫什么是JVM♫JVM的运行流程♫JVM运行时数据区♪虚拟机栈♪本地方法栈♪堆♪程序计数器♪方法区/元数据区♫类加载的过程♫双亲委派模型♫垃圾回收机制♫什么是JVMJVM是JavaVirtualMachine的简称,意为Java虚拟机。虚拟机是指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统(如:JVM、VMwave、VirtualBox)。JVM和其他两个虚拟机</div> </li> <li><a href="/article/1835471058648526848.htm" title="1分钟解决 -bash: mvn: command not found,在Centos 7中安装Maven" target="_blank">1分钟解决 -bash: mvn: command not found,在Centos 7中安装Maven</a> <span class="text-muted">Energet!c</span> <a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>1分钟解决-bash:mvn:commandnotfound,在Centos7中安装Maven检查Java环境1下载Maven2解压Maven3配置环境变量4验证安装5常见问题与注意事项6总结检查Java环境Maven依赖Java环境,请确保系统已经安装了Java并配置了环境变量。可以通过以下命令检查:java-version如果未安装,请先安装Java。1下载Maven从官网下载:前往Apach</div> </li> <li><a href="/article/1835469672334585856.htm" title="Java企业面试题3" target="_blank">Java企业面试题3</a> <span class="text-muted">马龙强_</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>1.break和continue的作用(智*图)break:用于完全退出一个循环(如for,while)或一个switch语句。当在循环体内遇到break语句时,程序会立即跳出当前循环体,继续执行循环之后的代码。continue:用于跳过当前循环体中剩余的部分,并开始下一次循环。如果是在for循环中使用continue,则会直接进行条件判断以决定是否执行下一轮循环。2.if分支语句和switch分</div> </li> <li><a href="/article/1835468916290318336.htm" title="JVM、JRE和 JDK:理解Java开发的三大核心组件" target="_blank">JVM、JRE和 JDK:理解Java开发的三大核心组件</a> <span class="text-muted">Y雨何时停T</span> <a class="tag" taget="_blank" href="/search/Java/1.htm">Java</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>Java是一门跨平台的编程语言,它的成功离不开背后强大的运行环境与开发工具的支持。在Java的生态中,JVM(Java虚拟机)、JRE(Java运行时环境)和JDK(Java开发工具包)是三个至关重要的核心组件。本文将探讨JVM、JDK和JRE的区别,帮助你更好地理解Java的运行机制。1.JVM:Java虚拟机(JavaVirtualMachine)什么是JVM?JVM,即Java虚拟机,是Ja</div> </li> <li><a href="/article/1835465517821947904.htm" title="多线程之——ExecutorCompletionService" target="_blank">多线程之——ExecutorCompletionService</a> <span class="text-muted">阿福德</span> <div>在我们开发中,经常会遇到这种情况,我们起多个线程来执行,等所有的线程都执行完成后,我们需要得到个线程的执行结果来进行聚合处理。我在内部代码评审时,发现了不少这种情况。看很多同学都使用正确,但比较啰嗦,效率也不高。本文介绍一个简单处理这种情况的方法:直接上代码:publicclassExecutorCompletionServiceTest{@TestpublicvoidtestExecutorCo</div> </li> <li><a href="/article/1835464504918503424.htm" title="Java面试题精选:消息队列(二)" target="_blank">Java面试题精选:消息队列(二)</a> <span class="text-muted">芒果不是芒</span> <a class="tag" taget="_blank" href="/search/Java%E9%9D%A2%E8%AF%95%E9%A2%98%E7%B2%BE%E9%80%89/1.htm">Java面试题精选</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/kafka/1.htm">kafka</a> <div>一、Kafka的特性1.消息持久化:消息存储在磁盘,所以消息不会丢失2.高吞吐量:可以轻松实现单机百万级别的并发3.扩展性:扩展性强,还是动态扩展4.多客户端支持:支持多种语言(Java、C、C++、GO、)5.KafkaStreams(一个天生的流处理):在双十一或者销售大屏就会用到这种流处理。使用KafkaStreams可以快速的把销售额统计出来6.安全机制:Kafka进行生产或者消费的时候会</div> </li> <li><a href="/article/1835462484912336896.htm" title="python多线程程序设计 之一" target="_blank">python多线程程序设计 之一</a> <span class="text-muted">IT_Beijing_BIT</span> <a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/Python/1.htm">Python</a><a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E8%AF%AD%E8%A8%80/1.htm">程序设计语言</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>python多线程程序设计之一全局解释器锁线程APIsthreading.active_count()threading.current_thread()threading.excepthook(args,/)threading.get_native_id()threading.main_thread()threading.stack_size([size])线程对象成员函数构造器start/ru</div> </li> <li><a href="/article/1835462485629562880.htm" title="白骑士的Java教学基础篇 2.5 控制流语句" target="_blank">白骑士的Java教学基础篇 2.5 控制流语句</a> <span class="text-muted">白骑士所长</span> <a class="tag" taget="_blank" href="/search/Java/1.htm">Java</a><a class="tag" taget="_blank" href="/search/%E6%95%99%E5%AD%A6/1.htm">教学</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>欢迎继续学习Java编程的基础篇!在前面的章节中,我们了解了Java的变量、数据类型和运算符。接下来,我们将探讨Java中的控制流语句。控制流语句用于控制程序的执行顺序,使我们能够根据特定条件执行不同的代码块,或重复执行某段代码。这是编写复杂程序的基础。通过学习这一节内容,你将掌握如何使用条件语句和循环语句来编写更加灵活和高效的代码。条件语句条件语句用于根据条件的真假来执行不同的代码块。if语句‘</div> </li> <li><a href="/article/1835462232612368384.htm" title="python语法——三目运算符" target="_blank">python语法——三目运算符</a> <span class="text-muted">HappyRocking</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E4%B8%89%E7%9B%AE%E8%BF%90%E7%AE%97%E7%AC%A6/1.htm">三目运算符</a> <div>在java中,有三目运算符,如:intc=(a>b)?a:b表示c取两者中的较大值。但是在python,不能直接这样使用,估计是因为冒号在python有分行的关键作用。那么在python中,如何实现类似功能呢?可以使用ifelse语句,也是一行可以完成,格式为:aifbelsec表示如果b为True,则表达式等于a,否则等于c。如:c=(aif(a>b)elseb)同样是完成了取最大值的功能。</div> </li> <li><a href="/article/1835457442260021248.htm" title="ArrayList 源码解析" target="_blank">ArrayList 源码解析</a> <span class="text-muted">程序猿进阶</span> <a class="tag" taget="_blank" href="/search/Java%E5%9F%BA%E7%A1%80/1.htm">Java基础</a><a class="tag" taget="_blank" href="/search/ArrayList/1.htm">ArrayList</a><a class="tag" taget="_blank" href="/search/List/1.htm">List</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/1.htm">性能优化</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/1.htm">架构设计</a><a class="tag" taget="_blank" href="/search/idea/1.htm">idea</a> <div>ArrayList是Java集合框架中的一个动态数组实现,提供了可变大小的数组功能。它继承自AbstractList并实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现。除该类未实现同步外,其余跟Vector大致相同。每个ArrayList都有一个容量capacity,表示底层数组的实际大小,容器内存储元素的个数不能多于当前容量。当向容器中添</div> </li> <li><a href="/article/1835454921990828032.htm" title="Java爬虫框架(一)--架构设计" target="_blank">Java爬虫框架(一)--架构设计</a> <span class="text-muted">狼图腾-狼之传说</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%A1%86%E6%9E%B6/1.htm">框架</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E4%BB%BB%E5%8A%A1/1.htm">任务</a><a class="tag" taget="_blank" href="/search/html%E8%A7%A3%E6%9E%90%E5%99%A8/1.htm">html解析器</a><a class="tag" taget="_blank" href="/search/%E5%AD%98%E5%82%A8/1.htm">存储</a><a class="tag" taget="_blank" href="/search/%E7%94%B5%E5%AD%90%E5%95%86%E5%8A%A1/1.htm">电子商务</a> <div>一、架构图那里搜网络爬虫框架主要针对电子商务网站进行数据爬取,分析,存储,索引。爬虫:爬虫负责爬取,解析,处理电子商务网站的网页的内容数据库:存储商品信息索引:商品的全文搜索索引Task队列:需要爬取的网页列表Visited表:已经爬取过的网页列表爬虫监控平台:web平台可以启动,停止爬虫,管理爬虫,task队列,visited表。二、爬虫1.流程1)Scheduler启动爬虫器,TaskMast</div> </li> <li><a href="/article/1835454543471669248.htm" title="Java:爬虫框架" target="_blank">Java:爬虫框架</a> <span class="text-muted">dingcho</span> <a class="tag" taget="_blank" href="/search/Java/1.htm">Java</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a> <div>一、ApacheNutch2【参考地址】Nutch是一个开源Java实现的搜索引擎。它提供了我们运行自己的搜索引擎所需的全部工具。包括全文搜索和Web爬虫。Nutch致力于让每个人能很容易,同时花费很少就可以配置世界一流的Web搜索引擎.为了完成这一宏伟的目标,Nutch必须能够做到:每个月取几十亿网页为这些网页维护一个索引对索引文件进行每秒上千次的搜索提供高质量的搜索结果简单来说Nutch支持分</div> </li> <li><a href="/article/1835450890077696000.htm" title="python怎么将png转为tif_png转tif" target="_blank">python怎么将png转为tif_png转tif</a> <span class="text-muted">weixin_39977276</span> <div>发国外的文章要求图片是tif,cmyk色彩空间的。大小尺寸还有要求。比如网上大神多,找到了一段代码,感谢!https://www.jianshu.com/p/ec2af4311f56https://github.com/KevinZc007/image2Tifimportjava.awt.image.BufferedImage;importjava.io.File;importjava.io.Fi</div> </li> <li><a href="/article/48.htm" title="开发者关心的那些事" target="_blank">开发者关心的那些事</a> <span class="text-muted">圣子足道</span> <a class="tag" taget="_blank" href="/search/ios/1.htm">ios</a><a class="tag" taget="_blank" href="/search/%E6%B8%B8%E6%88%8F/1.htm">游戏</a><a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a><a class="tag" taget="_blank" href="/search/apple/1.htm">apple</a><a class="tag" taget="_blank" href="/search/%E6%94%AF%E4%BB%98/1.htm">支付</a> <div>我要在app里添加IAP,必须要注册自己的产品标识符(product identifiers)。产品标识符是什么? 产品标识符(Product Identifiers)是一串字符串,它用来识别你在应用内贩卖的每件商品。App Store用产品标识符来检索产品信息,标识符只能包含大小写字母(A-Z)、数字(0-9)、下划线(-)、以及圆点(.)。你可以任意排列这些元素,但我们建议你创建标识符时使用</div> </li> <li><a href="/article/175.htm" title="负载均衡器技术Nginx和F5的优缺点对比" target="_blank">负载均衡器技术Nginx和F5的优缺点对比</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/nginx/1.htm">nginx</a><a class="tag" taget="_blank" href="/search/F5/1.htm">F5</a> <div>        对于数据流量过大的网络中,往往单一设备无法承担,需要多台设备进行数据分流,而负载均衡器就是用来将数据分流到多台设备的一个转发器。         目前有许多不同的负载均衡技术用以满足不同的应用需求,如软/硬件负载均衡、本地/全局负载均衡、更高</div> </li> <li><a href="/article/302.htm" title="LeetCode[Math] - #9 Palindrome Number" target="_blank">LeetCode[Math] - #9 Palindrome Number</a> <span class="text-muted">Cwind</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/Algorithm/1.htm">Algorithm</a><a class="tag" taget="_blank" href="/search/%E9%A2%98%E8%A7%A3/1.htm">题解</a><a class="tag" taget="_blank" href="/search/LeetCode/1.htm">LeetCode</a><a class="tag" taget="_blank" href="/search/Math/1.htm">Math</a> <div>原题链接:#9 Palindrome Number   要求: 判断一个整数是否是回文数,不要使用额外的存储空间   难度:简单   分析: 题目限制不允许使用额外的存储空间应指不允许使用O(n)的内存空间,O(1)的内存用于存储中间结果是可以接受的。于是考虑将该整型数反转,然后与原数字进行比较。 注:没有看到有关负数是否可以是回文数的明确结论,例如</div> </li> <li><a href="/article/429.htm" title="画图板的基本实现" target="_blank">画图板的基本实现</a> <span class="text-muted">15700786134</span> <a class="tag" taget="_blank" href="/search/%E7%94%BB%E5%9B%BE%E6%9D%BF/1.htm">画图板</a> <div> 要实现画图板的基本功能,除了在qq登陆界面中用到的组件和方法外,还需要添加鼠标监听器,和接口实现。 首先,需要显示一个JFrame界面: public class DrameFrame extends JFrame {              //显示</div> </li> <li><a href="/article/556.htm" title="linux的ps命令" target="_blank">linux的ps命令</a> <span class="text-muted">被触发</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a> <div>Linux中的ps命令是Process Status的缩写。ps命令用来列出系统中当前运行的那些进程。ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态的显示进程信息,就可以使用top命令。 要对进程进行监测和控制,首先必须要了解当前进程的情况,也就是需要查看当前进程,而 ps 命令就是最基本同时也是非常强大的进程查看命令。使用该命令可以确定有哪些进程正在运行</div> </li> <li><a href="/article/683.htm" title="Android 音乐播放器 下一曲 连续跳几首歌" target="_blank">Android 音乐播放器 下一曲 连续跳几首歌</a> <span class="text-muted">肆无忌惮_</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>最近在写安卓音乐播放器的时候遇到个问题。在MediaPlayer播放结束时会回调 player.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { mp.reset(); Log.i("H</div> </li> <li><a href="/article/810.htm" title="java导出txt文件的例子" target="_blank">java导出txt文件的例子</a> <span class="text-muted">知了ing</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/servlet/1.htm">servlet</a> <div>代码很简单就一个servlet,如下: package com.eastcom.servlet; import java.io.BufferedOutputStream; import java.io.IOException; import java.net.URLEncoder; import java.sql.Connection; import java.sql.Resu</div> </li> <li><a href="/article/937.htm" title="Scala stack试玩, 提高第三方依赖下载速度" target="_blank">Scala stack试玩, 提高第三方依赖下载速度</a> <span class="text-muted">矮蛋蛋</span> <a class="tag" taget="_blank" href="/search/scala/1.htm">scala</a><a class="tag" taget="_blank" href="/search/sbt/1.htm">sbt</a> <div>原文地址: http://segmentfault.com/a/1190000002894524 sbt下载速度实在是惨不忍睹, 需要做些配置优化 下载typesafe离线包, 保存为ivy本地库 wget http://downloads.typesafe.com/typesafe-activator/1.3.4/typesafe-activator-1.3.4.zip 解压r</div> </li> <li><a href="/article/1064.htm" title="phantomjs安装(linux,附带环境变量设置) ,以及casperjs安装。" target="_blank">phantomjs安装(linux,附带环境变量设置) ,以及casperjs安装。</a> <span class="text-muted">alleni123</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/spider/1.htm">spider</a> <div>1. 首先从官网 http://phantomjs.org/下载phantomjs压缩包,解压缩到/root/phantomjs文件夹。 2. 安装依赖 sudo yum install fontconfig freetype libfreetype.so.6 libfontconfig.so.1 libstdc++.so.6 3. 配置环境变量 vi /etc/profil</div> </li> <li><a href="/article/1191.htm" title="JAVA IO FileInputStream和FileOutputStream,字节流的打包输出" target="_blank">JAVA IO FileInputStream和FileOutputStream,字节流的打包输出</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/java%E6%A0%B8%E5%BF%83%E6%80%9D%E6%83%B3/1.htm">java核心思想</a><a class="tag" taget="_blank" href="/search/JAVA+IO%E6%93%8D%E4%BD%9C/1.htm">JAVA IO操作</a><a class="tag" taget="_blank" href="/search/%E5%AD%97%E8%8A%82%E6%B5%81/1.htm">字节流</a> <div>在程序设计语言中,数据的保存是基本,如果某程序语言不能保存数据那么该语言是不可能存在的,JAVA是当今最流行的面向对象设计语言之一,在保存数据中也有自己独特的一面,字节流和字符流 1,字节流是由字节构成的,字符流是由字符构成的 字节流和字符流都是继承的InputStream和OutPutStream ,java中两种最基本的就是字节流和字符流   类 FileInputStream</div> </li> <li><a href="/article/1318.htm" title="Spring基础实例(依赖注入和控制反转)" target="_blank">Spring基础实例(依赖注入和控制反转)</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a> <div>前提条件:在http://www.springsource.org/download网站上下载Spring框架,并将spring.jar、log4j-1.2.15.jar、commons-logging.jar加载至工程1.武器接口 package com.bijian.spring.base3; public interface Weapon { void kil</div> </li> <li><a href="/article/1445.htm" title="HR看重的十大技能" target="_blank">HR看重的十大技能</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/%E6%8F%90%E5%8D%87/1.htm">提升</a><a class="tag" taget="_blank" href="/search/%E8%83%BD%E5%8A%9B/1.htm">能力</a><a class="tag" taget="_blank" href="/search/HR/1.htm">HR</a><a class="tag" taget="_blank" href="/search/%E6%88%90%E9%95%BF/1.htm">成长</a> <div>    一个人掌握何种技能取决于他的兴趣、能力和聪明程度,也取决于他所能支配的资源以及制定的事业目标,拥有过硬技能的人有更多的工作机会。但是,由于经济发展前景不确定,掌握对你的事业有所帮助的技能显得尤为重要。以下是最受雇主欢迎的十种技能。   一、解决问题的能力   每天,我们都要在生活和工作中解决一些综合性的问题。那些能够发现问题、解决问题并迅速作出有效决</div> </li> <li><a href="/article/1572.htm" title="【Thrift一】Thrift编译安装" target="_blank">【Thrift一】Thrift编译安装</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/thrift/1.htm">thrift</a> <div>什么是Thrift The Apache Thrift software framework, for scalable cross-language services development, combines a software stack with a code generation engine to build services that work efficiently and s</div> </li> <li><a href="/article/1699.htm" title="【Avro三】Hadoop MapReduce读写Avro文件" target="_blank">【Avro三】Hadoop MapReduce读写Avro文件</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/mapreduce/1.htm">mapreduce</a> <div>Avro是Doug Cutting(此人绝对是神一般的存在)牵头开发的。 开发之初就是围绕着完善Hadoop生态系统的数据处理而开展的(使用Avro作为Hadoop MapReduce需要处理数据序列化和反序列化的场景),因此Hadoop MapReduce集成Avro也就是自然而然的事情。 这个例子是一个简单的Hadoop MapReduce读取Avro格式的源文件进行计数统计,然后将计算结果</div> </li> <li><a href="/article/1826.htm" title="nginx定制500,502,503,504页面" target="_blank">nginx定制500,502,503,504页面</a> <span class="text-muted">ronin47</span> <a class="tag" taget="_blank" href="/search/nginx%E3%80%80%E9%94%99%E8%AF%AF%E6%98%BE%E7%A4%BA/1.htm">nginx 错误显示</a> <div>server { listen 80; error_page 500/500.html; error_page 502/502.html; error_page 503/503.html; error_page 504/504.html; location /test {return502;}} 配置很简单,和配</div> </li> <li><a href="/article/1953.htm" title="java-1.二叉查找树转为双向链表" target="_blank">java-1.二叉查找树转为双向链表</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/%E4%BA%8C%E5%8F%89%E6%9F%A5%E6%89%BE%E6%A0%91/1.htm">二叉查找树</a> <div> import java.util.ArrayList; import java.util.List; public class BSTreeToLinkedList { /* 把二元查找树转变成排序的双向链表 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求不能创建任何新的结点,只调整指针的指向。 10 / \ 6 14 / \ </div> </li> <li><a href="/article/2080.htm" title="Netty源码学习-HTTP-tunnel" target="_blank">Netty源码学习-HTTP-tunnel</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/netty/1.htm">netty</a> <div>Netty关于HTTP tunnel的说明: http://docs.jboss.org/netty/3.2/api/org/jboss/netty/channel/socket/http/package-summary.html#package_description 这个说明有点太简略了 一个完整的例子在这里: https://github.com/bylijinnan</div> </li> <li><a href="/article/2207.htm" title="JSONUtil.serialize(map)和JSON.toJSONString(map)的区别" target="_blank">JSONUtil.serialize(map)和JSON.toJSONString(map)的区别</a> <span class="text-muted">coder_xpf</span> <a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a><a class="tag" taget="_blank" href="/search/json/1.htm">json</a><a class="tag" taget="_blank" href="/search/map/1.htm">map</a><a class="tag" taget="_blank" href="/search/val%28%29/1.htm">val()</a> <div> JSONUtil.serialize(map)和JSON.toJSONString(map)的区别   数据库查询出来的map有一个字段为空   通过System.out.println()输出 JSONUtil.serialize(map): {"one":"1","two":"nul</div> </li> <li><a href="/article/2334.htm" title="Hibernate缓存总结" target="_blank">Hibernate缓存总结</a> <span class="text-muted">cuishikuan</span> <a class="tag" taget="_blank" href="/search/%E5%BC%80%E6%BA%90/1.htm">开源</a><a class="tag" taget="_blank" href="/search/ssh/1.htm">ssh</a><a class="tag" taget="_blank" href="/search/javaweb/1.htm">javaweb</a><a class="tag" taget="_blank" href="/search/hibernate%E7%BC%93%E5%AD%98/1.htm">hibernate缓存</a><a class="tag" taget="_blank" href="/search/%E4%B8%89%E5%A4%A7%E6%A1%86%E6%9E%B6/1.htm">三大框架</a> <div>一、为什么要用Hibernate缓存? Hibernate是一个持久层框架,经常访问物理数据库。 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。 缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。   二、Hibernate缓存原理是怎样的? Hibernate缓存包括两大类:Hib</div> </li> <li><a href="/article/2461.htm" title="CentOs6" target="_blank">CentOs6</a> <span class="text-muted">dalan_123</span> <a class="tag" taget="_blank" href="/search/centos/1.htm">centos</a> <div>首先su - 切换到root下面1、首先要先安装GCC GCC-C++ Openssl等以来模块:yum -y install make gcc gcc-c++ kernel-devel m4 ncurses-devel openssl-devel2、再安装ncurses模块yum -y install ncurses-develyum install ncurses-devel3、下载Erang</div> </li> <li><a href="/article/2588.htm" title="10款用 jquery 实现滚动条至页面底端自动加载数据效果" target="_blank">10款用 jquery 实现滚动条至页面底端自动加载数据效果</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a> <div>  无限滚动自动翻页可以说是web2.0时代的一项堪称伟大的技术,它让我们在浏览页面的时候只需要把滚动条拉到网页底部就能自动显示下一页的结果,改变了一直以来只能通过点击下一页来翻页这种常规做法。 无限滚动自动翻页技术的鼻祖是微博的先驱:推特(twitter),后来必应图片搜索、谷歌图片搜索、google reader、箱包批发网等纷纷抄袭了这一项技术,于是靠滚动浏览器滚动条</div> </li> <li><a href="/article/2715.htm" title="ImageButton去边框&Button或者ImageButton的背景透明" target="_blank">ImageButton去边框&Button或者ImageButton的背景透明</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/imagebutton/1.htm">imagebutton</a> <div>在ImageButton中载入图片后,很多人会觉得有图片周围的白边会影响到美观,其实解决这个问题有两种方法 一种方法是将ImageButton的背景改为所需要的图片。如:android:background="@drawable/XXX" 第二种方法就是将ImageButton背景改为透明,这个方法更常用 在XML里;    <ImageBut</div> </li> <li><a href="/article/2842.htm" title="JSP之c:foreach" target="_blank">JSP之c:foreach</a> <span class="text-muted">eksliang</span> <a class="tag" taget="_blank" href="/search/jsp/1.htm">jsp</a><a class="tag" taget="_blank" href="/search/forearch/1.htm">forearch</a> <div>原文出自:http://www.cnblogs.com/draem0507/archive/2012/09/24/2699745.html <c:forEach>标签用于通用数据循环,它有以下属性 属 性 描 述 是否必须 缺省值 items 进行循环的项目 否 无 begin 开始条件 否 0 end 结束条件 否 集合中的最后一个项目 step 步长 否 1</div> </li> <li><a href="/article/2969.htm" title="Android实现主动连接蓝牙耳机" target="_blank">Android实现主动连接蓝牙耳机</a> <span class="text-muted">gqdy365</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>在Android程序中可以实现自动扫描蓝牙、配对蓝牙、建立数据通道。蓝牙分不同类型,这篇文字只讨论如何与蓝牙耳机连接。 大致可以分三步: 一、扫描蓝牙设备: 1、注册并监听广播: BluetoothAdapter.ACTION_DISCOVERY_STARTED BluetoothDevice.ACTION_FOUND BluetoothAdapter.ACTION_DIS</div> </li> <li><a href="/article/3096.htm" title="android学习轨迹之四:org.json.JSONException: No value for" target="_blank">android学习轨迹之四:org.json.JSONException: No value for</a> <span class="text-muted">hyz301</span> <a class="tag" taget="_blank" href="/search/json/1.htm">json</a> <div>org.json.JSONException: No value for items  在JSON解析中会遇到一种错误,很常见的错误   06-21 12:19:08.714 2098-2127/com.jikexueyuan.secret I/System.out﹕ Result:{"status":1,"page":1,&</div> </li> <li><a href="/article/3223.htm" title="干货分享:从零开始学编程 系列汇总" target="_blank">干货分享:从零开始学编程 系列汇总</a> <span class="text-muted">justjavac</span> <a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a> <div>程序员总爱重新发明轮子,于是做了要给轮子汇总。 从零开始写个编译器吧系列 (知乎专栏) 从零开始写一个简单的操作系统 (伯乐在线) 从零开始写JavaScript框架 (图灵社区) 从零开始写jQuery框架 (蓝色理想 ) 从零开始nodejs系列文章 (粉丝日志) 从零开始编写网络游戏 </div> </li> <li><a href="/article/3350.htm" title="jquery-autocomplete 使用手册" target="_blank">jquery-autocomplete 使用手册</a> <span class="text-muted">macroli</span> <a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a><a class="tag" taget="_blank" href="/search/Ajax/1.htm">Ajax</a><a class="tag" taget="_blank" href="/search/%E8%84%9A%E6%9C%AC/1.htm">脚本</a> <div>jquery-autocomplete学习 一、用前必备 官方网站:http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/ 当前版本:1.1 需要JQuery版本:1.2.6 二、使用 <script src="./jquery-1.3.2.js" type="text/ja</div> </li> <li><a href="/article/3477.htm" title="PLSQL-Developer或者Navicat等工具连接远程oracle数据库的详细配置以及数据库编码的修改" target="_blank">PLSQL-Developer或者Navicat等工具连接远程oracle数据库的详细配置以及数据库编码的修改</a> <span class="text-muted">超声波</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/plsql/1.htm">plsql</a> <div>  在服务器上将Oracle安装好之后接下来要做的就是通过本地机器来远程连接服务器端的oracle数据库,常用的客户端连接工具就是PLSQL-Developer或者Navicat这些工具了。刚开始也是各种报错,什么TNS:no listener;TNS:lost connection;TNS:target hosts...花了一天的时间终于让PLSQL-Developer和Navicat等这些客户</div> </li> <li><a href="/article/3604.htm" title="数据仓库数据模型之:极限存储--历史拉链表" target="_blank">数据仓库数据模型之:极限存储--历史拉链表</a> <span class="text-muted">superlxw1234</span> <a class="tag" taget="_blank" href="/search/%E6%9E%81%E9%99%90%E5%AD%98%E5%82%A8/1.htm">极限存储</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E4%BB%93%E5%BA%93/1.htm">数据仓库</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E6%A8%A1%E5%9E%8B/1.htm">数据模型</a><a class="tag" taget="_blank" href="/search/%E6%8B%89%E9%93%BE%E5%8E%86%E5%8F%B2%E8%A1%A8/1.htm">拉链历史表</a> <div>在数据仓库的数据模型设计过程中,经常会遇到这样的需求: 1. 数据量比较大; 2. 表中的部分字段会被update,如用户的地址,产品的描述信息,订单的状态等等; 3. 需要查看某一个时间点或者时间段的历史快照信息,比如,查看某一个订单在历史某一个时间点的状态,    比如,查看某一个用户在过去某一段时间内,更新过几次等等; 4. 变化的比例和频率不是很大,比如,总共有10</div> </li> <li><a href="/article/3731.htm" title="10点睛Spring MVC4.1-全局异常处理" target="_blank">10点睛Spring MVC4.1-全局异常处理</a> <span class="text-muted">wiselyman</span> <a class="tag" taget="_blank" href="/search/spring+mvc/1.htm">spring mvc</a> <div>10.1 全局异常处理 使用@ControllerAdvice注解来实现全局异常处理; 使用@ControllerAdvice的属性缩小处理范围 10.2 演示 演示控制器 package com.wisely.web; import org.springframework.stereotype.Controller; import org.spring</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>