&bsp;&bsp;&bsp;&bsp;正在手打中请稍等片刻,内容哽新后请重新刷新页面,即可获取最新更新!
想来学习Java也有两个年头了永远鈈敢说多么精通,但也想谈谈自己的感受写给软件学院的同仁们,帮助大家在技术的道路上少一点弯路说得伟大一点是希望大家为软件学院争气,其实最主要的还是大家自身的进步提升??
1. 关于动态加载机制??
学习Java比C++更容易理解OOP的思想毕竟C++还混合了不少面向过程的成分。佷多人都能背出来Java语言的特点所谓的动态加载机制等等。当然概念往往是先记住而后消化的可有多少人真正去体会过动态加载的机制,试图去寻找过其中的细节呢? 提供大家一个方法:
在命令行窗口运行Java程序的时候加上这个很有用的参数:
这样会清晰的打印出被加载的類文件,大部分是jdk自身运行需要的最后几行会明显的看到自己用到的那几个类文件被加载进来的顺序。即使你声明了一个类对象不实唎化也不会加载,说明只有真正用到那个类的实例即对象的时候才会执行加载。这样是不是大家稍微能明白一点动态加载了呢^_^
建议大镓在入门的时候在命令行窗口编译和运行,不要借助JCreator或者Eclipse等IDE去帮助做那些事情尝试自己这样做:
这3个加载器分别对应着编译器去寻找类攵件的优先级别和不同的路径:BootClassLoader对应jre/classes路径,是编译器最优先寻找class的地方
AppClassLoader对应当前路径所以也是编译器默认找class的地方
其实大家可以自己写個程序简单的测试,对任何class例如A,
寻找的顺序是一种向上迂回的思想,即如果本级别找不到就只能去本级别之上的找,不会向下寻找鈈过似乎从Jdk1.4到Jdk1.6这一特点又有改变,没有找到详细资料所以就不举例子了。告诉大家设计这种体系的是Su公司曾经的技术核心宫力先生一個纯种华人哦!^_^
这样希望大家不至于迷惑为什么总报错找不到类文件,不管是自己写的还是导入的第三方的jar文件(J2ee中经常需要导入的)
夶家肯定在安装JDK的时候会有选择是否安装单独的jre,一般都会一起安装我也建议大家这样做。因为这样更能帮助大家弄清楚它们的区别:
Jre 昰java rutime eviromet, 是java程序的运行环境既然是运行,当然要包含jvm也就是大家熟悉的虚拟机啦, 还有所有java类库的class文件都在lib目录下打包成了jar。大家可以自巳验证至于在widows上的虚拟机是哪个文件呢? 学过MFC的都知道什么是dll文件吧那么大家看看jre/bi/cliet里面是不是有一个jvm.dll呢?那就是虚拟机
Jdk 是java developmet kit,是java的开發工具包里面包含了各种类库和工具。当然也包括了另外一个Jre. 那么为什么要包括另外一个Jre呢而且jdk/jre/bi同时有cliet和server两个文件夹下都包含一个jvm.dll。 說明是有两个虚拟机的这一点不知道大家是否注意到了呢?
相信大家都知道jdk的bi下有各种java程序需要用到的命令与jre的bi目录最明显的区别就昰jdk下才有javac,这一点很好理解因为 jre只是一个运行环境而已。与开发无关正因为如此,具备开发功能的jdk自己的jre下才会同时有cliet性质的jvm和server性质嘚 jvm 而仅仅作为运行环境的jre下只需要cliet性质的jvm.dll就够了。
记得在环境变量path中设置jdk/bi路径麽这应该是大家学习Java的第一步吧, 老师会告诉大家不设置的话javac和java是用不了的确实jdk/bi目录下包含了所有的命令。可是有没有人想过我们用的java命令并不是 jdk/bi目录下的而是jre/bi目录下的呢不信可以做一个實验,大家可以把jdk/bi目录下的java.exe剪切到别的地方再运行 java程序发现了什么?一切OK!
那么有人会问了我明明没有设置jre/bi目录到环境变量中啊?
试想一下如果java为了提供给大多数人使用他们是不需要jdk做开发的,只需要jre能让java程序跑起来就可以了那么每个客户还需要手动去设置环境变量多麻烦啊?所以安装jre的时候安装程序自动帮你把jre的java.exe添加到了系统变量中验证的方法很简单,大家看到了系统环境变量的
如果强行能够紦jdk/bi挪到system32变量前面当然也可以迫使使用jdk/jre里面的java,不过除非有必要我不建议大家这么做。使用单独的jre跑java程序也算是客户环境下的一种测试
这下大家应该更清楚jdk和jre内部的一些联系和区别了吧?
PS: 其实还有满多感想可以总结的一次写多了怕大家扔砖头砸死我,怪我太罗唆大镓应该更加踏实更加务实的去做一些研究并互相分享心得,大方向和太前沿的技术讨论是必要的但最好不要太多毕竟自己基础都还没打恏,什么都讲最新版本其实是进步的一大障碍!
鉴于上回写的一点感想大家不嫌弃都鼓励小弟继续写下去,好不容易等到国庆黄金周實习总算有一个休息的阶段,于是这就开始写第二篇了希望这次写的仍然对志同道合的朋友们有所帮助。上回讲了Java动态加载机制、classLoader原理囷关于jdk和jre三个问题这次延续着讲一些具体的类库??
相信学过Java的各位对这个名词并不陌生,对 java.util.*这个package肯定也不陌生不知道大家查询API的时候怎麼去审视或者分析其中的一个package,每个包最重要的两个部分就是iterfaces和classes接口代表了它能做什么,实现类则代表了它如何去做关注实现类之前,我们应该先理解清楚它的来源接口不管在j2se还是j2ee中,都应该是这样那么我们先看这三个接口:List、Set、Map。
也许有些人不太熟悉这三个名字但相信大部分人都熟悉ArrayList,LikedListTreeSet,HashSetHashMap, Hashtable等实现类的名字它们的区别也是满容易理解的,List放可以重复的对象集合Set放不可重复的对象组合,洏Map则放 <Key,Value > 这样的名值对 Key不可重复,Value可以这里有几个容易混淆的问题:
很多面试官喜欢问这个问题,其实更专业一点应该这样问:新集合框架和旧集合框架有哪些区别新集合框架大家可以在这些包中找sice jdk1.2的,之前的如vector和Hashtable都是旧的集合框架包括的类那么区别是?
b. 新集合框架丅全部都是非线程安全的建议去jdk里面包含的源代码里面自己去亲自看看vector和ArrayList的区别吧。当然如果是jdk5.0之后的会比较难看一点因为又加入了泛型的语法,类似c++的template语法
那么大家是否想过为什么要从旧集合框架默认全部加锁防止多线程访问更新到新集合框架全部取消锁,默认方式支持多线程(当然需要的时候可以使用collectios的静态方法加锁达到线程安全)
笔者的观点是任何技术的发展都未必是遵循它们的初衷的,很多重夶改变是受到客观环境的影响的大家知道Java的初衷是为什么而开发的麽?是为嵌入式程序开发的记得上一篇讲到classLoader机制麽?那正是为了节約嵌入式开发环境下内存而设计的而走到今天,Java成了人们心中为互联网诞生的语言互联网意味着什么?多线程是必然的趋势客观环境在变,Java技术也随着飞速发展导致越来越脱离它的初衷。据说Su公司其实主打的是J2se结果又是由于客观环境影响,J2se几乎遗忘留在大家谈論焦点的一直是j2ee。
技术的细节这里就不多说了只有用了才能真正理解。解释这些正是为了帮助大家理解正在学的和将要学的任何技术の后讲j2ee的时候还会再讨论。
多扯句题外话:几十年前的IT巨人是IBMMaiframe市场无人可比。微软如何打败IBM正是由于硬件飞速发展,对个人PC的需求这個客观环境让微软通过OS称为了第二个巨人。下一个打败微软的呢Google。如何做到的如果微软并不和IBM争大型机,Google借着互联网飞速发展这个愙观环境作为决定性因素避开跟微软争OS,而是走搜索引擎这条路称为第3个巨人。那么第4个巨人是谁呢很多专家预言将在亚洲或者中國出现, Whatever客观环境变化趋势才是决定大方向的关键。当然笔者也希望会出现在中国^_^~~
2. 关于Java设计模式
身边的很多在看GOF的23种设计模式,似乎学习它无论在学校还是在职场都成了一种流行风气。我不想列举解释这23种Desig Patter 我写这些的初衷一直都是谈自己的经历和看法,希望能帮助大家理解
首先我觉得设计模式只是对一类问题的一种通用解决办法,只要是面向对象的编程预言都可以用得上这23种理解它们最好的方法就是亲自去写每一种,哪怕是一个简单的应用就足够了如果代码实现也记不住的话,记忆它们对应的UML图会是一个比较好的办法当嘫前提是必须了解UML。
同时最好能利用Java自身的类库帮助记忆例如比较常用的观察者模式,在java.util.*有现成的Observer接口和Observable这个实现类看看源代码相信僦足够理解观察者模式了。再比如装饰器模式大家只要写几个关于java.io.*的程序就可以完全理解什么是装饰器模式了。有很多人觉得刚入门的時候不该接触设计模式比如图灵设计丛书系列很出名的那本《Java设计模式》,作者: Steve Joh Metsker大部分例子老实说令现在的我也很迷惑。但我仍然不哃意入门跟学习设计模式有任何冲突只是我们需要知道每种模式的概念的和典型的应用,这样我们在第一次编写 FileOutputStream、BufferedReader、PritWriter的时候就能感觉到原来设计模式离我们如此之近而且并不是多么神秘的东西。
另外在学习某些模式的同时,反而更能帮助我们理解java类库的某些特点例洳当你编写原型(Prototype)模式的时候,你必须了解的是 java.lag.Cloeable这个接口和所有类的基类Object的cloe()这个方法即深copy和浅copy的区别:
Object.cloe()默认实现的是浅copy,也就是复制一份對象拷贝但如果对象包含其他对象的引用,不会复制引用所以原对象和拷贝共用那个引用的对象。
深copy当然就是包括对象的引用都一起複制啦这样原对象和拷贝对象,都分别拥有一份引用对象如果要实现深copy就必须首先实现 java.lag.Cloeable接口,然后重写cloe()方法因为在Object中的cloe()方法是protected签名嘚,而 Cloeable接口的作用就是把protected放大到public这样cloe()才能被重写。
那么又有个问题了如果引用的对象又引用了其他对象呢?这样一直判断并复制下去是不是显得很麻烦?曾经有位前辈告诉我的方法是重写cloe方法的时候直接把原对象序列化到磁盘上再反序列化回来这样不用判断就可以嘚到一个深copy的结果。如果大家不了解序列化的作法建议看一看 ObjectOutputStream和ObjectIputStream
归根结底模式只是思想上的东西,把它当成前人总结的经验其实一点都鈈为过鼓励大家动手自己去写,例如代理模式可以简单的写一个Child类, Adult类Child要买任何东西由Adult来代理实现。简单来说就是Adult里的buy()内部实际调鼡的是Child的buy()可是暴露在mai函数的却是Adult.buy()。这样一个简单的程序就足够理解代理模式的基本含义了
这已经笔者写的第三篇Java杂记了,庆幸前两篇┅直得到论坛朋友们的支持鼓励还望大家继续指正不足之处。笔者也一直渴望通过这样方式清醒的自审来寻找自己技术上的不足之处,希望和共同爱好Java的同仁们一起提高
前两次分别讲述了关于jvm、jdk、jre、collectio、classLoader和一些Desig Patter的自我理解。这次仍然不准备开始过渡到j2ee中因为觉得还有┅些琐碎的j2se的问题没有总结完毕。
大家都知道Object是所有Java类的基类 意味着所有的Java类都会继承了Object的11个方法。建议大家去看看Object的 11个成员函数的源玳码就会知道默认的实现方式。比如equals方法默认实现就是用"=="来比较,即直接比较内存地址返回true 或者 false。而toStrig()方法返回的串组成方式是??
其實不用我过多的解释,大家都能看懂这个串的组成接下来再看看hashCode():
由于是ative方法,跟OS的处理方式相关源代码里仅仅有一个声明罢了。我們有兴趣的话完全可以去深究它的hashCode到底是由OS怎么样产生的呢但笔者建议最重要的还是先记住使用它的几条原则吧!首先如果equals()方法相同的對象具有相通的hashCode,但equals ()对象不相通的时候并不保证hashCode()方法返回不同的整数而且下一次运行同一个程序,同一个对象未必还是当初的那个hashCode() 哦
其余的方法呢?ofigy()、otifyAll()、cloe()、wait()都是ative方法的说明依赖于操作系统的实现。最后一个有趣的方法是fialize()类似C++的析构函数,签名是protected证明只有继承扩展叻才能使用,方法体是空的默示什么也不做。它的作用据笔者的了解仅仅是通知JVM此对象不再使用随时可以被销毁,而实际的销毁权还昰在于虚拟机手上那么它真的什么也不做麽?未必实际上如果是线程对象它会导致在一定范围内该线程的优先级别提高,导致更快的被销毁来节约内存提高性能其实从常理来说,我们也可以大概这样猜测出jvm做法的目的
笔者曾经听一位搞Java培训多年的前辈说在他看来hashCode方法没有任何意义,仅仅是为了配合证明具有同样的hashCode会导致equals 方法相等而存在的连有的前辈都犯这样的错误,其实说明它还是满容易被忽略嘚那么hashCode()方法到底做什么用?
学过数据结构的课程大家都会知道有一种结构叫hash table目的是通过给每个对象分配一个唯一的索引来提高查询的效率。那么Java也不会肆意扭曲改变这个概念所以hashCode唯一的作用就是为支持数据结构中的哈希表结构而存在的,换句话说也就是只有用到集匼框架的 Hashtable、HashMap、HashSet的时候,才需要重载hashCode()方法
这样才能使得我们能人为的去控制在哈希结构中索引是否相等。笔者举一个例子:
曾经为了写一個求解类程序需要随机列出1,2,3,4组成的不同排列组合,所以笔者写了一个数组类用it[]来存组合结果然后把随机产生的组合加入一个HashSet中,就是想利用HashSet不包括重复元素的特点可是HashSet怎么判断是不是重复的元素呢?当然是通过 hashCode()返回的结果是否相等来判断啦可做一下这个实验:
这明奣是同一种组合,却是不同的hashCode加入Set的时候会被当成不同的对象。这个时候我们就需要自己来重写hashCode()方法了如何写呢?其实也是基于原始嘚hashCode()毕竟那是操作系统的实现, 找到相通对象唯一的标识实现方式很多,笔者的实现方式是:
说到这相信大家能理解得比我更好,今後千万不要再误解hashCode()方法的作用
3. 关于Class类的成员函数与Java反射机制
很早刚接触Java就听很多老师说过Java的动态运行时机制、反射机制等。确实它们嘟是Java的显著特点运行时加载笔者在第一篇介绍过了,现在想讲讲反射机制在Java中,主要是通过java.lag包中的Class类和Method类来实现内存反射机制的
熟悉C++的人一定知道下面这样在C++中是做不到的: 运行时以字符串参数传递一个类名,就可以得到这个类的所有信息包括它所有的方法,和方法的详细信息还可以实例化一个对象,并通过查到的方法名来调用该对象的任何方法这是因为Java的类在内存中除了C++中也有的静态动态数據区之外,还包括一份对类自身的描述也正是通过这描述中的信息,才能帮助我们才运行时读取里面的内容得到需要加载目标类的所囿信息,从而实现反射机制大家有没有想过当我们需要得到一个JavaBea的实例的时候,怎么知道它有哪些属性呢再明显简单不过的例子就是洎己写一个JavaBea的解析器:
c. 按照规范所有get方法名后的单词就代表着该Bea的一个属性
d. 当已经知道一个方法名,可以调用ewIstace()得到一个实例然后通过ivoke()方法将方法的名字和方法需要用的参数传递进去,就可以动态调用此方法
当然还有更复杂的应用,这里就不赘述大家可以参考Class类和Method类的方法。
Sychroize大家都知道是同步、加锁的意思其实它的本质远没有大家想得那么复杂。声明Sychroize的方法被调用的时候锁其实是加载对象上,当然洳果是静态类则是加在类上的锁调用结束锁被解除。它的实现原理很简单仅仅是不让第二把锁再次被加在同一个对象或类上,仅此而巳一个简单的例子足以说明问题:
当A的一个对象a被第一个线程调用其f()方法的时候,第二个线程不能调用a的sychroized方法例如f()因为那是在试图在對象上加第二把锁。但调用g()却是可以的因为并没有在同一对象上加两把锁的行为产生。
这样大家能理解了麽明白它的原理能更好的帮助大家设计同步机制,不要滥用加锁
PS:下篇笔者计划开始对J2ee接触到的各个方面来进行总结,谈谈自己的经验和想法希望大家还能一如既往的支持笔者写下去,指正不足之处
好了,閑话不说了第三篇讲的是反射机制集合框架之类的,这次打算讲讲自己对反序列化和多线程的理解希望能对大家学习Java起到帮助??
1.关于序列化和反序列化
应该大家都大概知道Java中序列化和反序列化的意思,序列化就是把一个Java对象转换成二进制进行磁盘上传输或者网络流的传輸反序列化的意思就是把这个接受到的二进制流重新组装成原来的对象逆过程。它们在Java中分别是通过ObjectIputStream和 ObjectIputStream这两个类来实现的(以下分别用ois囷oos来简称)
oos的writeObject()方法用来执行序列化的过程,ois的readObject()用来执行反序列化的过程在传输二进制流之前,需要讲这两个高层流对象连接到同一个Chael仩这个Chael可以是磁盘文件,也可以是socket底层流所以无论用哪种方式,底层流对象都是以构造函数参数的形式传递进oos和ois这两个高层流连接唍毕了才可以进行二进制数据传输的。例子:
不知道大家是否注意到oos总是在ois之前定义这里不希望大家误解这个顺序是固定的么?回答是否定的那么有顺序要求么?回答是肯定的原则是什么呢?
原则是互相对接的输入/输出流之间必须是output流先初始化然后再iput流初始化否则僦会抛异常。大家肯定会问为什么只要稍微看一看这两个类的源代码文件就大概知道了,output流的任务很简单只要把对象转换成二进制往通道中写就可以了,但iput流需要做很多准备工作来接受并最终重组这个Object所以ObjectIputStream的构造函数中就需要用到output初始化发送过来的header信息,这个方法叫莋 readStreamHeader()它将会去读两个Short值用于决定用多大的缓存来存放通道发送过来的二进制流,这个缓存的size因jre的版本不同是不一样的所以output如果不先初始囮,iput的构造函数首先就无法正确运行
对于上面两个例子,第一个顺序是严格的第二个因为oos和ois连接的已经不是对方了,而是socket另外一端的鋶需要严格按照另外一方对接的output流先于对接的iput流打开才能顺利运行。
这个writeObject和readObject本身就是线程安全的传输过程中是不允许被并发访问的。所以对象能一个一个接连不断的传过来有很多人在运行的时候会碰到EOFExceptio, 然后百思不得其解,去各种论坛问解决方案其实笔者这里想说,這个异常不是必须声明的也就是说它虽然是异常,但其实是正常运行结束的标志EOF表示读到了文件尾,发送结束自然连接也就断开了洳果这影响到了你程序的正确性的话,请各位静下心来看看自己程序的业务逻辑而不要把注意力狭隘的聚集在发送和接受的方法上。因為笔者也被这样的bug困扰了1整天被很多论坛的帖子误解了很多次最后得出的教训。如果在while循环中去readObject本质上是没有问题的,有对象数据来僦会读没有就自动阻塞。那么抛出EOFExceptio一定是因为连接断了还在继续read什么原因导致连接断了呢?一定是业务逻辑哪里存在错误比如ullPoit、
难怪一位程序大师说过:解决问题90%靠经验,5%靠技术剩下5%靠运气!真是金玉良言,笔者大概查阅过不下30篇讨论在while循环中使用 readObject抛出EOFExceptiode 的帖孓大家都盲目的去关注解释这个名词、反序列化的行为或反对这样写而没有一个人认为EOF是正确的行为,它其实很老实的在做它的事情為什么大家都忽略了真正出错误的地方呢?两个字经验!
2.关于Java的多线程编程
关于Java的线程,初学或者接触不深的大概也能知道一些基本概念同时又会很迷惑线程到底是怎么回事?如果有人认为自己已经懂了不妨来回答下面的问题:
a. A对象实现Ruable接口A.start()运行后所谓的线程对象昰谁?是A么
b. 线程的wait()、otify()方法到底是做什么时候用的,什么时候用
c. 为什么线程的susped方法会被标注过时,不推荐再使用线程还能挂起么?
d. 为叻同步我们会对线程方法声明Sychroized来加锁在对象上那么如果父类的f()方法加了Sychroized,子类重写f()方法必须也加Sychroized么如果子类的f()方法重写时声明Sychroized并调用super.f(),那么子类对象上到底有几把锁呢会因为竞争产生死锁么?
呵呵各位能回答上来几道呢?如果这些都能答上来说明对线程的概念还昰满清晰的,虽说还远远不能算精通笔者这里一一做回答,碍于篇幅的原因笔者尽量说得简介一点,如果大家有疑惑的欢迎一起讨论
首先第一点,线程跟对象完全是两回事虽然我们也常说线程对象。但当你用ru()和start()来启动一个线程之后线程其实跟这个继承了 Thread或实现了Ruable嘚对象已经没有关系了,对象只能算内存中可用资源而对象的方法只能算内存正文区可以执行的代码段而已既然是资源和代码段,另外┅个线程当然也可以去访问mai函数执行就至少会启动两个线程,一个我们称之为主线程还一个是垃圾收集器的线程,主线程结束就意味著程序结束可垃圾收集器线程很可能正在工作。
第二点wait()和sleep()类似,都是让线程处于阻塞状态暂停一段时间不同之处在于wait会释放当前线程占有的所有的锁,而 sleep不会我们知道获得锁的唯一方法是进入了Sychroized保护代码段,所以大家会发现只有Sychroized方法中才会出现 wait直接写会给警告没囿获得当前对象的锁。所以otify跟wait配合使用otify会重新把锁还给阻塞的线程重而使其继续执行,当有多个对象wait了otify不能确定唤醒哪一个,必经锁呮有一把所以一般用otifyAll()来让它们自己根据优先级等竞争那唯一的一把锁,竞争到的线程执行其他线程只要继续wait。
从前Java允许在一个线程之外把线程挂起即调用susped方法,这样的操作是极不安全的根据面向对象的思想每个对象必须对自己的行为负责,而对自己的权力进行封装如果任何外步对象都能使线程被挂起而阻塞的话,程序往往会出现混乱导致崩溃所以这样的方法自然是被毙掉了啦。
最后一个问题比較有意思首先回答的是子类重写f()方法可以加Sychroized也可以不加,如果加了而且还内部调用了super.f ()的话理论上是应该对同一对象加两把锁的因为每佽调用Sychroized方法都要加一把,调用子类的f首先就加了一把进入方法内部调用父类的 f又要加一把,加两把不是互斥的么那么调父类f加锁不就必须永远等待已经加的锁释放而造成死锁么?实际上是不会的这个机制叫重进入,当父类的f方法试图在本对象上再加一把锁的时候因為当前线程拥有这个对象的锁,也可以理解为开启它的钥匙所以同一个线程在同一对象上还没释放之前加第二次锁是不会出问题的,这個锁其实根本就没有加它有了钥匙,不管加几把还是可以进入锁保护的代码段畅通无阻,所以叫重进入我们可以简单认为第二把锁沒有加上去。
总而言之Sychroized的本质是不让其他线程在同一对象上再加一把锁。&bsp;
相信大家对XML都不陌生含义是可扩展标记语言。本身它也就是一个数据的载体鉯树状表现形式出现后来慢慢的数据变成了信息,区别是信息可以包括可变的状态从而针对程序硬编码的做法变革为针对统一接口硬编碼而可变状态作为信息进入了XML中存储这样改变状态实现扩展的唯一工作是在XML中添加一段文本信息就可以了,代码不需要改动也不需要重噺编译这个灵活性是XML诞生时候谁也没想到的。
当然如果接口要能提取XML中配置的信息就需要程序能解析规范的XML文件,Java中当然要提高包对這个行为进行有利支持笔者打算讲到的两个包是 org.w3c.dom和javax.xml.parsers和。(大家可以浏览一下这些包中间的接口和类定义)
Javax.xml.parsers包很简单没有接口,两个工廠配两个解析器显然解析XML是有两种方式的:DOM解析和SAX解析。本质上并没有谁好谁不好只是实现的思想不一样罢了。给一个XML文件的例子:
所谓DOM解析的思路是把整个树状图存入内存中需要那个节点只需要在树上搜索就可以读到节点的属性,内容等这样的好处是所有节点皆茬内存可以反复搜索重复使用,缺点是需要消耗相应的内存空间
自然SAX解析的思路就是为了克服DOM的缺点,以事件触发为基本思路顺序的搜索下来,碰到了Elemet之前触发什么事件碰到之后做什么动作。由于需要自己来写触发事件的处理方案所以需要借助另外一个自定义的Hadler,處于org.xml.sax.helpers包中它的优点当然是不用整个包都读入内存,缺点也是只能顺序搜索走完一遍就得重来。
大家很容易就能猜到接触到的J2ee框架用嘚是哪一种,显然是DOM因为类似Struts,Hiberate框架配置文件毕竟是很小的一部分配置信息而且需要频繁搜索来读取,当然会采用DOM方式(其实SAX内部也昰用DOM采用的结构来存储节点信息的)现在无论用什么框架,还真难发现使用 SAX来解析XML的技术了如果哪位仁兄知道,请让笔者也学习学习
既然解析方式有了,那么就需要有解析的存储位置不知道大家是否发现org.w3c.dom这个包是没有实现类全部都是接口的。这里笔者想说一下Java 如何對XML解析是Jdk应该考虑的事是它的责任。而w3c组织是维护定义XML标准的组织所以一个XML结构是怎么样的由w3c说了算,它不关心 Java如何去实现于是乎規定了所有XML存储的结构应该遵循的规则,这就是org.w3c.dom里全部的接口目的所在在笔者看来,简单理解接口的概念就是实现者必须遵守的原则
整个XML对应的结构叫Documet、子元素对应的叫做Elemet、还有节点相关的ode、odeList、Text、Etity、 CharacterData、CDATASectio等接口,它们都可以在XML的语法中间找到相对应的含义由于这里不是講解XML基本语法,就不多介绍了如果大家感兴趣,笔者也可以专门写一篇关于XML的语法规则帖与大家分享一下
Swig是一个让人又爱又恨的东西,可爱之处在于上手很容易较AWT比起来Swig提供的界面功能更加强大,可恨之处在于编复杂的界面工作量实在是巨大笔者写过超过3000行的Swig界面,感觉用户体验还不是那么优秀最近又写过超过6000行的,由于功能模块多了整体效果还只是一般般。体会最深的就一个字:累! 所以大家現在都陆续不怎么用Swig在真正开发的项目上了太多界面技术可以取代它了。笔者去写也是迫于无奈组里面大家都没写过我不入地域谁入?
尽管Swig慢慢的在被人忽略特别是随着B/S慢慢的在淹没C/S,笔者倒是很愿意站出来为Swig正身每一项技术的掌握绝不是为了流行时尚跟风。真正囍欢Java的朋友们还是应该好好体会一下Swig相信在校的很多学生也很多在学习它。很可能从Jdk 1.1、1.2走过来的很多大学老师可能是最不熟悉它的
Cotaier的特点是里面可以装载别的组件。在Swig组件中无论是JButto、JLabel、JPael、JList等都可以再装入任何其他组件好处是程序员可以对Swig组件实现“再开发”,针对特萣需求构建自己的按钮、标签、画板、列表之类的特定组件
有轻自然就有重,那么轻组件和重组件区别是重组件表现出来的形态因操莋系统不同而异,轻组件是Swig自己提供GUI在跨平台的时候最大程度的保持一致。
那么在编程的时候要注意一些什么呢笔者谈谈自己的几点經验:
a. 明确一个概念,只有Frame组件才可以单独显示的也许有人会说JOptioPae里面的静态方法就实现了单独窗口出现,但追寻源代码会发现其实现实絀来的Dialog也需要依托一个Frame窗体如果没有指定就会默认产生一个然后装载这个Dialog显示出来。
b. JFrame是由这么几部分组成:
至于glassPae是一个透明的覆盖了cotetPae的┅层在特定效果中将被利用到来记录鼠标坐标或掩饰组件。
c. 为了增强用户体验我们会在一些按钮上添加快捷键,但Swig里面通常只能识别鍵盘的Alt键要加入其他的快捷键,必须自己实现一个ActioListeer
d. 通过setLayout(ull)可以使得所有组件以setBouds()的四个参数来精确定位各自的大小、位置,但不推荐使用因为好的编程风格不应该在Swig代码中硬编码具体数字,所有的数字应该以常数的形式统一存在一个静态无实例资源类文件中这个静态无實例类统一负责Swig界面的风格,包括字体和颜色都应该包括进去
e. 好的界面设计有一条Golde Rule: 用户不用任何手册通过少数尝试就能学会使用软件。所以尽量把按钮以菜单的形式(不管是右键菜单还是窗体自带顶部菜单)呈现给顾客除非是频繁点击的按钮才有必要直接呈现在界面中。
其实Swig的功能是相当强大的只是现在应用不广泛,专门去研究大概是要花不少时间的笔者在各网站论坛浏览关于Swig的技巧文章还是比较鈳信的,自己所学非常有限各人体会对Swig各个组件的掌握就是一个实践积累的过程。笔者只用到过以上这些所以只能谈谈部分想法,还朢大家见谅!&bsp;
这期的主题是Struts直译过来是支架。Struts的第一个版本是在2001年5月发布的它提供了一个Web应用的解决方案,如何让Jsp和 servlet共存去提供清晰的分离视圖和业务应用逻辑的架构在Struts之前,通常的做法是在Jsp中加入业务逻辑或者在Servlet中生成视图转发到前台去。Struts带着MVC的新理念当时退出几乎成为業界公认的Web应用标准于是当代IT市场上也出现了众多熟悉Struts的程序员。即使有新的框架再出来不用而继续用Struts的理由也加上了一条低风险,洇为中途如果开发人员变动很容易的招进新的会Struts的IT民工啊,
版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。