JAVA是解释型语言还是编译型语言

 

JAVA是解释型语言还是编译型语言

 

JAVA是解释型语言还是编译型语言

概念:

  • 编译型语言:把做好的源程序全部编译成二进制代码的可运行程序。然后,可直接运行这个程序。
  • 解释型语言:把做好的源程序翻译一句,然后执行一句,直至结束!

 

区别:

  • 编译型语言,执行速度快、效率高;依赖编译器、跨平台性差些。如C、C++、Delphi、Pascal,Fortran。
  • 解释型语言,执行速度慢、效率低;依赖解释器、跨平台性好。如Java、Basic.

 

通俗的讲,编译语言是在编译后可以直接运行,而解释语言的执行需要一个解释环境。

 java很特殊,java程序也需要编译,但是没有直接编译称为机器语言,而是编译称为字节码,然后用解释方式执行字节码。

JIT:

  • 首先采用编译形式生成某种中介代码(Java bytecode/MSIL),然后在运行时将其(通常以函数或Block为单位)最终转换成机器码,然后执行,转化的机器码可以被cache,以提高重复执行的效率

动态语言和静态语言

 

1.动态语言Dynamically Typed Language

例如:ECMAScript(JavaScript)、Ruby、Python、VBScript、php

也叫动态类型定义语言

与静态类型定义相反,一种在执行期间才去发现数据类型的语言,

动态语言是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化。

动态语言的类型检查是在运行时做的。

它的优点是方便阅读,不需要写非常多的类型相关的代码;

缺点是不方便调试,命名不规范时会造成读不懂,不利于理解等。

目前java平台下的动态语言有Groovy、nice、BeanShell、Jython、JRuby、Rhino(JavaScript)、Jacl(TCL)、Bistro(SmallTalk)、Kawa(Lisp/Schema),真是越来越多了。java下这么多的动态语言建议选择Groovy,感觉血统较为正宗,兼容Java的语法,java程序员学习起来较为容易,上手较快。

2.静态语言Statically Typed Language

例如:C、C++、Java

也叫静态类型定义语言。即一种在编译时,数据类型是固定的语言。大多数静态类型定义语言强制这一点,它要求你在使用所有变量之前要声明它们的数据类型。

在使用数据之前,我们必须首先定义数据类型,这些数据类型包括int ,float,double等等。就相当于在使用它们之前,首先要为它们分配好内存空间。

静态类型语言的主要优点在于其结构非常规范,便于调试,方便类型安全;

缺点是为此需要写更多的类型相关代码,导致不便于阅读、不清晰明了。

3.强类型定义语言

一种总是强制类型定义的语言。Java和Python是强制类型定义的。如果你有一个整数,如果不显示地进行转换,你不能将其视为一个字符串

4.弱类型定义语言

一种类型可以被忽略的语言,与强类型定义相反。VBScript是弱类型定义

的。在VBScript中,可以将字符串 ’12′ 和整数 3 进行连接得到字符串 ’123′,

然后可以把它看成整数 123,而不需要显示转换。

5.脚本语言

脚本语言代表一套与系统程序设计语言不同的协定。

它们牺牲执行速度和与系统程序设计语言相关的类型长度而提供更高的编程创作力和软件重用。

脚本语言更适合在联系复杂的应用程序中进行胶着。

为了简化连接组件的工作,脚本语言被设计为无类型的,脚本语言一般是面向字符的,因为字符为许多不同的事物提供了一致的描述。

事实上,脚本语言都是动态语言,而动态语言都是解释型语言,不管它们是不是面向对象。

ASCII,Unicode和UTF-8 字符编码问题

 

ASCII,Unicode和UTF-8

ASCII码

  • 我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出 256种状态,这被称为一个字节(byte)。
  • 也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从 0000000到11111111。
  • 上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。
  • ASCII码一共规定了128个字符的编码,比如空格“SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。

非ASCII编码

  • 英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。 于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使 用的编码体系,可以表示最多256个符号。
  • 但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码 中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0—127表示的符号是一样的,不一样的只是128—255的这一段。
  • 至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。 比如,简体中文常见的编码方式是GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示256×256=65536个符号。
  • 中文编码的问题需要专文讨论,这篇笔记不涉及。这里只指出,虽然都是用多个字节表示一个符号,但是GB类的汉字编码与后文的Unicode和UTF-8是毫无关系的。

Unicode

  • 正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。
  • 可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是Unicode,就像它的名字都表示的,这是一种所有符号的编码。
  • Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字“严”。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表。

Unicode的问题

  • 需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。
  • 比如,汉字“严”的unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。
  • 这里就有两个严重的问题,第一个问题是,如何才能区别unicode和ascii?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号 呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必 然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。
  • 它们造成的结果是:1)出现了unicode的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示unicode。2)unicode在很长一段时间内无法推广,直到互联网的出现。

UTF-8

  • 互联网的普及,强烈要求出现一种统一的编码方式。UTF-8就是在互联网上使用最广的一种unicode的实现方式。其他实现方式还包括UTF-16和UTF-32,不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8是Unicode的实现方式之一。
  • UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
  • UTF-8的编码规则很简单,只有二条:
  • 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
  • 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
  • 下表总结了编码规则,字母x表示可用编码的位。

Unicode符号范围 | UTF-8编码方式

(十六进制) | (二进制)

——————–+———————————————

0000 0000-0000 007F | 0xxxxxxx

0000 0080-0000 07FF | 110xxxxx 10xxxxxx

0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx

0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

  • 下面,还是以汉字“严”为例,演示如何实现UTF-8编码。
  • 已知“严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是 “11100100 10111000 10100101”,转换成十六进制就是E4B8A5。

Unicode与UTF-8之间的转换

  • 通过上一节的例子,可以看到“严”的Unicode码是4E25,UTF-8编码是E4B8A5,两者是不一样的。它们之间的转换可以通过程序实现。
  • 在Windows平台下,有一个最简单的转化方法,就是使用内置的记事本小程序Notepad.exe。打开文件后,点击“文件”菜单中的“另存为”命令,会跳出一个对话框,在最底部有一个“编码”的下拉条。
  • 里面有四个选项:ANSI,Unicode,Unicode big endian 和 UTF-8。
  • ANSI是默认的编码方式。对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版会采用Big5码)。
  • Unicode编码指的是UCS-2编码方式,即直接用两个字节存入字符的Unicode码。这个选项用的little endian格式。
  • Unicode big endian编码与上一个选项相对应。我在下一节会解释little endian和big endian的涵义。
  • UTF-8编码,也就是上一节谈到的编码方法。
  • 选择完”编码方式“后,点击”保存“按钮,文件的编码方式就立刻转换好了。

Little endian和Big endian

  • 上一节已经提到,Unicode码可以采用UCS-2格式直接存储。以汉字”严“为例,Unicode码是4E25,需要用两个字节存储,一个字节 是4E,另一个字节是25。存储的时候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。
  • 这两个古怪的名称来自英国作家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战,战争起因是人们争论,吃鸡蛋时究竟是从大头(Big- Endian)敲开还是从小头(Little-Endian)敲开。为了这件事情,前后爆发了六次战争,一个皇帝送了命,另一个皇帝丢了王位。
  • 因此,第一个字节在前,就是”大头方式“(Big endian),第二个字节在前就是”小头方式“(Little endian)。
  • 那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?
  • Unicode规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做”零宽度非换行空格“(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。这正好是两个字节,而且FF比FE大1。
  • 如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

实例

  • 下面,举一个实例。
  • 打开”记事本“程序Notepad.exe,新建一个文本文件,内容就是一个”严“字,依次采用ANSI,Unicode,Unicode big endian 和 UTF-8编码方式保存。
  • 然后,用文本编辑软件UltraEdit中的”十六进制功能“,观察该文件的内部编码方式。
  • ANSI:文件的编码就是两个字节“D1 CF”,这正是“严”的GB2312编码,这也暗示GB2312是采用大头方式存储的。
  • Unicode:编码是四个字节“FF FE 25 4E”,其中“FF FE”表明是小头方式存储,真正的编码是4E25。
  • Unicode big endian:编码是四个字节“FE FF 4E 25”,其中“FE FF”表明是大头方式存储。
  • UTF-8:编码是六个字节“EF BB BF E4 B8 A5”,前三个字节“EF BB BF”表示这是UTF-8编码,后三个“E4B8A5”就是“严”的具体编码,它的存储顺序与编码顺序是一致的。

java学习资源

给大家分享点Java学习资源:

1、 http://java.sun.com/ (英文)
Sun的Java网站,是一个应该经常去看的地方。不用多说。

2、http://www.ibm.com/developerworks/cn/java/
关于 Java 标准和技术的文章、教程和其他技术资源
IBM的developerWorks网站,英语好的直接去英文主站点看。这里不但是一个极好的面向对象的分析设计网站,也是Web Services,Java,Linux极好的网站。强烈推荐!!!

3、http://www.javaworld.com/ (英文)
关于Java很多新技术的讨论和新闻。想多了解Java的方方面面的应用,这里比较好。

4、http://dev2dev.bea.com.cn/index.jsp
BEA的开发者园地,BEA作为最重要的App Server厂商,有很多独到的技术,在Weblogic上做开发的朋友不容错过。

5、http://www.huihoo.com/
灰狐动力网站,一个专业的中间件网站,虽然不是专业的Java网站,但是在J2EE企业应用技术方面有深厚的造诣。

6、http://www.theserverside.com/home/ (英文)
TheServerSide是一个著名的专门面向Java Server端应用的网站。

7、http://www.javaresearch.org/
Java研究组织,有很多优秀的Java方面的文章和教程,特别是在JDO方面的文章比较丰富。

8、http://www.cnjsp.org/
JSP技术网站,有相当多的Java方面的文章和资源。

9、http://www.jdon.com/
Jdon论坛,是一个个人性质的中文J2EE专业技术论坛,在众多的Java的中文论坛中,Jdon一个是技术含量非常高,帖子质量非常好的论坛。

10、http://sourceforge.net/
SourgeForge是一个开放源代码软件的大本营,其中也有非常非常丰富的Java的开放源代码的著名的软件。

11、http://www.chinajavaworld.com
java中文世界论坛

12、http://www.infoq.com/cn/
是一个时刻关注企业软件开发领域变化与创新的在线独立社区,读者受众群主要为技术架构师、技术团队带头人(高级开发人员)和项目经理等。

13、http://www.oschina.net/
OSChina.NET 找到您想要的开源软件,分享和交流

Java学习杂谈(十三)--ORM

这是最后一篇Java杂谈了,以ORM框架的谈论收尾,也算是把J2ee的最后一方面给涵盖到了,之所以这么晚才总结出ORM这方面,一是笔者这两周比较忙,另一方面也想善始善终,仔细的先自己好好研究一下ORM框架技术,不想草率的敷衍了事。  

        其实J2ee的规范指南里面就已经包括了一些对象持久化技术,例如JDO(Java       Data       Object)就是Java对象持久化的新规范,一个用于存取某种数据仓库中的对象的标准化API,提供了透明的对象存储,对开发人员来说,存储数据对象完全不需要额外的代码(如JDBC       API的使用)。这些繁琐的工作已经转移到JDO产品提供商身上,使开发人员解脱出来,从而集中时间和精力在业务逻辑上。另外,JDO很灵活,因为它可以在任何数据底层上运行。JDBC只是面向关系数据库(RDBMS)JDO更通用,提供到任何数据底层的存储功能,比如关系数据库、文件、XML以及对象数据库(ODBMS)等等,使得应用可移植性更强。我们如果要理解对象持久化技术,首先要问自己一个问题:为什么传统的JDBC来持久化不再能满足大家的需求了呢?  

        笔者认为最好是能用JDBC真正编写过程序了才能真正体会ORM的好处,同样的道理,真正拿Servlet/Jsp做过项目了才能体会到Struts、 Spring等框架的方便之处。很幸运的是笔者这两者都曾经经历过,用混乱的内嵌Java代码的Jsp加Servlet转发写过完整的Web项目,也用 JDBC搭建过一个完整C/S项目的后台。所以现在接触到新框架才更能体会它们思想和实现的优越之处,回顾从前的代码,真是丑陋不堪啊。^_^  

        回到正题,我们来研究一下为什么要从JDBC发展到ORM。简单来说,传统的JDBC要花大量的重复代码在初始化数据库连接上,每次增删改查都要获得 Connection对象,初始化Statement,执行得到ResultSet再封装成自己的List或者Object,这样造成了在每个数据访问方法中都含有大量冗余重复的代码,考虑到安全性的话,还要加上大量的事务控制和log记录。虽然我们学习了设计模式之后,可以自己定义Factory来帮助减少一部分重复的代码,但是仍然无法避免冗余的问题。其次,随着OO思想深入人心,连典型的过程化语言Perl等都冠冕堂皇的加上了OO的外壳,何况是 Java中繁杂的数据库访问持久化技术呢?强调面向对象编程的结果就是找到一个桥梁,使得关系型数据库存储的数据能准确的映射到Java的对象上,然后针对Java对象来设计对象和方法,如果我们把数据库的Table当作Class,Record当作Instance的话,就可以完全用面向对象的思想来编写数据层的代码。于是乎,Object       Relationship       Mapping的概念开始普遍受到重视,尽管很早很早就已经有人提出来了。  

        缺点我们已经大概清楚了,那么如何改进呢?对症下药,首先我们要解决的是如何从Data       Schema准备完美的映射到Object       Schema,另外要提供对数据库连接对象生命周期的管理,对事务不同粒度的控制和考虑到扩展性后提供对XML、Properties等可配置化的文件的支持。到目前为止,有很多框架和技术在尝试着这样做。例如似乎是封装管理得过了头的EJB、很早就出现目前已经不在开发和升级了的Apache       OJB、首先支持Manual       SQL的iBATIS,还有公认非常优秀的Hibernate等等。在分别介绍它们之前,我还想反复强调这些框架都在试图做什么:  

        毕竟Java       Object和数据库的每一条Record还是有很大的区别,就是类型上来说,DB是没有Boolean类型的。而Java也不得不用封装类(Integer、Double等)为了能映射上数据库中为null的情况,毕竟Primitive类型是没有null值的。还有一个比较明显的问题是,数据库有主键和外键,而Java中仍然只能通过基本类型来对应字段值而已,无法规定Unique等特征,更别提外键约束、事务控制和级联操作了。另外,通过Java       Object预设某Field值去取数据库记录,是否在这样的记录也是不能保证的。真的要设计到完全映射的话,Java的Static被所有对象共享的变量怎么办?在数据库中如何表现出来……  
我们能看到大量的问题像一座座大山横在那些框架设计者们面前,他们并不是没有解决办法,而是从不同的角度去考虑,会得到很多不同的解决方案,问题是应该采取哪一种呢?甚至只有等到真正设计出来了投入生产使用了,才能印证出当初的设想是否真的能为项目开发带来更多的益处。笔者引用一份文档中提到一个健壮的持久化框架应该具有的特点:  
        A       robust       persistence       layer       should       support—-  
        1.   Several       types       of       persistence       mechanism  
        2.   Full       encapsulation       of       the       persistence       mechanism.  
        3.   Multi-object       actions  
        4.   Transactions       Control  
        5.   Extensibility  
        6.   Object       identifiers  
        7.   Cursors:       logical       connection       to       the       persistence       mechanism  
        8.   Proxies:       commonly       used       when       the       results       of       a       query       are       to       be       displayed       in       a       list  
        9.   Records:     avoid     the     overhead       of       converting       database       records       to       objects       and       then       back       to       records  
        10.   Multi       architecture  
        11.   Various       database       version       and/or       vendors  
        12.   Multiple       connections  
        13.   Native       and       non-native       drivers  
        14.   Structured       query       language       queries(SQL)  

        现在来简短的介绍一下笔者用过的一些持久化框架和技术,之所以前面强调那么多共通的知识,是希望大家不要盲从流行框架,一定要把握它的本质和卓越的思想好在哪里。   

        1.   Apache       OJB  
        OJB代表Apache       Object       Relational       Bridge,是Apache开发的一个数据库持久型框架。它是基于J2ee规范指南下的持久型框架技术而设计开发的,例如实现了ODMG       3.0规范的API,实现了JDO规范的API,       核心实现是Persistence       Broker       API。OJB使用XML文件来实现映射并动态的在Metadata       layer听过一个Meta-Object-Protocol(MOP)来改变底层数据的行为。更高级的特点包括对象缓存机制、锁管理机制、 Virtual       代理、事务隔离性级别等等。举个OJB       Mapping的简单例子ojb-repository.xml:  

         
                                    jdbc-type=”INTEGER”       primarykey=”true”       autoincrement=”true”/>  

                 
       

       
                                jdbc-type=”INTEGER”       primarykey=”true”       autoincrement=”true”/>  

                 
                               
                 
                         
               
 
       

      2.   iBATIS  
      iBATIS最大的特点就是允许用户自己定义SQL来组配Bean的属性。因为它的SQL语句是直接写入XML文件中去的,所以可以最大程度上利用到 SQL语法本身能控制的全部特性,同时也能允许你使用特定数据库服务器的额外特性,并不局限于类似SQL92这样的标准,它最大的缺点是不支持枚举类型的持久化,即把枚举类型的几个对象属性拼成与数据库一个字段例如VARCHAR对应的行为。这里也举一个Mapping文件的例子sqlMap.xml:  
         
             

             
                     
                     
                     
           
 

             

             
                Update       Tests       set       Name=#name#,       Date=”date”       where       TestId=#testId#  
           
 
         

      3.   Hibernate  
      Hibernate无疑是应用最广泛最受欢迎的持久型框架,它生成的SQL语句是非常优秀。虽然一度因为不能支持手工SQL而性能受到局限,但随着新一代 Hibernate       3.x推出,很多缺点都被改进,Hibernate也因此变得更加通用而时尚。同样先看一个Mapping文件的例子customer.hbm.xml来有一个大概印象:  

       
               
               
                       
                                Customers_CustomerId_Seq    
                     
 
           
 

             
             

           
                   
                           
         
 
 
          …  
           

     

        Hibernate有很多显著的特性,最突出的就是它有自己的查询语言叫做HQL,在HQL中select       from的不是Table而是类名,一方面更加面向对象,另外一方面通过在hibernate.cfg.xml中配置Dialect为HQL可以使得整个后台与数据库脱离耦合,因为不管用那种数据库我都是基于HQL来查询,Hibernate框架负责帮我最终转换成特定数据库里的SQL语句。另外 Hibernate在Object-Caching这方面也做得相当出色,它同时管理两个级别的缓存,当数据被第一次取出后,真正使用的时候对象被放在一级缓存管理,这个时候任何改动都会影响到数据库;而空闲时候会把对象放在二级缓存管理,虽然这个时候与数据库字段能对应上但未绑定在一起,改动不会影响到数据库的记录,主要目的是为了在重复读取的时候更快的拿到数据而不用再次请求连接对象。其实关于这种缓存的设计建议大家研究一下Oracle的存储机制(原理是相通的),Oracle牺牲了空间换来时间依赖于很健壮的缓存算法来保证最优的企业级数据库访问速率。  

        以上是一些Mapping的例子,真正在Java代码中使用多半是继承各个框架中默认的Dao实现类,然后可以通过Id来查找对象,或者通过 Example来查找,更流行的是更具Criteria查找对象。Criteria是完全封装了SQL条件查询语法的一个工具类,任何一个查询条件都可以在Criteria中找到方法与之对应,这样可以在Java代码级别实现SQL的完全控制。另外,现在许多ORM框架的最新版本随着JDk       5.0加入Annotation特性都开始支持用XDoclet来自动根据Annotation来生成XML配置文件了。  

        笔者不可能详细的讲解每一个框架,也许更多的人在用Hibernate,笔者是从OJB开始接触ORM技术的,它很原始却更容易让人理解从JDBC到 ORM的过渡。更多的细节是可以从官方文档和书籍中学到的,但我们应该更加看中它们设计思想的来源和闪光点,不是盲从它们的使用方法。  

        到这里全部Java杂谈这个主题就正式结束了,笔者也可以长叹一口气,拿到毕设题目后也该开始忙自己的毕业设计了。最近看了很多Spring       AOP的资料,实习下班回家还会研究Ajax和极限编程,如果有时间了话,会把自己的学习笔记拿出来分享的。衷心希望大家都能不断的进步,在喜欢的道路上不回头的走下去……^_^

Java学习杂谈(十二)--JVM

本来这次应该讲讲ORM的几个框架,但是笔者还没有完全总结出来,所以这里先插入一次学习JVM的心得。作为一个Java程序员,如果不了解JVM的工作原理,就很难从底层去把握Java语言和Java程序的运作机制。这里先推荐一个最权威的讲解JVM的文档,大家只要查过Java       API的可以在里面的一个叫“API,       Language,       and       Virtual       Machine       Document”的标题下看到四个子标题,第一个是我们最熟悉的Java       API       Specification,很少会有人注意到第三和第四个子标题,分别是“The       Java       Language       Specification”和“The       Java       Machine       Specification”后面都带有(Download)字样,JVM的那个URL直接链接到http://java.sun.com/docs /books/vmspec/2nd-edition/这里地址。我们可以下载到一份非常权威详细的讲解JVM原理的官方文档。笔者业余时间花了1个星期来阅读,这里把自己的收获跟大家来分享一下,大概从这么几个方面来谈一谈:  

                1.   JVM的实现机制  
                Java虚拟机就是一个小的计算机,有自己的指令集,有自己的文件系统,管理内部的表和数据,负责读取class文件里面字节码,然后转换成不同操作系统的CPU指令,从而使得Java程序在不同的操作系统上顺利的跑起来。所以Window的JVM能把字节码转换成Window系统的指令集,Linux的 JVM能把字节码转换成Linux系统的字节,同理还有Solaris,它们彼此之间是不能通用的。最早一款的原型虽然是Sun公司开发的,但发展到现在其实任何厂商都可以自己去实现一个虚拟机,用来读取字节码转换成OS指令。甚至我们可以认为JVM跟Java编程语言都没有关系,因为你自己哪怕用记事本写一串字节码,也可以让JVM来解析运行,只要你的字节码能通过JVM的验证。  

                JVM的验证其实是很严格的,这里只讲一些有趣的地方。大家还记得Java的图标是一个杯咖啡麽?究其历史我们也许可以查出为什么,但还有更显而易见的方式是JVM怎么判断一个文件是否是class文件?JVM的做法是读取前4个字节转换成16进制数,判断是否等于0xCAFEBABE这个数。注意到这个单词了麽?“cafebabe”,代表着国外一种咖啡品牌,似乎叫做Peet’s       coffee-baristas之类。创造Java的人为了方便记忆,选择了这样一个16进制数作为标准class文件的头,所以任何class文件都必须具有这4个字节的头部。我们可以用DataInput这个接口的实现类来验证一下,读取任何一个class文件的第一个int,int在Java里面是四个字节。转换成16进制一定会是0xcafebabe的。  
                所以这里想告诉大家的是,JVM其实并没有那么神秘,我们完全可以理解它的构造。  

                2.   Java相关的基础概念  
                配合JVM的结构,在Java语言中也会有很多特点比较鲜明的地方。比如对数值计算从来不会检查位溢出。任何变量存储的二进制即使位全部为1了仍然可以加,全部为0了仍然可以减。大家只要稍微测试一下就知道了,看这几个例子:  
                int       max       =       Integer.MAX_VALUE;  
                int       min       =       Integer.MIN_VALUE;  
                max+1       ==       min;   //true  
                min-1       ==       max;                                   //true  
                0.0/0.0   //得到“NaN”(Not       a       number)  
                1/0.0   //Infinity  
                -1/0.0                                                                       //-Infinity  
                1或-1/0   //ArithmeticException唯一的异常情况  

                看完这几个例子,大家是否能更好的把握Java的数值运算呢?Java完全遵照IEEE-754的标准来定义单双精度浮点数以及其他的数值存储方式。  
               
                另外Java里面有一个概念叫做Daemon       Thread(守护线程),知道它的存在主要是为了理解虚拟机的生命周期。当我们运行java命令,从main函数进入的那一刻起,虚拟机就开始启动运行了。Main所在的主线程也会启动起来,它属于非守护线程。与之同时一些守护线程也会同时启动,最典型的守护线程代表就是GC(垃圾收集器)线程。JVM 虚拟机什么时候退出呢?是在所有的非守护线程结束的那一刻,JVM就exit。注意这个时候守护线程并未退出,很可能还要继续完成它的本职工作之后才会结束,但虚拟机的生命周期已经提前于它结束了。  

                3.   JVM内部的基本概念  
                虚拟机内部还有一些概念,全部列举是不现实的,太繁琐也没有意义。除非您真的想自己去做一个JVM。笔者只列举部分概念:  
                首先我们来看一个叫做ReturnAddress的变量,它是JVM用来存储方法出口或者说进行跳转的依据,把任何地址存入这个变量就一定会按照这个地址来跳转。我们需要注意的就是finally有比方法return更高的赋值给ReturnAddress的优先级。同时存在方法return和 finally       return的话,一定是按照finally里面的return为准。  
               
                JVM有自己的Heap,能被所有线程共享,存储着所有的对象,内存是动态被分配的。对于每个线程,拥有自己的Stack,栈里面存储的单位叫做 Frame(桢)。桢里面就记录着零时变量、对象引用地址、方法返回值等数据。JVM还有一个叫做Method       Area的地方,存储着一段一段的可执行代码,每一段就是一个方法体,也能被所有线程共享。所以我们说一个线程其实从run方法跑起来,跟它的类中声明的其他方法是两个概念。因为其他的方法包括的所有的对象,这个时候都充当为资源被线程使用。  

                JVM有自己管理内存的方案,因为它具有文件系统的功能,我们可以看成一个小型的数据库,内部有许许多多不同的表。表的字段可能是另外一张表的地址,也可以直接就是一个存储数据值的地址值。JVM所有对运行时候类的解析验证计算等管理工作,实际上都是在管理这些表的变动,如果我们从数据库的角度来看,JVM所做的就是根据你的代码来操作那么多个表最后返回给你结果的过程。里面的表结构包括class的表、field表、method表、 attribute表等。  

                4.   JVM的指令集  
                JVM有自己的指令集,笔者从前也看过一些计算机组成结构和汇编语言的数,建议大家也稍微看看,了解设计一个高效可用的计算机指令集是多么复杂又多么重要的过程。对于JVM的指令集,职责是管理好Java程序编译出来的字节码,相对而言指令集的名称就多少和Java语言相关了,比如指令集里就有 sastore,、saload表示array里面short的存和取、类似还有d2i表示从double转换成int、monitorenter表示进入synchronized块加锁、getstatic和putstatic表示对静态标量的存取、       jsr和ret等跳转指令……  

                为了便于记忆,设计JVM指令集的人们约定f开头的跟float有关,d跟double有关,i跟int有关,s跟short有关,a跟array有关。有兴趣的可以细读文档里面的每一个指令的作用。因为只是作为初步了解,这里就不多说了。  

                5.   一些Java关键字的实现原理  
                文档还很详细的列举了很多加载、初始化、加锁等操作的过程。笔者觉得比较有用的第一是记住Java里面只有Array不是由ClassLoader加载的对象,其他的对象全部都必须由一个ClassLoader来加载。另外package的概念除了类似于C++的namespace,是一种命名空间之外,底层的实现是规定同一个package下的类必须由同一个类加载器来加载,所以package的概念还可以认为是被同一个类加载器加载的类。  
               
                另外在多线程中,有很多细节值得去体会。每个线程有自己的Working       memory,它们从能被共享的Main       Memory中去读数据、修改、然后再存回去。笔者一直认为线程就是数据库里面事务的前身或者说祖先。我们只要稍微比较一下它们的行为,就会发现很多一致性。事务也是操作被事务共享的表数据,你改完我改,顺序不一致就会出现脏数据,而线程同样会出现脏数据。我们对线程加的锁策略,同样在事务中也有适用。当然多事务的情况显然比多线程更加复杂,但我们只要理解了多线程,相信对学习数据库事务的效果也是非常有帮助的。Java里面除了synchronized 能够帮助同步多线程之外,还有一个弱同步的操作关键字是volatile,它产生在变量上的约束在文档中也有详细的说明。因为很复杂,考虑到篇幅笔者就不打算解释一遍了。  

                好了,又是新的一篇结束了。大概再有一两篇笔者大学关于Java所学就差不多说完了。不足之处大家尽管提出来,笔者愿意接受各种职责批评,因为笔者认为失败的教训往往比成功更加助人成长。这个帖子一直以来得到那么多朋友的大力支持和鼓励,笔者在这里真诚的说一声谢谢!因为笔者即将毕业投入茫茫人海去从草根阶层开始挣扎,最近冷静的想了很多,即使毕业了,要提高的不止是技术,还包括很多综合素质,也许并不能马上找到如意的团队和工作岗位,只能承认自己是弱势群体,有时不得不向现实的生活低头,不知道今后是否还有这闲心去写学习笔记,去坚持走分享的道路。其实很多人我认为也很有心去分享,但被现实的生活束缚了手脚。所以也期望还呆在学校里的大学生们好好努力的珍惜那份无忧虑的心境和安静的环境,好好充实自己吧!

Java学习杂谈(十一)--Spring

笔者最近比较忙,一边在实习一边在寻找明年毕业更好的工作,不过论坛里的朋友非常支持小弟继续写,今天是周末,泡上一杯咖啡,继续与大家分享J2ee部分的学习经验。今天的主题是目前很流行也很好的一个开源框架-Spring。  

                引用《Spring2.0技术手册》上的一段话:  
                Spring的核心是个轻量级容器,它是实现IoC容器和非侵入性的框架,并提供AOP概念的实现方式;提供对持久层、事务的支持;提供MVC       Web框架的实现,并对于一些常用的企业服务API提供一致的模型封装,是一个全方位的应用程序框架,除此之外,对于现存的各种框架,Spring也提供了与它们相整合的方案。  
接下来笔者先谈谈自己的一些理解吧,Spring框架的发起者之前一本很著名的书名字大概是《J2ee       Development       without       EJB》,他提倡用轻量级的组件代替重量级的EJB。笔者还没有看完那本著作,只阅读了部分章节。其中有一点分析觉得是很有道理的:  

                EJB里在服务器端有Web       Container和EJB       Container,从前的观点是各层之间应该在物理上隔离,Web       Container处理视图功能、在EJB       Container中处理业务逻辑功能、然后也是EBJ       Container控制数据库持久化。这样的层次是很清晰,但是一个很严重的问题是Web       Container和EJB       Container毕竟是两个不同的容器,它们之间要通信就得用的是RMI机制和JNDI服务,同样都在服务端,却物理上隔离,而且每次业务请求都要远程调用,有没有必要呢?看来并非隔离都是好的。  

                再看看轻量级和重量级的区别,笔者看过很多种说法,觉得最有道理的是轻量级代表是POJO       +       IoC,重量级的代表是Container       +       Factory。(EJB2.0是典型的重量级组件的技术)我们尽量使用轻量级的Pojo很好理解,意义就在于兼容性和可适应性,移植不需要改变原来的代码。而Ioc与Factory比起来,Ioc的优点是更大的灵活性,通过配置可以控制很多注入的细节,而Factory模式,行为是相对比较封闭固定的,生产一个对象就必须接受它全部的特点,不管是否需要。其实轻量级和重量级都是相对的概念,使用资源更少、运行负载更小的自然就算轻量。  

                话题扯远了,因为Spring框架带来了太多可以探讨的地方。比如它的非侵入性:指的是它提供的框架实现可以让程序员编程却感觉不到框架的存在,这样所写的代码并没有和框架绑定在一起,可以随时抽离出来,这也是Spring设计的目标。Spring是唯一可以做到真正的针对接口编程,处处都是接口,不依赖绑定任何实现类。同时,Spring还设计了自己的事务管理、对象管理和Model2       的MVC框架,还封装了其他J2ee的服务在里面,在实现上基本都在使用依赖注入和AOP的思想。由此我们大概可以看到Spring是一个什么概念上的框架,代表了很多优秀思想,值得深入学习。笔者强调,学习并不是框架,而是框架代表的思想,就像我们当初学Struts一样……  

                1.Spring       MVC  
                关于IoC和AOP笔者在上篇已经稍微解释过了,这里先通过Spring的MVC框架来给大家探讨一下Spring的特点吧。(毕竟大部分人已经很熟悉Struts了,对比一下吧)  
众所周知MVC的核心是控制器。类似Struts中的ActionServlet,Spring里面前端控制器叫做DispatcherServlet。里面充当Action的组件叫做Controller,返回的视图层对象叫做ModelAndView,提交和返回都可能要经过过滤的组件叫做 Interceptor。  

                让我们看看一个从请求到返回的流程吧:  
                (1)   前台Jsp或Html通过点击submit,将数据装入了request域  
                (2)   请求被Interceptor拦截下来,执行preHandler()方法出前置判断  
                (3)   请求到达DispathcerServlet  
                (4)   DispathcerServlet通过Handler       Mapping来决定每个reuqest应该转发给哪个后端控制器Controller  
                (5)   各式各样的后端控制器Controller来处理请求,调用业务层对象来处理业务逻辑,然后返回一个ModelAndView对象  
                (6)   当Controller执行完毕,Interceptor会调用postHandle来做后置处理  
                (7)   ModelAndView代表了呈现画面是使用的Model数据对象和View对象,由于只能返回一个对象所有起了这个名字封装这两个对象。  
                (8)   由ViewResolver对象来解析每个返回的ModelAndView对象应该呈现到哪一个视图(Jsp/Html等)中(包括Exception       Resolver)  
                (9)   当View绘制完成之后Interceptor又会跳出来执行它的afterCompletion方法做善后处理。当然Interceptor的行为完全是配置的而不是强制的。  

                这样一个完整的流程就这样结束了,个人感觉Spring的MVC框架稍显复杂,不像Struts-1那么容易上手。不管是Controller、 Model、ViewRosovler、Handle       Mapping还是View,Spring       MVC框架都已经为你提供了多种实现,想最大程度的减少程序员的编码,增加框架的适用性。大家有兴趣可以继续深入研究哈!  

                2.Spring       AOP  
                记得最初笔者请教他人Spring是一个什么东西的时候,每个人都会提到AOP这个词语。笔者在上一篇已经解释过AOP基本原理,这次来跟大家说说 Spring的AOP编程吧。不同的AOP框架会有其对AOP概念不同的实现方式,主要的差别在于所提供的Pointcut、Aspects的丰富程度,以及它们如何被织入应用程序、代理的方式等等。先熟悉一下AOP中的几个重要概念:  
                (1)   Cross-cutting:横切,说白了就是需要统一处理的集合  
                (2)   Aspects:将散落各处的横切收集起来,设计成各个独立可重用的对象称为Aspects。  
                (3)   Advice:       对横切的具体实现,即等待插入一段逻辑。  
                (4)   Joinpoint:Advice插入流程的时机点。  
                (5)   Pointcut:       用于选择Joinpoint的程序结构,可以通过Annotation或者XML实现。  
                (6)   Weave:       Advice被应用至对象之上的过程称之为织入,有编译期、类加载期、运行期三种时间点策略。  

                如果你采用实现接口的方式,Spring会在执行时期适用java的动态代理,如果不实现接口,Spring会使用CGLIB产生代理类。AOP的概念很大很泛,而Spring只使用了其中的部分特性,毕竟Spring的目标是轻量级框架,比如它只支持对Method的Joinpoint,而不支持对 Field的Joinpoint,理由是为了封装性。  
   
                其实我们可以把概念看得简单一点,AOP的目的是减少冗余代码,增强对较大项目的全局监控。Spring利用AOP可以规定一个集合和一套规则,在这个集合里所有的方法被invoke即调用的时候,都必须按照那套规则走一遍。那么首先对其中10个方法都要用到的处理代码就只用写一遍,如果是这10个方法来了就织入这段代码;其次,按照规则,也许所有的牵扯某个模块的方法调用的时候,我都需要做日志或者进行验证,那么我只要立足于这个集合的入口和出口,管他从哪里来去哪里,都能被有效的监控。我监控的可能不止是某个方法单独的行为,我还可以加入对流程控制的监控规则。例如是论坛,我规定注册了才能登录,而登录后才能发帖回帖下资源,于是所有这类流程都会被收集到我眼皮地下通过。  

                PS:笔者最近忙于找工作的事,没有太多经历在论坛跟大家整理自己的笔记。最近也只是接触Spring的MVC比较多,对于Spring的其他特性,还没有更多的去实践,所以仅仅是泛泛而谈,只是介绍一个印象罢了。还是那句话,我们学习一个框架不是如何使用,而是它所带来的优秀的思想和理念,这比如何使用这个框架更有意义得多

Java学习杂谈(十)--Struts2

最近业余时间笔者一直Java       Virtual       Machine的研究,由于实习分配到项目组里面,不想从前那么闲了,好不容易才抽出时间来继续这个话题的帖子。我打算把J2ee的部分结束之后,再谈谈 JVM和JavaScript,只要笔者有最新的学习笔记总结出来,一定会拿来及时和大家分享的。衷心希望与热爱Java的关大同仁共同进步……  

        这次准备继续上次的话题先讲讲Struts-2,手下简短回顾一段历史:随着时间的推移,Web应用框架经常变化的需求,产生了几个下一代       Struts的解决方案。其中的Struts       Ti       继续坚持       MVC模式的基础上改进,继续Struts的成功经验WebWork项目是在2002年3月发布的,它对Struts式框架进行了革命性改进,引进了不少新的思想,概念和功能,但和原Struts代码并不兼容。WebWork是一个成熟的框架,经过了好几次重大的改进与发布。在2005年12 月,WebWork与Struts   Ti决定合拼,  再此同时,Struts   Ti  改名为 Struts Action  Framework  2.0,成为Struts真正的下一代。  

                看看Struts-2的处理流程:  
                1)   Browser产生一个请求并提交框架来处理:根据配置决定使用哪些拦截器、action类和结果等。  
                2)   请求经过一系列拦截器:根据请求的级别不同拦截器做不同的处理。这和Struts-1的RequestProcessor类很相似。  
                3)   调用Action:       产生一个新的action实例,调用业务逻辑方法。  
                4)   调用产生结果:匹配result       class并调用产生实例。  
                5)   请求再次经过一系列拦截器返回:过程也可配置减少拦截器数量  
                6)   请求返回用户:从control返回servlet,生成Html。  

                这里很明显的一点是不存在FormBean的作用域封装,直接可以从Action中取得数据。       这里有一个Strut-2配置的web.xml文件:  

 
                     
                          controller        
                          org.apache.struts.action2.dispatcher.FilterDispatcher    
               
 
                     
                          cotroller        
                          /*    
               
  

        注意到以往的servlet变成了filter,ActionServlet变成了FilterDispatcher,*.do变成了/*。filter 配置定义了名称(供关联)和filter的类。filter       mapping让URI匹配成功的的请求调用该filter。默认情况下,扩展名为   “.action   “。这个是在default.properties文件里的   “struts.action.extension   “属性定义的。  

        default.properties是属性定义文件,通过在项目classpath路径中包含一个名为“struts.properties”的文件来设置不同的属性值。而Struts-2的默认配置文件名为struts.xml。由于1和2的action扩展名分别为.do和.action,所以很方便能共存。我们再来看一个Struts-2的action代码:  

        public   class   MyAction   {  
              public   String   execute()   throws   Exception   {      
                      //do   the   work      
                      return   “success   “;  
              }  
        }  

        很明显的区别是不用再继承任何类和接口,返回的只是一个String,无参数。实际上在Struts-2中任何返回String的无参数方法都可以通过配置来调用action。所有的参数从哪里来获得呢?答案就是Inversion       of       Control技术(控制反转)。笔者尽量以最通俗的方式来解释,我们先试图让这个Action获得reuqest对象,这样可以提取页面提交的任何参数。那么我们把request设为一个成员变量,然后需要一个对它的set方法。由于大部分的action都需要这么做,我们把这个set方法作为接口来实现。  
        public   interface   ServletRequestAware   {  
                public   void   setServletRequest(HttpServletRequest   request);  
        }  

        public   class   MyAction   implements   ServletRequestAware   {      
                private   HttpServletRequest   request;      

                public   void   setServletRequest(HttpServletRequest   request)   {      
                        this.request   =   request;      
                }  
                               
                public   String   execute()   throws   Exception       {  
                          //     do   the   work   directly   using   the   request      
                          return       Action.SUCCESS;      
                }      
        }  

        那么谁来调用这个set方法呢?也就是说谁来控制这个action的行为,以往我们都是自己在适当的地方写上一句 action.setServletRequest(…),也就是控制权在程序员这边。然而控制反转的思想是在哪里调用交给正在运行的容器来决定,只要利用Java反射机制来获得Method对象然后调用它的invoke方法传入参数就能做到,这样控制权就从程序员这边转移到了容器那边。程序员可以减轻很多繁琐的工作更多的关注业务逻辑。Request可以这样注入到action中,其他任何对象也都可以。为了保证action的成员变量线程安全,Struts-2的action不是单例的,每一个新的请求都会产生一个新的action实例。  

        那么有人会问,到底谁来做这个对象的注入工作呢?答案就是拦截器。拦截器又是什么东西?笔者再来尽量通俗的解释拦截器的概念。大家要理解拦截器的话,首先一定要理解GOF23种设计模式中的Proxy模式。  

        A对象要调用f(),它希望代理给B来做,那么B就要获得A对象的引用,然后在B的f()中通过A对象引用调用A对象的f()方法,最终达到A的f()被调用的目的。有没有人会觉得这样很麻烦,为什么明明只要A.f()就可以完成的一定要封装到B的f()方法中去?有哪些好处呢?  

        1)   这里我们只有一个A,当我们有很多个A的时候,只需要监视B一个对象的f()方法就可以从全局上控制所有被调用的f()方法。  
        2)   另外,既然代理人B能获得A对象的引用,那么B可以决定在真正调A对象的f()方法之前可以做哪些前置工作,调完返回前可有做哪些后置工作。  

        讲到这里,大家看出来一点拦截器的概念了么?它拦截下一调f()方法的请求,然后统一的做处理(处理每个的方式还可以不同,解析A对象就可以辨别),处理完毕再放行。这样像不像对流动的河水横切了一刀,对所有想通过的水分子进行搜身,然后再放行?这也就是AOP(Aspect       of       Programming面向切面编程)的思想。  

        Anyway,Struts-2只是利用了AOP和IoC技术来减轻action和框架的耦合关系,力图到最大程度重用action的目的。在这样的技术促动下,Struts-2的action成了一个简单被框架使用的POJO(Plain       Old       Java       Object)罢了。实事上AOP和IoC的思想已经遍布新出来的每一个框架上,他们并不是多么新的技术,利用的也都是JDK早已可以最到的事情,它们代表的是更加面向接口编程,提高重用,增加扩展性的一种思想。Struts-2只是部分的使用这两种思想来设计完成的,另外一个最近很火的框架 Spring,更大程度上代表了这两种设计思想,笔者将于下一篇来进一步探讨Spring的结构。  

        PS:       关于Struts-2笔者也没真正怎么用过,这里是看了网上一些前辈的帖子之后写下自己的学习体验,不足之处请见谅!

Java学习杂谈(九)--Struts

Java杂谈(九)--Struts

                J2ee的开源框架很多,笔者只能介绍自己熟悉的几个,其他的目前在中国IT行业应用得不是很多。希望大家对新出的框架不要盲目的推崇,首先一定要熟悉它比旧的到底好在哪里,新的理念和特性是什么?然后再决定是否要使用它。  

                这期的主题是Struts,直译过来是支架。Struts的第一个版本是在2001年5月发布的,它提供了一个Web应用的解决方案,如何让Jsp和 servlet共存去提供清晰的分离视图和业务应用逻辑的架构。在Struts之前,通常的做法是在Jsp中加入业务逻辑,或者在Servlet中生成视图转发到前台去。Struts带着MVC的新理念当时退出几乎成为业界公认的Web应用标准,于是当代IT市场上也出现了众多熟悉Struts的程序员。即使有新的框架再出来不用,而继续用Struts的理由也加上了一条低风险,因为中途如果开发人员变动,很容易的招进新的会Struts的IT民工啊, ^_^!  

                笔者之前说的都是Struts-1,因为新出了Struts-2,使得每次谈到Struts都必须注明它是Struts-1还是2。笔者先谈比较熟悉的 Struts-1,下次再介绍一下与Struts-2的区别:  

                1.   Struts框架整体结构  

                Struts-1的核心功能是前端控制器,程序员需要关注的是后端控制器。前端控制器是是一个Servlet,在Web.xml中间配置所有 Request都必须经过前端控制器,它的名字是ActionServlet,由框架来实现和管理。所有的视图和业务逻辑隔离都是应为这个 ActionServlet,       它就像一个交通警察,所有过往的车辆必须经过它的法眼,然后被送往特定的通道。所有,对它的理解就是分发器,我们也可以叫做Dispatcher,其实了解Servlet编程的人自己也可以写一个分发器,加上拦截request的Filter,其实自己实现一个struts框架并不是很困难。主要目的就是让编写视图的和后台逻辑的可以脱离紧耦合,各自同步的完成自己的工作。  

                那么有了ActionServlet在中间负责转发,前端的视图比如说是Jsp,只需要把所有的数据Submit,这些数据就会到达适合处理它的后端控制器Action,然后在里面进行处理,处理完毕之后转发到前台的同一个或者不同的视图Jsp中间,返回前台利用的也是Servlet里面的forward 和redirect两种方式。所以到目前为止,一切都只是借用了Servlet的API搭建起了一个方便的框架而已。这也是Struts最显著的特性?? 控制器。  

                那么另外一个特性,可以说也是Struts-1带来的一个比较成功的理念,就是以xml配置代替硬编码配置信息。以往决定Jsp往哪个servlet提交,是要写进Jsp代码中的,也就是说一旦这个提交路径要改,我们必须改写代码再重新编译。而Struts提出来的思路是,编码的只是一个逻辑名字,它对应哪个class文件写进了xml配置文件中,这个配置文件记录着所有的映射关系,一旦需要改变路径,改变xml文件比改变代码要容易得多。这个理念可以说相当成功,以致于后来的框架都延续着这个思路,xml所起的作用也越来越大。  

                大致上来说Struts当初给我们带来的新鲜感就这么多了,其他的所有特性都是基于方便的控制转发和可扩展的xml配置的基础之上来完成它们的功能的。  

下面将分别介绍Action和FormBean,       这两个是Struts中最核心的两个组件。  

                    2.   后端控制器Action  

                Action就是我们说的后端控制器,它必须继承自一个Action父类,Struts设计了很多种Action,例如DispatchAction、 DynaValidationAction。它们都有一个处理业务逻辑的方法execute(),传入的request,       response,       formBean和actionMapping四个对象,返回actionForward对象。到达Action之前先会经过一个 RequestProcessor来初始化配置文件的映射关系,这里需要大家注意几点:  

                    1)   为了确保线程安全,在一个应用的生命周期中,Struts框架只会为每个Action类创建一个Action实例,所有的客户请求共享同一个Action 实例,并且所有线程可以同时执行它的execute()方法。所以当你继承父类Action,并添加了private成员变量的时候,请记住这个变量可以被多个线程访问,它的同步必须由程序员负责。(所有我们不推荐这样做)。在使用Action的时候,保证线程安全的重要原则是在Action类中仅仅使用局部变量,谨慎的使用实例变量。局部变量是对每个线程来说私有的,execute方法结束就被销毁,而实例变量相当于被所有线程共享。  

                    2)   当ActionServlet实例接收到Http请求后,在doGet()或者doPost()方法中都会调用process()方法来处理请求。 RequestProcessor类包含一个HashMap,作为存放所有Action实例的缓存,每个Action实例在缓存中存放的属性key为 Action类名。在RequestProcessor类的processActionCreate()方法中,首先检查在HashMap中是否存在 Action实例。创建Action实例的代码位于同步代码块中,以保证只有一个线程创建Action实例。一旦线程创建了Action实例并把它存放到 HashMap中,以后所有的线程会直接使用这个缓存中的实例。  

                    3)          元素的      属性指定访问这个Action用户必须具备的安全角色,多个角色之间逗号隔开。RequestProcessor类在预处理请求时会调用自身的 processRoles()方法,检查配置文件中是否为Action配置了安全角色,如果有,就调用HttpServletRequest的 isUserInRole()方法来判断用户是否具备了必要的安全性角色,如果不具备,就直接向客户端返回错误。(返回的视图通过      属性来指定)  

                3.   数据传输对象FormBean  

                Struts并没有把模型层的业务对象直接传递到视图层,而是采用DTO(Data       Transfer       Object)来传输数据,这样可以减少传输数据的冗余,提高传输效率;还有助于实现各层之间的独立,使每个层分工明确。Struts的DTO就是 ActionForm,即formBean。由于模型层应该和Web应用层保持独立。由于ActionForm类中使用了Servlet       API,       因此不提倡把ActionForm传递给模型层,       而应该在控制层把ActionForm       Bean的数据重新组装到自定义的DTO中,       再把它传递给模型层。它只有两个scope,分别是session和request。(默认是session)一个ActionForm标准的生命周期是:  

                1)   控制器收到请求       ->      

                2)   从request或session中取出ActionForm实例,如不存在就创建一个       ->  

                3)   调用ActionForm的reset()方法       ->      

                4)   把实例放入session或者request中       ->      

                5)   将用户输入表达数据组装到ActionForm中       ->      

                6)   如验证方法配置了就调用validate()方法           ->  

                7)   如验证错误就转发给      属性指定的地方,否则调用execute()方法  

                validate()方法调用必须满足两个条件:  

                1)   ActionForm       配置了Action映射而且name属性匹配  

                2)          元素的validate属性为true  

                如果ActionForm在request范围内,那么对于每个新的请求都会创建新的ActionForm实例,属性被初始化为默认值,那么reset ()方法就显得没有必要;但如果ActionForm在session范围内,同一个ActionForm实例会被多个请求共享,reset()方法在这种情况下极为有用。  

                4.   验证框架和国际化  

                Struts有许多自己的特性,但是基本上大家还是不太常用,说白了它们也是基于JDK中间的很多Java基础包来完成工作。例如国际化、验证框架、插件自扩展功能、与其他框架的集成、因为各大框架基本都有提供这样的特性,Struts也并不是做得最好的一个,这里也不想多说。Struts的验证框架,是通过一个validator.xml的配置文件读入验证规则,然后在validation-rules.xml里面找到验证实现通过自动为Jsp插入 Javascript来实现,可以说做得相当简陋。弹出来的JavaScript框不但难看还很多冗余信息,笔者宁愿用formBean验证或者 Action的saveErrors(),验证逻辑虽然要自己写,但页面隐藏/浮现的警告提示更加人性化和美观一些。  

                至于Struts的国际化,其实无论哪个框架的国际化,java.util.Locale类是最重要的Java       I18N类。在Java语言中,几乎所有的对国际化和本地化的支持都依赖于这个类。如果Java类库中的某个类在运行的时候需要根据Locale对象来调整其功能,那么就称这个类是本地敏感的(Locale-Sensitive),       例如java.text.DateFormat类就是,依赖于特定Locale。  

                创建Locale对象的时候,需要明确的指定其语言和国家的代码,语言代码遵从的是ISO-639规范,国家代码遵从ISO-3166规范,可以从  

                http://www.unicode.org/unicode/onlinedat/languages.html  

                http://www.unicode.org/unicode/onlinedat/countries.htm  

                Struts的国际化是基于properties的message/key对应来实现的,笔者曾写过一个程序,所有Jsp页面上没有任何Text文本串,全部都用的是      去Properties文件里面读,这个时候其实只要指定不同的语言区域读不同的Properties文件就实现了国际化。需要注意的是不同语言的字符写进Properties文件的时候需要转化成Unicode码,JDK已经带有转换的功能。JDK的bin目录中有native2ascii这个命令,可以完成对*.txt和*.properties的Unicode码转换。  

                OK,今天就说到这里,本文中的很多内容也不是笔者的手笔,是笔者一路学习过来自己抄下来的笔记,希望对大家有帮助!Java杂谈一路走来,感谢大家持续的关注,大概再有个2到3篇续篇就改完结了!笔者尽快整理完成后续的写作吧……^_^

Java学习杂谈(八)-Servlet/Jsp

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代码,如此而已。  </p> <p>说得明白一点的话还是举几个简单的例子说明一下吧:  </p> <p>                <jsp:include>   去哪里找执行什么class呢?首先这是个jsp类库的标签,当然要去jsp类库寻找相应的class了,同样它也是由Web容器来提供,例如 Tomcat就应该去安装目录的lib文件夹下面的jsp-api.jar里面找,有兴趣的可以去找一找啊!  </p> <p>                <c:forEach>   又去哪里找呢?这个是由Jsp2.0版本推荐的和核心标记库的内容,例如   <c:if>   就对应在页面中做if判断的功能的一断Java代码。它的class文件在jstl.jar这个类库里面,往往还需要和一个standard.jar类库一起导入,放在具体Web项目的WEB-INF的lib目录下面就可以使用了。  </p> <p>                顺便罗唆一句,Web       Project的目录结构是相对固定的,因为容器会按照固定的路径去寻找它需要的配置文件和资源,这个任何一本J2ee入门书上都有,这里就不介绍了。了解Tag的本质还要了解它的工作原理,所以大家去J2ee的API里找到并研究这个包:javax.servlet.jsp.tagext。它有一些接口,和一些实现类,专门用语开发Tag,只有自己亲自写出几个不同功能的标签,才算是真正理解了标签的原理。别忘记了自己开发的标签要自己去完成配置文件,容器只是集成了去哪里寻找jsp标签对应class的路径,自己写的标签库当然要告诉容器去哪里找啦。  </p> <p>                说了这么多,我们为什么要用标签呢?完全在Jsp里面来个   <%       %>   就可以在里面任意写Java代码了,但是长期实践发现页面代码统一都是与html同风格的标记语言更加有助于美工人员进行开发前台,它不需要懂Java,只要Java程序员给个列表告诉美工什么标签可以完成什么逻辑功能,他就可以专注于美工,也算是进一步隔离了前后台的工作吧!  </p> <p>                <strong>3.   成就Web框架</strong>  </p> <p>                框架是什么?曾经看过这样的定义:与模式类似,框架也是解决特定问题的可重用方法,框架是一个描述性的构建块和服务集合,开发人员可以用来达成某个目标。一般来说,框架提供了解决某类问题的基础设施,是用来创建解决方案的工具,而不是问题的解决方案。  </p> <p>                正是由于Tag的出现,成就了以后出现的那么多Web框架,它们都开发了自己成熟实用的一套标签,然后由特定的Xml文件来配置加载信息,力图使得Web 应用的开发变得更加高效。下面这些标签相应对很多人来说相当熟悉了:  </p> <p>                <html:password>  </p> <p>            <logic:equal>  </p> <p>                <bean:write>  </p> <p>                <f:view>  </p> <p>                <h:form>  </p> <p>                <h:message>  </p> <p>                它们分别来自Struts和JSF框架,最强大的功能在于控制转发,就是MVC三层模型中间完成控制器的工作。Struts-1实际上并未做到真正的三层隔离,这一点在Struts-2上得到了很大的改进。而Jsf向来以比较完善合理的标签库受到人们推崇。  </p> <p>                今天就大概讲这么多吧,再次需要强调的是Servlet/Jsp是学习J2ee必经之路,也是最基础的知识,希望大家给与足够的重视!</p> </div> </div> </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1280305695668846592"></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)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1939276846008954880.htm" title="Java Web二手物品交易平台课程设计项目" target="_blank">Java Web二手物品交易平台课程设计项目</a> <span class="text-muted">草莓味儿柠檬</span> <div>本文还有配套的精品资源,点击获取简介:盐鱼二手物品交易网站是一个基于Servlet和JSP的JavaWeb开发课程设计项目,适合Java初学者进行实战演练。项目内容包括Servlet与JSP的基础知识、MVC架构、数据库交互、会话管理、安全与性能优化、部署与运行,以及测试与调试等各个方面。学生通过此项目可以全面理解JavaWeb开发技术,并提升实战能力。1.Servlet生命周期与HTTP请求处理</div> </li> <li><a href="/article/1939270291054194688.htm" title="JSP学习" target="_blank">JSP学习</a> <span class="text-muted">sakoba</span> <a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>文章目录什么是JSP运行原理JSP基础语法JSP表达式JSP脚本片段JSP声明jsp指令九大内置对象&四大域对象内置对象四大域对象代码JSP标签、JSTL标签、EL表达式EL表达式JSP标签JSTL标签什么是JSPJSP(JavaServerPages)是由SUN公司在1996年6月发布的一种基于Java技术的服务器端编程技术,用于开发动态Web应用。从本质上讲,它是一个简化的Servlet设计。</div> </li> <li><a href="/article/1939267387769548800.htm" title="从阻塞到异步:Java NIO与AIO的高性能网络编程实战全解析" target="_blank">从阻塞到异步:Java NIO与AIO的高性能网络编程实战全解析</a> <span class="text-muted">小张在编程</span> <a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/nio/1.htm">nio</a> <div>引言在高并发网络时代,传统BIO的“一个连接一个线程”模式早已力不从心——当万级连接涌来时,服务器线程池瞬间告急,资源耗尽的警报此起彼伏。JavaNIO与AIO的出现,如同为网络编程装上了“多线程调度器”和“异步引擎”:NIO用非阻塞机制化解并发瓶颈,让单线程管理千个连接成为可能;AIO则更进一步,通过事件回调实现真正异步,让程序在I/O等待时不再“干瞪眼”。本文将从原理到实战,带您揭开这两大高级</div> </li> <li><a href="/article/1939265370242215936.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/%E7%88%AC%E8%99%AB/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>在电商领域,快速获取商品信息对于市场分析、选品上架、库存管理和价格策略制定等方面至关重要。京东作为国内领先的电商平台之一,提供了丰富的商品数据。虽然京东开放平台提供了官方API来获取商品信息,但有时使用爬虫技术来抓取数据也是一种有效的手段。本文将介绍如何利用Java按关键字搜索京东商品,并提供详细的代码示例。一、准备工作(一)Java开发环境确保你的Java开发环境已经安装了以下必要的库:Jsou</div> </li> <li><a href="/article/1939262092766932992.htm" title="Java 企业级 Jakarta EE 11 发布" target="_blank">Java 企业级 Jakarta EE 11 发布</a> <span class="text-muted">ejinxian</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/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/Jakarta/1.htm">Jakarta</a><a class="tag" taget="_blank" href="/search/EE/1.htm">EE</a><a class="tag" taget="_blank" href="/search/11/1.htm">11</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/EE/1.htm">EE</a><a class="tag" taget="_blank" href="/search/11/1.htm">11</a> <div>标志着企业级Java在简化开发、提升开发人员生产力和整体性能方面的进步。主要亮点包括:现代化的测试兼容性工具包(TCK)、全新JakartaData规范的引入、对现有规范的重大更新以及对最新JavaLTS版本的支持,使开发人员能够充分利用Java21中的增强功能,包括虚拟线程JakartaData在简化企业应用程序持久化逻辑方面迈出了重要一步。主要功能包括:BasicRepository:基础存储</div> </li> <li><a href="/article/1939250241110863872.htm" title="React - 错误边界(Error boundary)" target="_blank">React - 错误边界(Error boundary)</a> <span class="text-muted">风轻轻~</span> <a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/React__%E5%9F%BA%E7%A1%80/1.htm">React__基础</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a> <div>React-错误边界(Errorboundary)一.理解二.使用1.使用方式2.使用案例错误边界:https://zh-hans.reactjs.org/docs/error-boundaries.html一.理解部分UI的JavaScript错误不应该导致整个应用崩溃,为了解决这个问题,React16引入了一个新的概念——错误边界。错误边界是一种React组件,这种组件可以捕获发生在其子组件树</div> </li> <li><a href="/article/1939244437330784256.htm" title="PYTHON从入门到实践9-类和实例" target="_blank">PYTHON从入门到实践9-类和实例</a> <span class="text-muted"></span> <div>#【1】面向对象编程classStudent(object):#可以帮属性值绑定到对象上,self相当于JAVA的thisdef__init__(self,name,age):self.name=nameself.age=agedefspeak(self):print(self.name,'说:老师好')if__name__=='__main__':new_student1=Student('球球</div> </li> <li><a href="/article/1939244311145148416.htm" title="E IO流.java" target="_blank">E IO流.java</a> <span class="text-muted">是紫焅呢</span> <a class="tag" taget="_blank" href="/search/26%E5%AD%97%E6%AF%8D%E5%AD%A6%E4%B9%A0%EF%BC%9Ajava%E5%85%A5%E9%97%A8%E7%AF%87/1.htm">26字母学习:java入门篇</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><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0%E6%96%B9%E6%B3%95/1.htm">学习方法</a><a class="tag" taget="_blank" href="/search/visual/1.htm">visual</a><a class="tag" taget="_blank" href="/search/studio/1.htm">studio</a><a class="tag" taget="_blank" href="/search/code/1.htm">code</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>前言:I/O(输入/输出)操作是构建各类应用程序的基石之一。Java提供了功能强大且灵活的I/O流机制,用于处理数据的读取与写入,无论是简单的文本文件操作,还是复杂的网络数据传输,都离不开I/O流的支持。目录一、初识JavaI/O流数据的“传送带”二、字节流操作从读取到写入的实战1.读取文件(字节流)2.写入文件(字节流)三、字符流操作读写文本文件的简便之道1.读取文件(字符流)2.写入文件(字符</div> </li> <li><a href="/article/1939238638692921344.htm" title="并发基础7(守护线程)" target="_blank">并发基础7(守护线程)</a> <span class="text-muted">浅水壁虎</span> <a class="tag" taget="_blank" href="/search/%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">多线程</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/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>目录1:什么守护线程2:守护线程使用3:守护线程案例1:什么守护线程守护线程是Java中的一种特殊的线程类型,它为其他线程(非守护线程)提供后台支持服务。在Java多线程编程中,有两种特殊类型的线程:后台线程和守护线程。这两种线程在一些特定的场景下非常有用,但也需要谨慎使用。本文将详细介绍后台线程和守护线程的概念、特性、用法,以及注意事项。守护线程的特点服务性质:守护线程通常用于执行后台任务,如J</div> </li> <li><a href="/article/1939236871318073344.htm" title="基于Anaconda环境开发IntelliJ IDEA实用JSON转Java实体插件" target="_blank">基于Anaconda环境开发IntelliJ IDEA实用JSON转Java实体插件</a> <span class="text-muted">七夜zippoe</span> <a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a><a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><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/json/1.htm">json</a><a class="tag" taget="_blank" href="/search/intellij-idea/1.htm">intellij-idea</a> <div>在软件开发中,将JSON数据转换为Java实体类是常见需求。借助Anaconda环境强大的包管理能力与IntelliJIDEA的插件开发体系,我们可以打造一款高效实用的JSON转Java实体插件,显著提升开发效率。下面将从需求分析、技术选型、开发实现到优化部署,全方位阐述这款插件的开发过程。需求分析:明确痛点与功能方向在日常开发中,开发者经常需要根据JSON数据结构手动创建对应的Java实体类,这</div> </li> <li><a href="/article/1939235862176919552.htm" title="我的世界进阶模组开发教程——机械动力的数据生成(1)" target="_blank">我的世界进阶模组开发教程——机械动力的数据生成(1)</a> <span class="text-muted">lemon_sjdk</span> <a class="tag" taget="_blank" href="/search/%E6%88%91%E7%9A%84%E4%B8%96%E7%95%8C/1.htm">我的世界</a> <div>机械动力注册元素的方式是依赖registrateAPI来实现注册的,这个API和之前说的GlitchCore库所用的注册方式高效多了,不管是开发效率还是可维护性,都比bop式注册好多了,因此学习第三篇和第四篇文章是重中之重代码解析:Create模组主类(Create.java)核心字段解析基础标识字段ID="create":模组唯一标识符,用于资源定位(如create:gear)。NAME="Cr</div> </li> <li><a href="/article/1939235356981391360.htm" title="我的世界1.20.1forge模组开发进阶教程——Geckolib动画实体(3)" target="_blank">我的世界1.20.1forge模组开发进阶教程——Geckolib动画实体(3)</a> <span class="text-muted">lemon_sjdk</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%88%91%E7%9A%84%E4%B8%96%E7%95%8C/1.htm">我的世界</a><a class="tag" taget="_blank" href="/search/%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91/1.htm">模组开发</a> <div>注意:本章涉及大量的geckolib底层代码,补充讲解了上一节没讲的,如果看不懂请去学习JavaGeoEntity////Sourcecoderecreatedfroma.classfilebyIntelliJIDEA//(poweredbyFernFlowerdecompiler)//packagesoftware.bernie.geckolib.animatable;importjavax</div> </li> <li><a href="/article/1939233336996196352.htm" title="为啥枚举天生线程安全?" target="_blank">为啥枚举天生线程安全?</a> <span class="text-muted">chi_666</span> <a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E5%AE%89%E5%85%A8/1.htm">安全</a> <div>枚举天生线程安全的特性,主要源于其在Java语言中的设计机制和类加载机制。以下是具体原因分析:一、枚举的本质:静态final的实例枚举在Java中本质上是一个继承了java.lang.Enum的特殊类,每个枚举常量在编译时会被转换为该类的静态final实例。例如:publicenumThreadSafeEnum{INSTANCE;//其他属性和方法}编译后等价于:publicfinalclassT</div> </li> <li><a href="/article/1939231067668017152.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/eclipse/1.htm">eclipse</a> <div>1.创建一个标识有“关闭”按钮的语句是()A.TextFieldb=newTextField(“关闭”);B.Lableb=newLable(“关闭”);C.Checkboxb=newCheckbox(“关闭”);D.Buttonb=newButton(“关闭”);解:①根据英语单词的意思来选择就行,Button类是专用于创建可点击的按钮控件。②TextField是输入框的意思,Lable是只读文</div> </li> <li><a href="/article/1939230689069166592.htm" title="函数的进阶" target="_blank">函数的进阶</a> <span class="text-muted">小盐巴小严</span> <a class="tag" taget="_blank" href="/search/web%E5%89%8D%E5%90%8E%E7%AB%AF%E5%BC%80%E5%8F%91%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/1.htm">web前后端开发学习笔记</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/es6/1.htm">es6</a> <div>JavaScript函数概念构成函数主体的JavaScript代码在定义之时并不会执行,只有在调用函数时,函数才会执行。调用JavaScript函数的方法:作为函数作为方法作为构造函数通过函数的call()和apply()间接调用函数属性length属性在函数体例,arguments.length表示传入函数的实参的个数函数本身的length属性是只读的,代表函数声明的实际参数的数量functio</div> </li> <li><a href="/article/1939230310730362880.htm" title="我的世界模组开发进阶教程——机械动力的数据生成(2)" target="_blank">我的世界模组开发进阶教程——机械动力的数据生成(2)</a> <span class="text-muted">lemon_sjdk</span> <a class="tag" taget="_blank" href="/search/%E6%88%91%E7%9A%84%E4%B8%96%E7%95%8C/1.htm">我的世界</a><a class="tag" taget="_blank" href="/search/%E6%A8%A1%E7%BB%84%E5%BC%80%E5%8F%91/1.htm">模组开发</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>==这篇文字继续来看看机械动力的数据生成==Create源码AssetLookupAssetLookup是Minecraft模组开发中用于简化数据生成的工具类,专注于自动处理方块(Block)和物品(Item)的模型(Model)文件路径生成与状态映射。其核心功能是根据规则动态构造资源路径,并适配不同状态(如供电状态、指示器数值)的模型。以下从两个维度详细解析:一、String...语法:Java</div> </li> <li><a href="/article/1939230058623332352.htm" title="基于Redis分布式的限流" target="_blank">基于Redis分布式的限流</a> <span class="text-muted">chi_666</span> <a class="tag" taget="_blank" href="/search/redis/1.htm">redis</a><a class="tag" taget="_blank" href="/search/%E5%88%86%E5%B8%83%E5%BC%8F/1.htm">分布式</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a> <div>以下是基于Redis实现分布式限流的Java解决方案,包含多种限流算法和完整实现代码:一、限流算法选择与实现1.固定窗口算法(SimpleRateLimiter)publicclassRedisFixedWindowRateLimiter{privatefinalStringRedisTemplateredisTemplate;privatefinalStringscript="localcurr</div> </li> <li><a href="/article/1939226528248295424.htm" title="JavaScript基础-常见网页特效案例" target="_blank">JavaScript基础-常见网页特效案例</a> <span class="text-muted">咖啡の猫</span> <a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</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/ecmascript/1.htm">ecmascript</a> <div>一、前言在前端开发中,实现网页特效(如轮播图、下拉菜单、Tab切换、拖拽效果等)是提升用户体验和页面交互性的关键手段之一。这些特效不仅能增强用户对网站的粘性,也是衡量一个前端开发者能力的重要标准。JavaScript是实现网页特效的核心技术之一,结合HTML和CSS,可以轻松构建丰富的交互效果。本文将带你深入了解:常见网页特效的实现原理;如何使用原生JavaScript实现经典特效;每个案例附带完</div> </li> <li><a href="/article/1939226528818720768.htm" title="JavaScript基础-触屏事件" target="_blank">JavaScript基础-触屏事件</a> <span class="text-muted">咖啡の猫</span> <a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</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/ecmascript/1.htm">ecmascript</a> <div>一、前言随着移动端设备的普及,网页不仅要适配PC浏览器,更要兼容手机和平板等触摸设备。传统的鼠标事件(如click、mousedown等)在触控操作中存在一定的延迟和局限性,因此JavaScript提供了专门用于处理触摸操作的API——触屏事件(TouchEvents)。本文将带你深入了解:触屏事件的基本概念;常见的触屏事件类型(touchstart、touchmove、touchend等);如何</div> </li> <li><a href="/article/1939224002769776640.htm" title="JavaScript 核心对象深度解析:Math、Date 与 String" target="_blank">JavaScript 核心对象深度解析:Math、Date 与 String</a> <span class="text-muted">小宁爱Python</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</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/ecmascript/1.htm">ecmascript</a> <div>JavaScript作为Web开发的核心语言,提供了丰富的内置对象来简化编程工作。本文将深入探讨三个重要的内置对象:Math、Date和String,通过详细的代码示例和综合案例帮助你全面掌握它们的用法。一、Math对象Math对象提供了一系列静态属性和方法,用于执行各种数学运算,无需实例化即可使用。常用属性:console.log(Math.PI);//圆周率:3.141592653589793</div> </li> <li><a href="/article/1939220979209269248.htm" title="零基础打造优雅的AI诗词创作助手" target="_blank">零基础打造优雅的AI诗词创作助手</a> <span class="text-muted">BaiYiQingXiang99</span> <a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a> <div>零基础打造优雅的AI诗词创作助手:一个纯前端实现的智能写诗工具项目介绍大家好,今天要和大家分享我的一个AI项目——AI诗词创作助手。这是一个完全使用原生JavaScript开发的智能写诗工具,不需要复杂的框架,也不需要后端服务器,就能实现专业级的AI诗词创作功能。在线体验地址GitHub地址主要特性1.多样化的创作选项支持多个主流AI模型(Deepseek、Moonshot(Kimi)、通义千问)</div> </li> <li><a href="/article/1939220727068684288.htm" title="从入门到精通:前端工程师必学的 JSON 全解析" target="_blank">从入门到精通:前端工程师必学的 JSON 全解析</a> <span class="text-muted">前端视界</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/json/1.htm">json</a><a class="tag" taget="_blank" href="/search/%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F/1.htm">状态模式</a><a class="tag" taget="_blank" href="/search/ai/1.htm">ai</a> <div>从入门到精通:前端工程师必学的JSON全解析关键词:JSON、前端工程师、数据交换、JavaScript、数据格式摘要:本文围绕前端工程师必学的JSON展开全面解析。从JSON的基本概念、背景知识入手,深入探讨其核心原理、算法实现、数学模型等方面。通过详细的代码示例和实际应用场景分析,帮助前端工程师从入门到精通掌握JSON的使用。同时,提供了丰富的学习资源、开发工具和相关论文推荐,最后对JSON的</div> </li> <li><a href="/article/1939208372943384576.htm" title="如何在编辑器wangEditor中完美复制粘贴WORD内容?" target="_blank">如何在编辑器wangEditor中完美复制粘贴WORD内容?</a> <span class="text-muted">M_Snow</span> <a class="tag" taget="_blank" href="/search/%E7%BC%96%E8%BE%91%E5%99%A8/1.htm">编辑器</a><a class="tag" taget="_blank" href="/search/word/1.htm">word</a><a class="tag" taget="_blank" href="/search/umeditor%E7%B2%98%E8%B4%B4word/1.htm">umeditor粘贴word</a><a class="tag" taget="_blank" href="/search/ueditor%E7%B2%98%E8%B4%B4word/1.htm">ueditor粘贴word</a><a class="tag" taget="_blank" href="/search/ueditor%E5%A4%8D%E5%88%B6word/1.htm">ueditor复制word</a><a class="tag" taget="_blank" href="/search/ueditor%E4%B8%8A%E4%BC%A0word%E5%9B%BE%E7%89%87/1.htm">ueditor上传word图片</a><a class="tag" taget="_blank" href="/search/ueditor%E5%AF%BC%E5%85%A5word/1.htm">ueditor导入word</a> <div>要求:开源,免费,技术支持编辑器:wangEditor前端:vue2,vue3,vue-cli,html5后端:java,jsp,springboot,asp.net,php,asp,.netcore,.netmvc,.netform群体:学生,个人用户,外包,自由职业者,中小型网站,博客,场景:数字门户,数字中台,站群,内网,外网,信创国产化环境,web截屏行业:医疗,教育,建筑,政府,党政,国</div> </li> <li><a href="/article/1939208373668999168.htm" title="黑马JVM解析笔记(六):深入理解JVM类加载机制与运行时优化" target="_blank">黑马JVM解析笔记(六):深入理解JVM类加载机制与运行时优化</a> <span class="text-muted">null不是我干的</span> <a class="tag" taget="_blank" href="/search/JVM/1.htm">JVM</a><a class="tag" taget="_blank" href="/search/jvm/1.htm">jvm</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a> <div>1.JVM类加载类加载是Java虚拟机将描述类.class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被JVM直接使用的Java类型的过程。核心阶段:加载—>连接—>初始化1.1加载,以jdk1.8为例类加载器先把Person.class字节码解析为InstanceKlass(底层是c++)结构,存放一些关键信息和对象的引用,生命周期与类加载器相同(类卸载时才释放)然后就是把新</div> </li> <li><a href="/article/1939208245839196160.htm" title="网页版wangEditor如何实现WORD图片的高效粘贴?" target="_blank">网页版wangEditor如何实现WORD图片的高效粘贴?</a> <span class="text-muted">M_Snow</span> <a class="tag" taget="_blank" href="/search/word/1.htm">word</a><a class="tag" taget="_blank" href="/search/umeditor%E7%B2%98%E8%B4%B4word/1.htm">umeditor粘贴word</a><a class="tag" taget="_blank" href="/search/ueditor%E7%B2%98%E8%B4%B4word/1.htm">ueditor粘贴word</a><a class="tag" taget="_blank" href="/search/ueditor%E5%A4%8D%E5%88%B6word/1.htm">ueditor复制word</a><a class="tag" taget="_blank" href="/search/ueditor%E4%B8%8A%E4%BC%A0word%E5%9B%BE%E7%89%87/1.htm">ueditor上传word图片</a><a class="tag" taget="_blank" href="/search/ueditor%E5%AF%BC%E5%85%A5word/1.htm">ueditor导入word</a><a class="tag" taget="_blank" href="/search/ueditor%E5%AF%BC%E5%85%A5pdf/1.htm">ueditor导入pdf</a> <div>要求:开源,免费,技术支持编辑器:wangEditor前端:vue2,vue3,vue-cli,html5后端:java,jsp,springboot,asp.net,php,asp,.netcore,.netmvc,.netform群体:学生,个人用户,外包,自由职业者,中小型网站,博客,场景:数字门户,数字中台,站群,内网,外网,信创国产化环境,web截屏行业:医疗,教育,建筑,政府,党政,国</div> </li> <li><a href="/article/1939205348690817024.htm" title="并发编程 - 守护线程与非守护线程" target="_blank">并发编程 - 守护线程与非守护线程</a> <span class="text-muted">ゞ浪人与酒丶0</span> <a class="tag" taget="_blank" href="/search/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/1.htm">并发编程</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">多线程</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>多线程–守护线程与非守护线程1.什么是守护线程,什么是非守护线程什么是守护线程,和main相关,用户线程,用户自己创建的线程,如果主线程停止掉,不会影响用户线程用户线程也叫非守护线程gc线程(线程不定时回收垃圾)属于守护线程当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程2.守护线程特征:有一个特征,和主线程一起销毁3.非守护线程特征:和主线程互不影响Java中有两种线程,</div> </li> <li><a href="/article/1939205095979806720.htm" title="spring06-配置类的作用" target="_blank">spring06-配置类的作用</a> <span class="text-muted">ruleslol</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a> <div>一、配置类的作用是什么?简单来说:配置类是一个专门用于告诉Spring:“我要哪些对象成为Bean,被Spring管理”的类。它的作用主要是:配置和注册Bean到Spring容器中,也就是你说的“管理Bean”。二、配置类=Bean管理中心你可以用两种方式告诉Spring管Bean:方式举例本质注解扫描方式@Component/@Service/@Controller自动注册到容器Java配置类方</div> </li> <li><a href="/article/1939203203111383040.htm" title="【头歌】MapReduce基础实战 答案" target="_blank">【头歌】MapReduce基础实战 答案</a> <span class="text-muted">Seven_Two2</span> <a class="tag" taget="_blank" href="/search/%E5%A4%B4%E6%AD%8C%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%AE%9E%E9%AA%8C%E7%AD%94%E6%A1%88/1.htm">头歌大数据实验答案</a><a class="tag" taget="_blank" href="/search/c%23/1.htm">c#</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>本专栏已收集大数据所有答案第1关:成绩统计编程要求使用MapReduce计算班级每个学生的最好成绩,输入文件路径为/user/test/input,请将计算后的结果输出到/user/test/output/目录下。答案:需要先在命令行启动HDFS#命令行start-dfs.sh再在代码文件中写入以下代码#代码文件importjava.io.IOException;importjava.util.S</div> </li> <li><a href="/article/1939200553485660160.htm" title="基于Java+Vue的数字化人力资源管理系统,高效整合数据,赋能企业人力精细化管理" target="_blank">基于Java+Vue的数字化人力资源管理系统,高效整合数据,赋能企业人力精细化管理</a> <span class="text-muted">软件源码专题社区</span> <a class="tag" taget="_blank" href="/search/%E6%BA%90%E7%A0%81%E5%85%B1%E4%BA%AB/1.htm">源码共享</a><a class="tag" taget="_blank" href="/search/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B/1.htm">软件工程</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a><a class="tag" taget="_blank" href="/search/%E6%BA%90%E4%BB%A3%E7%A0%81%E7%AE%A1%E7%90%86/1.htm">源代码管理</a> <div>前言:在当今数字化浪潮席卷的时代,企业对于人力资源管理的效率和精准度提出了更高要求。传统的人力资源管理模式已难以满足企业快速发展的需求,繁琐的手工操作、信息传递不及时、数据统计不准确等问题,严重制约了企业人力资源管理的效能。数字化人力资源管理系统的出现,为企业提供了一种全新的解决方案,它借助先进的信息技术,将人力资源管理的各个环节进行整合和优化,实现人力资源管理的自动化、智能化和精细化,从而提升企</div> </li> <li><a href="/article/1939198158529687552.htm" title="2025年AI编程工具推荐" target="_blank">2025年AI编程工具推荐</a> <span class="text-muted">小猴崽</span> <a class="tag" taget="_blank" href="/search/AI%E7%BC%96%E7%A8%8B/1.htm">AI编程</a><a class="tag" taget="_blank" href="/search/AI%E7%BC%96%E7%A8%8B/1.htm">AI编程</a><a class="tag" taget="_blank" href="/search/ai%E7%BC%96%E7%A8%8B/1.htm">ai编程</a> <div>以下基于2025年权威技术报告、开发者社区评测及厂商白皮书,对当前主流AI编程工具进行客观综述与推荐。数据来源包括IDC《2025中国生态告》、信通院《AI辅助编程技术成熟度评》、StackOverflow开发者调查及头部企业实测案例。一、国际主流AI编程工具GitHubCopilotX核心能力:基于GPT-4模型升级,支持37种编程语言(Python/Java/JS等),可解析数万行代码库的全局</div> </li> <li><a href="/article/6.htm" title="[黑洞与暗粒子]没有光的世界" target="_blank">[黑洞与暗粒子]没有光的世界</a> <span class="text-muted">comsci</span> <div>     无论是相对论还是其它现代物理学,都显然有个缺陷,那就是必须有光才能够计算      但是,我相信,在我们的世界和宇宙平面中,肯定存在没有光的世界....      那么,在没有光的世界,光子和其它粒子的规律无法被应用和考察,那么以光速为核心的 &nbs</div> </li> <li><a href="/article/133.htm" title="jQuery Lazy Load 图片延迟加载" target="_blank">jQuery Lazy Load 图片延迟加载</a> <span class="text-muted">aijuans</span> <a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a> <div>基于 jQuery 的图片延迟加载插件,在用户滚动页面到图片之后才进行加载。 对于有较多的图片的网页,使用图片延迟加载,能有效的提高页面加载速度。 版本: jQuery v1.4.4+ jQuery Lazy Load v1.7.2 注意事项: 需要真正实现图片延迟加载,必须将真实图片地址写在 data-original 属性中。若 src</div> </li> <li><a href="/article/260.htm" title="使用Jodd的优点" target="_blank">使用Jodd的优点</a> <span class="text-muted">Kai_Ge</span> <a class="tag" taget="_blank" href="/search/jodd/1.htm">jodd</a> <div>1.  简化和统一 controller ,抛弃 extends SimpleFormController ,统一使用 implements Controller 的方式。 2.  简化 JSP 页面的 bind, 不需要一个字段一个字段的绑定。 3.  对 bean 没有任何要求,可以使用任意的 bean 做为 formBean。   使用方法简介</div> </li> <li><a href="/article/387.htm" title="jpa Query转hibernate Query" target="_blank">jpa Query转hibernate Query</a> <span class="text-muted">120153216</span> <a class="tag" taget="_blank" href="/search/Hibernate/1.htm">Hibernate</a> <div>public List<Map> getMapList(String hql, Map map) { org.hibernate.Query jpaQuery = entityManager.createQuery(hql); if (null != map) { for (String parameter : map.keySet()) { jp</div> </li> <li><a href="/article/514.htm" title="Django_Python3添加MySQL/MariaDB支持" target="_blank">Django_Python3添加MySQL/MariaDB支持</a> <span class="text-muted">2002wmj</span> <a class="tag" taget="_blank" href="/search/mariaDB/1.htm">mariaDB</a> <div>现状 首先,Django@Python2.x 中默认的引擎为 django.db.backends.mysql 。但是在Python3中如果这样写的话,会发现 django.db.backends.mysql 依赖 MySQLdb[5] ,而 MySQLdb 又不兼容 Python3 于是要找一种新的方式来继续使用MySQL。 MySQL官方的方案 首先据MySQL文档[3]说,自从MySQL</div> </li> <li><a href="/article/641.htm" title="在SQLSERVER中查找消耗IO最多的SQL" target="_blank">在SQLSERVER中查找消耗IO最多的SQL</a> <span class="text-muted">357029540</span> <a class="tag" taget="_blank" href="/search/SQL+Server/1.htm">SQL Server</a> <div>返回做IO数目最多的50条语句以及它们的执行计划。 select top 50   (total_logical_reads/execution_count) as avg_logical_reads,  (total_logical_writes/execution_count) as avg_logical_writes,  (tot</div> </li> <li><a href="/article/768.htm" title="spring UnChecked 异常 官方定义!" target="_blank">spring UnChecked 异常 官方定义!</a> <span class="text-muted">7454103</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a> <div>  如果你接触过spring的 事物管理!那么你必须明白 spring的 非捕获异常! 即 unchecked 异常! 因为 spring 默认这类异常事物自动回滚!! public static boolean isCheckedException(Throwable ex) { return !(ex instanceof RuntimeExcep</div> </li> <li><a href="/article/895.htm" title="mongoDB 入门指南、示例" target="_blank">mongoDB 入门指南、示例</a> <span class="text-muted">adminjun</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/mongodb/1.htm">mongodb</a><a class="tag" taget="_blank" href="/search/%E6%93%8D%E4%BD%9C/1.htm">操作</a> <div>一、准备工作 1、 下载mongoDB 下载地址:http://www.mongodb.org/downloads 选择合适你的版本 相关文档:http://www.mongodb.org/display/DOCS/Tutorial 2、 安装mongoDB A、 不解压模式: 将下载下来的mongoDB-xxx.zip打开,找到bin目录,运行mongod.exe就可以启动服务,默</div> </li> <li><a href="/article/1022.htm" title="CUDA 5 Release Candidate Now Available" target="_blank">CUDA 5 Release Candidate Now Available</a> <span class="text-muted">aijuans</span> <a class="tag" taget="_blank" href="/search/CUDA/1.htm">CUDA</a> <div>The CUDA 5 Release Candidate is now available at http://developer.nvidia.com/<wbr></wbr>cuda/cuda-pre-production. Now applicable to a broader set of algorithms, CUDA 5 has advanced fe</div> </li> <li><a href="/article/1149.htm" title="Essential Studio for WinRT网格控件测评" target="_blank">Essential Studio for WinRT网格控件测评</a> <span class="text-muted">Axiba</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/html5/1.htm">html5</a> <div>Essential Studio for WinRT界面控件包含了商业平板应用程序开发中所需的所有控件,如市场上运行速度最快的grid 和chart、地图、RDL报表查看器、丰富的文本查看器及图表等等。同时,该控件还包含了一组独特的库,用于从WinRT应用程序中生成Excel、Word以及PDF格式的文件。此文将对其另外一个强大的控件——网格控件进行专门的测评详述。 网格控件功能 1、</div> </li> <li><a href="/article/1276.htm" title="java 获取windows系统安装的证书或证书链" target="_blank">java 获取windows系统安装的证书或证书链</a> <span class="text-muted">bewithme</span> <a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a> <div>      有时需要获取windows系统安装的证书或证书链,比如说你要通过证书来创建java的密钥库  。 有关证书链的解释可以查看此处 。   public static void main(String[] args) { SunMSCAPI providerMSCAPI = new SunMSCAPI(); S</div> </li> <li><a href="/article/1403.htm" title="NoSQL数据库之Redis数据库管理(set类型和zset类型)" target="_blank">NoSQL数据库之Redis数据库管理(set类型和zset类型)</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/redis/1.htm">redis</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/NoSQL/1.htm">NoSQL</a> <div>4.sets类型         Set是集合,它是string类型的无序集合。set是通过hash table实现的,添加、删除和查找的复杂度都是O(1)。对集合我们可以取并集、交集、差集。通过这些操作我们可以实现sns中的好友推荐和blog的tag功能。         sadd:向名称为key的set中添加元</div> </li> <li><a href="/article/1530.htm" title="异常捕获何时用Exception,何时用Throwable" target="_blank">异常捕获何时用Exception,何时用Throwable</a> <span class="text-muted">bingyingao</span> <div>用Exception的情况 try {        //可能发生空指针、数组溢出等异常         } catch (Exception e) {          </div> </li> <li><a href="/article/1657.htm" title="【Kafka四】Kakfa伪分布式安装" target="_blank">【Kafka四】Kakfa伪分布式安装</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/kafka/1.htm">kafka</a> <div>在http://bit1129.iteye.com/blog/2174791一文中,实现了单Kafka服务器的安装,在Kafka中,每个Kafka服务器称为一个broker。本文简单介绍下,在单机环境下Kafka的伪分布式安装和测试验证   1. 安装步骤   Kafka伪分布式安装的思路跟Zookeeper的伪分布式安装思路完全一样,不过比Zookeeper稍微简单些(不</div> </li> <li><a href="/article/1784.htm" title="Project Euler" target="_blank">Project Euler</a> <span class="text-muted">bookjovi</span> <a class="tag" taget="_blank" href="/search/haskell/1.htm">haskell</a> <div>Project Euler是个数学问题求解网站,网站设计的很有意思,有很多problem,在未提交正确答案前不能查看problem的overview,也不能查看关于problem的discussion thread,只能看到现在problem已经被多少人解决了,人数越多往往代表问题越容易。     看看problem 1吧: Add all the natural num</div> </li> <li><a href="/article/1911.htm" title="Java-Collections Framework学习与总结-ArrayDeque" target="_blank">Java-Collections Framework学习与总结-ArrayDeque</a> <span class="text-muted">BrokenDreams</span> <a class="tag" taget="_blank" href="/search/Collections/1.htm">Collections</a> <div>        表、栈和队列是三种基本的数据结构,前面总结的ArrayList和LinkedList可以作为任意一种数据结构来使用,当然由于实现方式的不同,操作的效率也会不同。         这篇要看一下java.util.ArrayDeque。从命名上看</div> </li> <li><a href="/article/2038.htm" title="读《研磨设计模式》-代码笔记-装饰模式-Decorator" target="_blank">读《研磨设计模式》-代码笔记-装饰模式-Decorator</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/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a> <div>声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/ import java.io.BufferedOutputStream; import java.io.DataOutputStream; import java.io.FileOutputStream; import java.io.Fi</div> </li> <li><a href="/article/2165.htm" title="Maven学习(一)" target="_blank">Maven学习(一)</a> <span class="text-muted">chenyu19891124</span> <a class="tag" taget="_blank" href="/search/Maven%E7%A7%81%E6%9C%8D/1.htm">Maven私服</a> <div>    学习一门技术和工具总得花费一段时间,5月底6月初自己学习了一些工具,maven+Hudson+nexus的搭建,对于maven以前只是听说,顺便再自己的电脑上搭建了一个maven环境,但是完全不了解maven这一强大的构建工具,还有ant也是一个构建工具,但ant就没有maven那么的简单方便,其实简单点说maven是一个运用命令行就能完成构建,测试,打包,发布一系列功</div> </li> <li><a href="/article/2292.htm" title="[原创]JWFD工作流引擎设计----节点匹配搜索算法(用于初步解决条件异步汇聚问题) 补充" target="_blank">[原创]JWFD工作流引擎设计----节点匹配搜索算法(用于初步解决条件异步汇聚问题) 补充</a> <span class="text-muted">comsci</span> <a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E5%B7%A5%E4%BD%9C/1.htm">工作</a><a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/1.htm">搜索引擎</a><a class="tag" taget="_blank" href="/search/%E5%B5%8C%E5%85%A5%E5%BC%8F/1.htm">嵌入式</a> <div>本文主要介绍在JWFD工作流引擎设计中遇到的一个实际问题的解决方案,请参考我的博文"带条件选择的并行汇聚路由问题"中图例A2描述的情况(http://comsci.iteye.com/blog/339756),我现在把我对图例A2的一个解决方案公布出来,请大家多指点 节点匹配搜索算法(用于解决标准对称流程图条件汇聚点运行控制参数的算法) 需要解决的问题:已知分支</div> </li> <li><a href="/article/2419.htm" title="Linux中用shell获取昨天、明天或多天前的日期" target="_blank">Linux中用shell获取昨天、明天或多天前的日期</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/shell/1.htm">shell</a><a class="tag" taget="_blank" href="/search/%E4%B8%8A%E5%87%A0%E5%B9%B4/1.htm">上几年</a><a class="tag" taget="_blank" href="/search/%E6%98%A8%E5%A4%A9/1.htm">昨天</a><a class="tag" taget="_blank" href="/search/%E8%8E%B7%E5%8F%96%E4%B8%8A%E5%87%A0%E4%B8%AA%E6%9C%88/1.htm">获取上几个月</a> <div>在Linux中可以通过date命令获取昨天、明天、上个月、下个月、上一年和下一年 # 获取昨天 date -d 'yesterday'  # 或 date -d 'last day' # 获取明天 date -d 'tomorrow'   # 或 date -d 'next day' # 获取上个月 date -d 'last month' # </div> </li> <li><a href="/article/2546.htm" title="我所理解的云计算" target="_blank">我所理解的云计算</a> <span class="text-muted">dongwei_6688</span> <a class="tag" taget="_blank" href="/search/%E4%BA%91%E8%AE%A1%E7%AE%97/1.htm">云计算</a> <div>      在刚开始接触到一个概念时,人们往往都会去探寻这个概念的含义,以达到对其有一个感性的认知,在Wikipedia上关于“云计算”是这么定义的,它说:        Cloud computing is a phrase used to describe a variety of computing co</div> </li> <li><a href="/article/2673.htm" title="YII CMenu配置" target="_blank">YII CMenu配置</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/yii/1.htm">yii</a> <div>Adding id and class names to CMenu We use the id and htmlOptions to accomplish this. Watch. //in your view $this->widget('zii.widgets.CMenu', array( 'id'=>'myMenu', 'items'=>$this-&g</div> </li> <li><a href="/article/2800.htm" title="设计模式之静态代理与动态代理" target="_blank">设计模式之静态代理与动态代理</a> <span class="text-muted">come_for_dream</span> <a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a> <div>静态代理与动态代理        代理模式是java开发中用到的相对比较多的设计模式,其中的思想就是主业务和相关业务分离。所谓的代理设计就是指由一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理。比如我们在进行删除操作的时候需要检验一下用户是否登陆,我们可以删除看成主业务,而把检验用户是否登陆看成其相关业务</div> </li> <li><a href="/article/2927.htm" title="【转】理解Javascript 系列" target="_blank">【转】理解Javascript 系列</a> <span class="text-muted">gcc2ge</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a> <div>理解Javascript_13_执行模型详解 摘要: 在《理解Javascript_12_执行模型浅析》一文中,我们初步的了解了执行上下文与作用域的概念,那么这一篇将深入分析执行上下文的构建过程,了解执行上下文、函数对象、作用域三者之间的关系。函数执行环境简单的代码:当调用say方法时,第一步是创建其执行环境,在创建执行环境的过程中,会按照定义的先后顺序完成一系列操作:1.首先会创建一个</div> </li> <li><a href="/article/3054.htm" title="Subsets II" target="_blank">Subsets II</a> <span class="text-muted">hcx2013</span> <a class="tag" taget="_blank" href="/search/set/1.htm">set</a> <div>Given a collection of integers that might contain duplicates, nums, return all possible subsets. Note: Elements in a subset must be in non-descending order. The solution set must not conta</div> </li> <li><a href="/article/3181.htm" title="Spring4.1新特性——Spring缓存框架增强" target="_blank">Spring4.1新特性——Spring缓存框架增强</a> <span class="text-muted">jinnianshilongnian</span> <a class="tag" taget="_blank" href="/search/spring4/1.htm">spring4</a> <div>目录 Spring4.1新特性——综述 Spring4.1新特性——Spring核心部分及其他 Spring4.1新特性——Spring缓存框架增强 Spring4.1新特性——异步调用和事件机制的异常处理 Spring4.1新特性——数据库集成测试脚本初始化 Spring4.1新特性——Spring MVC增强 Spring4.1新特性——页面自动化测试框架Spring MVC T</div> </li> <li><a href="/article/3308.htm" title="shell嵌套expect执行命令" target="_blank">shell嵌套expect执行命令</a> <span class="text-muted">liyonghui160com</span> <div>    一直都想把expect的操作写到bash脚本里,这样就不用我再写两个脚本来执行了,搞了一下午终于有点小成就,给大家看看吧.   系统:centos 5.x   1.先安装expect yum -y install expect   2.脚本内容: cat auto_svn.sh   #!/bin/bash </div> </li> <li><a href="/article/3435.htm" title="Linux实用命令整理" target="_blank">Linux实用命令整理</a> <span class="text-muted">pda158</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a> <div>0. 基本命令   linux 基本命令整理    1. 压缩 解压   tar -zcvf a.tar.gz a   #把a压缩成a.tar.gz   tar -zxvf a.tar.gz     #把a.tar.gz解压成a    2. vim小结   2.1 vim替换   :m,ns/word_1/word_2/gc  </div> </li> <li><a href="/article/3562.htm" title="独立开发人员通向成功的29个小贴士" target="_blank">独立开发人员通向成功的29个小贴士</a> <span class="text-muted">shoothao</span> <a class="tag" taget="_blank" href="/search/%E7%8B%AC%E7%AB%8B%E5%BC%80%E5%8F%91/1.htm">独立开发</a> <div> 概述:本文收集了关于独立开发人员通向成功需要注意的一些东西,对于具体的每个贴士的注解有兴趣的朋友可以查看下面标注的原文地址。 明白你从事独立开发的原因和目的。 保持坚持制定计划的好习惯。 万事开头难,第一份订单是关键。 培养多元化业务技能。 提供卓越的服务和品质。 谨小慎微。 营销是必备技能。 学会组织,有条理的工作才是最有效率的。 “独立</div> </li> <li><a href="/article/3689.htm" title="JAVA中堆栈和内存分配原理" target="_blank">JAVA中堆栈和内存分配原理</a> <span class="text-muted">uule</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>1、栈、堆 1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)3. 堆:存放所有new出来的对象。4. 静态域:存放静态成员(static定义的)5. 常量池:存放字符串常量和基本类型常量(public static f</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>