Factory, Abstract Factory, Factory Method, 和Builder

Factory, Abstract Factory, Factory Method, 和Builder 选这4个模式在一起讨论首先是因为它们的功能比较类似,都是用来制造对象实例的,从归类来说,他们都属于制造类模式(creational patterns),其次她们们在工作中比较常用,由于功能太过相似,往往导致在某个实际问题上让人举棋不定,似乎选哪个都可以解决问题,可是真的选择某个模式后,又会发现不是完全合适。今天我们就来讨论讨论在什么情况下选择什么模式来解决问题比较合适。 考虑到不是所有的朋友都对以上提到的4种模式都了如指掌,在开始讨论之前先简单的介绍一下这4个模式,对这4种模式熟悉的朋友也可以顺便回顾一下。请注意,这里我只会做简短的介绍,如果要比较深入地了解她们的话,还请去看模式相关的书籍,比较浅显易懂的我推荐 “Head First Design Patterns”。如果要在工作中反复参考的我推荐 “Applied Java Patterns”。那本经典的GOF Design Patterns由于写的时间比较早,举的例子不太适合现在的软件开发,我个人认为初学者或者是没有太多时间的朋友没有必要去读那本书,尽管她的确是经典。 Factory Pattern 中文叫工厂模式, 这个是我们在面向对象编程中最常用的模式之一了,她的主要功能就是制造对象,也正是这个原因才叫她为工厂模式,工厂干什么?生产产品。通常情况而言某个工厂所生产的产品总是一个系列的不同种类,大体上相同,细节上有差异。 图1 展示了一个非常简单的例子,通常CarFactory类会提供下列方法来生产车辆, 如代码片断1所示: public class CarFactory { public Car createBusinessCar() {….} public Car createSportCar() {…} } 代码片断 1 http://www.wiloon.com/wp-content/uploads/2012/10/x1pBG_wmiiVq4fKhMkEoTbjopPcKCE3u0uJjfqcYoYvgBeu5PDT5UndtcNdt48rY80PV_fd8Ce5pLpHavAj520cgRoVa4EmOhjE5VNS7GnBHl126UUuSSCrcM8YMFLVb3mp_UsivKRLJ1HKESriM5FDQA-1.gif 图1 Factory Pattern Abstract Factory Pattern 中文叫抽象工厂模式,顾名思义,就是把工厂模式在进一步抽象化,进一步细化。我们继续沿用上面的例子,不过这次增加产品的种类,如图2所示。由于我们增加了一层分类,当我们要生产某种车的时候就需要询问要哪种车, 商用还是跑车?不然的话就要增加create方法,如果分类多了,create方法就会成几何数量增长。 public class CarFactory { public Car createBusinessBMWCar() {….} public Car createBusinessBenzCar() {…} public Car createSportBMWCar() {….} public Car createSportBenzCar() {…} } 代码片断 2 图2 bad Factory Pattern ...

2012-10-11 · 2 min · 236 words · -

阿贝尔群

阿贝尔群 阿贝尔群 (Abelian Group) ,又称交换群或加群,是这样一类群 (G, *): 对任意 a,b 属于 G,满足 a * b = b * a。阿贝尔群以挪威数学家尼尔斯·阿贝尔命名。由阿贝尔群分解定理, 任何阿贝尔群可以分解成一些整数群和剩余类群的直和, 这个分解是唯一的, 其中分解出来的整数群的个数称为阿贝尔群的秩。 比阿贝尔群更广泛的概念是模的概念 记号方式 可换群有两个传统的记号方式. - 加法及乘法.

2012-10-10 · 1 min · 26 words · -

JAVA 浅复制与深复制/深克隆/深拷贝

JAVA 浅复制与深复制/深克隆/深拷贝 1.浅复制与深复制概念 ⑴浅复制 (浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。 ⑵深复制 (深克隆) 被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。 2.Java的clone()方法 ⑴clone方法将对象复制了一份并返回给调用者。一般而言,clone () 方法满足: ①对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象 ②对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样 ③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。 ⑵Java中对象的克隆 ①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。 ②在派生类中覆盖基类的clone()方法,并声明为public。 ③在派生类的clone()方法中,调用super.clone()。 ④在派生类中实现Cloneable接口。 请看如下代码: class Student implements Cloneable { String name; int age; Student(String name,int age) { this.name=name; this.age=age; } public Object clone() { Object o=null; try { o=(Student)super.clone();//Object中的clone()识别出你要复制的是哪一个对象。 } catch(CloneNotSupportedException e) { System.out.println(e.toString()); } return o; } public static void main(String[] args) { Student s1=new Student("zhangsan",18); Student s2=(Student)s1.clone(); s2.name="lisi"; s2.age=20; System.out.println("name="+s1.name+","+"age="+s1.age);//修改学生2后,不影响学生1的值。 } } 说明: ...

2012-10-09 · 2 min · 369 words · -

抽象工厂模式解析例子

抽象工厂模式解析例子 抽象工厂模式中的有以下的四种角色: 抽象工厂 (Abstract Factory) 角色: 担任这个角色的是工厂方法模式的核心,它是与应用系统业务逻辑无关的。 具体工厂 (Concrete Factory) 角色: 这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的业务逻辑紧密相关的。 抽象产品 (Abstract Product) 角色: 担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。 具体产品 (Concrete Product) 角色: 这个角色用以代表具体的产品。 抽象工厂模式就相当于创建实例对象的new,由于经常要根据类生成实例对象,抽象工厂模式也是用来创建实例对象的,所以在需要新的事例对象时便可以考虑是否使用工厂模式。虽然这样做可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。 举例来说: 生产餐具和相应食物的工厂,有两个车间,其中一个车间用以生产餐具,一个车间用以生产相应的食物。 当消费者消费时,只需要向相应的具体工厂请求具体餐具和具体食物便可以使用餐具消费食物。 每个具体工厂生产出来的具体产品根据不同工厂的不同各不相同,但是客户使用产品的方法是一致的。比如客户在得到餐具和食物之后,两者的搭配是正确的 (使用汤匙喝牛奶,使用刀子切面包) 。 在本例子中有3个具体工厂AKetchen, BKetchen, BKetchen,分别生产牛奶和汤匙、面包和刀、肉和叉子。牛奶、面包和肉都实现了食物接口。汤匙、刀和叉子都实现了餐具接口。 抽象工厂的接口定义如下所示; public interface KetchenFactory{ public Food getFood(); public TableWare getTableWare(); } //抽象餐具的接口定义如下所示: public interface TableWare{ public String getTool(); } //抽象食物的接口定义如下所示: public interface Food{ public String getEatable(); } //而具体的实现也非常简单,以AKetchen为例子 //具体工厂AKetchen的定义如下所示; public class AKetchen implements KetchenFactory{ public Food getFood(){ return new Milk(); } public TableWare getTableWare(){ return new Spoon(); } } //具体餐具(spoon)的定义如下所示: public class Spoon implements TableWare{ public String getTool() { return "spoon"; } } //具体食物(milk)的定义如下所示: public class Milk implements Food{ public String getEatable(){ return "milk"; } } //客户端的定义如下: public class Client{ public void eat(KetchenFactory k){ System.out.println("A person eat "+k.getFood().getEatable() +" with "+k.getTableWare().getTool()+"!"); } public static void main(String[] args){ Client client= new Client(); KetchenFactory kf = new AKetchen(); client.eat(kf); kf=new BKetchen(); client.eat(kf); kf= new CKetchen(); client.eat(kf); } } 小结: 抽象工厂模式特别适合于这样的一种产品结构: 产品分为几个系列,在每个系列中,产品的布局都是要同的,在一个系列中某个位置的产品,在另一个系列中一定有一个对应的产品。这样的产品结构是存在的,这几个系列中同一位置的产品可能是互斥的,它们是针对不同客户的解决方案,每个客户都只择其一。 ...

2012-10-09 · 1 min · 159 words · -

webkit

webkit WebKit 是一个开源的浏览器引擎,与之相对应的引擎有Gecko (Mozilla Firefox 等使用) 和Trident (也称MSHTML,IE 使用) 。同时WebKit 也是苹果Mac OS X 系统引擎框架版本的名称,主要用于Safari,Dashboard,Mail 和其他一些Mac OS X 程序。WebKit 前身是 KDE 小组的 KHTML,WebKit 所包含的 WebCore 排版引擎和 JSCore 引擎来自于 KDE 的 KHTML 和 KJS,当年苹果比较了 Gecko 和 KHTML 后,仍然选择了后者,就因为它拥有清晰的源码结构、极快的渲染速度。Apple将 KHTML 发扬光大,推出了装备 KHTML 改进型 WebKit 引擎的浏览器 Safari。 WebKit 所包含的 WebCore 排版引擎和 JSCore 引擎,均是从KDE的KHTML及KJS引擎衍生而来,它们都是自由软件,在GPL条约下授权,同时支持BSD系统的开发。所以Webkit也是自由软件,同时开放源代码。 WebKit的优势在于高效稳定,兼容性好,且源码结构清晰,易于维护。 尽管Webkit内核是个非常好的网页解析机制,但是由于以往微软把IE捆绑在Windows里(同样的Webkit内核的Safari捆绑在Apple产品里,Google Chrome捆绑在Google产品里),导致许多网站都是按照IE来架设的,很多网站不兼容Webkit内核,比如登录界面、网银等网页均不可使用Webkit内核。目前几乎所有网站和网银已经逐渐支持WebKit,未来可能将取代IE内核的浏览器。 WebKit 内核在手机上的应用也十分广泛,例如 Google 的手机 Android、 Apple 的 iPhone, Nokia’s Series 60 browser 等所使用的 Browser 内核引擎,都是基于 WebKit。 WebKit是开源的Web浏览器引擎,苹果的Safari、谷歌的Chrome浏览器都是基于这个框架来开发的。WebKit 还支持移动设备和手机,包括iPhone和Android手机都是使用WebKit做为浏览器的核心。 ...

2012-10-09 · 1 min · 176 words · -

浏览器加载和渲染网页的过程

浏览器加载和渲染网页的过程 关于网页加载和渲染的过程,在网络上的讨论并不多。可能是因为这个过程比较复杂,而且浏览器执行的速度太快,目前还没有发现什么比较好的工具可以清楚的看到浏览器解析网页的每一个过程。通过firedug和httpWatch可以看到浏览器的http请求,但是对于浏览器如何paint和flow处理html元素,我们仍然是不得而知。“flow"这个词借鉴于reflow,表示浏览器第一次加载网页的过程。在网络上搜索了一下,学习如下。 关于浏览器加载网页过程的有趣视频 可以参见: http://www.aoao.org.cn/blog/2008/05/reflow/ (形象化的reflow) 。这个视频展现了网页加载的过程,看着比较有趣。要是可以更加形象化,就更好了,可以帮助我们书写更好的提高网页加载速度的代码。 浏览器内核 不同的浏览器内核,对于网页的解析过程肯定也不尽相同。http://www.mac52ipod.cn/post/Trident-Gecko-WebKit-Presto.php 一文对各种浏览器的页面渲染引擎进行了简介。目前主要有基于 (1) Trident页面渲染引擎 –> IE系列浏览器; (2) Gecko页面渲染引擎 –> Mozilla Firefox; (3) KHTML页面渲染引擎或WebKit框架 –> Safafi和Google Chrome; (4) Presto页面渲染引擎 –> Opera 详细的介绍可以参见原文。 浏览器解析网页的过程 http://hi.baidu.com/seosky/blog/item/78d3394c130f86ffd72afc56.html 浏览器加载和渲染原理分析一文中通过一定的方法,推断了浏览器加载解析网页的顺序大致如下: IE下载的顺序是从上到下,渲染的顺序也是从上到下,下载和渲染是同时进行的; 在渲染到页面的某一部分时,其上面的所有部分都已经下载完成 (并不是说所有相关联的元素都已经下载完) ; 在下载过程中,如果遇到某一标签是嵌入文件,并且文件是具有语义解释性的 (例如: JS脚本,CSS样式) ,那么此时IE的下载过程会启用单独连接进行下载,并且在下载后进行解析,解析 (JS、CSS中如有重定义,后定义函数将覆盖前定义函数) 过程中,停止页面所有往下元素的下载; 样式表文件比较特殊,在其下载完成后,将和以前下载的所有样式表一起进行解析,解析完成后,将对此前所有元素 (含以前已经渲染的) 重新进行样式渲染。并以此方式一直渲染下去,直到整个页面渲染完成。 当然这是一个推断的过程。 借助Google PageSpeed和Yahoo YSlow分析网页加载 通过这两个工具,测试网页加载过程,可以得到一些提高网页加载速度的建议。使用Google PageSpeed对Google首页进行分析,可以得到建议: (1) 压缩javascript和CSS; (2) 合并外部javascript和CSS; (3) 减少DNS寻址时间;这条与将图片分散到不同的域名存储这条折中处理; (4) 使用缓存; (5) 尽量避免CSS表达式; (6) 为图片增加宽度和高度属性; (7) 将css放在网页头部,合理放置js的位置。 同时,利用YSlow对google首页进行分析,我们也可以得到一些改进的建议。这些建议差不太多,就不在详细说明。 合理使用这两个工具,优化我们的网页,提高网页加载速度,增强用户体验。 我自己的误解 过去一直以为,一个容器如果没有读到自己的结束标签,那么这个容器就不会在浏览器中显示出来。今天测试了下,却发现浏览器在读到一个容器的开始标签的时候,就可以显示该容器了。关于浏览器如何一个一个的paint HTML中的元素,如果flow它们,这个过程还需要进一步了解。当然,也可以不管过程,只看加载的结果,通过pagespeed和Yslow来优化自己的网页。个人在做布局的时候,还是会秉承一条原则: 尽量让一个父容器小一些! 参考文献 ...

2012-10-08 · 1 min · 86 words · -

DOM, BOM

DOM, BOM BOM 浏览器对象模型 提供了独立于内容而与浏览器窗口进行交互的对象。描述了与浏览器进行交互的方法和接口,可以对浏览器窗口进行访问和操作,譬如可以弹出新的窗口,改变状态栏中的文本,对Cookie的支持,IE还扩展了BOM,加入了ActiveXObject类,可以通过js脚本实例化ActiveX对象等等) 文档结构图 BOM由以一系列相关的对象组成。下图展示了基本的BOM体系结构。 BOM中的对象 Window对象: 是整个BOM的核心,所有对象和集合都以某种方式回接到window对象。Window对象表示整个浏览器窗口,但不必表示其中包含的内容。 Document对象: 实际上是window对象的属性。这个对象的独特之处是唯一一个既属于BOM又属于DOM的对象。从BOM角度看,document对象由一系列集合构成,这些集合可以访问文档的各个部分。 Location对象: 它是window对象和document对象的属性。Location对象表示载入窗口的URL,此外它还可以解析URI. Navigator对象: Navigator包含大量Web浏览器相关的信息。各种浏览器支持该对象的属性和方法不尽相同。 Screen对象: 通过其可以获取用户屏幕相关的信息 DOM 文档对象模型 DOM是针对XML的基于树的API。描述了处理网页内容的方法和接口,是HTML和XML的API,DOM把整个页面规划成由节点层级构成的文档。 DOM本身是与语言无关的API,它并不与Java,JavaScript或其他语言绑定。 特定语言的DOM 针对XHTML和HTML的DOM。这个DOM定义了一个HTMLDocument和HTMLElement做为这种实现的基础。 其他的包括SVG的DOM 对于DOM的支持 各种浏览器对于DOM的支持不一样。 Mozila支持最好,几乎所有的DOM Level 2以及部分DOM Level 3。在 Opera和Safrai支持所有的DOM Level1和大部分DOM Level2。 IE,支持大部分的DOM Level 1。 DOM 的各种 Level DOM Level 1 包括 DOM Core 和 DOM HTML。前者提供了基于XML的文档结构图。后者添加了一些HTML专用的对象和方法,从而扩展了DOM Core. DOM Level 2 引入几个新模块: DOM视图,事件,样式,遍历和范围 DOM Level 3 引入了以统一的方式载入和保存文档的方法。DOM Core被扩展支持所有的XML1.0的特性 http://titan.iteye.com/blog/60389 DOM 事件 onblur="hanshu(this)" 获得焦点: onfocus="hanshu(this)"

2012-10-08 · 1 min · 67 words · -

java Delegate

java Delegate 委派,也可以叫做委托,从字面上来理解的话,应该是委托其他类做事情而自己不做或者只做一部分工作;而回调,就是调用自己的方法。 在 java 中,这两种机制很类似,你姑且可以认为它们就是一码事。 java 中,实现委派和回调都是通过接口来实现的。下面举个小例子吧! 该例子是这样的 (只是一个例子) : ProfessionalWorker 、SparetimeWorker 负责发射 Rocket,Rocket 类通过接口 IRocketDelegate 委派 (或者说是回调) ProfessionalWorker 、SparetimeWorker自己发射。 总之,Rocket不做具体的事情。看实例代码: IRocketDelegate.java源码 public interface IRocketDelegate { public abstract long startAtTime(); public abstract long endAtTime(); public abstract void sendDidFail(); } 共有三个方法,分别是用于计算 Rocket 发射时间、计算 Rocket 发射完毕的时间以及发送是否失败的。 Rocket.java源码 public class Rocket { IRocketDelegate delegate = null; public Rocket(IRocketDelegate delegate) { this.delegate = delegate; } private long getRocketStartTime() { long startTime = delegate.startAtTime(); return startTime; } private long getRocketEndTime() { long endTime = delegate.endAtTime(); return endTime; } public boolean isOk() { // 超时0.1秒为失败 if (getRocketEndTime() - getRocketStartTime() >= 100) { delegate.sendDidFail(); return false; } return true; } } 在这个类中,声明一个 IRocketDelegate 接口对象,使用该对象调用接口的方法。我们知道,接口不可以直接实例化,换句话说,实例化接口必须实现接口的所有方法。 ...

2012-10-08 · 2 min · 302 words · -

里氏代换原则

里氏代换原则 里氏代换原则 (Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对"开-闭"原则的补充。实现"开-闭"原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。LSP讲的是基类和子类的关系。只有当这种关系存在时,里氏代换关系才存在。如果两个具体的类A,B之间的关系违反了LSP的设计,(假设是从B到A的继承关系)那么根据具体的情况可以在下面的两种重构方案中选择一种。 –创建一个新的抽象类C,作为两个具体类的超类,将A,B的共同行为移动到C中来解决问题。 –从B到A的继承关系改为委派关系。 为了说明,我们先用第一种方法来看一个例子,第二种办法在另外一个原则中说明。我们就看那个著名的长方形和正方形的例子。对于长方形的类,如果它的长宽相等,那么它就是一个正方形,因此,长方形类的对象中有一些正方形的对象。对于一个正方形的类,它的方法有个setSide和getSide,它不是长方形的子类,和长方形也不会符合LSP。 eg: 长方形类: public class Rectangle{ … setWidth(int width){ this.width=width; } setHeight(int height){ this.height=height } } 正方形类: public class Square{ … setWidth(int width){ this.width=width; this. height=width; } setHeight(int height){ this.setWidth(height); } } 例子中改变边长的函数: public void resize(Rectangle r){ while(r.getHeight()<=r.getWidth){ r.setHeight(r.getWidth+1); } } 那么,如果让正方形当做是长方形的子类,会出现什么情况呢?我们让正方形从长方形继承,然后在它的内部设置width等于height,这样,只要width或者height被赋值,那么width和height会被同时赋值,这样就保证了正方形类中,width和height总是相等的.现在我们假设有个客户类,其中有个方法,规则是这样的,测试传入的长方形的宽度是否大于高度,如果满足就停止下来,否则就增加宽度的值。现在我们来看,如果传入的是基类长方形,这个运行的很好。根据LSP,我们把基类替换成它的子类,结果应该也是一样的,但是因为正方形类的width和height会同时赋值,这个方法没有结束的时候,条件总是不满足,也就是说,替换成子类后,程序的行为发生了变化,它不满足LSP。 那么我们用第一种方案进行重构,我们构造一个抽象的四边形类,把长方形和正方形共同的行为放到这个四边形类里面,让长方形和正方形都是它的子类,问题就OK了。对于长方形和正方形,取width和height是它们共同的行为,但是给width和height赋值,两者行为不同,因此,这个抽象的四边形的类只有取值方法,没有赋值方法。上面的例子中那个方法只会适用于不同的子类,LSP也就不会被破坏。在进行设计的时候,我们尽量从抽象类继承,而不是从具体类继承。如果从继承等级树来看,所有叶子节点应当是具体类,而所有的树枝节点应当是抽象类或者接口。当然这个只是一个一般性的指导原则,使用的时候还要具体情况具体分析。

2012-10-08 · 1 min · 53 words · -

戴森球

戴森球 戴森球[1]是一种设想中的巨型人造结构,由弗里曼·戴森先生提出。这样一个"球体"是由环绕太阳的卫星所构成,完全包围恒星并且获得其绝大多数或全部的能量输出。戴森认为这样的结构是在宇宙中长期存在并且能源需求不断上升的文明的逻辑必然,并且他建议搜寻这样的人造天体结构以便找到外星超级文明。 从那时起,各种各样的设计,包括建造人工天体或一系列这样的结构以便包围太阳,便不断地由一些狂想的工程学家或科幻小说所提出,并冠以"戴森球"之名。这些后续的设想没有仅仅在从太阳能收集站上止步-许多工程设计还包括建设人类殖民地和工业基地。 http://baike.baidu.com/view/468337.htm

2012-10-08 · 1 min · 4 words · -

图像二值化

图像二值化 就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的黑白效果。 将256个亮度等级的灰度图像通过适当的阈值选取而获得仍然可以反映图像整体和局部特征的二值化图像。在数字图像处理中,二值图像占有非常重要的地位,首先,图像的二值化有利于图像的进一步处理,使图像变得简单,而且数据量减小,能凸显出感兴趣的目标的轮廓。其次,要进行二值图像的处理与分析,首先要把灰度图像二值化,得到二值化图像。 所有灰度大于或等于阀值的像素被判定为属于特定物体,其灰度值为255表示,否则这些像素点被排除在物体区域以外,灰度值为0,表示背景或者例外的物体区域。

2012-09-30 · 1 min · 4 words · -

java ocr tesseract

java ocr tesseract http://ykf.iteye.com/blog/212431

2012-09-30 · 1 min · 4 words · -

OCR之 Tesseract

OCR之 Tesseract http://www.cnblogs.com/brooks-dotnet/archive/2010/10/05/1844203.html 光学字符识别(OCR,Optical Character Recognition)是指对文本资料进行扫描,然后对图像文件进行分析处理,获取文字及版面信息的过程。OCR技术非常专业,一般多是印刷、打印行业的从业人员使用,可以快速的将纸质资料转换为电子资料。关于中文OCR,目前国内水平较高的有清华文通、汉王、尚书,其产品各有千秋,价格不菲。国外OCR发展较早,像一些大公司,如IBM、微软、HP等,即使没有推出单独的OCR产品,但是他们的研发团队早已掌握核心技术,将OCR功能植入了自身的软件系统。对于我们程序员来说,一般用不到那么高级的,主要在开发中能够集成基本的OCR功能就可以了。这两天我查找了很多免费OCR软件、类库,特地整理一下,今天首先来谈谈Tesseract,下一次将讨论下Onenote 2010中的OCR API实现。可以在这里查看OCR技术的发展简史。 测试代码下载 转载请注明出处: http://www.cnblogs.com/brooks-dotnet/archive/2010/10/05/1844203.html 1、Tesseract概述 Tesseract的OCR引擎最先由HP实验室于1985年开始研发,至1995年时已经成为OCR业内最准确的三款识别引擎之一。然而,HP不久便决定放弃OCR业务,Tesseract也从此尘封。 数年以后,HP意识到,与其将Tesseract束之高阁,不如贡献给开源软件业,让其重焕新生--2005年,Tesseract由美国内华达州信息技术研究所获得,并求诸于Google对Tesseract进行改进、消除Bug、优化工作。 Tesseract目前已作为开源项目发布在Google Project,其项目主页在这里查看,其最新版本3.0已经支持中文OCR,并提供了一个命令行工具。本次我们来测试一下Tesseract 3.0,由于命令行对最终用户不太友好,我用WPF简单封装了一下,就可以方便的进行中文OCR了。

2012-09-30 · 1 min · 17 words · -

java取整和四舍五入

java取整和四舍五入 Math.round Math.round(-1.1): -1 Math.round(-1.5): -1 Math.round(-1.6): -2 Math.round(0.1): 0 Math.round(0.5): 1 Math.round(0.6): 1 Math.round(1.1): 1 Math.round(1.5): 2 Math.round(1.6): 2 round 方法,我们通常会说这个方法表示"四舍五入",但是当参数为负数时,就不太好理解。 所以也有以下形式 即将原来的数字加上0.5后再向下取整。 Math.round(x) = Math.floor(x + 0.5) import java.math.BigDecimal; import java.text.DecimalFormat; public class TestGetInt{ public static void main(String[] args){ double i=2, j=2.1, k=2.5, m=2.9; System.out.println(“舍掉小数取整:Math.floor(2)=” + (int)Math.floor(i)); System.out.println(“舍掉小数取整:Math.floor(2.1)=” + (int)Math.floor(j)); System.out.println(“舍掉小数取整:Math.floor(2.5)=” + (int)Math.floor(k)); ...

2012-09-30 · 2 min · 287 words · -

Java Image与BufferedImage

Java Image 与 BufferedImage Image是一个抽象类,BufferedImage是Image的实现。Image和BufferedImage的主要作用就是将一副图片加载到内存中。 Java将一副图片加载到内存中的方法是: String imgPath = “C://demo.jpg”; BufferedImage image = ImageIO.read(new FileInputStream(imgPath)); 该方法可以获得图片的详细信息,例如: 获得图片的宽度: image.getWidth(null);图片只有加载内存中才能对图片进行进一步的处理。 还有一个方法 String imgPath = "C://demo.jpg"; Image imageToolkit.getDefaultToolkit().getImage(imgPath); 但该方法不能把图片加载到内存中,仅仅是得到图片,所以也就不能获得图片的信息,图片的长宽信息都无法拿到。 文章地址: http://javapub.iteye.com/blog/683944

2012-09-30 · 1 min · 28 words · -

短信验证码

短信验证码 短信验证码有效期2分钟 验证码 6 位纯数字 每个手机号60秒内只能发一次短信验证码, 前后端都要做验证 同一个手机号在同一时间可以有多个有效的验证码 验证码不记录到日志 验证码使用后作废 (使用后作废,不太友好,如果有其它信息填写错误得等1分钟再重新取验证码) 验证码至多可以使用3次,无论是否匹配都作废,防止暴力攻击 (一个手机号验证三次之后, 作废关联的验证码) java 识别验证码 http://blog.csdn.net/problc/article/details/5800093 https://www.cnblogs.com/guokun/p/11042903.html https://insights.thoughtworks.cn/sms-authentication-login-api/

2012-09-30 · 1 min · 19 words · -

Map, Dictionary

Map, Dictionary Dictionary Dictionary 是 Hashtable 的抽象父类,在 java.util包下,他的子类有 Hashtable, Properties. 它的主要作用是用于记录 键到值的一一对应关系。没错,从数学的概念上讲,这种映射关系就是一对一的。也就是说,一个key最多只能找到一个value. 如果给出一个 Dictionary 的子类对象和一个 key, 就可以查找有没有包含相关的元素。需要注意的是:任何非空(non-null)的对象才能用作 key 和 value. 通常,类的实现应使用 equals 方法来确定两个键是否相同。 注意:此类已过时。 新的实现应实现 Map 接口,而不是扩展此类。 Map 接口 Map 是一个接口,还是看图: Map 是一个将 keys 映射到 values 的对象。一个 map 对象不能包含重复的 keys. 每一个 key 最多只能映射到一个对象。 Map 这个接口是为了取代 Dictionary 这个抽象类的,更直白的说,就是拿一个接口去取代之前抽象类。 three collection views Map 接口提供了三套查看方法来查看map所包含的内容。 查看它所包含的所有 keys (view as a set of keys) 查看它所包含的所有 values(view as collection of values) 查看它所包含的键-值映射。(view as a set of key-value mappings) ...

2012-09-27 · 1 min · 78 words · -

回车, 换行符, CRLF, LF

回车, 换行符, CRLF, LF 换行 line feed, LF, newline, \n, ascii 码: 0x0A 回车, carriage return, CR, return, \r, ascii 码: 0x0D CRLF, Carriage return & line feed unix: 换行, \n windows: 换行(回车+换行), \r\n, Unix/Mac 下打开会显示成 ^M macos: Line Feed, LF https://blog.csdn.net/wjcquking/article/details/6634504 回车符号和换行符号产生背景 关于"回车" (carriage return) 和"换行" (line feed) 这两个概念的来历和区别。 在计算机还没有出现之前,有一种叫做电传打字机 (Teletype Model 33) 的玩意,每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。 于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做"回车",告诉打字机把打印头定位在左边界;另一个叫做"换行",告诉打字机把纸向下移一行。 这就是"换行"和"回车"的来历,从它们的英语名字上也可以看出一二。 后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。 Unix系统里,每行结尾只有"<换行>",即"\n";Windows系统里面,每行结尾是" <回车><换行>",即"\r\n";Mac系统里,每行结尾是"<回车>"。一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在 Unix/Mac 下打开的话,在每行的结尾可能会多出一个^M符号 windows创建的文件是 \n\r 结束的, 而linux,mac这种unix类系统是\n结束的。 所以unix的文本到windows会出现换行丢失 (ultraedit这种软件可以正确识别) ; 而反过来就会出现^M的符号了 ...

2012-09-27 · 1 min · 138 words · -

java读写文件

java读写文件 Java获取当前路径 利用System.getProperty()函数获取当前路径: System.out.println(System.getProperty(“user.dir”));//user.dir指定了当前的路径 使用File提供的函数获取当前路径: File directory = new File("");//设定为当前文件夹 try{ System.out.println(directory.getCanonicalPath());//获取标准的路径 System.out.println(directory.getAbsolutePath());//获取绝对路径 }catch(Exceptin e){} File.getCanonicalPath()和File.getAbsolutePath()大约只是对于new File(".")和new File("..")两种路径有所区别。 对于getCanonicalPath()函数,".“就表示当前的文件夹,而”..“则表示当前文件夹的上一级文件夹 对于getAbsolutePath()函数,则不管”."、"..",返回当前的路径加上你在new File()时设定的路径 至于getPath()函数,得到的只是你在new File()时设定的路径 http://sharewind.iteye.com/blog/227538 ```java //=============================写文件 package fier; import java.io.*; public class write { public static void main(String[] args) { write("E:\123.txt", "hello"); } public static void write(String path, String content) { String s = new String(); String s1 = new String(); try { File f = new File(path); if (f.exists()) { System.out.println("文件存在"); } else { System.out.println("文件不存在,正在创建..."); if (f.createNewFile()) { System.out.println("文件创建成功!"); } else { System.out.println("文件创建失败!"); } } BufferedReader input = new BufferedReader(new FileReader(f)); while ((s = input.readLine()) != null) { s1 += s + "n"; } System.out.println("文件内容: " + s1); input.close(); s1 += content; BufferedWriter output = new BufferedWriter(new FileWriter(f)); output.write(s1); output.close(); } catch (Exception e) { e.printStackTrace(); } } } //=============================读文件 package fier; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStreamReader; public class sdsd { /** * @param args */ public static void main(String[] args) { read("E:\123.txt"); } public static void read(String file) { String s = null; StringBuffer sb = new StringBuffer(); File f = new File(file); if (f.exists()) { System.out.println("文件存在"); try { BufferedReader br = new BufferedReader(new InputStreamReader( new FileInputStream(f))); while ((s = br.readLine()) != null) { sb.append(s); } System.out.println(sb); } catch (Exception e) { e.printStackTrace(); } }else{ System.out.println("文件不存在!"); } } } ```

2012-09-27 · 2 min · 217 words · -

Java Http连接中 (HttpURLConnection) 中使用代理 (Proxy) 及其验证 (Authentication)

Java Http连接中 (HttpURLConnection) 中使用代理 (Proxy) 及其验证 (Authentication) System.setProperty("http.proxyHost", "www.proxy.com"); System.setProperty("http.proxyPort", "8080"); 使用Java的HttpURLConnection类可以实现HttpClient的功能,而不需要依赖任何其他类库。所有有时候大家就直接使用它来完成一些简单 (或复杂) 的功能。但是你活在伟大的{print G.F.W}后面,如果你需要访问的网站被墙了,那HttpURLConnection类就会出现连接超时的错误。这时候就需要给他设置代理 (Proxy) 了。 设置代理 (Proxy) 可以有两种方式: 1、通过设置系统属性(System.setPropery(String key, String value)的方式 首先你可以在这里看到Java支持的属性。我们可以使用其中的http.proxyHost,http.proxyPort这两个属性。顾名思义,就是分别设置代理服务器地址和代理端口。 [c language="-sharp"][/c] 替换上面的www.proxy.com为你的代理服务器地址或IP地址,以及相应的端口为真实端口,Http连接及可以工作了。需要注意的是如果你设置了这些属性,那么所有的Http请求都会通过代理服务器。这些属性是JVM级别的,设置了以后对所有的同类请求都有效。比如上面的是关于http的,还有关于ftp的等等。 如果你的代理服务器不需要验证,那到此就结束了。但一般都是需要验证的。但是你要是看了上面Java支持的属性列表,你就会发现那里面并没有期望中的 [c language="-sharp"][/c] http://blog.csdn.net/redhat456/article/details/6149774# http.proxyUserName=username http.proxyPassword=password 这两个属性。 这时就需要java.net.Authenticator类来完成一般的Http验证。但是java.net.Authenticator这个类却是个抽象类,我们要使用还需要实例化一下子自己的类。个人觉得这里很不方便。如下: ```java``` http://blog.csdn.net/redhat456/article/details/6149774# http://blog.csdn.net/redhat456/article/details/6149774# Authenticator.setDefault(new BasicAuthenticator(userName, password)); 这样就提供了基于Http Basic的验证,接着就可以顺畅的使用需要验证的代理了。 2、通过java.net.Proxy类。 这种方式是实例化一个Proxy类提供代理服务器的信息,如端口和地址。 ```java``` http://blog.csdn.net/redhat456/article/details/6149774# Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port)); URLConnection conn = url.openConnection(proxy); 使用代理的方式是在打开Http连接的时候同时传递一个Proxy参数。如果需要验证信息的话我们可以添加一个Http头参数来实现。 ```java``` http://blog.csdn.net/redhat456/article/details/6149774# ...

2012-09-27 · 1 min · 83 words · -