├── README.md ├── code ├── README.md └── simple-threadpool-master │ ├── .gitattributes │ ├── .project │ ├── README.md │ ├── pom.xml │ └── src │ ├── main │ └── java │ │ └── com │ │ └── tinymood │ │ └── threadpool │ │ ├── SimpleThreadFactory.java │ │ ├── SimpleThreadPool.java │ │ └── ThreadPool.java │ └── test │ └── java │ └── com │ └── tinymood │ └── threadpool │ └── SimpleThreadPoolTest.java ├── docs ├── .DS_Store ├── java │ ├── java基础 │ │ ├── hashmap源码阅读.md │ │ ├── java中的四种引用.md │ │ ├── java中的接口和抽象类.md │ │ ├── java内存泄露.md │ │ ├── 泛型.md │ │ ├── 线程、多线程和线程池.md │ │ └── 集合类.md │ ├── java进阶 │ │ └── 虚拟机 │ │ │ ├── java虚拟机的内存划分.md │ │ │ ├── jvm中的垃圾回收机制.md │ │ │ └── 反射机制.md │ └── spring │ │ └── filter过滤器.md ├── 操作系统 │ ├── 操作系统常见问题.md │ └── 电脑中常用的“扇区”、“簇”、“块”、“页”等概念.md ├── 数据库 │ ├── 数据库事务的隔离级别.md │ ├── 索引结构——单维.md │ └── 索引结构——多维.md ├── 框架 │ └── 远程通信的方式及选择,RPC RMI WebServer HTTP JMS.md ├── 计算机网络 │ ├── .DS_Store │ ├── IP协议_TCP:UDP协议基础.md │ └── socket_tcp:ip_http关系.md.md ├── 设计模式 │ ├── DesignPattern │ │ ├── .classpath │ │ ├── .gitignore │ │ ├── .project │ │ ├── lib │ │ │ ├── cglib-2.2.jar │ │ │ └── cglib-nodep-2.2.jar │ │ └── src │ │ │ └── com │ │ │ └── i3geek │ │ │ └── pattern │ │ │ ├── adapter │ │ │ ├── Adaptee │ │ │ │ └── TwoPlug.java │ │ │ ├── Adapter │ │ │ │ ├── Two2ThreeAdapter.java │ │ │ │ └── Two2ThreeAdapterExtends.java │ │ │ ├── Client.java │ │ │ ├── README.md │ │ │ └── Target │ │ │ │ └── ThreePlug.java │ │ │ ├── bridge │ │ │ ├── Client.java │ │ │ ├── Readme.md │ │ │ ├── first │ │ │ │ ├── ConcreteImplementorA.java │ │ │ │ ├── ConcreteImplementorB.java │ │ │ │ └── Implementor.java │ │ │ ├── second │ │ │ │ ├── Abstraction.java │ │ │ │ ├── RefinedAbstractionA.java │ │ │ │ └── RefinedAbstractionB.java │ │ │ └── third │ │ │ │ ├── Graphy.java │ │ │ │ ├── GraphyA.java │ │ │ │ └── GraphyB.java │ │ │ ├── builder │ │ │ ├── Readme.md │ │ │ ├── builder │ │ │ │ └── Builder.java │ │ │ ├── client.java │ │ │ ├── concreteBuilder │ │ │ │ ├── BrickBuilder.java │ │ │ │ └── ThatchedBuilder.java │ │ │ ├── director │ │ │ │ └── Director.java │ │ │ └── product │ │ │ │ └── House.java │ │ │ ├── command │ │ │ ├── Client.java │ │ │ ├── Readme.md │ │ │ ├── command │ │ │ │ └── Command.java │ │ │ ├── concreteCommand │ │ │ │ └── LightOnCommand.java │ │ │ ├── invoker │ │ │ │ └── SimpleRemoteControl.java │ │ │ └── receiver │ │ │ │ └── Light.java │ │ │ ├── decorate │ │ │ ├── Client.java │ │ │ ├── Readme.md │ │ │ ├── component │ │ │ │ └── Beverage.java │ │ │ ├── concreteComponent │ │ │ │ ├── Espresso.java │ │ │ │ └── HouseBlend.java │ │ │ ├── concreteDecorator │ │ │ │ └── Mocha.java │ │ │ └── decorator │ │ │ │ └── CondimentDecorator.java │ │ │ ├── facade │ │ │ ├── Readme.md │ │ │ ├── client.java │ │ │ ├── facade │ │ │ │ └── Cinema.java │ │ │ └── subSystem │ │ │ │ ├── DVDplayer.java │ │ │ │ ├── Light.java │ │ │ │ └── Screen.java │ │ │ ├── factory │ │ │ ├── Client.java │ │ │ ├── Readme.md │ │ │ ├── abstractFactory │ │ │ │ ├── AFactory.java │ │ │ │ ├── BFactory.java │ │ │ │ ├── IFactory.java │ │ │ │ └── product │ │ │ │ │ ├── AText.java │ │ │ │ │ ├── BText.java │ │ │ │ │ └── Text.java │ │ │ ├── factory │ │ │ │ ├── AButtonFactory.java │ │ │ │ ├── BButtonFactory.java │ │ │ │ └── Factory.java │ │ │ ├── product │ │ │ │ ├── AButton.java │ │ │ │ ├── BButton.java │ │ │ │ └── Button.java │ │ │ └── simpleFactory │ │ │ │ └── ButtonSFactory.java │ │ │ ├── iterator │ │ │ ├── Client.java │ │ │ ├── Readme.md │ │ │ ├── aggregate │ │ │ │ └── List.java │ │ │ ├── concreteAggregate │ │ │ │ └── ConcreteAggregate.java │ │ │ ├── concreteiterator │ │ │ │ └── ConcreteIterator.java │ │ │ └── iterator │ │ │ │ └── Iterator.java │ │ │ ├── observer │ │ │ ├── Client.java │ │ │ ├── Readme.md │ │ │ ├── observer │ │ │ │ ├── ConcreteObserver.java │ │ │ │ └── Observer.java │ │ │ └── subject │ │ │ │ ├── AbstractSubject.java │ │ │ │ └── ConcreteSubject.java │ │ │ ├── proxy │ │ │ ├── Client.java │ │ │ ├── README.md │ │ │ ├── dynamicProxy │ │ │ │ ├── cglib │ │ │ │ │ └── cglibProxy.java │ │ │ │ └── jdk │ │ │ │ │ └── TimeHandler.java │ │ │ ├── real │ │ │ │ ├── Car.java │ │ │ │ ├── Moveable.java │ │ │ │ └── Train.java │ │ │ └── staticProxy │ │ │ │ ├── CarExtend.java │ │ │ │ └── CarImplement.java │ │ │ ├── responsibilityChain │ │ │ ├── Client.java │ │ │ ├── concreteHandler │ │ │ │ ├── DeptHandler.java │ │ │ │ ├── GeneralHandler.java │ │ │ │ └── ProjectHandler.java │ │ │ └── handler │ │ │ │ └── Handler.java │ │ │ ├── singleton │ │ │ ├── Client.java │ │ │ ├── Readme.md │ │ │ └── singleton │ │ │ │ ├── HungrySingleton.java │ │ │ │ └── LazySingleton.java │ │ │ ├── strategy │ │ │ ├── Client.java │ │ │ ├── Readme.md │ │ │ ├── concreteStrategy │ │ │ │ ├── quickSort.java │ │ │ │ └── selectSort.java │ │ │ ├── context │ │ │ │ └── context.java │ │ │ └── strategy │ │ │ │ └── Strategy.java │ │ │ └── template │ │ │ ├── Abstract │ │ │ └── Base.java │ │ │ ├── Client.java │ │ │ ├── Concrete │ │ │ ├── Coffee.java │ │ │ └── Tea.java │ │ │ └── Readme.md │ ├── 代理模式.md │ ├── 单例模式.md │ ├── 建造者模式.md │ ├── 桥接模式.md │ ├── 模板方法模式.md │ ├── 策略模式.md │ ├── 简单工厂模式、工厂方法模式、抽象工厂模式.md │ ├── 装饰模式.md │ ├── 责任链模式.md │ └── 适配器模式.md └── 项目 │ └── websocket介绍,与socket的区别.md └── nowcoder ├── .classpath ├── .project ├── .settings └── org.eclipse.jdt.core.prefs └── src ├── nowcoder ├── leetcode │ ├── common │ │ └── ListNode.java │ └── reorder_list.java ├── y2016 │ └── m4 │ │ ├── Printer.java │ │ ├── StringRotation.java │ │ └── clockwisePrint.java ├── 一站通offer │ ├── test.java │ ├── test2.java │ └── test3.java └── 剑指offer │ ├── code10.java │ ├── code11.java │ ├── code12.java │ ├── code13.java │ ├── code14.java │ ├── code15.java │ ├── code16.java │ ├── code17.java │ ├── code18.java │ ├── code19.java │ ├── code20.java │ ├── code21.java │ ├── code22.java │ ├── code23.java │ ├── code24.java │ ├── code25.java │ ├── code26.java │ ├── code27.java │ ├── code28.java │ ├── code29.java │ ├── code3.java │ ├── code30.java │ ├── code31.java │ ├── code32.java │ ├── code33.java │ ├── code34.java │ ├── code35.java │ ├── code36.java │ ├── code37.java │ ├── code38.java │ ├── code39.java │ ├── code4.java │ ├── code40.java │ ├── code41.java │ ├── code42.java │ ├── code43.java │ ├── code44.java │ ├── code45.java │ ├── code46.java │ ├── code47.java │ ├── code48.java │ ├── code49.java │ ├── code5.java │ ├── code50.java │ ├── code51.java │ ├── code6.java │ ├── code7.java │ ├── code8.java │ ├── code9.java │ └── util │ ├── ListNode.java │ ├── RandomListNode.java │ └── TreeNode.java └── practice ├── Binary.java ├── MergeSort.java ├── ThreadLocalp.java ├── quickSort.java ├── reject.java ├── test.java └── tree_traversal.java /code/README.md: -------------------------------------------------------------------------------- 1 | # 代码仓库 2 | 3 | -------------------------------------------------------------------------------- /code/simple-threadpool-master/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /code/simple-threadpool-master/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | simple-threadpool 4 | NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse. 5 | 6 | 7 | 8 | org.eclipse.jdt.core.javabuilder 9 | 10 | 11 | org.eclipse.m2e.core.maven2Builder 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | org.eclipse.m2e.core.maven2Nature 17 | 18 | -------------------------------------------------------------------------------- /code/simple-threadpool-master/README.md: -------------------------------------------------------------------------------- 1 | # simple-threadpool 2 | Java实现的简单线程池 -------------------------------------------------------------------------------- /code/simple-threadpool-master/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.tinymood.threadpool 5 | simple-threadpool 6 | 0.0.1-SNAPSHOT 7 | simple-threadpool 8 | 9 | 10 | 1.7 11 | 1.7 12 | UTF-8 13 | 14 | 15 | 16 | 17 | junit 18 | junit 19 | 4.12 20 | test 21 | 22 | 23 | -------------------------------------------------------------------------------- /code/simple-threadpool-master/src/main/java/com/tinymood/threadpool/SimpleThreadFactory.java: -------------------------------------------------------------------------------- 1 | package com.tinymood.threadpool; 2 | 3 | import java.util.concurrent.ThreadFactory; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | 7 | public class SimpleThreadFactory implements ThreadFactory { 8 | private static final String MARK = "SimpleThreadPool-Worker-"; 9 | 10 | private AtomicInteger id = new AtomicInteger(); 11 | 12 | private boolean isDaemon = false; 13 | 14 | @Override 15 | public Thread newThread(Runnable r) { 16 | Thread thread = new Thread(r, MARK+id.incrementAndGet()); 17 | thread.setDaemon(isDaemon); 18 | 19 | return thread; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /code/simple-threadpool-master/src/main/java/com/tinymood/threadpool/SimpleThreadPool.java: -------------------------------------------------------------------------------- 1 | package com.tinymood.threadpool; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.BlockingQueue; 6 | import java.util.concurrent.LinkedBlockingQueue; 7 | import java.util.concurrent.ThreadFactory; 8 | 9 | public class SimpleThreadPool implements ThreadPool { 10 | private static final int DEFAULT_POOL_SIZE = Runtime.getRuntime().availableProcessors(); 11 | 12 | // 任务队列 13 | private final BlockingQueue taskQueue = new LinkedBlockingQueue(); 14 | 15 | // 线程类Worker,抓取任务并执行任务 16 | private final List workers = new ArrayList(DEFAULT_POOL_SIZE); 17 | 18 | private final ThreadFactory threadFactory = new SimpleThreadFactory(); 19 | 20 | private int size; 21 | 22 | public SimpleThreadPool(int size) { 23 | this.size = size < 1 ? DEFAULT_POOL_SIZE:size; 24 | prestartThread(); 25 | } 26 | 27 | private void prestartThread() { 28 | for (int i=0; i 来创建弱引用。具体代码如下: 32 | 33 | Counter counter = new Counter(); 34 | WeakReference weakCounter = new WeakReference(counter); 35 | counter = null; 36 | 37 | 1)创建强引用对象counter 38 | 39 | 2)创建弱引用对象weakCounter 40 | 41 | 3)将强引用对象置空,此时垃圾回收器发现该对象时将立即回收。 42 | 43 | ## 虚引用 44 | 45 | 虚引用,就是形同虚设,不影响对象的生命周期,一个对象持有虚引用和没有引用的效果是一样的。任何时候 都可能被垃圾回收机制所回收。和软引用、弱引用的区别主要在于,**必须与引用队列联合使用**。主要用来跟踪对象被垃圾回收的活动。 46 | 47 | java.lang.ref.PhantomReference 来创建虚引用。具体代码如下: 48 | 49 | DigitalCounter digit = new DigitalCounter(); 50 | PhantomReference phantom = new PhantomReference(digit); 51 | digit = null; 52 | 53 | 用途: 54 | 处理类似图片的大文件的情况。当你确定一个图片数据对象应该被回收,你可以利用虚引用来判断这个对象回收之后在继续加载下一张图片。 55 | 56 | ## 引用队列 57 | 58 | 软引用、弱引用和虚引用可以使用引用队列。**当该引用的对象被垃圾回收器标记为待回收时,便会加入到引用队列中。**可以通过判断对象是否在引用队列中得知,对象是否将被回收,从而完成相关的删除工作。 59 | 60 | ReferenceQueue refQueue = new ReferenceQueue(); DigitalCounter digit = new DigitalCounter(); 61 | PhantomReference phantom = new PhantomReference(digit, refQueue); 62 | 63 | ## 总结 64 | 65 | 强引用:永远不会被垃圾回收器删除。(垃圾回收器是回收不可达的对象,不可达代表没有引用所指) 66 | 67 | 软引用:内存不足时进行回收。可以做缓存用 68 | 69 | 弱引用:只要发现就进行回收。可以做缓存、存储元数据、大数据等用 70 | 71 | 虚引用:和没有引用一样,必须与引用队列一起使用。可以用于跟踪对象是否被回收。 72 | 73 | 引用队列:被回收器标记的对象,该引用则会加入引用队列中。(只有软引用、弱引用和虚引用可以使用) -------------------------------------------------------------------------------- /docs/java/java基础/java中的接口和抽象类.md: -------------------------------------------------------------------------------- 1 | # JAVA中的接口和抽象类 2 | 3 | 抽象是面向对象设计的几大特点之一,在JAVA中的体现则是抽象类和接口。这两者十分的相似,想很多初学者甚至接触java几年的人也很难分清他们。今天笔者在查看集合类相关的代码的时候,发现了有部分是接口如List、Map等,有部分是抽象类如AbstractList、AbstractSet等,由于对两者不是十分的清楚,比较迷惑。所以今天笔者在本文则主要介绍下这两者的区别。 4 | 5 | ## 抽象类 6 | 7 | ### 抽象方法 8 | 9 | 利用abstract修饰只有声明没有实现的方法,叫做抽象方法。如: 10 | 11 | abstract void fun(); 12 | 13 | ### 抽象类 14 | 15 | 利用abstract修饰的类,叫做抽象类。如: 16 | 17 | abstract class ClassA{ 18 | } 19 | 20 | **有抽象方法的类,必须是抽象类。抽象类可以没有抽象方法。**抽象类和普通的类一样,可以拥有成员变量和普通的成员方法。 21 | 22 | **因为抽象类中含有无具体实现的方法,所以不能用抽象类创建实例对象!**当然可能一个类,只用abstract修饰,但是却没有抽象方法,这也属于抽象类,是不可以实例化的。但是如果要是没有抽象方法的话为什么还要设计成抽象类呢?所以不必去深究。 23 | 24 | ### 作用 25 | 26 | 因此可以看出,抽象类就是为了继承而存在的。如果定义了一个抽象类却不继承,那是没有任何用处的。当然,**在继承之后,之类必须对父类中所有没有实现的方法进行实现,**否则是不被允许的(除非是抽象类继承的抽象类,此时可以不实现)。 27 | 28 | ### 和普通类的区别 29 | 30 | 1. 抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。 31 | 2. 抽象类不能用来创建对象; 32 | 3. 若子类继承抽象类,则子类必须实现父类的抽象方法。否则子类必须也定义为抽象类。 33 | 34 | 在其他方面,抽象类和普通的类并没有区别。 35 |    36 | ## 接口 37 | 38 | 接口是一种极度抽象的类型,它比抽象类更加抽象。接口中可以有变量和方法。但是接口中的**变量会被隐式地指定为public static final变量(定义成其他类型,如private会报错),同时也意味着变量必须进行初始化**。接口中的**方法会被隐式地指定为public abstract方法(用其他关键字,比如private、protected、static、 final等会报错)**。 39 | 40 | 并且接口中所有的方法不能有具体的实现,**接口中的方法必须都是抽象方法。** 41 | 42 | **同样当一个非抽象类实现了接口的话,必须实现全部方法。否则该类必须是抽象类,或者接口** 43 | 44 | ## 抽象类和接口比较 45 | 46 | ### 语法层面上的区别 47 | 48 | 1. 接口只能有public abstract 方法,抽象类的方法类型更多,可以有普通方法; 49 | 2. 接口中的成员变量只能是public static final类型的,抽象类的变量类型更多,可以有普通变量; 50 | 3. **接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;** 51 | 4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。 52 | 53 | ### 设计层面上的区别 54 | 55 | 1)抽象类是对事物的抽象(类的抽象),接口是对行为的抽象。 56 | 57 | 比如定义Bird是一个抽象类,实现它的有各种鸟类。定义一个接口是fly,各种鸟类可以实现这个接口。通俗来说:继**承是一个 "是不是"的关系,而 接口 实现则是 "有没有"的关系。**鸟类继承了Bird,那就注定它的种类,而至于是否实现fly接口,只是觉得它是否拥有这项特点(行为)。 58 | 59 | 2)抽象类是一种模板式设计,接口是一种行为规范,一种辐射式设计。 60 | 61 | 比如对于同一个方法,通过抽象类模板式设计后,当修改该方法时,只需要在模板中修改,所有子类均可得到更新;通过接口辐射式设计后,当修改该方法时,需要在所有实现类中进行修改,才可以得到更新,相互独立的。 62 | 63 | ### 两者使用上的联系 64 | 65 | 1. **接口若继承,则必须继承接口。不能实现。不能继承抽象类** 66 | 2. **抽象类 可以实现接口,可以继承抽象类,不能继承接口** -------------------------------------------------------------------------------- /docs/java/java基础/java内存泄露.md: -------------------------------------------------------------------------------- 1 | http://www.i3geek.com/archives/1241 2 | 3 | # Java内存泄露 4 | 5 | > 内存泄露是指当不再使用的对象没有得到释放,还占有内存,从而造成内存浪费的情况。 6 | 7 | 在C++中,内存是由程序员进行管理的,从内存的创建、使用和释放都是程序员去操作。很多时候因为疏忽忘记对对象的释放,从而导致无用对象不断增加,导致内存不足,产生内存泄露的现象。 8 | 9 | ## 原因 10 | 11 | 一般产生内存泄露的原因主要有如下两种:第一种,没有释放掉不需要的内存;第二种,内存对象明明已经不需要,但还保留着这块内存和它的访问引用。 12 | 13 | 在java中,对于对象的回收是由垃圾回收器进行处理的,并不需要程序员的干涉,所以基本不存在第一种情况。那产生内存泄漏的原因主要是第二种情况,因为程序员的操作导致明明不需要的、该被回收的对象,没有被认定为垃圾,没有回收掉,则产生了内存泄露。 14 | 15 | ### 根本原因 16 | 17 | 根本原因就是,长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收。 18 | 19 | 说的比较抽象 看看下面的例子: 20 | 21 | Vector v = new Vector( 100 ); 22 | for ( int i = 1 ;i < 100 ; i ++ ){ 23 | Object o = new Object(); 24 | v.add(o); 25 | o = null ; //认为此时想回收o 26 | } 27 | 28 | 此时将o置为null后仍然不被进行回收。因为短生命周期(Object)对象虽然被置空,但是长生命周期的Vector仍然持有。所以导致不需要的对象,仍然存在,没有被回收,产生内存泄露。此时的解决办法是,将v也置null 29 | 30 | ## 常见场景 31 | 32 | ### 集合类 33 | 34 | 1、如上例,不同生命周期 35 | 36 | 2、在HashMap中,加入数据后,修改数据内容,导致hashcode不同,从而无法根据hashcode删除元素,产生内存溢出 37 | 38 | Set set = new HashSet(); 39 | Person p1 = new Person("张三","pwd1",25); 40 | set.add(p1); //设:此时p1的hashcode为25,HashSet根据25存储 41 | p1.setAge(2); //修改对象,此时p1的hashcode为1 42 | set.remove(p1);//根据hashcode删除时,找不到对象,删除失败 43 | 44 | ### 单例模式 45 | 46 | 使用单例模式的类,长期持有单例的对象,可能会导致内存泄露。 47 | 48 | ## 避免办法 49 | 50 | 使用java中的多种引用,比如弱引用、软引用和虚引用等,在不同需求下进行使用,从而避免内存泄漏 -------------------------------------------------------------------------------- /docs/java/java基础/泛型.md: -------------------------------------------------------------------------------- 1 | # 泛型 -------------------------------------------------------------------------------- /docs/java/java进阶/虚拟机/java虚拟机的内存划分.md: -------------------------------------------------------------------------------- 1 | 原文:http://www.i3geek.com/archives/1201 2 | 3 | ## java虚拟机的内存划分 4 | 5 | java虚拟机是java程序运行的基础,所有的java程序在生成字节码.class后都被加载后运行在虚拟机上。每一个线程虚拟机都会为其划分出一定的内存空间,若想优化程序并了解运行原理,就必须掌握虚拟机中内存的分配。本文则主要介绍内存划分后的基本用途和概念。 6 | 7 | ### java程序的执行过程 8 | 9 | ![image](http://pic.i3geek.com/uploads/2016/04/java_zxgc.png) 10 | 11 | 如上图所示,在java源码书写完成后,首先需要通过java编译器进行编译,编译后生成.class字节码文件,才可以运行。 12 | 13 | 在运行中,首先由类加载器(class loader)进行加载相应类,具体的加载方法可以了解后续的文章。加载后,交由执行引擎执行,同时jvm也会分配出一块内存空间也就是运行时数据区(JVM 内存)。因此在虚拟机中的内存分配、划分或者是回收机制都是针对这块运行时数据区而言的。 14 | 15 | ### JVM内存的主要部分 16 | 17 | 根据《Java虚拟机规范》的规定,运行时数据区(JVM 内存)主要包含:Java栈、堆、本地方法栈、程序计数器和方法区,五大部分。 18 | 19 | ### 分别的用途 20 | 21 | #### Java栈 22 | 23 | java栈也称作java虚拟机栈,也就是经常说的栈内存。既然叫做栈,顾名思义,就是在内存中以类似于栈的数据结构形式进行存储的。 24 | 25 | 栈中存放的是一个个的栈帧(Stack Frame),每一个栈帧代表一个被调用的方法。其中包括:局部变量表(Local Variables)、操作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池(运行时常量池的概念在方法区部分会谈到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些额外的附加信息。 26 | 27 | 当每一个线程执行每一个方法时,便会向栈中压人一个对应的栈帧,当执行完成后,便弹出栈帧达到销毁的目的。**所以每一个线程会维护一个独立的栈。而且当前线程正在执行的方法的栈帧必定位于栈顶。**同样,在程序递归调用时,容易产生栈内存溢出的问题。**这部分空间是由系统进行自动的创建和释放的,对开发人员来说是透明的。** 28 | 29 | ![image](http://pic.i3geek.com/uploads/2016/04/java_stack.png) 30 | 31 | * 局部变量表:用来存储方法中的局部变量。对于基本类型变量则存储的是其值,若是引用类型变量则存储的是其堆内存的对象引用。**局部变量表的大小,在编译器期间就可以确定,因此是不会发生变化的** 32 | * 操作数栈:线程运行时,计算过程中借助的操作数栈 33 | * 指向运行时常量池的引用:因为在方法执行的过程中有可能需要用到类中的常量,所以必须要有一个引用指向运行时常量。 34 | * 方法返回地址:当方法执行完后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。 35 | 36 | #### 堆 37 | 38 | java中的堆内存(heap)主要是用来存储对象本身和数组的(引用均在栈内存中,堆只存储具体数据),java中的对象可以通过new 方法生成,但是对于对象的回收销毁并不用程序员所操心,Java的垃圾回收机制(GC)会自动进行处理。 39 | 40 | 因此,此后要研究的内存回收机制,java的垃圾收集器主要是针对这部分区域。**另外,堆是被所有线程共享的,在JVM中只有一个堆。** 41 | 42 | #### 本地方法栈 43 | 44 | 本地方法栈与Java栈的作用和原理非常相似。区别只不过是Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的。在JVM规范中,并没有对本地方发展的具体实现方法以及数据结构作强制规定,虚拟机可以自由实现它。在HotSopt虚拟机中直接就把本地方法栈和Java栈合二为一。 45 | 46 | #### 程序计数器 47 | 48 | 程序计数器也称为PC寄存器,是用来存储CPU执行时下一条指令的地址。当CPU要执行指令时,根据寄存器的地址获得下一条指令,同时程序计数器的地址加一或者跳到下一个指令的地址,待CPU处理完成后会再次向寄存器获取地址执行指令,如此循环直到程序执行完毕。 49 | 50 | 由于JVM中的多线程是通过CPU的轮流切换所实现的,因此,为了使线程在轮流切换后仍能继续执行刚刚的指令,**所以每一个线程会单独维护一个程序计数器,切互不干扰的** 51 | 52 | 在JVM规范中规定,如果线程执行的是非native方法,则程序计数器中保存的是当前需要执行的指令的地址;如果线程执行的是native方法,则程序计数器中的值是undefined。由于程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,因此,对于程序计数器是不会发生内存溢出现象(OutOfMemory)的。 53 | 54 | #### 方法区 55 | 56 | JVM的方法区类似于堆内存一样,主要存储了每个类的信息(类名、方法信息和字段信息)、静态变量、常亮以及编译器编译后的代码等。**所以方法区在线程中是被共享的** 57 | 58 | 方法区中有一个很重要的部分就是**常量池**,当每一个类和接口被加载到JVM后,对应的常量池就被创建出来。不仅class字节码文件的常量会写入运行时常量池,在运行期间创建的新的常量也会写入常量池中,如String的intern方法。 59 | 60 | 在JVM规范中,**没有强制要求方法区必须实现垃圾回收。**很多人习惯将方法区称为“永久代”,是因为HotSpot虚拟机以永久代来实现方法区,从而JVM的垃圾收集器可以像管理堆区一样管理这部分区域,从而不需要专门为这部分设计垃圾回收机制。不过自从JDK7之后,Hotspot虚拟机便将运行时常量池从永久代移除了。 61 | 62 | ### 总结 63 | 64 | #### 1、线程间相互独立的内存区 65 | 66 | Java栈内存、本地方法栈和程序计数器 67 | 68 | #### 2、线程间相互共享的内存区 69 | 70 | 堆内存、方法区 71 | 72 | #### 3、需要依靠垃圾回收机制进行回收的内存区 73 | 74 | 堆内存 75 | 76 | #### 4、不会发生溢出的内存区 77 | 78 | 程序计数器 -------------------------------------------------------------------------------- /docs/java/java进阶/虚拟机/反射机制.md: -------------------------------------------------------------------------------- 1 | 万事万物皆对象。类本身也是对象,类是 Java.Long.class的对象 2 | 3 | class foo{} 4 | 5 | //foo是类,该类的实例对象 6 | foo f = new foo(); 7 | //foo是类,本身也是java.long.Class的对象 8 | //任何一个类都是Class的实例对象,(构造函数是私有的)不可以实例化,只有JVM可以进行实例化。这个对象有三种表示方法: 9 | //第一种:->任何一个类都有一个隐含的静态成员变量class 10 | Class c1 = foo.class; 11 | //第二种:已知该类的对象,通过getClass方法获得该类 12 | Class c2 = f.getClass(); 13 | 14 | //c1 c2 分别表示foo类的类类型。类也是对象,是Class类的实例对象,称该对象为该类的类类型 15 | 16 | System.out.println(c1 == c2);//true 17 | //c1 or c2 都表示foo类的类类型。都是Class类的实例对象,一个Class只能有一个实例对象,所以c1==c2 18 | 19 | //第三种:Class.forName("") 20 | Class c3 = null; 21 | try{ 22 | c3 = Class.forName("com.test.foo"); 23 | }catch(Exception e){ 24 | e.printStackTrace(); 25 | } 26 | 27 | System.out.println(c2==c3); //true 28 | 29 | 允许通过类类型创建该类的对象实例 -> 通过c1/c2/c3的newInstance方法创建foo的实例,此处需要强制转换并注意异常 30 | 31 | foo f2 = (foo)c1.newInstance();//前提需要有无参数的构造方法 32 | 33 | ## 动态加载类 Class.forName("") 34 | 35 | - 静态加载类:编译时刻加载类是静态加载类。new出来的都是 静态加载类 36 | - 动态加载类:运行时刻加载类是动态加载类。Class.forName("") 生成类类型,之后用newInstance创建对象 强制转型——接口编程 37 | 38 | //动态加载类 39 | Class c = Class.forName(args[0]); 40 | //通过类类型,加载类对象,*Able为接口* 41 | Able a = (Able)c.newInstance(); 42 | a.start(); 43 | 44 | interface Able{ 45 | public abstract void start(); 46 | } 47 | 48 | class A implements Able{ 49 | public void start(){ 50 | System.out.println(); 51 | } 52 | } 53 | 54 | ## Method类,方法对象 55 | 56 | 一个成员方法就是一个Method对象, 57 | 58 | - getMethods()方法获取的是所有的public的函数,包括父类继承而来的 59 | - getDeclaredMethods()获取的是所有该类自己声明的方法,不管权限,但是不包括父类继承的 60 | - 返回都是数组 61 | 62 | Method[] ms = c.getMethods(); 63 | 64 | 利用反射方法操作对象 65 | 66 | foo f = new foo(); 67 | //获得类类型 68 | Class c = f.getClass(); 69 | //获取方法 print(String,int) 70 | Method m1 = c.getMethod("print",String.class,int.class);//方法名,参数(可变参数 可以直接写 也可以用数组) 71 | //或者 72 | m1 = c.getMethod("print",new class[]{String.class,int.class}); 73 | //用反射操作对象 74 | Object o = m1.invoke(f,"Hello",0);//对象,参数,返回值o是函数的返回值 75 | 76 | ## Field类,成员变量对象 77 | 78 | 一个成员变量是一个Field对象 79 | 80 | - getFields()方法获取的是所有的public的成员变量信息,包括父类继承的 81 | - getDeclareFields() 82 | 83 | ## Constructor类,构造函数对象 84 | 85 | 一个构造函数也是一个Constructor对象 86 | 87 | - getConstructors() 所有public 的构造方法。肯定是自己生命的 88 | - getDeclareConstructors() 所有自己声明的构造方法。 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /docs/java/spring/filter过滤器.md: -------------------------------------------------------------------------------- 1 | # Filter过滤器 2 | 3 | ## 工作原理 4 | 5 | 过滤器是一个服务器端的组件,它可以截取用户端的请求与相应信息,并对这些信息进行过滤。 6 | 可以转发链接,但是不可以响应数据。 7 | 8 | 配置项: 9 | 1. filter配置:filter名称和filter类 10 | 2. filter-map配置:filter名称和(url-pattern路径 或者 servlet名称) 11 | 注:servlet名称意思是,将调用该servlet的servlet-map 同servlet相同的路径。 12 | 13 | ## 生命周期 14 | 15 | 实例化 -> web.xml 只容器加载实例化一次 16 | 17 | 初始化 -> init 只容器加载实例化后初始化一次 调用init方法 18 | 19 | 过滤 -> dofilter 每次过滤调用一次dofilter方法,调用n次 20 | 21 | 销毁 -> destory 容器销毁 执行一次,destory方法 22 | 23 | ## 责任链模式 24 | 25 | 请求 过滤器1 过滤器2 资源(servlet) 26 | 27 | req --> code1 28 | | 29 | chain.dofilter --> code1 30 | | 31 | chain.dofilter --> doGet/doPost 32 | | 33 | res <-- code2 <-- code2 <-- <- 34 | 35 | ## 过滤器类型 36 | 37 | ### request 38 | 39 | 每个请求,直接访问时,进入过滤器 40 | 41 | HttpServletRequest req = (HttpServletRequest) request; 42 | HttpServletResponse res = (HttpServletResponse) response; 43 | //重定向 -> 走的request -> 告诉浏览器新地址,全新访问,地址变化 44 | res.sendRedirect(req.getContextPath()+"/main.jsp"); 45 | //转发 -> 没有走request,走的forward -> 走的内部方法,浏览器不知道,地址不变化 46 | req.getRequestDispatcher("main.jsp").forward(request,response); 47 | 48 | ### forward 49 | 50 | 通过RequestDispatcher的forward访问时,进入过滤器,例如jsp的forward转发也会进入过滤器 51 | 52 | 53 | 54 | 也会进入过滤器,但是直接请求 request不会进入过滤器。 55 | 56 | ### include 57 | 58 | 同forward,只是RequestDispatcher的include访问时会进入过滤器 59 | 60 | ### Error 61 | 62 | 目标资源通过声明式异常处理机制调用时,过滤器被调用 63 | 64 | 一般下配合error-page使用。用于当页面跳转到错误页面 比如404时,执行过滤器 65 | 66 | 67 | 404 68 | /error.jsp 69 | 70 | 71 | ErrorFilter 72 | com.ErrorFilter 73 | 74 | 75 | ErrorFilter 76 | /error.jsp 77 | ERROR 78 | 79 | 80 | 只有标注为error类型,当跳转到404时才会执行filter,否则不会执行 81 | 82 | ### Async(Servlet3.0 异步处理) 83 | 84 | ## 应用 85 | 86 | 登陆判断、编码转换、数据过滤替换、图像格式转换、内容压缩、加密处理 87 | -------------------------------------------------------------------------------- /docs/操作系统/电脑中常用的“扇区”、“簇”、“块”、“页”等概念.md: -------------------------------------------------------------------------------- 1 | ## 1、什么是扇区和(磁盘)块? 2 | 3 | 物理层面:一个磁盘按层次分为 **磁盘组合 -> 单个磁盘 -> 某一盘面 -> 某一磁道 -> 某一扇区** 4 | 5 | 扇区,顾名思义,每个磁盘有多条同心圆似的磁道,磁道被分割成多个部分。每部分的弧长加上到圆心的两个半径,恰好形成一个扇形,所以叫做扇区。**扇区是磁盘中最小的物理存储单位。****通常情况下每个扇区的大小是512字节。(由于不断提高磁盘的大小,部分厂商设定每个扇区的大小是4096字节)** 6 | 7 | 逻辑层面: 磁盘块(虚拟出来的)。 **块是操作系统中最小的逻辑存储单位。**操作系统与磁盘打交道的最小单位是磁盘块。 8 | 9 | ## 2、什么是簇?和块什么区别? 10 | 11 | 通俗的来讲,在**Windows下如NTFS等文件系统中叫做簇;**在**Linux下如Ext4等文件系统中叫做块**(block)。每个簇或者块可以包括2、4、8、16、32、64...2的n次方个扇区。 12 | 13 | ## 3、为什么存在磁盘块? 14 | 15 | 读取方便:由于扇区的数量比较小,数目众多在寻址时比较困难,所以操作系统就将相邻的扇区组合在一起,形成一个块,再对块进行整体的操作。 16 | 17 | 分离对底层的依赖:操作系统忽略对底层物理存储结构的设计。通过虚拟出来磁盘块的概念,在系统中认为块是最小的单位。 18 | 19 | ## 4、怎么映射磁盘块? 20 | 21 | **磁盘控制器,**其作用除了读取数据、控制磁头等作用外,还有的功能就是**映射扇区和磁盘块的关系。** 22 | 23 | ## 5、磁盘的读写基本单位是什么? 24 | 25 | 答案:**读写基本单位是扇区。**磁盘的原理,物理实现,**磁盘控制器是按照扇区这个单位读取等操作数据的。操作系统是通过块簇来做为单位读取等操作数据的。**此题问磁盘的读写,和操作系统没有关系,千万不要联系到操作系统层面去了。 26 | 27 | **文件系统就是操作系统的一部分,所以文件系统操作文件的最小单位是块。** 28 | 29 | ## 6、磁盘块与扇区的大小 30 | 31 | 既然磁盘块是一个虚拟概念。是操作系统自己"杜撰"的。软件的概念,不是真实的。所以大小由操作系统决定,操作系统可以配置一个块多大。 32 | 33 | **一个块大小=一个扇区大小*2的n次方。** 34 | 35 | N是可以修改的。 36 | 37 | ## 7、为什么磁盘块大小必须是扇区大小的整数倍呢? 38 | 39 | 磁盘读取数据的基本单位就是一个扇区的大小,一个块的大小对于磁盘来说就是一次获取数据读取的扇区数*扇区大小,如果是整数倍的扇区数对于磁盘的IO更好,速度更快,也会更合理的利用资源。否则会对扇区进行分割。 40 | 41 | 一个扇区是512字节。有些硬盘厂商会提供4k大小扇区。这是物理结构。磁盘定下来的结构就是没法修改的。所以必须要将块设置为磁盘的大小。 42 | 43 | ## 8、4k对齐 44 | 45 | 随着时代发展,硬盘容量不断扩展,使得之前定义的每个扇区512字节不再是那么的合理,于是将每个扇区512字节改为每个扇区4096 个字节,也就是现在常说的“4K扇区”。随着NTFS成为了标准的硬盘文件系统,其文件系统的默认分配单元大小(簇)也是4096字节,为了使簇与扇区相对应,即使物理硬盘分区与计算机使用的逻辑分区对齐,保证硬盘读写效率,所以就有了“4K对齐”的概念。 46 | 47 | 新标准的"4K扇区"的硬盘在厂商为了保证与操作系统兼容的前提下,也将扇区模拟成512B,会默认定义为4096字节大小为一个簇,但因为**其引导区占用了一个磁道共63个扇区**,真正的文件系统在63号扇区之后。 48 | 我们通过计算得出前63个扇区大小为:512Bx63=32256B 49 | 并按照默认簇大小得出63扇区为:32256B÷4096B=7.875簇 50 | 即从第63个扇区结束,往后的每一个簇都会跨越两个物理单元,占据前一个单元的一小部分和后一个单元的一大部分。 51 | 52 | 而“4K对齐”主要是**将硬盘的模拟扇区(512B)对齐到8的整数倍个“实际”4K扇区,**即4096B*8=32768B,其正好跨过了63扇区的特性,从第64个扇区对齐。 53 | 54 | ## 9、块与页的关系 55 | 56 | 操作系统经常与内存和硬盘这两种存储设备进行通信,类似于“块”的概念,都需要一种虚拟的基本单位。所以,**与内存操作,是虚拟一个页的概念来作为最小单位。与硬盘打交道,就是以块为最小单位。** -------------------------------------------------------------------------------- /docs/数据库/数据库事务的隔离级别.md: -------------------------------------------------------------------------------- 1 | # 数据库事务的隔离级别 2 | 3 | 事务是数据库管理系统的执行单位,可以执行一个数据库操作或是一组数据库操作。事务的ACID属性;事务的四个隔离级别。 4 | 5 | 事务的隔离级别由高到低分别是:串行化、可重复读、读已提交、读未提交。通常是使用锁来实现隔离的等级,但是在设置中只需要写上等级,对应的锁会由系统自动添加。 6 | 7 | ## 隔离级别 8 | 9 | ### 串行化 10 | 11 | 所有事务都一个接一个的串行执行,避免幻读,通过范围锁进行保证。 12 | 13 | ### 可重复读 14 | 15 | 所有被Select的数据都不可以被修改,这样可以避免前后数据不一致的问题,利用读锁。但是会产生幻读,因为只是控制了不能修改,但是可以增加数据 16 | 17 | Transaction 1 Transaction 2 18 | 19 | SELECT * FROM users 20 | WHERE age BETWEEN 10 AND 30; 21 | 22 | INSERT INTO users VALUES ( 3, 'Bob', 27 ); 23 | COMMIT; 24 | 25 | SELECT * FROM users 26 | WHERE age BETWEEN 10 AND 30; 27 | 28 | ### 读已提交 29 | 30 | 被读取的数据可以被其他事务修改。数据读取完立即释放读锁(和上一个级别的差距在 不用等事务结束后再释放) 31 | 32 | Transaction 1 Transaction 2 33 | 34 | SELECT * FROM users WHERE id = 1; 35 | 36 | UPDATE users SET age = 21 WHERE id = 1; 37 | COMMIT; 38 | 39 | SELECT * FROM users WHERE id = 1; 40 | 41 | ### 读未提交 42 | 43 | 允许其他事务看到没有提交的数据。导致脏读 44 | 45 | Transaction 1 Transaction 2 46 | 47 | SELECT * FROM users WHERE id = 1; 48 | 49 | UPDATE users SET age = 21 WHERE id = 1; 50 | 51 | SELECT * FROM users WHERE id = 1; 52 | 53 | RollBack 54 | 55 | ## 相关概念 56 | 57 | ### 幻读 58 | 59 | 对于两个事物 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段. 之后, 若 T2 回滚, T1读取的内容就是临时且无效的. 60 | 61 | ### 不可重复读 62 | 63 | 对于两个事物 T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段. 之后, T1再次读取同一个字段, 值就不同了. 64 | 65 | ### 脏读 66 | 67 | 对于两个事物 T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行. 68 | 69 | ## 总结 70 | 71 | 隔离级别(使用的锁、避免的问题):串行化(范围锁、幻读)、可重复读(事务完释放读锁、不可重复读)、读已提交(立即释放读锁、脏读)、读未提交 72 | 73 | 隔离等级 脏读 不可重复读 幻读 74 | 读未提交 YES YES YES 75 | 读已提交 NO YES YES 76 | 可重复读 NO NO YES 77 | 串行化 NO NO NO -------------------------------------------------------------------------------- /docs/数据库/索引结构——单维.md: -------------------------------------------------------------------------------- 1 | #索引结构——单维索引 2 | 3 | > 索引的重要性:能够加速在一个或多个属性上对特定值的查询。具体来说就是,我们只需查看所有可能记录中的小部分就能找到所需记录。 4 | 5 | ##索引的基础结构 6 | 7 | 稠密索引、稀疏索引、主索引(聚集索引)、辅助索引(非聚集索引) 8 | 9 | ### 主索引(聚集索引) 10 | 11 | 能够确定记录在数据文件中的位置,索引的顺序与物理顺序相对应,通常在主键上建立索引。 12 | 13 | **特点:** 14 | 1. 顺序与物理顺序相对应 15 | 2. **一个表只能有一个聚集索引** 16 | 3. 通常在主键上建立 17 | 4. 要求必须唯一 18 | 19 | ### 辅助索引(非聚集索引) 20 | 21 | ![image](http://pic.7tool.cn/uploads/2016/11/index_assist.png) 22 | 23 | 不能确定记录在数据文件中的位置,与物理顺序不匹配,通常在其他属性上建立附注索引。 24 | 25 | **特点:** 26 | 1. 顺序与物理顺序无关、不匹配,仅能告诉我们记录当前的存放位置 27 | 2. 通常在其他键上建立 28 | 3. 不要求唯一 29 | 30 | ###稠密索引 31 | 32 | ![image](http://pic.7tool.cn/uploads/2016/11/index_dense.png) 33 | 34 | **为每一个元组创建一个对应的索引项,索引文件的顺序与元组顺序一致。**例如在顺序文件上构建稠密索引,索引内仅包含每一个元组的主键记录和指向记录本身的指针。 35 | 36 | > 顺序文件是对关系中的元组按照主键进行排序而生成的文件。 37 | 38 | **特点:** 39 | 1. 稠密索引的顺序与文件中元组的顺序必须一致,且一一对应 40 | 2. 每一个元组都有一个索引项。 41 | 3. 不用排序 42 | 43 | ### 稀疏索引 44 | 45 | ![image](http://pic.7tool.cn/uploads/2016/11/index_sparse.png) 46 | 47 | **为每一个存储块建立一个索引项,建立稠密索引是必须排好序的记录。**例如在顺序文件上构建稀疏索引,索引内包含每个数据块中第一个记录对应的值和指向记录本身的指针。 48 | 49 | **特点:** 50 | 1. 稀疏索引必须是排好序的键 51 | 2. 每一个数据块有一个索引项 52 | 3. 更节省索引空间 53 | 54 | ### 多级索引 55 | 56 | ![image](http://pic.7tool.cn/uploads/2016/11/index_more.png) 57 | 58 | 索引的索引,为了压缩很大的索引文件。 59 | 60 | **特点:** 61 | 1. 多级索引只能是稀疏索引 62 | 2. 层级越多,空间越小,但是查询的效率会降低 63 | 64 | ## B树 65 | 66 | 索引的常用数据结构,可以减少定位记录时所经历的中间过程,从而加快存取速度 67 | 68 | ### 数据结构 69 | 70 | ![image](http://pic.7tool.cn/uploads/2016/11/B_tree.png) 71 | 72 | B树是广义化的二叉搜索树,只是每个节点不仅仅只有两个子数。是一颗平衡树。 73 | 74 | ### B树的应用 75 | 76 | 由于其叶子节点的指针,可以指向任一数据记录,所以B树可以用到任何的索引结构中。如: 77 | 78 | 1. 查找键是主键,且索引是稠密的。(主索引、稠密索引) 79 | 2. 数据按主键排序,且索引是稀疏的。(稀疏索引) 80 | 3. 按其他键建立索引,可以有重复值。(辅助索引) 81 | 82 | ### B树的查找 83 | 84 | 1. 指定值查找,从根到叶递归查找 85 | 2. 范围查找,一次查找找出下界,在该叶节点中依次往后查找 若当前节点没有大于上界的值 则可以利用下一节点指针在后续节点中继续查找直至找到大于上界的值或结束。 86 | 87 | ### B树的其他操作 88 | 89 | 插入、删除等,在此不再赘述。 90 | 91 | ## 散列表 92 | 93 | ### 数据结构 94 | 95 | 哈希链表 96 | 97 | ### 应用 98 | 99 | 已知一个散列函数,查找键利用该散列函数可以计算出一个介于0到B-1的整数。(B是桶的数目)桶数组是一个序号从0到B-1的数组,其中包含了B个链表的头(每个数组元素是一个存储块,为了便于理解认为数组中存的是该块的指针链的头指针)。通过散列函数,将每个记录分别放到对应的桶中,如果桶溢出,可以加一个溢出块链。 100 | 101 | ### 操作 102 | 103 | 插入、删除等不再赘述 104 | 105 | ## 比较B树和散列表 106 | 107 | 1. 散列表方法适用于查找给定值的查询 108 | 2. B树适用于范围查询 109 | -------------------------------------------------------------------------------- /docs/数据库/索引结构——多维.md: -------------------------------------------------------------------------------- 1 | #索引结构——多维索引 2 | 3 | 利用传统的B树或者散列表进行建立单维索引,在处理多维数据时会遇到问题。例如地理信息系统,其中数据是两维的(如经度、维度),因此利用传统索引无法高效的解决问题,所以需要多维索引。 4 | 5 | 本文主要介绍两类多维索引:类散列表方法和类树方法。类散列方法包括:网格文件、分段散列;类树方法包括:多键索引、kd树、四叉树、r树。以及最后会简单介绍位图索引。 6 | 7 | ## 类散列表方法 8 | 9 | ### 网格文件 10 | 11 | 一个n维空间,每一维度是每一查找键。对每一维度进行划分,形成可以大小不等的多个空间,使每一个元组落入不同的空间中,可以让每个空间内的数目不同。 12 | 13 | 被划分后的每个空间可以看做是每个桶,落入该区域的数据放入该桶中,若溢出可以添加溢出块,不同维的值共同决定桶的位置。 14 | 15 | ![image](http://pic.7tool.cn/uploads/2016/11/index_gird.png) 16 | 17 | **优点:**对于近邻查询、区域查询比较好 18 | 19 | **缺点:**数据维数多时难以维护 20 | 21 | ### 分段散列 22 | 23 | 为每一维属性设计一个散列函数,通过该函数产生若干个二进制位。最后将这几个属性产生的二进制位拼接。 24 | 25 | ![image](http://pic.7tool.cn/uploads/2016/11/index_hash.png) 26 | 27 | ![image](http://pic.7tool.cn/uploads/2016/11/index_hash4.png) 28 | 29 | **优点:**数据分布比较均匀 30 | **缺点:**对近邻查询、区域查询无用 31 | 32 | ## 类树方法 33 | 34 | ### 多建索引 35 | 36 | 索引的索引,树中每一次结点都是一个属性的索引 37 | 38 | ![image](http://pic.7tool.cn/uploads/2016/11/index_index.png) 39 | 40 | ### KD树 41 | 42 | k维搜索树,是一个二叉树。所有维的属性在内结点的层间循环,所以树的不同层上的属性是不同的。 43 | 44 | ![image](http://pic.7tool.cn/uploads/2016/11/index_kdtree.png) 45 | 46 | ### 四叉树 47 | 48 | 将二维空间换分成四个正方形的区域,每个内结点对应于空间内的一个区域。 49 | 50 | ![image](http://pic.7tool.cn/uploads/2016/11/index_fourtree.png) 51 | 52 | ### R树 53 | 54 | B树的拓展,利用B树的某些本质特征来处理多维数据对象的数据结构。利用矩形将空间划分并利用层次结构组织多维数据对象。 55 | 56 | ![image](http://pic.7tool.cn/uploads/2016/11/index_rtree.png) 57 | 58 | ## 位图索引 59 | 60 | 关系R有n个元组,属性F的位图索引是指一个长度为n的二进制数,它的第i位是序号为i的元组的记录值,若相同则为1,否则为0 61 | 62 | ![image](http://pic.7tool.cn/uploads/2016/11/index_image.png) 63 | 64 | 解释:以字段F为例,共6条记录 所以定义长度为6的二进制数。第1位 代表序号为1的元组(30,foo)所以在30对应的数列中第1位是1,同理第2位是1,同理30对应的数列是11001,同理得出值为40、50的数列,从而得出F的位图索引。 65 | 66 | ### 位图索引的压缩 67 | 68 | 利用分段长度编码来压缩位图索引中数列的“0”。先计算“1”之前“0”的个数i,确定i的二进制表示位数j。则压缩后的表示为:j-1个"1"和一个"0"表示i的位数,后面加上i的二进制数。 69 | 70 | 例如:数列00010000 "1"前面有3个"0",需要2位二进制数来表示"0"的个数。(即i=3 j=2) 所以前半部分为10,后半部分为11,压缩后为1011 -------------------------------------------------------------------------------- /docs/计算机网络/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangengzhe/coding-guide_i3geek/43235acc9502bef94e5e0cd3346f7c215e115d94/docs/计算机网络/.DS_Store -------------------------------------------------------------------------------- /docs/计算机网络/IP协议_TCP:UDP协议基础.md: -------------------------------------------------------------------------------- 1 | # IP协议 TCP、UDP协议基础 2 | ## 网络层次 3 | 4 | 应用层 -- HTTP协议 5 | 传输控制层 -- TCP/UDP协议 -> Socket封装 6 | 网络层 -- IP协议、ICMP协议 7 | 8 | ## IP协议 9 | 10 | IP协议处于网络层,用于更底层(数据链路层)与上层传输控制层(TCP/UDP)之间传输数据。通过解析或指定目的地址的IP,来确定一条网络计算机中的链路。 11 | 12 | 简单来说,就是通过IP来确定一台网络上的电脑,确立一条网络路径。 13 | 14 | 协议头: 15 | 16 | * 版本:占4位,指IP协议的版本。 17 | * 首部长度:占4位,可表示的最大十进制数值是15。 18 | * 区分服务:占8位,用来获得更好的服务。 19 | * 总长度:总长度指首部和数据之和的长度,单位为字节。总长度字段为16位,因此数据报的最大长度为216-1=65535字节。 20 | * 标识(identification):占16位。 21 | * 标志(flag):占3位,但目前只有2位有意义。 22 | * 片偏移:占13位。 23 | * 生存时间:占8位,生存时间字段常用的的英文缩写是TTL(Time To Live),表明是数据报在网络中的寿命。 24 | * 协议:占8位,协议字段指出此数据报携带的数据是使用何种协议,以便使目的主机的IP层知道应将数据部分上交给哪个处理过程。 25 | * 首部检验和:占16位。 26 | * 源IP地址:占32位。 27 | * 目的IP地址:占32位。 28 | 29 | 主要包含:IMCP协议(ping)、IP协议(TCP/IP协议组) 30 | 31 | ## TCP协议 32 | 33 | **TCP协议是面向连接、保证高可靠性(数据无丢失、数据无失序、数据无错误、数据无重复到达)传输层协议。** 34 | 35 | 协议头(20字节): 36 | 37 | * 源端口号[2字节] 38 | * 目的端口号[2字节] 39 | * SEQ序号[4字节] 40 | * ACK序号[4字节] 41 | * 偏移[0.5字节] 42 | * Reserved [0.5字节] 43 | * 标志[1字节] 44 | * 窗口大小(window)[2字节] 45 | * 校验和[2字节] 46 | * 紧急指针[2字节] 47 | 48 | 主要涉及技术:三次握手链接、四次挥手关闭链接、TCP可靠性的保证(带重传功能的肯定确认)、滑动窗口技术 49 | 50 | ## UDP协议 51 | 52 | **UDP协议也是传输层协议,它是无连接,不保证可靠的传输层协议。** 53 | 54 | 协议头(8字节): 55 | 56 | * 源端口号[2字节] 57 | * 目的端口号[2字节] 58 | * Length[2字节] 59 | * 校验和[2字节] 60 | 61 | ## TCP和UDP协议的小结 62 | 63 | ### TCP 64 | 65 | **提供IP环境下的数据可靠传输**,它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。TCP通过面向连接、端到端和可靠的数据包发送。**通俗说,它是事先为所发送的数据开辟出连接好的通道,然后再进行数据发送。** 66 | 67 | TCP对应的是可靠性要求高的应用,支持的应用协议主要有:Telnet、FTP、SMTP等 68 | 69 | ### UDP 70 | 71 | **UDP则不为IP提供可靠性、流控或差错恢复功能** 72 | 73 | UDP对应的则是可靠性要求低、传输经济的应用,支持的应用层协议主要有:NFS(网络文件系统)、SNMP(简单网络管理协议)、DNS(主域名称系统)、TFTP(通用文件传输协议)等 74 | 75 | ### 区别: 76 | 77 | 1. 基于连接与无连接; 78 | 2. 对系统资源的要求(TCP较多,UDP少); 79 | 3. UDP程序结构较简单; 80 | 4. 流模式与数据报模式 ; 81 | 5. TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。 82 | 83 | ## TCP/IP协议 84 | 85 | 传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本的协议、Internet国际互联网络的基础,**由网络层的IP协议和传输层的TCP协议组成。**通俗而言:TCP负责发现传输的问题,一有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地。而IP是给因特网的每一台联网设备规定一个地址。 86 | 87 | 通过层次结构中可以看到,TCP/IP协议涉及到网络层和传输控制层,可以说是网络传输的基础。设备连接入网络,比如手机设备,就是实现了底层TCP协议后才可以在网络上进行传输。 88 | 89 | ### TCP/IP协议和UDP协议的关系 90 | 91 | TCP/IP是协议族,由TCP和IP协议构成,TCP负责发现问题,请求重传,IP负责确立链路链接。 92 | 93 | UDP是不可靠传输,也可以说是UDP/IP协议族,可是一般情况下意义不大,比较传输层都是会经过网络层的。 -------------------------------------------------------------------------------- /docs/计算机网络/socket_tcp:ip_http关系.md.md: -------------------------------------------------------------------------------- 1 | # socket tcp/ip http关系 2 | 3 | ## Socket 4 | 5 | socket是对TCP/UDP协议的封装和应用(编程角度)。所以属于对传输控制层的操作,主要解决数据在网络中传输的问题;而HTTP是应用层协议,主要解决如何包装数据。简单的说,**就是HTTP协议通信功能是利用了Socket封装的TCP/IP协议接口所实现的。**例如,在java中可以分为udp Socket和tcp Socket。 6 | 7 | **Socket本身并不是协议,而是对TCP/IP协议的封装,是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。 **实际上,Socket跟TCP/IP协议没有必然的联系。Socket编程接口在设计的时候,就希望也能适应其他的网络协议。所以说,Socket的出现 只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口,比如create、 listen、connect、accept、send、read和write等等。 8 | 9 | **可以跨平台,跨语言(需要注意编码等问题)** 10 | 11 | ## HTTP协议 12 | 13 | HTTP协议是Web联网的基础,也是手机联网常用的协议之一,**HTTP协议是建立在TCP协议之上的一种应用。** 14 | 15 | HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。 16 | 17 | 1)在HTTP 1.0中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。 18 | 2)在HTTP 1.1中,规定了默认保持长连接(HTTP persistent connection ,也有翻译为持久连接),数据传输完成了保持TCP连接不断开(不发RST包、不四次握手),等待在同域名下继续用这个通道传输数据 19 | 20 | ### 短连接 21 | 22 | 由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。通常的做法是即时不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。 23 | 24 | ### 长连接 25 | 26 | 数据传输完成了保持TCP连接不断开,进行下一次传输,从而减少创建链接和关闭链接的资源消耗。 27 | 28 | 从HTTP1.1中,就可以添加HTTP首部的Connection: Keep-alive来达到长连接的目的。当然不能让服务器无休止的等下去,一般还会设置Keep-Alive: timeout=20,链接的保持时间。 29 | 30 | 更多长连接的问题:http://www.cnblogs.com/skynet/archive/2010/12/11/1903347.html 31 | 32 | ## Socket和HTTP、TCP/IP小结 33 | 34 | ### SOCKET连接与TCP/IP连接 35 | 36 | 创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。 37 | 38 | ### Socket连接与HTTP连接 39 | 40 | Socket连接通常情况下就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 Socket 连接断连。因此Socket链接中,客户端需要通过轮询告诉服务器网络,该连接处于活跃状态。 41 | 42 | HTTP连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。 43 | 44 | 很多情况下,需要服务器端主动向客户端推送数据,保持客户端与服务器数据的实时与同步。此时若双方建立的是Socket连接,服务器就可以直接将数据传送给客户端;若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求,不仅可以保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。 45 | 46 | ### TCP/IP连接和HTTP连接 47 | 48 | HTTP是应用层协议,TCP/IP是传输层协议族,因此可以理解为,HTTP链接是基于TCP/IP连接所实现的。 49 | 50 | HTTP工作原理: 51 | 52 | 1. 封成HTTP请求数据包 53 | 2. 封成TCP包 54 | 3. 建立TCP连接(三次握手) 55 | 4. 客户端发请求 56 | 5. 服务器返回响应 57 | 6. 服务器关闭TCP连接(四次挥手) -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | DesignPattern 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/lib/cglib-2.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangengzhe/coding-guide_i3geek/43235acc9502bef94e5e0cd3346f7c215e115d94/docs/设计模式/DesignPattern/lib/cglib-2.2.jar -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/lib/cglib-nodep-2.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangengzhe/coding-guide_i3geek/43235acc9502bef94e5e0cd3346f7c215e115d94/docs/设计模式/DesignPattern/lib/cglib-nodep-2.2.jar -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/adapter/Adaptee/TwoPlug.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.adapter.Adaptee; 2 | 3 | 4 | /** 5 | * 二相插座(被适配类 原始类 不兼容的类) 6 | * @date 2016年12月29日 下午4:16:49 7 | * @author yangengzhe 8 | * 9 | */ 10 | public class TwoPlug { 11 | public void powerWithTwo(){ 12 | System.out.println("正在使用二相电流供电"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/adapter/Adapter/Two2ThreeAdapter.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.adapter.Adapter; 2 | 3 | import com.i3geek.pattern.adapter.Adaptee.TwoPlug; 4 | import com.i3geek.pattern.adapter.Target.ThreePlug; 5 | 6 | /** 7 | * 二相转三相的适配器 (目标接口的实现、目标接口的实例) 8 | * 对象适配器 9 | * @date 2016年12月29日 下午4:30:24 10 | * @author yangengzhe 11 | * 12 | */ 13 | public class Two2ThreeAdapter implements ThreePlug { 14 | 15 | private TwoPlug plug; 16 | 17 | public Two2ThreeAdapter(TwoPlug plug){ 18 | this.plug = plug; 19 | } 20 | @Override 21 | public void powerWithThree() { 22 | System.out.println("通过组合适配器"); 23 | plug.powerWithTwo(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/adapter/Adapter/Two2ThreeAdapterExtends.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.adapter.Adapter; 2 | 3 | import com.i3geek.pattern.adapter.Adaptee.TwoPlug; 4 | import com.i3geek.pattern.adapter.Target.ThreePlug; 5 | 6 | 7 | /** 8 | * 继承方式的类适配器 9 | * @date 2016年12月29日 下午4:50:15 10 | * @author yangengzhe 11 | * 12 | */ 13 | public class Two2ThreeAdapterExtends extends TwoPlug implements ThreePlug { 14 | 15 | @Override 16 | public void powerWithThree() { 17 | System.out.println("通过继承适配器"); 18 | this.powerWithTwo(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/adapter/Client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.adapter; 2 | 3 | import com.i3geek.pattern.adapter.Adaptee.TwoPlug; 4 | import com.i3geek.pattern.adapter.Adapter.Two2ThreeAdapter; 5 | import com.i3geek.pattern.adapter.Adapter.Two2ThreeAdapterExtends; 6 | import com.i3geek.pattern.adapter.Target.ThreePlug; 7 | 8 | public class Client { 9 | 10 | public static void main(String args[]){ 11 | //对象适配器 12 | TwoPlug twoPlug = new TwoPlug(); 13 | ThreePlug plug = new Two2ThreeAdapter(twoPlug); 14 | plug.powerWithThree(); 15 | 16 | //类适配器 17 | plug = new Two2ThreeAdapterExtends(); 18 | plug.powerWithThree(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/adapter/README.md: -------------------------------------------------------------------------------- 1 | # 适配器模式 2 | 3 | ## 实现功能: 4 | 5 | 模拟三相插头 插入二相插口,其中适配器相当于插头转换器 6 | 7 | ## 动机 8 | 9 | 将一个类的接口,**通过适配器**转换成另外一个期望的接口。(使原本不兼容的接口 而能够相互兼容一起工作)这就是适配器模式的模式动机。 10 | 11 | 接口A(实际接口) ===适配器(转换的过程)====》 接口B(不同的,期望的接口) 12 | 13 | 比如: 三相插头 ===适配器(插口转换器)====》 两相插口 14 | 15 | ## 定义 16 | 17 | 适配器模式将一个类的接口转换成期望的另一个接口,使得原本不能一起工作的类可以在一起工作。 18 | 19 | ## 功能 20 | 21 | 适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器可以使由于接口不兼容而不能交互的类可以一起工作。 22 | 23 | ## 实现(两种) 24 | 25 | 对象适配器(组合方式):实现期望接口,内部含有被适配类对象,实现方法中调用被适配类的原始方法 26 | 27 | 类适配器(继承方式):实现期望接口,继承被适配类,实现方法中调用父类的原始方法 28 | 29 | - Target:目标抽象类 客户端的目标接口 30 | - Adapter:适配器类 实现期望接口,通过内部对被适配类实例的操作,成为期望接口的实例 31 | - Adaptee:适配者类 一个已经实现的不兼容的类 32 | - Client:客户类 33 | 34 | ## 应用 35 | 36 | **只要把不兼容 变成兼容的就是适配器!** 37 | 38 | JDBC数据库驱动,JDBC驱动做为数据库引擎(Mysql、Oracle、SQL Server等)与JDBC标准接口的一个桥梁(适配器软件)。 39 | 40 | 可以让开发人员在开发中,对数据库的操作透明,通过适配器(JDBC驱动),实例化出目标接口(JDBC标准统一接口),对接口编程,更换不同的被适配类(各种数据库引擎) 41 | 42 | *原文:http://www.i3geek.com/archives/1369* 43 | *实现源代码:https://github.com/yangengzhe/coding-guide_i3geek/tree/master/docs/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F* -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/adapter/Target/ThreePlug.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.adapter.Target; 2 | 3 | 4 | /** 5 | * 三相插座(目标接口) 6 | * @date 2016年12月29日 下午4:10:38 7 | * @author yangengzhe 8 | * 9 | */ 10 | public interface ThreePlug { 11 | //使用三相电流供电 12 | public void powerWithThree(); 13 | } 14 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/bridge/Client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.bridge; 2 | 3 | import com.i3geek.pattern.bridge.first.ConcreteImplementorA; 4 | import com.i3geek.pattern.bridge.first.Implementor; 5 | import com.i3geek.pattern.bridge.second.Abstraction; 6 | import com.i3geek.pattern.bridge.second.RefinedAbstractionA; 7 | import com.i3geek.pattern.bridge.third.Graphy; 8 | import com.i3geek.pattern.bridge.third.GraphyA; 9 | 10 | /** 11 | * 桥接设计模式,三层关系解耦 12 | * @date 2017年2月22日 上午10:14:29 13 | * @author gengzhe.ygz 14 | * 15 | */ 16 | public class Client { 17 | 18 | public static void main(String[] args) { 19 | //第一层 20 | Implementor first = new ConcreteImplementorA(); 21 | //第二层 22 | Abstraction second = new RefinedAbstractionA(first); 23 | //第三层 24 | Graphy third = new GraphyA(second); 25 | 26 | //测试 27 | third.func(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/bridge/Readme.md: -------------------------------------------------------------------------------- 1 | ## 动机 2 | 3 | 有圆形、矩形2个形状,还有红色、绿色2个颜色。如果想实现不同形状和不同颜色的组合,我们有两种方案:第一种,为每一种形状的每一种颜色设计一个类,问题冗余,类过多;第二种,根据实际的需要,对形状和颜色进行组合。 4 | 5 | 第二种方案就是最佳方案,在多维度影响因素下,将他们分离,也就是桥接模式的动机。将继承关系转化为关联关系,从而降低了类与类之间的耦合,减少了代码的编写量。 6 | 7 | ## 定义 8 | 9 | 将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。 10 | 11 | ## 功能 12 | 13 | 将抽象部分与实现部分分离,使它们都可以独立的变化。具体使用时,通过**组装的方式**形成需要的产品 14 | 15 | 特点,可以实现多维影响因素的解耦,通过一层一层往外套 16 | 17 | ## 实现 18 | 19 | - Abstraction:抽象类 :第二维影响因素的接口 20 | - RefinedAbstraction:扩充抽象类 :第二维影响因素的具体实现 21 | - Implementor:实现类接口 : 第一维影响因素的接口 22 | - ConcreteImplementor:具体实现类 :第一维影响因素的具体实现 23 | 24 | 可以一层层继续往外包装接口和实现类(通过组合来调用上一层接口),从而实现多层的影响因素(详细看代码 实现三维影响因素) 25 | 26 | ## 应用 27 | 28 | Java为AWT中的每一个GUI构件都提供了一个Peer构件,使得Java软件运行在不同操作系统中有不同的视感。在AWT中的Peer架构就使用了桥接模式。 29 | 30 | *原文:http://www.i3geek.com/archives/1373* 31 | *实现源代码:https://github.com/yangengzhe/coding-guide_i3geek/tree/master/docs/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F* -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/bridge/first/ConcreteImplementorA.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.bridge.first; 2 | 3 | 4 | /** 5 | * DesignPattern 6 | * @date 2017年2月22日 上午10:05:08 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public class ConcreteImplementorA implements Implementor { 11 | 12 | @Override 13 | public void func() { 14 | System.out.println("矩形"); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/bridge/first/ConcreteImplementorB.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.bridge.first; 2 | 3 | 4 | /** 5 | * DesignPattern 6 | * @date 2017年2月22日 上午10:05:30 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public class ConcreteImplementorB implements Implementor { 11 | 12 | @Override 13 | public void func() { 14 | System.out.println("矩形"); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/bridge/first/Implementor.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.bridge.first; 2 | 3 | 4 | /** 5 | * 第一层维度 6 | * @date 2017年2月22日 上午10:04:23 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public interface Implementor { 11 | public void func(); 12 | } 13 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/bridge/second/Abstraction.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.bridge.second; 2 | 3 | import com.i3geek.pattern.bridge.first.Implementor; 4 | 5 | /** 6 | * 第二层维度 7 | * @date 2017年2月22日 上午10:06:31 8 | * @author gengzhe.ygz 9 | * 10 | */ 11 | public interface Abstraction { 12 | public void func(); 13 | } 14 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/bridge/second/RefinedAbstractionA.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.bridge.second; 2 | 3 | import com.i3geek.pattern.bridge.first.Implementor; 4 | 5 | /** 6 | * DesignPattern 7 | * @date 2017年2月22日 上午10:07:56 8 | * @author gengzhe.ygz 9 | * 10 | */ 11 | public class RefinedAbstractionA implements Abstraction { 12 | 13 | Implementor first; 14 | 15 | public RefinedAbstractionA(Implementor first){ 16 | this.first =first; 17 | } 18 | @Override 19 | public void func() { 20 | System.out.println("红色的"); 21 | first.func(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/bridge/second/RefinedAbstractionB.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.bridge.second; 2 | 3 | import com.i3geek.pattern.bridge.first.Implementor; 4 | 5 | /** 6 | * DesignPattern 7 | * @date 2017年2月22日 上午10:08:07 8 | * @author gengzhe.ygz 9 | * 10 | */ 11 | public class RefinedAbstractionB implements Abstraction { 12 | 13 | Implementor first; 14 | 15 | public RefinedAbstractionB(Implementor first){ 16 | this.first =first; 17 | } 18 | 19 | @Override 20 | public void func() { 21 | System.out.println("绿色的"); 22 | first.func(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/bridge/third/Graphy.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.bridge.third; 2 | 3 | 4 | /** 5 | * 第三层因素 6 | * @date 2017年2月22日 上午10:12:08 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public interface Graphy { 11 | public void func(); 12 | } 13 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/bridge/third/GraphyA.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.bridge.third; 2 | 3 | import com.i3geek.pattern.bridge.second.Abstraction; 4 | 5 | /** 6 | * DesignPattern 7 | * @date 2017年2月22日 上午10:12:39 8 | * @author gengzhe.ygz 9 | * 10 | */ 11 | public class GraphyA implements Graphy { 12 | 13 | Abstraction second; 14 | 15 | public GraphyA(Abstraction second){ 16 | this.second =second; 17 | } 18 | @Override 19 | public void func() { 20 | System.out.println("手绘"); 21 | second.func(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/bridge/third/GraphyB.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.bridge.third; 2 | 3 | import com.i3geek.pattern.bridge.second.Abstraction; 4 | 5 | /** 6 | * DesignPattern 7 | * @date 2017年2月22日 上午10:12:50 8 | * @author gengzhe.ygz 9 | * 10 | */ 11 | public class GraphyB implements Graphy { 12 | 13 | Abstraction second; 14 | 15 | public GraphyB(Abstraction second){ 16 | this.second =second; 17 | } 18 | 19 | @Override 20 | public void func() { 21 | System.out.println("机器绘制"); 22 | second.func(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/builder/Readme.md: -------------------------------------------------------------------------------- 1 | ## 动机 2 | 3 | 说道建造者肯定联想到建筑工人,比如在建筑一个茅草屋和一个砖瓦房时,过程一样只是用的材料不同。比如第一步建立地基:茅草屋用工具,砖瓦房用机器;第二步建立框架:茅草屋用树木,砖瓦房用混凝土;第三步建立房屋:茅草屋用茅草,砖瓦房用砌砖。 4 | 5 | 可以看出过程是一样的,只是用到的材料不同。因此将过程和材料解耦,将这些复杂材料的生产分离出来(建造者),流程独立化出来(指挥者)。 6 | 7 | ## 定义 8 | 9 | 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 10 | 11 | ## 功能 12 | 13 | 通过不同的建造者实例,生产不同的材料,利用统一的指挥者流程,可以规范标准化的生产出各种产品。 14 | 15 | 在客户端中无须关心产品中具体零件是怎么生产的(建造者)和怎么组装的(指挥者),只需要确定具体建造者就可以得出相对应的产品。 16 | 17 | ## 实现 18 | 19 | - builder:建造者抽象接口,声明产品中包含的全部零部件。 20 | - ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,实现不同零部件的创建。 21 | - Director:调用具体建造者来创建每个零部件,并根据统一的建造过程,组装零部件并返回产品。 22 | - Product:最终要建造的产品。 23 | 24 | ## 应用 25 | 26 | 在很多游戏软件中,地图包括天空、地面、背景等组成部分,人物角色包括人体、服装、装备等组成部分,可以使用建造者模式对其进行设计,通过不同的具体建造者创建不同类型的地图或人物。 27 | 28 | *原文:http://www.i3geek.com/archives/1332* 29 | *实现源代码:https://github.com/yangengzhe/coding-guide_i3geek/tree/master/docs/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F* -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/builder/builder/Builder.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.builder.builder; 2 | 3 | 4 | /** 5 | * 所需要的零部件 6 | * @date 2017年2月18日 下午12:04:44 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public interface Builder { 11 | void buildFoundation(); 12 | void buildFrame(); 13 | void buildWall(); 14 | String getType(); 15 | } 16 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/builder/client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.builder; 2 | 3 | import com.i3geek.pattern.builder.builder.Builder; 4 | import com.i3geek.pattern.builder.concreteBuilder.BrickBuilder; 5 | import com.i3geek.pattern.builder.director.Director; 6 | import com.i3geek.pattern.builder.product.House; 7 | 8 | /** 9 | * DesignPattern 10 | * @date 2017年2月18日 下午12:25:40 11 | * @author gengzhe.ygz 12 | * 13 | */ 14 | public class client { 15 | 16 | public static void main(String args[]){ 17 | Director director = new Director(); 18 | Builder builder = new BrickBuilder(); 19 | 20 | House house = director.Construct(builder); 21 | System.out.println(house.getType()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/builder/concreteBuilder/BrickBuilder.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.builder.concreteBuilder; 2 | 3 | import com.i3geek.pattern.builder.builder.Builder; 4 | 5 | 6 | /** 7 | * 砖瓦房 8 | * @date 2017年2月18日 下午12:09:35 9 | * @author gengzhe.ygz 10 | * 11 | */ 12 | public class BrickBuilder implements Builder { 13 | public String type = "砖瓦房"; 14 | 15 | @Override 16 | public void buildFoundation() { 17 | System.out.println("砖瓦房地基"); 18 | } 19 | 20 | @Override 21 | public void buildFrame() { 22 | System.out.println("砖瓦房框架"); 23 | } 24 | 25 | @Override 26 | public void buildWall() { 27 | System.out.println("砖瓦房墙壁"); 28 | } 29 | 30 | @Override 31 | public String getType() { 32 | return type; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/builder/concreteBuilder/ThatchedBuilder.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.builder.concreteBuilder; 2 | 3 | import com.i3geek.pattern.builder.builder.Builder; 4 | 5 | 6 | /** 7 | * DesignPattern 8 | * @date 2017年2月18日 下午12:08:40 9 | * @author gengzhe.ygz 10 | * 11 | */ 12 | public class ThatchedBuilder implements Builder { 13 | public String type = "茅草屋"; 14 | 15 | @Override 16 | public void buildFoundation() { 17 | System.out.println("茅草屋地基"); 18 | } 19 | 20 | @Override 21 | public void buildFrame() { 22 | System.out.println("茅草屋框架"); 23 | } 24 | 25 | @Override 26 | public void buildWall() { 27 | System.out.println("茅草屋墙壁"); 28 | } 29 | 30 | @Override 31 | public String getType() { 32 | return type; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/builder/director/Director.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.builder.director; 2 | 3 | import com.i3geek.pattern.builder.builder.Builder; 4 | import com.i3geek.pattern.builder.product.House; 5 | 6 | /** 7 | * 指挥者 8 | * @date 2017年2月18日 下午12:03:58 9 | * @author gengzhe.ygz 10 | * 11 | */ 12 | public class Director { 13 | 14 | public House Construct(Builder builder){ 15 | builder.buildFoundation(); 16 | builder.buildFrame(); 17 | builder.buildWall(); 18 | return new House(builder.getType()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/builder/product/House.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.builder.product; 2 | 3 | 4 | /** 5 | * DesignPattern 6 | * @date 2017年2月18日 下午12:16:32 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public class House { 11 | public String type; 12 | 13 | public House(String type){ 14 | this.type = type; 15 | } 16 | 17 | public String getType(){ 18 | return type; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/command/Client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.command; 2 | 3 | import com.i3geek.pattern.command.concreteCommand.LightOnCommand; 4 | import com.i3geek.pattern.command.invoker.SimpleRemoteControl; 5 | import com.i3geek.pattern.command.receiver.Light; 6 | 7 | /** 8 | * DesignPattern 9 | * @date 2017年2月26日 下午12:23:39 10 | * @author gengzhe.ygz 11 | * 12 | */ 13 | public class Client { 14 | 15 | public static void main(String[] args) { 16 | // 控制器就是调用者,会传入一个命令对象,可以用来发出请求 17 | SimpleRemoteControl remote = new SimpleRemoteControl(); 18 | // 现在创建了一个电灯对象,此对象也就是请求的接收者 19 | Light light = new Light(); 20 | // 在这里创建一个命令,然后将接收者传给它 21 | LightOnCommand lightOn = new LightOnCommand(light); 22 | 23 | // 把命令传给调用者 24 | remote.setCommand(lightOn); 25 | // 模拟按下按钮 26 | remote.buttonPressed(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/command/Readme.md: -------------------------------------------------------------------------------- 1 | # 动机 2 | 3 | 在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。 4 | 5 | # 定义 6 | 7 | 将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。 8 | 9 | # 作用 10 | 11 | 命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。 12 | 13 | 调用者(请求者/Invoker) ===绑定命令对象,需要执行命令时,执行统一方法===> 命令对象(封装接收者)进行执行,完成请求 ====> 接收者(Receiver):真正的执行人 14 | 15 | 比如:可以兼容各种功能的遥控器。 16 | 遥控器(Invoker)拥有多个卡槽(Command),每个卡槽用来放一种命令(ConcreteCommand),命令中含有具体的接收者(Receiver)用来真正执行任务。 17 | 用户只需要把命令请求对象(ConcreteCommand)传入遥控器(Invoker),需要执行时,调用统一运行方法(比如按下按钮),即可运行该命令的内容。而具体的命令执行过程由 命令对象所持有的接收者(Receiver)执行,发送者并不知道。 18 | 19 | # 实现 20 | 21 | 命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。 22 | 23 | ../_images/Command.jpg 24 | ../_images/seq_Command.jpg 25 | - Command: 抽象命令类 26 | - ConcreteCommand: 具体命令类 27 | - Invoker: 调用者(请求者) 28 | - Receiver: 接收者 29 | - Client:客户类 30 | 31 | # 应用 32 | 33 | Tomcat中Connector 也是通过命令模式调用 Container 34 | 图 4. Tomcat 命令模式的结构图 35 | Connector 作为抽象请求者,HttpConnector 作为具体请求者。HttpProcessor 作为命令。Container 作为命令的抽象接受者,ContainerBase 作为具体的接受者。客户端就是应用服务器 Server 组件了。Server 首先创建命令请求者 HttpConnector 对象,然后创建命令 HttpProcessor 命令对象。再把命令对象交给命令接受者 ContainerBase 容器来处理命令。命令的最终是被 Tomcat 的 Container 执行的。命令可以以队列的方式进来,Container 也可以以不同的方式来处理请求,如 HTTP1.0 协议和 HTTP1.1 的处理方式就会不同。 -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/command/command/Command.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.command.command; 2 | 3 | 4 | /** 5 | * 命令抽象接口 6 | * @date 2017年2月26日 下午12:17:02 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public interface Command { 11 | //执行命令 12 | public void execute(); 13 | 14 | //撤销命令 15 | public void undo(); 16 | } 17 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/command/concreteCommand/LightOnCommand.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.command.concreteCommand; 2 | 3 | import com.i3geek.pattern.command.command.Command; 4 | import com.i3geek.pattern.command.receiver.Light; 5 | 6 | 7 | /** 8 | * 命令实现类——对接收者的操作 9 | * @date 2017年2月26日 下午12:17:52 10 | * @author gengzhe.ygz 11 | * 12 | */ 13 | public class LightOnCommand implements Command { 14 | 15 | //接收者绑定:真正执行的人 16 | Light light; 17 | 18 | public LightOnCommand(Light light){ 19 | this.light = light; 20 | } 21 | 22 | @Override 23 | public void execute() { 24 | light.on(); 25 | } 26 | 27 | @Override 28 | public void undo() { 29 | light.off(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/command/invoker/SimpleRemoteControl.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.command.invoker; 2 | 3 | import com.i3geek.pattern.command.command.Command; 4 | 5 | /** 6 | * 发送者(调用者) 7 | * @date 2017年2月26日 下午12:21:40 8 | * @author gengzhe.ygz 9 | * 10 | */ 11 | public class SimpleRemoteControl { 12 | //持有命令 13 | Command slot; 14 | 15 | //设置命令,可以改变行为 16 | public void setCommand(Command command) { 17 | slot = command; 18 | } 19 | 20 | //统一方法,按下按钮 21 | public void buttonPressed(){ 22 | slot.execute(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/command/receiver/Light.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.command.receiver; 2 | 3 | 4 | /** 5 | * 命令接收者,真正执行的人 6 | * @date 2017年2月26日 下午12:18:39 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public class Light { 11 | public void on(){ 12 | System.out.println("开灯"); 13 | } 14 | 15 | public void off(){ 16 | System.out.println("关灯"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/decorate/Client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.decorate; 2 | 3 | import com.i3geek.pattern.decorate.component.Beverage; 4 | import com.i3geek.pattern.decorate.concreteComponent.Espresso; 5 | import com.i3geek.pattern.decorate.concreteComponent.HouseBlend; 6 | import com.i3geek.pattern.decorate.concreteDecorator.Mocha; 7 | 8 | /** 9 | * 装饰模式 10 | * @date 2017年2月23日 上午11:07:26 11 | * @author gengzhe.ygz 12 | * 13 | */ 14 | public class Client { 15 | 16 | public static void main(String args[]){ 17 | 18 | //没有装饰的情况下 19 | Beverage beverage = new Espresso(); 20 | System.out.println(beverage.getDescription() + " $ "+beverage.cost()); 21 | 22 | //装饰后 23 | beverage = new HouseBlend(); 24 | beverage = new Mocha(beverage); //开始装饰第一层 25 | //可以装饰很多层 26 | //... 27 | System.out.println(beverage.getDescription() + " $ "+beverage.cost()); //完全一样的操作 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/decorate/Readme.md: -------------------------------------------------------------------------------- 1 | ## 动机 2 | 3 | 对客户透明的方式动态地给一个对象附加上更多的责任(行为),换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。这就是装饰模式的模式动机。 4 | 5 | ## 定义 6 | 7 | 动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。 8 | 9 | ## 功能 10 | 11 | 装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。 12 | 13 | 特点:装饰者必须实现被装饰者接口,从而对用户透明,完全替代被装饰类。 14 | 15 | ## 实现 16 | 17 | ../_images/Decorator.jpg 18 | - Component: 抽象构件 19 | - ConcreteComponent: 具体构件(被装饰者) 20 | - Decorator: 抽象装饰类 21 | - ConcreteDecorator: 具体装饰类(用来包装的装饰者) 22 | 23 | 注意: 24 | 1. 装饰者和被装饰者有相同的接口 25 | 2. 可以用一个或多个装饰者包装一个对象 26 | 3. 对象可以在任何时候被装饰,可以动态的、不限量的装饰 27 | 28 | ## 应用 29 | 30 | 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。可以动态的增加或撤销功能。 31 | 32 | *原文:http://www.i3geek.com* 33 | *实现源代码:https://github.com/yangengzhe/coding-guide_i3geek/tree/master/docs/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F* -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/decorate/component/Beverage.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.decorate.component; 2 | 3 | 4 | /** 5 | * 基本组件,相当于抽象的Component类,被装饰者的抽象接口 6 | * @date 2017年2月23日 上午10:54:08 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public interface Beverage { 11 | 12 | //获取描述信息 13 | public String getDescription(); 14 | //获取价格 15 | public int cost(); 16 | } 17 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/decorate/concreteComponent/Espresso.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.decorate.concreteComponent; 2 | 3 | import com.i3geek.pattern.decorate.component.Beverage; 4 | 5 | 6 | /** 7 | * 被装饰者,具体构件 8 | * 我们将要动态地加上新行为的对象,它扩展自Component 9 | * @date 2017年2月23日 上午10:56:17 10 | * @author gengzhe.ygz 11 | * 12 | */ 13 | public class Espresso implements Beverage { 14 | 15 | @Override 16 | public String getDescription() { 17 | return "Espresso"; 18 | } 19 | 20 | @Override 21 | public int cost() { 22 | return 10; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/decorate/concreteComponent/HouseBlend.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.decorate.concreteComponent; 2 | 3 | import com.i3geek.pattern.decorate.component.Beverage; 4 | 5 | 6 | /** 7 | * 另一个构件 8 | * @date 2017年2月23日 上午10:57:59 9 | * @author gengzhe.ygz 10 | * 11 | */ 12 | public class HouseBlend implements Beverage { 13 | 14 | @Override 15 | public String getDescription() { 16 | return "HouseBlend"; 17 | } 18 | 19 | @Override 20 | public int cost() { 21 | return 20; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/decorate/concreteDecorator/Mocha.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.decorate.concreteDecorator; 2 | 3 | import com.i3geek.pattern.decorate.component.Beverage; 4 | import com.i3geek.pattern.decorate.decorator.CondimentDecorator; 5 | 6 | 7 | /** 8 | * ConcreteDecorator 具体装饰者类 9 | * 实现装饰者的方法,对被装饰者进行增强 10 | * @date 2017年2月23日 上午11:05:22 11 | * @author gengzhe.ygz 12 | * 13 | */ 14 | public class Mocha implements CondimentDecorator { 15 | 16 | //被装饰者 17 | Beverage beverage; 18 | 19 | public Mocha(Beverage beverage){ 20 | this.beverage = beverage; 21 | } 22 | 23 | //具体的方法增强 24 | @Override 25 | public String getDescription() { 26 | return beverage.getDescription()+", Mocha"; 27 | } 28 | 29 | @Override 30 | public int cost() { 31 | return beverage.cost()+5; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/decorate/decorator/CondimentDecorator.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.decorate.decorator; 2 | 3 | import com.i3geek.pattern.decorate.component.Beverage; 4 | 5 | /** 6 | * 装饰者抽象类 Decorator 7 | * 必须让CondimentDecorator能取代Beverage,所以将CondimentDecorator扩展自Beverage类 8 | * @date 2017年2月23日 上午11:02:21 9 | * @author gengzhe.ygz 10 | * 11 | */ 12 | public interface CondimentDecorator extends Beverage{ 13 | 14 | } 15 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/facade/Readme.md: -------------------------------------------------------------------------------- 1 | ## 动机 2 | 3 | 适配器模式是为了将一个类的接口转换成另一个符合用户期望的接口。现在想改变成一个新的接口,目的是简化接口,用一个统一的接口来访问子系统中的一群接口,这就是外观模式(门面模式)的动机,将一切复杂的都隐藏在背后,只显露出一个干净美好的外观。 4 | 5 | ## 定义 6 | 7 | 外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。 8 | 9 | ## 功能 10 | 11 | 外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。 12 | 13 | 比如:一个看电影的操作,需要关灯、放屏幕、开投影机、打开音响、播放DVD等很多步骤,但是为了让更容易,开发一个更高级的接口,其中包含以上全部内容,这样通过调用一个方法达到以上目的。 14 | 15 | ## 实现 16 | 17 | 利用组合的方式,组合需要的全部组件;定义一个统一接口按顺序调用相应步骤以达到最终功能的目的。 18 | 19 | - Facade: 外观角色 20 | - SubSystem:子系统角色 21 | 22 | ## 应用 23 | 24 | 门面设计模式在 Tomcat 中有多处使用,在 Request 和 Response 对象封装中、Standard Wrapper 到 ServletConfig 封装中、ApplicationContext 到 ServletContext 封装中等都用到了这种设计模式。 25 | Request 上使用的门面设计模式: 26 | 图 2. Request 的门面设计模式类图 27 | 28 | *原文:http://www.i3geek.com* 29 | *实现源代码:https://github.com/yangengzhe/coding-guide_i3geek/tree/master/docs/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F* -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/facade/client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.facade; 2 | 3 | import com.i3geek.pattern.facade.facade.Cinema; 4 | import com.i3geek.pattern.facade.subSystem.DVDplayer; 5 | import com.i3geek.pattern.facade.subSystem.Light; 6 | import com.i3geek.pattern.facade.subSystem.Screen; 7 | 8 | /** 9 | * DesignPattern 10 | * @date 2017年2月25日 下午12:03:24 11 | * @author gengzhe.ygz 12 | * 13 | */ 14 | public class client { 15 | public static void main(String args[]){ 16 | //准备组件(子系统) 17 | DVDplayer dvdplayer = new DVDplayer(); 18 | Light light = new Light(); 19 | Screen screen = new Screen(); 20 | //准备门面类 21 | Cinema cinema = new Cinema(light, screen, dvdplayer); 22 | 23 | //看电影 24 | cinema.WatchMovie(); 25 | 26 | //看完电影 27 | cinema.EndMovie(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/facade/facade/Cinema.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.facade.facade; 2 | 3 | import com.i3geek.pattern.facade.subSystem.DVDplayer; 4 | import com.i3geek.pattern.facade.subSystem.Light; 5 | import com.i3geek.pattern.facade.subSystem.Screen; 6 | 7 | /** 8 | * 门面类 9 | * @date 2017年2月25日 上午11:58:03 10 | * @author gengzhe.ygz 11 | * 12 | */ 13 | public class Cinema { 14 | private Light light; 15 | private Screen screen; 16 | private DVDplayer dvdplayer; 17 | 18 | public Cinema(Light light,Screen screen,DVDplayer dvdplayer){ 19 | this.light = light; 20 | this.screen = screen; 21 | this.dvdplayer = dvdplayer; 22 | } 23 | 24 | public void WatchMovie(){ 25 | System.out.println("开始放映"); 26 | light.close(); 27 | screen.down(); 28 | dvdplayer.play(); 29 | } 30 | 31 | public void EndMovie(){ 32 | System.out.println("放映结束"); 33 | light.open(); 34 | screen.up(); 35 | dvdplayer.stop(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/facade/subSystem/DVDplayer.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.facade.subSystem; 2 | 3 | 4 | /** 5 | * 子系统——控制DVD 6 | * @date 2017年2月25日 上午11:56:35 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public class DVDplayer { 11 | public void play(){ 12 | System.out.println("播放DVD"); 13 | } 14 | public void stop(){ 15 | System.out.println("停止播放"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/facade/subSystem/Light.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.facade.subSystem; 2 | 3 | 4 | /** 5 | * 子系统——控制灯 6 | * @date 2017年2月25日 上午11:54:29 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public class Light { 11 | public void open(){ 12 | System.out.println("灯已经打开"); 13 | } 14 | 15 | public void close(){ 16 | System.out.println("灯已经关闭"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/facade/subSystem/Screen.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.facade.subSystem; 2 | 3 | 4 | /** 5 | * 子系统——控制投影幕 6 | * @date 2017年2月25日 上午11:55:46 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public class Screen { 11 | public void down(){ 12 | System.out.println("放下投影幕"); 13 | } 14 | 15 | public void up(){ 16 | System.out.println("升上投影幕"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/Client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory; 2 | 3 | import com.i3geek.pattern.factory.abstractFactory.AFactory; 4 | import com.i3geek.pattern.factory.abstractFactory.BFactory; 5 | import com.i3geek.pattern.factory.abstractFactory.IFactory; 6 | import com.i3geek.pattern.factory.abstractFactory.product.Text; 7 | import com.i3geek.pattern.factory.factory.AButtonFactory; 8 | import com.i3geek.pattern.factory.factory.BButtonFactory; 9 | import com.i3geek.pattern.factory.factory.Factory; 10 | import com.i3geek.pattern.factory.product.Button; 11 | import com.i3geek.pattern.factory.simpleFactory.ButtonSFactory; 12 | 13 | /** 14 | * 三种工厂方法模式 15 | * @date 2017年2月20日 上午9:56:23 16 | * @author gengzhe.ygz 17 | * 18 | */ 19 | public class Client { 20 | 21 | public static void main(String[] args) { 22 | //简单工厂模式 23 | ButtonSFactory sf = new ButtonSFactory(); 24 | Button button = sf.createButton(0); // 同一工厂根据不同的参数 生产不同的产品 25 | // button = sf.createButton(1); 26 | button.click(); 27 | 28 | //工厂方法模式 29 | Factory factory = new AButtonFactory();//不同的工厂 生产不同的产品 30 | // factory = new BButtonFactory(); 31 | button = factory.createButton(); 32 | button.click(); 33 | 34 | //抽象工厂模式 35 | IFactory iFactory = new AFactory();//不同的工厂 生产不同系列的产品 36 | // iFactory = new BFactory(); 37 | button = iFactory.createButton(); 38 | Text text = iFactory.createText(); 39 | button.click(); 40 | text.input(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/abstractFactory/AFactory.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory.abstractFactory; 2 | 3 | import com.i3geek.pattern.factory.abstractFactory.product.AText; 4 | import com.i3geek.pattern.factory.abstractFactory.product.Text; 5 | import com.i3geek.pattern.factory.product.AButton; 6 | import com.i3geek.pattern.factory.product.Button; 7 | 8 | 9 | /** 10 | * DesignPattern 11 | * @date 2017年2月20日 上午10:24:53 12 | * @author gengzhe.ygz 13 | * 14 | */ 15 | public class AFactory implements IFactory { 16 | 17 | @Override 18 | public Button createButton() { 19 | return new AButton(); 20 | } 21 | 22 | @Override 23 | public Text createText() { 24 | return new AText(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/abstractFactory/BFactory.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory.abstractFactory; 2 | 3 | import com.i3geek.pattern.factory.abstractFactory.product.BText; 4 | import com.i3geek.pattern.factory.abstractFactory.product.Text; 5 | import com.i3geek.pattern.factory.product.BButton; 6 | import com.i3geek.pattern.factory.product.Button; 7 | 8 | 9 | /** 10 | * DesignPattern 11 | * @date 2017年2月20日 上午10:25:30 12 | * @author gengzhe.ygz 13 | * 14 | */ 15 | public class BFactory implements IFactory { 16 | 17 | @Override 18 | public Button createButton() { 19 | return new BButton(); 20 | } 21 | 22 | @Override 23 | public Text createText() { 24 | return new BText(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/abstractFactory/IFactory.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory.abstractFactory; 2 | 3 | import com.i3geek.pattern.factory.abstractFactory.product.Text; 4 | import com.i3geek.pattern.factory.product.Button; 5 | 6 | /** 7 | * 抽象工厂方法 8 | * 工厂方法模式+多个抽象产品 9 | * @date 2017年2月20日 上午10:20:27 10 | * @author gengzhe.ygz 11 | * 12 | */ 13 | public interface IFactory { 14 | public Button createButton(); 15 | public Text createText(); 16 | } 17 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/abstractFactory/product/AText.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory.abstractFactory.product; 2 | 3 | 4 | /** 5 | * DesignPattern 6 | * @date 2017年2月20日 上午10:26:27 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public class AText implements Text { 11 | 12 | @Override 13 | public void input() { 14 | System.out.println("A文本框"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/abstractFactory/product/BText.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory.abstractFactory.product; 2 | 3 | 4 | /** 5 | * DesignPattern 6 | * @date 2017年2月20日 上午10:27:12 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public class BText implements Text { 11 | 12 | @Override 13 | public void input() { 14 | System.out.println("B文本框"); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/abstractFactory/product/Text.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory.abstractFactory.product; 2 | 3 | 4 | /** 5 | * DesignPattern 6 | * @date 2017年2月20日 上午10:26:16 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public interface Text { 11 | void input(); 12 | } 13 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/factory/AButtonFactory.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory.factory; 2 | 3 | import com.i3geek.pattern.factory.product.AButton; 4 | import com.i3geek.pattern.factory.product.Button; 5 | 6 | 7 | /** 8 | * DesignPattern 9 | * @date 2017年2月20日 上午10:11:50 10 | * @author gengzhe.ygz 11 | * 12 | */ 13 | public class AButtonFactory implements Factory { 14 | 15 | @Override 16 | public Button createButton() { 17 | return new AButton(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/factory/BButtonFactory.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory.factory; 2 | 3 | import com.i3geek.pattern.factory.product.BButton; 4 | import com.i3geek.pattern.factory.product.Button; 5 | 6 | /** 7 | * DesignPattern 8 | * @date 2017年2月20日 上午10:12:02 9 | * @author gengzhe.ygz 10 | * 11 | */ 12 | public class BButtonFactory implements Factory { 13 | 14 | @Override 15 | public Button createButton() { 16 | return new BButton(); 17 | } 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/factory/Factory.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory.factory; 2 | 3 | import com.i3geek.pattern.factory.product.Button; 4 | 5 | /** 6 | * 工厂方法模式,工厂抽象类 7 | * 简单工厂模式下+多个工厂实现类(生成一个工厂抽象类) 8 | * @date 2017年2月20日 上午10:10:50 9 | * @author gengzhe.ygz 10 | * 11 | */ 12 | public interface Factory { 13 | public Button createButton(); 14 | } 15 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/product/AButton.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory.product; 2 | 3 | 4 | /** 5 | * DesignPattern 6 | * @date 2017年2月20日 上午10:01:38 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public class AButton implements Button { 11 | 12 | @Override 13 | public void click() { 14 | System.out.println("按钮A"); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/product/BButton.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory.product; 2 | 3 | 4 | /** 5 | * DesignPattern 6 | * @date 2017年2月20日 上午10:01:50 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public class BButton implements Button { 11 | 12 | @Override 13 | public void click() { 14 | System.out.println("按钮B"); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/product/Button.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory.product; 2 | 3 | 4 | /** 5 | * 产品抽象类 6 | * @date 2017年2月20日 上午10:01:11 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public interface Button { 11 | 12 | public void click(); 13 | } 14 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/factory/simpleFactory/ButtonSFactory.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.factory.simpleFactory; 2 | 3 | import com.i3geek.pattern.factory.product.AButton; 4 | import com.i3geek.pattern.factory.product.BButton; 5 | import com.i3geek.pattern.factory.product.Button; 6 | 7 | /** 8 | * 简单工厂模式,按钮工厂 9 | * 1个工厂实现类+N个产品实现类 10 | * 11 | * @date 2017年2月20日 上午9:52:57 12 | * @author gengzhe.ygz 13 | */ 14 | public class ButtonSFactory { 15 | 16 | public Button createButton(int type) { 17 | if (type == 0) return new AButton(); 18 | else return new BButton(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/iterator/Client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.iterator; 2 | 3 | import com.i3geek.pattern.iterator.aggregate.List; 4 | import com.i3geek.pattern.iterator.concreteAggregate.ConcreteAggregate; 5 | import com.i3geek.pattern.iterator.iterator.Iterator; 6 | 7 | /** 8 | * DesignPattern 9 | * @date 2017年2月28日 下午1:16:24 10 | * @author gengzhe.ygz 11 | * 12 | */ 13 | public class Client { 14 | 15 | public static void main(String[] args) { 16 | 17 | List list=new ConcreteAggregate(); 18 | list.add("a"); 19 | list.add("b"); 20 | list.add("c"); 21 | list.add("d"); 22 | Iterator it=list.iterator(); 23 | while(it.hasNext()){ 24 | System.out.println(it.next()); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/iterator/Readme.md: -------------------------------------------------------------------------------- 1 | ## 定义 2 | 3 | 提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节。 4 | 5 | ## 实现 6 | 7 | 8 | - 迭代器角色(Iterator):定义遍历元素所需要的方法,一般来说会有这么三个方法:取得下一个元素的方法next(),判断是否遍历结束的方法hasNext()),移出当前对象的方法remove(), 9 | - 具体迭代器角色(Concrete Iterator):实现迭代器接口中定义的方法,完成集合的迭代。 10 | - 容器角色(Aggregate): 一般是一个接口,提供一个iterator()方法,例如java中的Collection接口,List接口,Set接口等 11 | - 具体容器角色(ConcreteAggregate):就是抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkList,Set接口的哈希列表的实现HashSet等。 12 | 13 | ## 优缺点 14 | 15 | 优点: 16 | - 简化了遍历方式,对于对象集合的遍历,还是比较麻烦的,对于数组或者有序列表,我们尚可以通过游标来取得,但用户需要在对集合了解很清楚的前提下,自行遍历对象,但是对于hash表来说,用户遍历起来就比较麻烦了。而引入了迭代器方法后,用户用起来就简单的多了。 17 | - 可以提供多种遍历方式,比如说对有序列表,我们可以根据需要提供正序遍历,倒序遍历两种迭代器,用户用起来只需要得到我们实现好的迭代器,就可以方便的对集合进行遍历了。 18 | - 封装性良好,用户只需要得到迭代器就可以遍历,而对于遍历算法则不用去关心。 19 | 缺点: 20 | 对于比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐,大家可能都有感觉,像ArrayList,我们宁可愿意使用for循环和get方法来遍历集合。 21 | 22 | ## 总结 23 | 迭代器模式是与集合共生共死的,一般来说,我们只要实现一个集合,就需要同时提供这个集合的迭代器,就像java中的Collection,List、Set、Map等,这些集合都有自己的迭代器。假如我们要实现一个这样的新的容器,当然也需要引入迭代器模式,给我们的容器实现一个迭代器。 24 | 但是,由于容器与迭代器的关系太密切了,所以大多数语言在实现容器的时候都给提供了迭代器,并且这些语言提供的容器和迭代器在绝大多数情况下就可以满足我们的需要,所以现在需要我们自己去实践迭代器模式的场景还是比较少见的,我们只需要使用语言中已有的容器和迭代器就可以了。 25 | 26 | --- 27 | 参考:http://cashow.github.io/head-first-design-patterns-notes-iterator-pattern.html -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/iterator/aggregate/List.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.iterator.aggregate; 2 | 3 | import com.i3geek.pattern.iterator.iterator.Iterator; 4 | 5 | /** 6 | * 容器角色 7 | * @date 2017年2月28日 下午1:14:34 8 | * @author gengzhe.ygz 9 | * 10 | */ 11 | //定义集合可以进行的操作 12 | public interface List { 13 | 14 | public void add(Object obj); 15 | public Object get(int index); 16 | public Iterator iterator(); 17 | public int getSize(); 18 | } -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/iterator/concreteAggregate/ConcreteAggregate.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.iterator.concreteAggregate; 2 | 3 | import com.i3geek.pattern.iterator.aggregate.List; 4 | import com.i3geek.pattern.iterator.concreteiterator.ConcreteIterator; 5 | import com.i3geek.pattern.iterator.iterator.Iterator; 6 | 7 | /** 8 | * 具体角色 9 | * @date 2017年2月28日 下午1:15:21 10 | * @author gengzhe.ygz 11 | * 12 | */ 13 | public class ConcreteAggregate implements List{ 14 | 15 | private Object[] list; 16 | private int size=0; 17 | private int index=0; 18 | public ConcreteAggregate(){ 19 | index=0; 20 | size=0; 21 | list=new Object[100]; 22 | } 23 | @Override 24 | public void add(Object obj) { 25 | list[index++]=obj; 26 | size++; 27 | } 28 | 29 | @Override 30 | public Iterator iterator() { 31 | 32 | return new ConcreteIterator(this); 33 | } 34 | @Override 35 | public Object get(int index) { 36 | 37 | return list[index]; 38 | } 39 | @Override 40 | public int getSize() { 41 | 42 | return size; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/iterator/concreteiterator/ConcreteIterator.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.iterator.concreteiterator; 2 | 3 | import com.i3geek.pattern.iterator.aggregate.List; 4 | import com.i3geek.pattern.iterator.iterator.Iterator; 5 | 6 | 7 | /** 8 | * 具体迭代器角色 9 | * @date 2017年2月28日 下午1:13:37 10 | * @author gengzhe.ygz 11 | * 12 | */ 13 | public class ConcreteIterator implements Iterator { 14 | 15 | private List list = null; 16 | private int index; 17 | 18 | public ConcreteIterator(List list) { 19 | super(); 20 | this.list = list; 21 | } 22 | 23 | @Override 24 | public boolean hasNext() { 25 | if (index >= list.getSize()) { 26 | return false; 27 | } else { 28 | return true; 29 | } 30 | } 31 | 32 | @Override 33 | public Object next() { 34 | Object object = list.get(index); 35 | index++; 36 | return object; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/iterator/iterator/Iterator.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.iterator.iterator; 2 | 3 | 4 | /** 5 | * 迭代器接口 6 | * @date 2017年2月28日 下午1:12:50 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public interface Iterator { 11 | public boolean hasNext(); 12 | public Object next(); 13 | } 14 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/observer/Client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.observer; 2 | 3 | import com.i3geek.pattern.observer.observer.ConcreteObserver; 4 | import com.i3geek.pattern.observer.observer.Observer; 5 | import com.i3geek.pattern.observer.subject.AbstractSubject; 6 | import com.i3geek.pattern.observer.subject.ConcreteSubject; 7 | 8 | /** 9 | * DesignPattern 10 | * @date 2017年2月26日 下午5:45:23 11 | * @author gengzhe.ygz 12 | * 13 | */ 14 | public class Client { 15 | public static void main(String args[]){ 16 | //目标类,被观察者 17 | ConcreteSubject subject = new ConcreteSubject(); 18 | 19 | //观察者,被通知者 两个A和B 20 | Observer observerA = new ConcreteObserver(); 21 | Observer observerB = new ConcreteObserver(); 22 | 23 | //注册观察者 24 | subject.attach(observerA); 25 | subject.attach(observerB); 26 | 27 | //更改目标类,通知观察者 28 | subject.setSubjectState("内容1"); 29 | subject.setSubjectState("内容2"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/observer/Readme.md: -------------------------------------------------------------------------------- 1 | ## 动机 2 | 3 | 建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。这就是观察者模式的模式动机。 4 | 5 | ## 定义 6 | 7 | 对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 8 | 9 | ## 作用 10 | 11 | 订阅、发布 12 | 13 | 发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展 14 | 15 | ## 实现 16 | 17 | ../_images/Obeserver.jpg 18 | - Subject: 目标 19 | - ConcreteSubject: 具体目标 20 | - Observer: 观察者 21 | - ConcreteObserver: 具体观察者 22 | 23 | ## 应用 24 | 25 | Tomcat中控制组件生命周期的 Lifecycle 就是这种模式的体现,还有对 Servlet 实例的创建、Session 的管理、Container 等都是同样的原理。 26 | 27 | 图 3. Lifecycle 的观察者模式结构图 28 | 上面的结构图中,LifecycleListener 代表的是抽象观察者,它定义一个 lifecycleEvent 方法,这个方法就是当主题变化时要执行的方法。 ServerLifecycleListener 代表的是具体的观察者,它实现了 LifecycleListener 接口的方法,就是这个具体的观察者具体的实现方式。Lifecycle 接口代表的是抽象主题,它定义了管理观察者的方法和它要所做的其它方法。而 StandardServer 代表的是具体主题,它实现了抽象主题的所有方法。 29 | 30 | 这里 Tomcat 对观察者做了扩展,增加了另外两个类:LifecycleSupport、LifecycleEvent,它们作为辅助类扩展了观察者的功能。LifecycleEvent 使得可以定义事件类别,不同的事件可区别处理,更加灵活。LifecycleSupport 类代理了主题对多观察者的管理,将这个管理抽出来统一实现,以后如果修改只要修改 LifecycleSupport 类就可以了,不需要去修改所有具体主题,因为所有具体主题的对观察者的操作都被代理给 LifecycleSupport 类了。这可以认为是观察者模式的改进版。 -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/observer/observer/ConcreteObserver.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.observer.observer; 2 | 3 | import com.i3geek.pattern.observer.subject.AbstractSubject; 4 | import com.i3geek.pattern.observer.subject.ConcreteSubject; 5 | 6 | public class ConcreteObserver implements Observer { 7 | 8 | String ObserverState; 9 | @Override 10 | public void update(AbstractSubject subject) { 11 | this.ObserverState = ((ConcreteSubject)subject).getSubjectState(); 12 | System.out.println("收到更新·通知:"+ObserverState); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/observer/observer/Observer.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.observer.observer; 2 | 3 | import javax.security.auth.Subject; 4 | 5 | import com.i3geek.pattern.observer.subject.AbstractSubject; 6 | 7 | /** 8 | * 观察者接口(被通知者),定义通知接口 9 | * @date 2017年1月16日 下午7:18:13 10 | * @author yangengzhe 11 | * 12 | */ 13 | public interface Observer { 14 | //目标发送改变时,调用的方法 15 | public void update(AbstractSubject subject); 16 | } 17 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/observer/subject/AbstractSubject.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.observer.subject; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.i3geek.pattern.observer.observer.Observer; 7 | 8 | /** 9 | * 目标抽象类(被观察者)。用于保存观察者列表,提供注册和删除观察者的操作。 10 | * 一旦自己改变,立刻通知观察者 11 | * @date 2017年1月16日 下午7:21:49 12 | * @author yangengzhe 13 | * 14 | */ 15 | public abstract class AbstractSubject { 16 | private List observers = new ArrayList(); 17 | 18 | //注册 19 | public void attach(Observer observer){ 20 | observers.add(observer); 21 | } 22 | 23 | //删除 24 | public void detach(Observer observer){ 25 | observers.remove(observer); 26 | } 27 | 28 | //通知 29 | protected void notifyObservers(){ 30 | for (Observer observer : observers) { 31 | observer.update(this); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/observer/subject/ConcreteSubject.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.observer.subject; 2 | 3 | 4 | /** 5 | * 具体目标类,达到效果:当subjectState变化 就通知所有观察者 6 | * @date 2017年1月16日 下午7:27:03 7 | * @author yangengzhe 8 | * 9 | */ 10 | public class ConcreteSubject extends AbstractSubject { 11 | //目标对象的状态 《== 变化时就通知所有观察者 12 | private String subjectState; 13 | 14 | 15 | public String getSubjectState() { 16 | return subjectState; 17 | } 18 | 19 | 20 | public void setSubjectState(String subjectState) { 21 | this.subjectState = subjectState; 22 | System.out.println("通知大家了!"); 23 | this.notifyObservers(); 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/proxy/Client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.proxy; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Proxy; 5 | 6 | import com.i3geek.pattern.proxy.dynamicProxy.cglib.cglibProxy; 7 | import com.i3geek.pattern.proxy.dynamicProxy.jdk.TimeHandler; 8 | import com.i3geek.pattern.proxy.staticProxy.CarExtend; 9 | import com.i3geek.pattern.proxy.staticProxy.CarImplement; 10 | import com.i3geek.pattern.proxy.real.Car; 11 | import com.i3geek.pattern.proxy.real.Moveable; 12 | import com.i3geek.pattern.proxy.real.Train; 13 | 14 | public class Client { 15 | 16 | public static void main(String args[]) { 17 | 18 | /**静态代理**/ 19 | //静态代理 继承 20 | Moveable moveable = new CarExtend(); 21 | moveable.move(); 22 | 23 | //静态代理 聚合 24 | Car car = new Car(); 25 | moveable = new CarImplement(car); 26 | moveable.move(); 27 | 28 | 29 | /**动态代理**/ 30 | /**Cglib**/ 31 | cglibProxy proxy = new cglibProxy(); 32 | //获得被代理类的子类 33 | Train train = (Train)proxy.getProxy(Train.class); 34 | train.move(); 35 | 36 | /**JDK**/ 37 | car =new Car(); 38 | InvocationHandler h =new TimeHandler(car); 39 | Class cls = car.getClass(); 40 | 41 | //loader 类加载器,interfaces 实现接口,InvocationHandler 42 | //返回:代理后的对象 43 | Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h); 44 | 45 | m.move(); 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/proxy/README.md: -------------------------------------------------------------------------------- 1 | # 代理模式 2 | 3 | ## 静态代理 4 | 5 | 真实类Car 实现接口Moveable,功能开车。 6 | 代理类 ,功能开车+计时。 7 | 8 | 方法一:继承(不推荐) 9 | 10 | 代理类CarExtend 继承真实类Car,并对父类Car进行增强 11 | 12 | 方法二:聚合(实现接口) 13 | 14 | 代理类CarImplement实现了接口Moveable,其中含有Car对象,在方法的实现中,调用Car的原始方法并增强。 15 | 16 | ###比较 17 | 18 | 继承方式,要为不同的代理内容创建不同的代理类(功能的叠加)。例如若先执行增强功能1,再执行增强功能2,需要创建代理类A;若先执行增强功能2,再执行增强功能1,需要创建代理类B…… 19 | 20 | 聚合方式,为不同的功能创建不同的代理类,在使用时只需要迭代实例化即可。 21 | 22 | 继承方式是针对代理类来编程,一个代理类代表一个完整的代理后对象。聚合方式是针对代理方法来编程,一个代理类代表一个完整的代理功能,需要传入真实对象后才可以用。 23 | 24 | ## 动态代理 25 | 26 | 把手动编写,变成动态产生。 27 | 28 | 方法一:JDK动态代理(反射) 29 | 30 | 在运行时生成代理后的Class,必须被代理类要实现接口,必须实现Handler(具体业务在Handler) 31 | 32 | 1、创建并实现InvocationHandler类,并实现invoke方法(完成代理增强功能) 33 | 2、创建被代理类 34 | 3、利用Proxy.newProxyInstance方法创建一个代理类 35 | 4、调用代理类的方法 36 | 37 | 方法二:CGLIB动态代理(继承) 38 | 39 | ###对比 40 | 41 | JDK动态代理:只能代理实现了接口的类。 42 | CGLIB代理:针对类实现代理,生成一个子类。(final的类不可以) 43 | 44 | ##总结 45 | 46 | 静态代理,对固定真实类做代理。如:CarProxy -> Car ; TrainProxy ->Train ...... 47 | 假设有100种交通工具,则需要100个代理类,每个类中代理方法一样,只是聚合的对象类型不同,甚至执行的方法都一样。 48 | 49 | 动态代理,对任意真实类做代理。如:Proxy -> Car、Train....... 50 | 一个代理类,动态产生不同的真实类。 -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/proxy/dynamicProxy/cglib/cglibProxy.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.proxy.dynamicProxy.cglib; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import com.sun.org.apache.bcel.internal.generic.NEW; 6 | 7 | import net.sf.cglib.proxy.Enhancer; 8 | import net.sf.cglib.proxy.MethodInterceptor; 9 | import net.sf.cglib.proxy.MethodProxy; 10 | 11 | public class cglibProxy implements MethodInterceptor{ 12 | private Enhancer enhancer = new Enhancer(); 13 | 14 | public Object getProxy(Class clazz){ 15 | //设置创建子类的类(设置被代理类) 16 | enhancer.setSuperclass(clazz); 17 | enhancer.setCallback(this); 18 | 19 | return enhancer.create();//返回子类 20 | } 21 | /** 22 | * 拦截所有目标类方法的调用 23 | * @param obj 目标类的实例 24 | * @param m目标方法的反射对象 25 | * @param args方法的参数 26 | * @param proxy代理类的实例 27 | * @return 28 | * @throws Throwable 29 | * @author ygz 下午8:16:40 30 | */ 31 | @Override 32 | public Object intercept(Object obj,Method m,Object[] args,MethodProxy proxy) throws Throwable{ 33 | System.out.println("开始"); 34 | //代理类调用父类的方法 35 | proxy.invokeSuper(obj,args); 36 | System.out.println("结束"); 37 | return null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/proxy/dynamicProxy/jdk/TimeHandler.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.proxy.dynamicProxy.jdk; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | 6 | 7 | public class TimeHandler implements InvocationHandler { 8 | 9 | private Object target; 10 | 11 | public TimeHandler(Object target){ 12 | this.target = target; 13 | } 14 | /* proxy : 被代理对象 15 | * method : 被代理对象的方法 16 | * args : 方法的参数 17 | * 18 | * 返回值 19 | * Object : 方法返回值 20 | * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) 21 | */ 22 | @Override 23 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 24 | long starttime = System.currentTimeMillis(); 25 | method.invoke(target); 26 | long endtime = System.currentTimeMillis(); 27 | System.out.println("汽车结束行驶,用时:"+(endtime -starttime)); 28 | return null; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/proxy/real/Car.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.proxy.real; 2 | 3 | import java.util.Random; 4 | 5 | public class Car implements Moveable { 6 | 7 | @Override 8 | public void move() { 9 | 10 | //实现开车 11 | try { 12 | Thread.sleep(new Random().nextInt(1000)); 13 | } catch (InterruptedException e) { 14 | // TODO Auto-generated catch block 15 | e.printStackTrace(); 16 | } 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/proxy/real/Moveable.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.proxy.real; 2 | 3 | 4 | public interface Moveable { 5 | void move(); 6 | } 7 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/proxy/real/Train.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.proxy.real; 2 | 3 | 4 | public class Train { 5 | public void move(){ 6 | System.out.println("火车行驶中"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/proxy/staticProxy/CarExtend.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.proxy.staticProxy; 2 | 3 | import com.i3geek.pattern.proxy.real.Car; 4 | 5 | 6 | public class CarExtend extends Car { 7 | 8 | @Override 9 | public void move() { 10 | long starttime = System.currentTimeMillis(); 11 | super.move(); 12 | long endtime = System.currentTimeMillis(); 13 | System.out.println("汽车结束行驶,用时:"+(endtime -starttime)); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/proxy/staticProxy/CarImplement.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.proxy.staticProxy; 2 | 3 | import com.i3geek.pattern.proxy.real.Car; 4 | import com.i3geek.pattern.proxy.real.Moveable; 5 | 6 | 7 | public class CarImplement implements Moveable { 8 | 9 | private Car car; 10 | 11 | public CarImplement(Car car){ 12 | this.car =car; 13 | } 14 | @Override 15 | public void move() { 16 | long starttime = System.currentTimeMillis(); 17 | car.move(); 18 | long endtime = System.currentTimeMillis(); 19 | System.out.println("汽车结束行驶,用时:"+(endtime -starttime)); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/responsibilityChain/Client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.responsibilityChain; 2 | 3 | import com.i3geek.pattern.responsibilityChain.concreteHandler.DeptHandler; 4 | import com.i3geek.pattern.responsibilityChain.concreteHandler.GeneralHandler; 5 | import com.i3geek.pattern.responsibilityChain.concreteHandler.ProjectHandler; 6 | 7 | /** 8 | * DesignPattern 9 | * @date 2017年2月26日 下午6:16:39 10 | * @author gengzhe.ygz 11 | * 12 | */ 13 | public class Client { 14 | 15 | public static void main(String[] args) { 16 | //创建每一层的责任 17 | ProjectHandler projectHandler =new ProjectHandler(); 18 | DeptHandler deptHandler =new DeptHandler(); 19 | GeneralHandler generalHandler =new GeneralHandler(); 20 | //建立链 21 | projectHandler.setNextHandler(deptHandler); 22 | deptHandler.setNextHandler(generalHandler); 23 | 24 | //开始执行 25 | projectHandler.doHandler(100); 26 | projectHandler.doHandler(600); 27 | projectHandler.doHandler(1100); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/responsibilityChain/concreteHandler/DeptHandler.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.responsibilityChain.concreteHandler; 2 | 3 | import com.i3geek.pattern.responsibilityChain.handler.Handler; 4 | 5 | 6 | /** 7 | * 第二层 责任处理者 8 | * @date 2017年2月26日 下午6:14:50 9 | * @author gengzhe.ygz 10 | * 11 | */ 12 | public class DeptHandler extends Handler { 13 | 14 | @Override 15 | public void doHandler(int money) { 16 | if(money<1000) 17 | System.out.println("部门经理审批:"+money); 18 | else{ 19 | System.out.println("部门经理上交"); 20 | getNextHandler().doHandler(money); 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/responsibilityChain/concreteHandler/GeneralHandler.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.responsibilityChain.concreteHandler; 2 | 3 | import com.i3geek.pattern.responsibilityChain.handler.Handler; 4 | 5 | 6 | /** 7 | * 最顶层 责任处理者 8 | * @date 2017年2月26日 下午6:10:09 9 | * @author gengzhe.ygz 10 | * 11 | */ 12 | public class GeneralHandler extends Handler { 13 | 14 | @Override 15 | public void doHandler(int money) { 16 | System.out.println("总经理审批:"+money); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/responsibilityChain/concreteHandler/ProjectHandler.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.responsibilityChain.concreteHandler; 2 | 3 | import com.i3geek.pattern.responsibilityChain.handler.Handler; 4 | 5 | 6 | /** 7 | * 最底层(入口) 责任处理者 8 | * @date 2017年2月26日 下午6:14:50 9 | * @author gengzhe.ygz 10 | * 11 | */ 12 | public class ProjectHandler extends Handler { 13 | 14 | @Override 15 | public void doHandler(int money) { 16 | if(money<500) 17 | System.out.println("项目经理审批:"+money); 18 | else{ 19 | System.out.println("项目经理上交"); 20 | getNextHandler().doHandler(money); 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/responsibilityChain/handler/Handler.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.responsibilityChain.handler; 2 | 3 | 4 | /** 5 | * 责任链抽象类 6 | * @date 2017年2月26日 下午6:07:44 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public abstract class Handler { 11 | private Handler nextHandler; 12 | //获得下一个责任者 13 | public Handler getNextHandler(){ 14 | return nextHandler; 15 | } 16 | 17 | //设置下一个责任 18 | public void setNextHandler(Handler nextHandler){ 19 | this.nextHandler = nextHandler; 20 | } 21 | 22 | //处理 23 | public abstract void doHandler(int money); 24 | } 25 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/singleton/Client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.singleton; 2 | 3 | import com.i3geek.pattern.singleton.singleton.HungrySingleton; 4 | 5 | /** 6 | * DesignPattern 7 | * @date 2017年2月19日 上午10:51:11 8 | * @author gengzhe.ygz 9 | * 10 | */ 11 | public class Client { 12 | public static void main(String args[]){ 13 | HungrySingleton singleton = HungrySingleton.getInstance(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/singleton/Readme.md: -------------------------------------------------------------------------------- 1 | ## 动机 2 | 3 | 有些系统中只有一个实例工作很重要,比如递增ID的生成器,多个线程使用该生成器要保证生成唯一递增的ID,那必然需要调用同一个生成器,如何保证大家调用的都是同一个实例呢? 4 | 5 | 让类自身保存它的唯一实例,该类不可以实例化出实例,但是对外提供方法可以提供一个可访问的实例,以此保证所有通过该类得到的实例都是相同的。这就是单例模式的动机。 6 | 7 | ## 定义 8 | 9 | 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。 10 | 11 | ## 功能 12 | 13 | 单例类拥有一个私有构造函数,使用户无法通过new来实例化它,从而保证了一个类仅有一个实例,并提供一个工厂方法,用来创建并返回保持的唯一对象。 14 | 15 | ## 实现 16 | 17 | - Singleton:单例类:(1)单例类的构造函数为私有;(2)提供一个自身的静态私有成员变量;(3)提供一个公有的静态工厂方法。 18 | 19 | 饿汉模式:类加载时进行实例化,从而保证了线程的安全,但是因为还没有使用就加载可能会造成资源浪费 但是第一次调用时初始化时间少。 20 | 懒汉模式:方法工厂中进行实例化,线程不安全。可以通过加锁的方式实现同步。 21 | 22 | ## 应用 23 | 24 | 连接池、线程池、Spring Ioc 25 | 26 | *原文:http://www.i3geek.com/archives/1346* 27 | *实现源代码:https://github.com/yangengzhe/coding-guide_i3geek/tree/master/docs/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F* -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/singleton/singleton/HungrySingleton.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.singleton.singleton; 2 | 3 | /** 4 | * 单例模式 饿汉模式 线程安全 5 | * @date 2017年2月19日 上午10:47:29 6 | * @author gengzhe.ygz 7 | * 8 | */ 9 | public class HungrySingleton { 10 | private static HungrySingleton instance = new HungrySingleton(); 11 | private HungrySingleton(){} 12 | 13 | public static HungrySingleton getInstance(){ 14 | return instance; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/singleton/singleton/LazySingleton.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.singleton.singleton; 2 | 3 | 4 | /** 5 | * 单例模式 懒汉 线程不安全 6 | * @date 2017年2月19日 上午10:43:11 7 | * @author gengzhe.ygz 8 | * 9 | */ 10 | public class LazySingleton { 11 | private static LazySingleton instance; 12 | private LazySingleton(){} 13 | 14 | public static LazySingleton getInstance(){ 15 | if(instance == null) 16 | instance = new LazySingleton(); 17 | return instance; 18 | } 19 | 20 | //同步的方法 线程安全 21 | public static synchronized LazySingleton getInstanceSyn(){ 22 | if(instance == null) 23 | instance = new LazySingleton(); 24 | return instance; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/strategy/Client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.strategy; 2 | 3 | import com.i3geek.pattern.strategy.concreteStrategy.quickSort; 4 | import com.i3geek.pattern.strategy.concreteStrategy.selectSort; 5 | import com.i3geek.pattern.strategy.context.context; 6 | 7 | public class Client { 8 | public static void main(String args[]){ 9 | quickSort quick = new quickSort(); 10 | selectSort select = new selectSort(); 11 | 12 | context c = new context(); 13 | c.setStrategy(quick); 14 | c.doAction(); 15 | 16 | //更换算法 17 | c.setStrategy(select); 18 | c.doAction(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/strategy/Readme.md: -------------------------------------------------------------------------------- 1 | # 策略模式 2 | 3 | ## 定义 4 | 5 | 策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。 6 | 7 | ## 实现 8 | 9 | 环境类(context) 10 | 11 | 利用聚合,把抽象策略类放入类中进行使用。 12 | 13 | 抽象策略类(Strategy) 14 | 15 | 将可变的部分从程序中抽象分离成算法接口 16 | 17 | 具体策略类(ConcreteStrategy) 18 | 19 | 在该接口下分别封装一系列算法实现 20 | 21 | 客户端(client) 22 | 23 | 让算法独立于使用它的客户而变化 -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/strategy/concreteStrategy/quickSort.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.strategy.concreteStrategy; 2 | 3 | import com.i3geek.pattern.strategy.strategy.Strategy; 4 | 5 | 6 | /** 7 | * 具体策略 8 | * @date 2017年2月26日 下午6:00:00 9 | * @author yangengzhe 10 | * 11 | */ 12 | public class quickSort implements Strategy { 13 | 14 | @Override 15 | public void algorithm() { 16 | System.out.println("选择排序算法"); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/strategy/concreteStrategy/selectSort.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.strategy.concreteStrategy; 2 | 3 | import com.i3geek.pattern.strategy.strategy.Strategy; 4 | 5 | 6 | /** 7 | * 具体策略 8 | * @date 2017年2月26日 下午6:00:09 9 | * @author yangengzhe 10 | * 11 | */ 12 | public class selectSort implements Strategy { 13 | 14 | @Override 15 | public void algorithm() { 16 | System.out.println("快排算法"); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/strategy/context/context.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.strategy.context; 2 | 3 | import com.i3geek.pattern.strategy.strategy.Strategy; 4 | 5 | /** 6 | * 环境类,存放策略 7 | * @date 2017年2月26日 下午5:59:25 8 | * @author yangengzhe 9 | * 10 | */ 11 | public class context { 12 | private Strategy strategy; 13 | 14 | public void doAction(){ 15 | strategy.algorithm(); 16 | } 17 | 18 | public Strategy getStrategy() { 19 | return strategy; 20 | } 21 | 22 | 23 | public void setStrategy(Strategy strategy) { 24 | this.strategy = strategy; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/strategy/strategy/Strategy.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.strategy.strategy; 2 | 3 | 4 | /** 5 | * 抽象策略类 6 | * @date 2017年1月7日 上午9:10:41 7 | * @author yangengzhe 8 | * 9 | */ 10 | public interface Strategy { 11 | public void algorithm(); 12 | } 13 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/template/Abstract/Base.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.template.Abstract; 2 | 3 | import sun.io.ByteToCharMacHebrew; 4 | 5 | /** 6 | * 抽象基类,为所有子类提供一个算法框架 7 | * @date 2017年1月3日 下午3:31:05 8 | * @author yangengzhe 9 | * 10 | */ 11 | public abstract class Base { 12 | 13 | /** 14 | * 该方法即模板方法,规范了算法(过程)的实现步骤 15 | * 模板方法,封装了所有子类共同遵循的算法步骤框架,不能被修改 因此不能被继承 16 | * @author ygz 下午3:32:44 17 | */ 18 | public final void prepareTemplate(){ 19 | //步骤一:将水煮沸 20 | boilWater(); 21 | //步骤二:泡制饮料 22 | brew(); 23 | //步骤三:倒入杯中 24 | pourInCup(); 25 | //步骤四:加入调味料 26 | addCondiments(); 27 | } 28 | 29 | /** 30 | * 抽象的基本方法,用于加入调料,由子类实现 31 | * @author ygz 下午4:02:02 32 | * @return 33 | */ 34 | protected abstract void addCondiments(); 35 | 36 | /** 37 | * 基本方法,通用的,没有区别的方法。不用子类考虑,因此定义为私有的 38 | * @author ygz 下午4:00:26 39 | */ 40 | private void pourInCup() { 41 | System.out.println("倒入杯中"); 42 | } 43 | 44 | /** 45 | * 抽象的基本方法,用于泡制饮料,由子类实现 46 | * @author ygz 下午4:02:02 47 | * @return 48 | */ 49 | protected abstract void brew(); 50 | 51 | /** 52 | * 基本方法,通用的,没有区别的方法。不用子类考虑,因此定义为私有的 53 | * @author ygz 下午4:00:26 54 | */ 55 | private void boilWater() { 56 | System.out.println("煮沸水"); 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/template/Client.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.template; 2 | 3 | import com.i3geek.pattern.template.Abstract.Base; 4 | import com.i3geek.pattern.template.Concrete.Coffee; 5 | import com.i3geek.pattern.template.Concrete.Tea; 6 | 7 | public class Client { 8 | 9 | public static void main(String[] args) { 10 | Base base = new Coffee(); 11 | base.prepareTemplate(); 12 | 13 | base = new Tea(); 14 | base.prepareTemplate(); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/template/Concrete/Coffee.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.template.Concrete; 2 | 3 | import com.i3geek.pattern.template.Abstract.Base; 4 | 5 | 6 | /** 7 | * 具体子类 8 | * 9 | * 提供了咖啡的实现 10 | * @date 2017年1月3日 下午4:06:15 11 | * @author yangengzhe 12 | * 13 | */ 14 | public class Coffee extends Base { 15 | 16 | @Override 17 | protected void addCondiments() { 18 | System.out.println("加入糖和牛奶"); 19 | } 20 | 21 | @Override 22 | protected void brew() { 23 | System.out.println("冲泡咖啡"); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/template/Concrete/Tea.java: -------------------------------------------------------------------------------- 1 | package com.i3geek.pattern.template.Concrete; 2 | 3 | import com.i3geek.pattern.template.Abstract.Base; 4 | 5 | 6 | public class Tea extends Base { 7 | 8 | @Override 9 | protected void addCondiments() { 10 | System.out.println("加入柠檬"); 11 | } 12 | 13 | @Override 14 | protected void brew() { 15 | System.out.println("用80度水浸泡"); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /docs/设计模式/DesignPattern/src/com/i3geek/pattern/template/Readme.md: -------------------------------------------------------------------------------- 1 | # 模板方法模式 2 | 3 | ## 实例目的 4 | 5 | 实现饮料机冲泡饮料的功能。 6 | 7 | 饮料机冲饮料的步骤是相同的:1、将水煮沸;2、泡制饮料;3、倒入杯中;4、加入调味料 8 | 9 | 但是某一步不同,比如第二步泡制饮料,根据不同的饮料需要倒入不同的原料。 10 | 11 | ##思路 12 | 13 | 步骤相同,所以用了模板方法:在抽象基类中声明了每一步方法,并定义了每一步方法的执行步骤。 14 | 具体的子类中,实现每一步的操作 15 | 16 | ##实现 17 | 18 | ### Abstract 19 | 20 | 抽象基类,说明所有子类共同遵守的算法框架(步骤) 21 | 22 | 需要子类考虑的方法用抽象类;不需要的方法用private或final实现 23 | 24 | ### Concrete 25 | 26 | 具体实现类,用于实现抽象类的方法,个性的实现不同的功能 -------------------------------------------------------------------------------- /docs/设计模式/代理模式.md: -------------------------------------------------------------------------------- 1 | # 代理模式 2 | 3 | ## 定义 4 | 5 | 为被代理对象提供一种代理,来控制对该对象的访问。(通过引入代理对象来间接访问一个对象) 中介作用,起到隐藏功能或增加功能的效果。 6 | 7 | ## 作用 8 | 9 | 被代理类A ==方法增强==> 代理类B (增强方法,保护真实类) 10 | 11 | 比如:火车站售票处(卖票和退票的功能) ==代理类==> 火车站代售处(卖票功能) 12 | 13 | ## 分类 14 | 15 | 远程代理:为不同地域的对象提供局域网代表的对象,虚拟代理:大对象的延迟创建,保护代理:控制对一个对象的访问权限,智能引用代理:对目标对象提供一些额外的服务 16 | 17 | ## 实现(智能引用代理) 18 | 19 | ### 静态代理 20 | 21 | 在编译前已经完成了代理工作,即编写两个类都实现了相同的接口或继承了相同的类。 22 | 23 | 方法一:继承(不推荐) 24 | 25 | 方法二:聚合(实现接口) 26 | 27 | ### 动态代理 28 | 29 | 运行中,动态为真实类生成对应的代理类并加载。 30 | 31 | 方法一:JDK动态代理(反射) 注:必须实现接口 32 | 33 | 方法二:CGLIB动态代理(继承) 34 | 35 | ## 应用 36 | 37 | EJB、Web Service等分布式技术都是代理模式的应用。在EJB中使用了RMI机制,远程服务器中的企业级Bean在本地有一个桩代理,客户端通过桩来调用远程对象中定义的方法,而无须直接与远程对象交互。在EJB的使用中需要提供一个公共的接口,客户端针对该接口进行编程,无须知道桩以及远程EJB的实现细节。 -------------------------------------------------------------------------------- /docs/设计模式/单例模式.md: -------------------------------------------------------------------------------- 1 | ## 动机 2 | 3 | 有些系统中只有一个实例工作很重要,比如递增ID的生成器,多个线程使用该生成器要保证生成唯一递增的ID,那必然需要调用同一个生成器,如何保证大家调用的都是同一个实例呢? 4 | 5 | 让类自身保存它的唯一实例,该类不可以实例化出实例,但是对外提供方法可以提供一个可访问的实例,以此保证所有通过该类得到的实例都是相同的。这就是单例模式的动机。 6 | 7 | ## 定义 8 | 9 | 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。 10 | 11 | ## 功能 12 | 13 | 单例类拥有一个私有构造函数,使用户无法通过new来实例化它,从而保证了一个类仅有一个实例,并提供一个工厂方法,用来创建并返回保持的唯一对象。 14 | 15 | ## 实现 16 | 17 | - Singleton:单例类:(1)单例类的构造函数为私有;(2)提供一个自身的静态私有成员变量;(3)提供一个公有的静态工厂方法。 18 | 19 | 饿汉模式:类加载时进行实例化,从而保证了线程的安全,但是因为还没有使用就加载可能会造成资源浪费 但是第一次调用时初始化时间少。 20 | 懒汉模式:方法工厂中进行实例化,线程不安全。可以通过加锁的方式实现同步。 21 | 22 | ## 应用 23 | 24 | 连接池、线程池、Spring Ioc 25 | 26 | *原文:http://www.i3geek.com/archives/1346* 27 | *实现源代码:https://github.com/yangengzhe/coding-guide_i3geek/tree/master/docs/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F* -------------------------------------------------------------------------------- /docs/设计模式/建造者模式.md: -------------------------------------------------------------------------------- 1 | # 建造者模式 2 | ## 动机 3 | 4 | 说道建造者肯定联想到建筑工人,比如在建筑一个茅草屋和一个砖瓦房时,过程一样只是用的材料不同。比如第一步建立地基:茅草屋用工具,砖瓦房用机器;第二步建立框架:茅草屋用树木,砖瓦房用混凝土;第三步建立房屋:茅草屋用茅草,砖瓦房用砌砖。 5 | 6 | 可以看出过程是一样的,只是用到的材料不同。因此将过程和材料解耦,将这些复杂材料的生产分离出来(建造者),流程独立化出来(指挥者)。 7 | 8 | ## 定义 9 | 10 | 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 11 | 12 | ## 功能 13 | 14 | 通过不同的建造者实例,生产不同的材料,利用统一的指挥者流程,可以规范标准化的生产出各种产品。 15 | 16 | 在客户端中无须关心产品中具体零件是怎么生产的(建造者)和怎么组装的(指挥者),只需要确定具体建造者就可以得出相对应的产品。 17 | 18 | ## 实现 19 | 20 | 21 | - builder:建造者抽象接口,声明产品中包含的全部零部件。 22 | - ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,实现不同零部件的创建。 23 | - Director:调用具体建造者来创建每个零部件,并根据统一的建造过程,组装零部件并返回产品。 24 | - Product:最终要建造的产品。 25 | 26 | ## 应用 27 | 28 | 在很多游戏软件中,地图包括天空、地面、背景等组成部分,人物角色包括人体、服装、装备等组成部分,可以使用建造者模式对其进行设计,通过不同的具体建造者创建不同类型的地图或人物。 29 | 30 | *原文:http://www.i3geek.com/archives/1332* 31 | *实现源代码:https://github.com/yangengzhe/coding-guide_i3geek/tree/master/docs/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F* -------------------------------------------------------------------------------- /docs/设计模式/桥接模式.md: -------------------------------------------------------------------------------- 1 | #桥接模式 2 | 3 | ## 动机 4 | 5 | 有圆形、矩形2个形状,还有红色、绿色2个颜色。如果想实现不同形状和不同颜色的组合,我们有两种方案:第一种,为每一种形状的每一种颜色设计一个类,问题冗余,类过多;第二种,根据实际的需要,对形状和颜色进行组合。 6 | 7 | 第二种方案就是最佳方案,在多维度影响因素下,将他们分离,也就是桥接模式的动机。将继承关系转化为关联关系,从而降低了类与类之间的耦合,减少了代码的编写量。 8 | 9 | ## 定义 10 | 11 | 将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。 12 | 13 | ## 功能 14 | 15 | 将抽象部分与实现部分分离,使它们都可以独立的变化。具体使用时,通过**组装的方式**形成需要的产品 16 | 17 | 特点,可以实现多维影响因素的解耦,通过一层一层往外套 18 | 19 | ## 实现 20 | ../_images/Bridge.jpg 21 | - Abstraction:抽象类 :第二维影响因素的接口 22 | - RefinedAbstraction:扩充抽象类 :第二维影响因素的具体实现 23 | - Implementor:实现类接口 : 第一维影响因素的接口 24 | - ConcreteImplementor:具体实现类 :第一维影响因素的具体实现 25 | 26 | 可以一层层继续往外包装接口和实现类(通过组合来调用上一层接口),从而实现多层的影响因素(详细看代码 实现三维影响因素) 27 | 28 | ## 应用 29 | 30 | Java为AWT中的每一个GUI构件都提供了一个Peer构件,使得Java软件运行在不同操作系统中有不同的视感。在AWT中的Peer架构就使用了桥接模式。 31 | 32 | *原文:http://www.i3geek.com/archives/1373* 33 | *实现源代码:https://github.com/yangengzhe/coding-guide_i3geek/tree/master/docs/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F* -------------------------------------------------------------------------------- /docs/设计模式/模板方法模式.md: -------------------------------------------------------------------------------- 1 | # 模板方法模式 2 | 3 | ## 定义 4 | 5 | 一个操作中的算法的骨架,而将步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤。 6 | 7 | ## 作用 8 | 9 | 抽象类A(算法骨架) 《==实现=== 具体类B(实现抽象方法) 10 | 11 | 比如:银行中办理业务,不管什么业务流程都是相同的:领号排队、填写单据、等待叫好、办理业务。但是某一步 比如填写单据,根据办理不同的业务需要写不同的单据,不同人写的单据也不同。 12 | 13 | ## 实现 14 | 15 | ### Abstract 16 | 17 | 抽象基类,说明所有子类共同遵守的算法框架(步骤) 18 | 19 | 需要子类考虑的方法用抽象类;不需要的方法用private或final实现 20 | 21 | ### Concrete 22 | 23 | 具体实现类,用于实现抽象类的方法,个性的实现不同的功能 24 | 25 | ## 应用 26 | 27 | 用冒泡算法非别对整型数组、浮点数数组、日期数组实现排序。 -------------------------------------------------------------------------------- /docs/设计模式/策略模式.md: -------------------------------------------------------------------------------- 1 | # 策略模式 2 | 3 | ## 定义 4 | 5 | 将可变的部分从程序中抽象分离成算法接口,在该接口下分别封装一系列算法实现,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化。 6 | 7 | ## 功能 8 | 9 | 分离、抽象出不变的部分形成接口,将算法的实现分别封装,这样会使客户端不受算法改变而受到影响。 10 | 11 | 如:结算购物车时,付款提供商(接口)==实现==》招商银行、建设银行……等很多的付款方式。 12 | 13 | ## 实现 14 | 15 | 1、通过分离变化得出策略接口 16 | 17 | 2、为接口提供实现类 18 | 19 | 3、针对接口编程,在客户程序中 持有接口变量,并赋予相应的实现类对象 20 | 21 | ## 应用 -------------------------------------------------------------------------------- /docs/设计模式/简单工厂模式、工厂方法模式、抽象工厂模式.md: -------------------------------------------------------------------------------- 1 | ## 简单工厂模式 2 | 3 | 一个工厂实现类,一个产品抽象类,N个产品实现类。 4 | 5 | 像工厂一样,可以生产出来多个产品。比如一个按钮工厂,可以生产出来圆形按钮、矩形按钮、三角形按钮等等,但是所有的按钮都继承自原始的按钮抽象基类。 6 | 7 | 特点是:传入一个值不同的参数可以生产出不同的按钮。各自的形状属性可能不同,但是都有相同的方法。 8 | 9 | 优点:不用考虑如何生产的过程。只要传入不同参数就可以得到不同产品。 10 | 11 | 例如:工厂类 buttonFactory ;产品抽象类 Button ;多个产品实现类 AButton,BButton,CButton; 12 | 13 | buttonFactory bfactory = new buttonFactory(); 14 | Button abutton = bfactory.getButton("A");//通过传入参数A 获得AButton 15 | Button bbutton = bfactory.getButton("B");//通过传入参数B 获得BButton 16 | Button cbutton = bfactory.getButton("C");//通过传入参数C 获得CButton 17 | 18 | 问题(缺点):如果要加入新的产品,必须要修改工厂实现类,违背“开闭原则”。 19 | 20 | ## 工厂方法模式 21 | 22 | 一个工厂抽象类,N个工厂实现类,一个产品抽象类,N个产品实现类。 23 | 24 | 在简单工厂模式的基础上,为工厂创建抽象类,生产不同的按钮由不同的工厂实现类完成。 25 | 26 | 特点是:不同工厂生产不同产品。(或者传入一个值不同的参数可以实例化出不同的工厂,从而产出不同的产品) 27 | 28 | 优点:增加新产品时,无需修改抽象工厂或其他具体的工厂,只需要添加一个具体工厂和具体产品就可以了。 29 | 30 | 例如:工厂抽象类 Factory ; 多个工厂实现类 AbuttonFactory,BbuttonFactory,CbuttonFactory ;产品抽象类 Button ;多个产品实现类 AButton,BButton,CButton; 31 | 32 | buttonFactory bfactory = new AbuttonFactory();//获得AbuttonFactory工厂实现类 33 | Button abutton = bfactory.getButton();//通过传入参数A 获得AButton 34 | bfactory = new BbuttonFactory();//获得BbuttonFactory工厂实现类 35 | Button bbutton = bfactory.getButton();//通过传入参数B 获得BButton 36 | bfactory = new CbuttonFactory();//获得CbuttonFactory工厂实现类 37 | Button cbutton = bfactory.getButton();//通过传入参数C 获得CButton 38 | 39 | <更进一步> 工厂抽象类 Factory ; 工厂工具类 BaseFactory ;多个工厂实现类 AbuttonFactory,BbuttonFactory,CbuttonFactory ;产品抽象类 Button ;多个产品实现类 AButton,BButton,CButton; 40 | 41 | BaseFactory factory = new BaseFactory();//实例化工厂工具类 42 | buttonFactory bfactory = factory.getFactory("A");//获得AbuttonFactory工厂实现类 43 | Button abutton = bfactory.getButton();//通过传入参数A 获得AButton 44 | bfactory = factory.getFactory("B");//获得BbuttonFactory工厂实现类 45 | Button bbutton = bfactory.getButton();//通过传入参数B 获得BButton 46 | bfactory = factory.getFactory("C");//获得CbuttonFactory工厂实现类 47 | Button cbutton = bfactory.getButton();//通过传入参数C 获得CButton 48 | 49 | 应用:JDBC中的工厂方法: 50 | 51 | Connection conn=DriverManager.getConnection("jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=DB;user=sa;password="); 52 | Statement statement=conn.createStatement(); 53 | ResultSet rs=statement.executeQuery("select * from UserInfo"); 54 | 55 | 问题(缺点):一个工厂只能生产一类产品对象,如果生产多类产品呢? 56 | 57 | ## 抽象工厂模式 58 | 59 | 一个工厂抽象类,N个工厂实现类,N个产品抽象类,N个产品实现类。 60 | 61 | 在工厂方法模式的基础上,每一个工厂不仅可以生产各自特有的按钮,还可以生产各自特有的输入框。比如,生产圆形按钮的工厂可以生产圆形按钮和圆形输入框;生产方形按钮的工厂可以生产方形按钮和方形输入框…… 62 | 63 | 特点是:同一工厂可以生产多种不同类商品。 64 | 65 | 优点:只需更换工厂的实例,就可以改变全部生产产品(比如将生产圆形的工厂改成生产方形的工厂,则由原工厂生产的按钮、输入框全都变成了方形);保证所有不同类的商品都源自一个工厂;增加新的具体工厂和对应的各类商品实例很方便,无须修改原有系统(比如增加个三角形工厂,再增加三角形按钮和三角形输入框的实现类即可) 66 | 67 | 例如:工厂抽象类 Factory ; 多个工厂实现类 AFactory,BFactory ;多个产品抽象类(一个产品抽象类可以想象成一类商品) Button,Text ;多个产品实现类 AButton,BButton,AText,BText; 68 | 69 | Factory factory = new AFactory(); // 实例化AFactory对象 70 | Button button = factory.getButton(); //获得AButton对象 71 | Text text = factory.getText(); //获得AText对象 72 | 73 | factory = new BFactory(); // 实例化BFactory对象 74 | Button button = factory.getButton(); //获得BButton对象 75 | Text text = factory.getText(); // 获得BText对象 76 | 77 | 应用:软件系统中的界面主题,当主题变更时,所有的按钮、文本框、背景色等一起发生变化。 78 | -------------------------------------------------------------------------------- /docs/设计模式/装饰模式.md: -------------------------------------------------------------------------------- 1 | ## 动机 2 | 3 | 对客户透明的方式动态地给一个对象附加上更多的责任(行为),换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。这就是装饰模式的模式动机。 4 | 5 | # 装饰模式 6 | 7 | ## 定义 8 | 9 | 动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。 10 | 11 | ## 功能 12 | 13 | 装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。 14 | 15 | 特点:装饰者必须实现被装饰者接口,从而对用户透明,完全替代被装饰类。 16 | 17 | ## 实现 18 | 19 | ../_images/Decorator.jpg 20 | - Component: 抽象构件 21 | - ConcreteComponent: 具体构件(被装饰者) 22 | - Decorator: 抽象装饰类 23 | - ConcreteDecorator: 具体装饰类(用来包装的装饰者) 24 | 25 | 注意: 26 | 1. 装饰者和被装饰者有相同的接口 27 | 2. 可以用一个或多个装饰者包装一个对象 28 | 3. 对象可以在任何时候被装饰,可以动态的、不限量的装饰 29 | 30 | ## 应用 31 | 32 | 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。可以动态的增加或撤销功能。 33 | 34 | *原文:http://www.i3geek.com* 35 | *实现源代码:https://github.com/yangengzhe/coding-guide_i3geek/tree/master/docs/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F* -------------------------------------------------------------------------------- /docs/设计模式/责任链模式.md: -------------------------------------------------------------------------------- 1 | # 责任链模式 2 | 3 | ## 定义 4 | 5 | 将接收者对象连接成一条链,并在该链上传递请求,直到有一个接收者对象处理它。通过让更多对象有机会处理请求,避免了请求发送者和接收者之间的耦合。 6 | 7 | ## 作用 8 | 9 | 请求 ===> 第一个处理者 ===> 第二个处理者 ... ===> 第n个处理者 10 | 11 | 比如:公司的层次结构,CEO、经理、运营员 的权限不同,遇到问题需要从下至上一层层传递。 12 | 13 | ## 缺点 14 | 15 | 性能问题 -------------------------------------------------------------------------------- /docs/设计模式/适配器模式.md: -------------------------------------------------------------------------------- 1 | # 适配器模式 2 | 3 | ## 定义 4 | 5 | 适配器模式将一个类的接口转换成期望的另一个接口,使得原本不能一起工作的类可以在一起工作。 6 | 7 | ## 作用 8 | 9 | 接口A(实际接口) ===适配器(转换的过程)====》 接口B(不同的,期望的接口) 10 | 11 | 比如: 三相插头 ===适配器(插口转换器)====》 两相插口 12 | 13 | 将一个类的接口,**通过适配器**转换成另外一个期望的接口。(使原本不兼容的接口 而能够相互兼容一起工作) 14 | 15 | ## 类图理解 16 | 17 | 期望接口 ---> 接口 18 | 19 | 适配器类 ---> 实现期望接口,通过内部对被适配类实例的操作,成为期望接口的实例 20 | 21 | 被适配类 ---> 一个已经实现的类 22 | 23 | ## 分类 24 | 25 | 对象适配器(组合方式):实现期望接口,内部含有被适配类对象,实现方法中调用被适配类的原始方法 26 | 27 | 类适配器(继承方式):实现期望接口,继承被适配类,实现方法中调用父类的原始方法 28 | 29 | ## 功能 30 | 31 | ### 透明 32 | 33 | 可以调用统一的对外接口,不用考虑内部的实现关系 34 | 35 | ### 重用 36 | 37 | 重用已经存在类,解决类不一致导致不能使用的问题 38 | 39 | ### 低耦合 40 | 41 | 将目标类和适配者类解耦(遵循开闭原则——修改关闭 扩展开放) 42 | 43 | ## 总结 44 | 45 | 只要把不兼容 变成兼容的就是适配器! 46 | 47 | ### 适用环境 48 | 49 | 需要使用现有类,但是现有类并不符合目前的接口需要;建立一个可复用的类,用于一些没有太大关联的类。 50 | 51 | ### 应用 52 | 53 | JDBC数据库驱动,JDBC驱动做为数据库引擎(Mysql、Oracle、SQL Server等)与JDBC标准接口的一个桥梁(适配器软件)。 54 | 55 | 可以让开发人员在开发中,对数据库的操作透明,通过适配器(JDBC驱动),实例化出目标接口(JDBC标准统一接口),对接口编程,更换不同的被适配类(各种数据库引擎) -------------------------------------------------------------------------------- /docs/项目/websocket介绍,与socket的区别.md: -------------------------------------------------------------------------------- 1 | # WebSocket介绍,与Socket的区别 2 | 3 | ## WebSocket介绍与原理 4 | 5 | > WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成。 6 | > ——百度百科 7 | 8 | ### 目的:即时通讯,替代轮询 9 | 10 | 网站上的即时通讯是很常见的,比如网页的QQ,聊天系统等。按照以往的技术能力通常是采用**轮询**技术解决。 11 | 12 | HTTP协议是非持久化的,单向的网络协议,在建立连接后只允许浏览器向服务器发出请求后,服务器才能返回相应的数据。当需要即时通讯时,通过轮询在特定的时间间隔(如1秒),由浏览器向服务器发送Request请求,然后将最新的数据返回给浏览器。这样的方法最明显的缺点就是需要不断的发送请求,而且通常HTTP request的Header是非常长的,为了传输一个很小的数据 需要付出巨大的代价,是很不合算的,占用了很多的宽带。 13 | 14 | 然而WebSocket的出现可以弥补这一缺点。在WebSocket中,只需要服务器和浏览器通过HTTP协议进行一个握手的动作,然后单独建立一条TCP的通信通道进行数据的传送。 15 | 16 | ### 原理 17 | 18 | WebSocket同HTTP一样也是应用层的协议,但是它是一种**双向通信协议**,是建立在TCP之上的。 19 | 20 | ![image](http://pic.7tool.cn/uploads/2016/07/080903326.png) 21 | 22 | #### 连接过程 —— 握手过程 23 | 24 | 1. 浏览器、服务器建立TCP连接,三次握手。这是通信的基础,传输控制层,若失败后续都不执行。 25 | 2. TCP连接成功后,浏览器通过HTTP协议向服务器传送WebSocket支持的版本号等信息。(**开始前的HTTP握手**) 26 | 3. 服务器收到客户端的握手请求后,**同样采用HTTP协议**回馈数据。 27 | 4. 当收到了连接成功的消息后,通过TCP通道进行传输通信。 28 | 29 | ## WebSocket与HTTP的关系 30 | 31 | ### 相同点 32 | 33 | 1. 都是一样基于TCP的,都是可靠性传输协议。 34 | 2. 都是应用层协议。 35 | 36 | ### 不同点 37 | 38 | 1. WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息。HTTP是单向的。 39 | 2. WebSocket是需要握手进行建立连接的。 40 | 41 | ### 联系 42 | 43 | WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的。 44 | 45 | ## WebSocket与Socket的关系 46 | 47 | Socket其实并不是一个协议,而是为了方便使用TCP或UDP而抽象出来的一层,是位于应用层和传输控制层之间的一组接口。 48 | 49 | > Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。 50 | 51 | 当两台主机通信时,必须通过Socket连接,Socket则利用TCP/IP协议建立TCP连接。TCP连接则更依靠于底层的IP协议,IP协议的连接则依赖于链路层等更低层次。 52 | 53 | WebSocket则是一个典型的应用层协议。 54 | 55 | ![image](http://pic.7tool.cn/uploads/2016/07/socket.gif) 56 | 57 | ### 区别 58 | 59 | **Socket是传输控制层协议,WebSocket是应用层协议。** 60 | 61 | ## HTML5与WebSocket的关系 62 | 63 | WebSocket API 是 HTML5 标准的一部分, 但这并不代表 WebSocket 一定要用在 HTML 中,或者只能在基于浏览器的应用程序中使用。 64 | 65 | 实际上,许多语言、框架和服务器都提供了 WebSocket 支持,例如: 66 | 67 | * 基于 C 的 libwebsocket.org 68 | * 基于 Node.js 的 Socket.io 69 | * 基于 Python 的 ws4py 70 | * 基于 C++ 的 WebSocket++ 71 | * Apache 对 WebSocket 的支持: Apache Module mod_proxy_wstunnel 72 | * Nginx 对 WebSockets 的支持: NGINX as a WebSockets Proxy 、 NGINX Announces Support for WebSocket Protocol 、WebSocket proxying 73 | * lighttpd 对 WebSocket 的支持:mod_websocket -------------------------------------------------------------------------------- /nowcoder/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /nowcoder/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | nowcoder 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /nowcoder/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.7 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.source=1.7 12 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/leetcode/common/ListNode.java: -------------------------------------------------------------------------------- 1 | package nowcoder.leetcode.common; 2 | 3 | 4 | public class ListNode { 5 | public int val; 6 | public ListNode next; 7 | public ListNode(int x) { 8 | val = x; 9 | next = null; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/leetcode/reorder_list.java: -------------------------------------------------------------------------------- 1 | package nowcoder.leetcode; 2 | 3 | import java.util.Stack; 4 | 5 | import nowcoder.leetcode.common.ListNode; 6 | 7 | public class reorder_list { 8 | public void reorderList2(ListNode head) { 9 | if(head == null) return; 10 | Stack stack = new Stack(); 11 | ListNode temp = head; 12 | while(temp!=null){ 13 | stack.push(temp); 14 | temp = temp.next; 15 | } 16 | while(head!=stack.peek()){ 17 | ListNode last = stack.pop(); 18 | last.next = head.next; 19 | head.next = last; 20 | head = head.next.next; 21 | if(last.next == last){ 22 | last.next = null; 23 | return; 24 | } 25 | } 26 | head.next = null; 27 | } 28 | public void reorderList(ListNode head) { 29 | if(head == null) return; 30 | ListNode slow= head,fast = head; 31 | //寻找中点 32 | while(fast.next!=null && fast.next.next!=null){ 33 | slow = slow.next; 34 | fast = fast.next.next; 35 | } 36 | //原地翻转后半部分链表 37 | ListNode temp = slow,last = null; 38 | slow = slow.next; 39 | while(slow!=null){ 40 | ListNode next = slow.next; 41 | slow.next = last; 42 | last = slow; 43 | if(next == null) 44 | temp.next = slow; 45 | slow = next; 46 | } 47 | //链表合并 48 | slow = temp.next; 49 | temp.next = null; 50 | while(slow!=null){ 51 | ListNode next = slow.next; 52 | slow.next = head.next; 53 | head.next = slow; 54 | head = head.next.next; 55 | slow = next; 56 | } 57 | } 58 | 59 | 60 | 61 | public static void main(String args[]){ 62 | ListNode head = new ListNode(1); 63 | ListNode iterator = head; 64 | iterator.next = new ListNode(2); 65 | iterator = iterator.next; 66 | iterator.next = new ListNode(3); 67 | iterator = iterator.next; 68 | iterator.next = new ListNode(4); 69 | iterator = iterator.next; 70 | iterator.next = new ListNode(5); 71 | 72 | reorder_list test = new reorder_list(); 73 | test.reorderList(head); 74 | while(head!=null){ 75 | System.out.println(head.val); 76 | head = head.next; 77 | } 78 | 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/y2016/m4/Printer.java: -------------------------------------------------------------------------------- 1 | package nowcoder.y2016.m4; 2 | 3 | 4 | public class Printer { 5 | public static void main(String args[]) { 6 | int[][] mat = {{1,2,3},{4,5,6},{7,8,9},{10,11,12}}; 7 | System.out.println(printMatrix(mat,4,3)[0]);//[1,2,3,6,5,4,7,8,9,12,11,10] 8 | } 9 | public static int[] printMatrix(int[][] mat, int n, int m) { 10 | int[] result = new int[n*m]; 11 | for(int i=0;i (n-1) ? (i+p-n):i+p; 23 | b[i] = a[m]; 24 | } 25 | return new String(b); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/y2016/m4/clockwisePrint.java: -------------------------------------------------------------------------------- 1 | package nowcoder.y2016.m4; 2 | 3 | /** 4 | * 思路:矩阵 左上角和右下角两个点为标准点,不断向内缩小范围, 5 | * 顺时针打印矩阵 6 | * 对于一个矩阵,请设计一个算法从左上角(mat[0][0])开始,顺时针打印矩阵元素。 7 | 给定int矩阵mat,以及它的维数nxm,请返回一个数组,数组中的元素为矩阵元素的顺时针输出。 8 | * @date 2016年4月22日 下午4:44:40 9 | * @author yangengzhe 10 | * 11 | */ 12 | public class clockwisePrint { 13 | public static void main(String args[]){ 14 | clockwisePrint c = new clockwisePrint(); 15 | int[][] a = {{57,50,59,18,31,13},{67,86,93,86,4,9},{38,98,83,56,82,90},{66,50,67,11,7,69},{20,58,55,24,66,10},{43,26,65,0,64,28},{62,86,38,19,37,98}}; 16 | // int[][]a = {{1},{2},{3},{4},{5},{6},{7}}; 17 | int n=3; 18 | int m=2; 19 | int[] result = c.clockwisePrint(a, n,m); 20 | for(int i = 0;ij1;o--)//左移 46 | result[count++] = mat[i2][o]; 47 | for(int o=i2;o>i1;o--)//上移 48 | result[count++] = mat[o][j1]; 49 | i1++; 50 | j1++; 51 | i2--; 52 | j2--; 53 | } 54 | return result; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/一站通offer/test.java: -------------------------------------------------------------------------------- 1 | package nowcoder.一站通offer; 2 | 3 | import java.util.Collection; 4 | import java.util.LinkedHashMap; 5 | import java.util.Map; 6 | import java.util.Map.Entry; 7 | 8 | public class test { 9 | public static void main(String args[]){ 10 | String src= "now coder"; 11 | int n = 9; 12 | byte[] str = src.getBytes(); 13 | 14 | fun(str, 0, n-1, true); 15 | int m=0; 16 | for(int i=0;i='a') 49 | return (byte)(c+num); 50 | else if(c<='Z' && c>='A') 51 | return (byte)(c-num); 52 | else 53 | return c; 54 | } 55 | } -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/一站通offer/test2.java: -------------------------------------------------------------------------------- 1 | package nowcoder.一站通offer; 2 | 3 | 4 | public class test2 { 5 | public static void main(String args[]){ 6 | 7 | int[][] land = {{1,1,1,1},{0,0,0,0},{1,0,1,1}}; 8 | int n = 4; 9 | int m = 3; 10 | 11 | 12 | int[] land_num = new int[n]; 13 | for(int i=0;i (right+1)?length:(right+1); 30 | } 31 | else{ 32 | max= max>left?max:left; 33 | max = max>right?max:right; 34 | max = max>length?max:length; 35 | length = length>1?length:1; 36 | } 37 | if(root.right!=null &&root.left!=null &&root.right.val == root.left.val && root.val == root.left.val){ 38 | max = max>(left+right+1)?max:(left+right+1); 39 | } 40 | return length; 41 | } 42 | 43 | public int findPath(TreeNode root) { 44 | int num = search(root); 45 | max = max>num?max:num; 46 | return max; 47 | } 48 | } 49 | 50 | 51 | 52 | 53 | //public class LongestPath { 54 | // int max = 0; 55 | // public int findPath(TreeNode root) { 56 | // // write code here 57 | // if (root == null) return 0; 58 | // helper(root); 59 | // return max; 60 | // } 61 | // 62 | // int helper(TreeNode root){ 63 | // int left = 0, right = 0; 64 | // if (root.left != null){ 65 | // int tmp = helper(root.left); 66 | // if (root.val == root.left.val) 67 | // left = tmp; 68 | // } 69 | // if (root.right != null){ 70 | // int tmp = helper(root.right); 71 | // if (root.val == root.right.val) 72 | // right = tmp; 73 | // } 74 | // max = Math.max(left + right + 1, max); 75 | // return Math.max(left, right) + 1; 76 | // } 77 | //} -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code10.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 跳台阶 ★★★ 6 | * 7 | * 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 8 | * 9 | * 思路:动态规划。1级台阶 1种;2级台阶 2种;3级台阶 方案一,跳一级,后面有2级台阶的种数 方案二,跳两级,后面有1级台阶的种数;n级台阶 方案一+方案二 :f(n-2)+f(n-1) 10 | * (对于第n个台阶来说,只能从n-1或者n-2的台阶跳上来,所以F(n) = F(n-1) + F(n-2) ) 11 | * 其实就是斐波那契数列 12 | * 13 | * @date 2016年4月27日 下午6:44:23 14 | * @author yangengzhe 15 | * 16 | */ 17 | public class code10 { 18 | //叠加遍历 19 | public int JumpFloor(int target) { 20 | if(target<3) return target; 21 | int a=1,b=2,c=3; 22 | while(target>2){ 23 | c = a+b; 24 | a=b; 25 | b=c; 26 | target--; 27 | } 28 | return c; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code11.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | import java.util.Vector; 4 | 5 | /** 6 | * 变态跳台阶 ★★★★★ 7 | * 8 | * 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 9 | * 10 | * 思路:方法一:动态规划 同上,N级台阶需要: f(n) = f(n-1)+f(n-2)+..+f(n- (n-1) )+f(n-n) 同时注意存储已经算好的数字 ;f(1) =1; f(2) = 2;f(3) = f(0)+f(1)+f(2) f(0)表示一次跳的方法 11 | * 方法二:根据推倒可得 f(n) = 2 ^ (n-1) 即:f(n) = 2*f(n-1) 12 | * 13 | * @date 2016年4月27日 下午6:54:21 14 | * @author yangengzhe 15 | * 16 | */ 17 | public class code11 { 18 | Vector vectors = new Vector(); 19 | //公式 20 | public int JumpFloorII(int target) { 21 | int result = 1; 22 | while(target-->1) 23 | result = result*2; 24 | return result; 25 | } 26 | //递归 27 | public int JumpFloorII2(int target) { 28 | int sum = 0; 29 | if(vectors.size()==0) vectors.add(0,1); 30 | if(vectors.size()>target) return vectors.get(target); 31 | for(int i=0;i vector = new Vector(); 18 | public int fun(int a){ 19 | if(vector.size()>a) return vector.get(a); 20 | int result = fun(a-1)+fun(a-2); 21 | vector.add(a,result); 22 | return result; 23 | } 24 | public int RectCover2(int target) { 25 | vector.add(0,1); 26 | vector.add(1,1); 27 | vector.add(2,2); 28 | return fun(target); 29 | } 30 | 31 | //非递归方法 32 | public int RectCover(int target) { 33 | if(target<2) return 1; 34 | int a=1,b=1,c=2; 35 | while(target>=2){ 36 | c=a+b; 37 | a=b; 38 | b=c; 39 | target--; 40 | } 41 | return c; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code13.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 二进制中1的个数 ★★★ 6 | * 7 | * 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 8 | * 9 | * 思路:常规思路 与运算取最后一位后右移。但是负数会死循环。左移按位与的数字,使原数不变。 10 | * 优化思路 一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0 11 | * 12 | * @date 2016年5月1日 下午2:40:48 13 | * @author yangengzhe 14 | * 15 | */ 16 | public class code13 { 17 | //常规算法,容易死循环(负数时候 因为负数右移 补位1) 18 | public int NumberOf12(int n) { 19 | int a=0; 20 | 21 | while(n!=0){ 22 | if((n&1) == 1) a++; 23 | n=n>>1; 24 | } 25 | return a; 26 | } 27 | 28 | //正数范围内可用 因为右移相当于除2,但是不能替换 这个效率低 29 | public int NumberOf13(int n) { 30 | int a=0; 31 | while(n!=0){ 32 | if(n%2==1) a++; 33 | n=n/2; 34 | } 35 | return a; 36 | } 37 | 38 | //常规,移动“与”的数字 32位int形。注意 待位移比较的数字应为无符号整型,java中由于不支持无符号 所以用long 39 | public int NumberOf1_1(int n) { 40 | long a=1; 41 | int count=0; 42 | for(int i=0;i<32;i++){ 43 | if((n&a) == a) count++; 44 | a=a<<1; 45 | } 46 | return count; 47 | } 48 | //一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0 49 | public int NumberOf1_2(int n) { 50 | int count=0; 51 | while(n!=0){ 52 | n=(n&(n-1)); 53 | count++; 54 | } 55 | return count; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code14.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | /** 4 | * 数值的整数次方 ★★ 5 | * 6 | * 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 7 | * 8 | * 思路:比较简单,主要是考虑边界问题。如果exponent小于0呢?如果exponent和base都是0呢? 9 | * 方法二:n^32次方 可以认为是n^16次方的平方,因此利用递归 避免多次的循环 10 | * 11 | * @date 2016年5月3日 下午3:48:57 12 | * @author yangengzhe 13 | * 14 | */ 15 | public class code14 { 16 | //递归方法 17 | public double Power(double base, int exponent) { 18 | if(exponent==0) return 1; 19 | if(base == 0) return 0; 20 | if(exponent==1) return base; 21 | if(exponent == -1) return 1/base; 22 | double result = Power(base, exponent>>1); 23 | result = result*result; 24 | if((exponent&1)==1) 25 | result = result*base; 26 | return result; 27 | } 28 | //普通方法 29 | public double Power2(double base, int exponent) { 30 | if(base == 0 && exponent==0) return 1; 31 | boolean sign = exponent>0?true:false; 32 | exponent = Math.abs(exponent); 33 | double result = 1; 34 | while(exponent>0){ 35 | exponent--; 36 | result = result*base; 37 | } 38 | if(sign) 39 | return result; 40 | else 41 | return 1.0/result; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code15.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 调整数组顺序使奇数位于偶数前面 ★★ 6 | * 7 | * 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。 8 | * 9 | * 思路:重点在顺序不发生变化。两个指针,从头开始,第一个指针找偶数,第二个指针在后面找奇数,找到后移动位置(不能交换),直到结束。 10 | * 方法二:类似冒泡排序思想,遇到前偶后奇就交换 11 | * 方法三:常规方法,创建一个数组,遍历两遍 12 | * @date 2016年5月3日 下午4:23:48 13 | * @author yangengzhe 14 | * 15 | */ 16 | public class code15 { 17 | //1234567 1324567 1352467 18 | public void reOrderArray(int [] array) { 19 | int i=0,j=0; 20 | while(ji;m--) 29 | array[m] = array[m-1]; 30 | array[i] = temp; 31 | } 32 | } 33 | } 34 | //类似冒泡 35 | void reOrderArray2(int [] array) { 36 | for (int i = 0; i < array.length;i++) 37 | { 38 | for (int j = array.length - 1; j>i;j--) 39 | { 40 | if (array[j] % 2 == 1 && array[j - 1]%2 == 0) //前偶后奇交换 41 | { 42 | int temp = array[j]; 43 | array[j] = array[j-1]; 44 | array[j-1] = temp; 45 | } 46 | } 47 | } 48 | } 49 | 50 | public static void main(String args[]){ 51 | code15 c = new code15(); 52 | int[] a = new int[]{1,2,3,4,5,6,7}; 53 | c.reOrderArray(a); 54 | for(int i=0;i printMatrix(int [][] matrix) { 13 | ArrayList result = new ArrayList(); 14 | int x1=0,y1=0,x2=matrix[0].length-1,y2=matrix.length-1; 15 | while (x1x1;i--) 21 | result.add(matrix[y2][i]); 22 | for(int i=y2;i>y1;i--) 23 | result.add(matrix[i][x1]); 24 | x1++; 25 | y1++; 26 | x2--; 27 | y2--; 28 | } 29 | 30 | while(x1==x2 && y1 re =c.printMatrix(n); 48 | for (Integer integer : re) { 49 | System.out.println(integer); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code22.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * 包含min函数的栈 ★★★★ 7 | * 8 | * 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。 9 | * 10 | * 思路:定义两个栈,一个栈是普通使用,一个是最小栈,记录当时的最小元素 11 | * 12 | * @date 2016年5月9日 下午8:41:43 13 | * @author yangengzhe 14 | * 15 | */ 16 | public class code22 { 17 | 18 | Stack stack = new Stack(); 19 | Stack min = new Stack(); 20 | 21 | public void push(int node) { 22 | stack.push(node); 23 | if(min.empty()) 24 | min.push(node); 25 | else 26 | min.push(min.peek()>node?node:min.peek()); 27 | } 28 | 29 | public void pop() { 30 | stack.pop(); 31 | min.pop(); 32 | } 33 | 34 | public int top() { 35 | return stack.peek(); 36 | } 37 | 38 | public int min() { 39 | return min.peek(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code23.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | import java.util.ArrayList; 4 | 5 | import javax.swing.text.StyledEditorKit.ForegroundAction; 6 | 7 | /** 8 | * 从上往下打印二叉树 ★ 9 | * 10 | * 从上往下打印出二叉树的每个节点,同层节点从左至右打印。 11 | * 12 | * 思路:广度优先用队列。深度优先(前序遍历)用栈。 本题是广度优先遍历 13 | * @date 2016年5月11日 下午8:18:35 14 | * @author yangengzhe 15 | * 16 | */ 17 | public class code23 { 18 | //栈 19 | public ArrayList PrintFromTopToBottom2(TreeNode root) { 20 | ArrayList result = new ArrayList(); 21 | ArrayList list = new ArrayList(); 22 | if(root == null) return result; 23 | list.add(root); 24 | while(!list.isEmpty()){ 25 | TreeNode temp =list.remove(0); 26 | result.add(temp.val); 27 | if(temp.left!=null) 28 | list.add(temp.left); 29 | if(temp.right!=null) 30 | list.add(temp.right); 31 | } 32 | return result; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code24.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 二叉搜索树的后序遍历序列 ★★★ 6 | * 7 | * 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。 8 | * 9 | * 思路:后续遍历 最后一个是顶点。二叉查找树 顶点左侧小于顶点,右侧大于顶点。 10 | * 第一步:先找到根节点。最右侧的数 11 | * 第二步:确定左右子树,遍历 第一个大于根节点之前的 都是左子树,剩余都是右子树 12 | * 第三部:验证右子树, 13 | * 第四部:循环遍历 左右子树 14 | * 15 | * @date 2016年5月12日 下午1:25:17 16 | * @author yangengzhe 17 | * 18 | */ 19 | public class code24 { 20 | public boolean fun(int[] sequence,int start,int end){ 21 | if(start >= end) return true; 22 | int head = sequence[end]; 23 | int mid=start; 24 | while(sequence[mid] stack = new Stack(); 24 | int a=0; 25 | for(int i=0;i stack = new Stack(); 47 | int j = 0; 48 | for (int i = 0; i < popA.length; i++) { 49 | stack.push(pushA[i]); 50 | while (j < popA.length && stack.peek() == popA[j]) { 51 | stack.pop(); 52 | j++; 53 | } 54 | } 55 | return stack.empty(); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code26.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.Stack; 6 | 7 | /** 8 | * 二叉树中和为某一值的路径 ★★★★★ 9 | * 10 | * 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。 11 | * 12 | * 思路:类似深度优先,但是不能用栈,因为无法记录结点。 13 | * 利用递归前序循环遍历,其中用栈存储路过的结点即可 14 | * 15 | * @date 2016年5月14日 下午8:18:59 16 | * @author yangengzhe 17 | * 18 | */ 19 | public class code26 { 20 | public void fun(TreeNode node,Stack stack,int sum,int target ,ArrayList> result){ 21 | if(node == null) return; 22 | sum = sum+node.val; 23 | stack.push(node.val); 24 | if(node.left == null && node.right == null){ 25 | if(sum == target){ 26 | //输出队列 27 | Iterator it = stack.iterator(); 28 | ArrayList list = new ArrayList(); 29 | while(it.hasNext()){ 30 | list.add(it.next()); 31 | } 32 | result.add(list); 33 | } 34 | } 35 | else{ 36 | fun(node.left, stack, sum, target,result); 37 | fun(node.right, stack, sum, target,result); 38 | } 39 | stack.pop(); 40 | return; 41 | } 42 | public ArrayList> FindPath(TreeNode root,int target) { 43 | Stack stack = new Stack(); 44 | ArrayList> result = new ArrayList>(); 45 | fun(root, stack, 0, target, result); 46 | return result; 47 | } 48 | 49 | public static void main(String args[]){ 50 | code26 c = new code26(); 51 | TreeNode root = new TreeNode(10); 52 | TreeNode node = new TreeNode(5); 53 | node.left = new TreeNode(4); 54 | node.right = new TreeNode(7); 55 | root.left = node; 56 | root.right = new TreeNode(12); 57 | c.FindPath(root, 22); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code27.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | import java.util.HashMap; 4 | 5 | import nowcoder.剑指offer.util.RandomListNode; 6 | 7 | /** 8 | * 复杂链表的复制 ★★★★ 9 | * 10 | * 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点)。 11 | * 12 | * 思路:1.粗暴的方法,遍历多次,先复制链表,在遍历复制每一个的随机指针 时间复杂度O(n2) 13 | * 2. 空间换时间,利用HashMap 做一个节点的映射关系 占用O(n)空间,时间复杂度O(n) 14 | * 3. 复制成一个链表,如: a->b 复制成 a->a'->b->b'。之后拆分成两个链表,时间复杂度O(n) 15 | * 16 | * @date 2016年5月16日 下午6:15:22 17 | * @author yangengzhe 18 | * 19 | */ 20 | public class code27 { 21 | 22 | //方法三 23 | public void copy(RandomListNode pHead){ 24 | while(pHead!=null){ 25 | RandomListNode temp = new RandomListNode(pHead.label); 26 | temp.next = pHead.next; 27 | pHead.next = temp; 28 | pHead = temp.next; 29 | } 30 | } 31 | public void copyRandom(RandomListNode pHead){ 32 | while(pHead!=null){ 33 | RandomListNode node = pHead.next; 34 | if(pHead.random!=null) 35 | node.random = pHead.random.next; 36 | else 37 | node.random = null; 38 | pHead = node.next; 39 | } 40 | } 41 | public RandomListNode divide(RandomListNode pHead){ 42 | RandomListNode result = pHead.next; 43 | RandomListNode _result = result; 44 | while(pHead!=null){ 45 | pHead.next = result.next; 46 | pHead = pHead.next; 47 | if(pHead!=null){ 48 | result.next = pHead.next; 49 | result = result.next; 50 | } 51 | else{ 52 | result.next = null; 53 | } 54 | } 55 | return _result; 56 | } 57 | public RandomListNode Clone(RandomListNode pHead){ 58 | if(pHead == null) return null; 59 | copy(pHead); 60 | copyRandom(pHead); 61 | return divide(pHead); 62 | } 63 | //方法二 64 | public RandomListNode Clone2(RandomListNode pHead) 65 | { 66 | if(pHead == null) return null; 67 | HashMap map = new HashMap(); 68 | RandomListNode _head = pHead; 69 | RandomListNode result = new RandomListNode(_head.label); 70 | RandomListNode _result = result; 71 | map.put(_head, result); 72 | _head = _head.next; 73 | while(_head!=null){ 74 | RandomListNode temp = new RandomListNode(_head.label); 75 | result.next = temp; 76 | map.put(_head, temp); 77 | result = result.next; 78 | _head = _head.next; 79 | } 80 | result = _result; 81 | _head = pHead; 82 | while(result!=null){ 83 | result.random = map.get(_head.random); 84 | result = result.next; 85 | _head = _head.next; 86 | } 87 | return _result; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code28.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * 二叉搜索树与双向链表 ★★★ 7 | * 8 | * 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。 9 | * 10 | * 思路 : 1. 中序遍历,二叉搜索树的中序遍历就是排好序的 11 | * 12 | * @date 2016年5月18日 下午7:17:12 13 | * @author yangengzhe 14 | * 15 | */ 16 | public class code28 { 17 | ArrayList list = new ArrayList(); 18 | public void fun(TreeNode node){ 19 | if(node == null) return; 20 | fun(node.left); 21 | list.add(node); 22 | fun(node.right); 23 | } 24 | public TreeNode Convert(TreeNode pRootOfTree) { 25 | if(pRootOfTree == null) return null; 26 | fun(pRootOfTree); 27 | TreeNode temp = null; 28 | for(int i=0;i result = new TreeSet(); 26 | public void fun(char[] strs,int begin){ 27 | if(begin == strs.length){ 28 | result.add(new String(strs)); 29 | }else{ 30 | for(int i=begin;i!=strs.length;i++){ 31 | char temp = strs[i]; 32 | strs[i] = strs[begin]; 33 | strs[begin] = temp; 34 | 35 | fun(strs, begin+1); 36 | 37 | temp = strs[i]; 38 | strs[i] = strs[begin]; 39 | strs[begin] = temp; 40 | } 41 | } 42 | 43 | } 44 | public ArrayList Permutation(String str) { 45 | ArrayList arrange = new ArrayList(); 46 | if(str == null || str.isEmpty()) return arrange; 47 | char[] strs = str.toCharArray(); 48 | fun(strs,0); 49 | Iterator it = result.iterator(); 50 | while(it.hasNext()){ 51 | arrange.add(it.next()); 52 | } 53 | return arrange; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code3.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 二维数组中的查找 ★★★ 6 | * 7 | * 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 8 | * 9 | * @date 2016年4月22日 下午2:16:24 10 | * @author yangengzhe 11 | * 12 | */ 13 | public class code3 { 14 | 15 | public static void main(String[] args) { 16 | int[][] array={{1,2,8,9},{2,4,9,12},{4,7,10,13},{6,8,11,15}}; 17 | code3 c = new code3(); 18 | System.out.println(c.Find(array, 1)); 19 | } 20 | 21 | /** 22 | * 23 | * @param array 待查找的二维数组 24 | * @param target 查找的数字 25 | * @return 26 | * @author ygz 下午2:19:15 27 | */ 28 | public boolean Find(int [][] array,int target) { 29 | int row = 0; 30 | int column = array[0].length-1; 31 | while(row=0){ 32 | if(array[row][column] == target) 33 | return true; 34 | else if(array[row][column]>target) 35 | column--; 36 | else if(array[row][column]=arr[start]) start++; 29 | arr[end] =arr[start]; 30 | } 31 | arr[start] = temp; 32 | return start; 33 | } 34 | public ArrayList GetLeastNumbers_Solution(int [] input, int k) { 35 | ArrayList result = new ArrayList(); 36 | if(input.length < k || k == 0) return result; 37 | int start = 0; 38 | int end = input.length-1; 39 | int index = partition(input,start,end); 40 | while(index!= k-1){ 41 | if(index>k-1){ 42 | end = index-1; 43 | index = partition(input, start, end); 44 | }else{ 45 | start = index+1; 46 | index = partition(input, start, end); 47 | } 48 | } 49 | for(int i=0;i GetLeastNumbers_Solution3(int [] input, int k) { 55 | if(input == null) 56 | return null; 57 | ArrayList list = new ArrayList(k); 58 | if(k > input.length) 59 | return list; 60 | TreeSet tree = new TreeSet(); 61 | for(int i = 0 ; i < input.length; i++){ 62 | tree.add(input[i]); 63 | } 64 | int i = 0; 65 | for(Integer elem : tree){ 66 | if(i >= k) 67 | break; 68 | list.add(elem); 69 | i++; 70 | } 71 | return list; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code32.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 连续子数组的最大和 ★★★ 6 | * 7 | * 思路:1.常规遍历 O(n^2) 8 | * 2.规律(动态规划):正数只管加,遇到负数时候 最大和会变小,所以考虑是否要舍弃之前的和。 9 | * 因此,用临时变量保存当前和,遇到正数:和只会越来越大,所以遇到正数只管加; 10 | * 遇到负数:先比较记录原先的最大和,再加,加完后需要额外判断 加完的负数是否比本身还小,若小则舍弃,保留自身。 11 | * 12 | * @date 2016年5月30日 下午1:45:13 13 | * @author yangengzhe 14 | * 15 | */ 16 | public class code32 { 17 | public int FindGreatestSumOfSubArray(int[] array) { 18 | if(array.length <1) return 0; 19 | if(array.length == 1) return array[0]; 20 | int sum = Integer.MIN_VALUE; 21 | int temp = array[0]; 22 | for(int i=1;itemp?sum:temp; 25 | temp = temp+array[i] >array[i]?temp+array[i]:array[i]; 26 | } 27 | sum = sum>temp?sum:temp; 28 | return sum; 29 | } 30 | 31 | public static void main(String args[]){ 32 | // int[] array = {6,-3,-2,7,-15,1,2,2}; 33 | // int[] array = {-2,-8,-1,-5,-9}; 34 | // int[] array = {1,-2,3,10,-4,7,2,-5}; 35 | int[] array = {2,8,1,5,9}; 36 | code32 c =new code32(); 37 | System.out.println(c.FindGreatestSumOfSubArray(array)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code33.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | /** 4 | * 整数中1出现的次数(从1到n整数中1出现的次数) ★★★ 5 | * 6 | * 思路:1.逐个遍历 时间复杂度O(n^2) 7 | * 2. 转换成字符串的逐个遍历 8 | * 3. 数字规律:http://www.cnblogs.com/nailperry/p/4752987.html 9 | * 当计算右数第 i 位包含的 X 的个数时: 10 | * 1) 取第 i 位左边(高位)的数字,乘以 10 i−1 ,得到基础值 a 。 11 | * 2) 取第 i 位数字,计算修正值: 12 | * 如果大于 X,则结果为 a+ 10 i−1 。 13 | * 如果小于 X,则结果为 a 。 14 | * 如果等 X,则取第 i 位右边(低位)数字,设为 b ,最后结果为 a+b+1 。 15 | * 相应的代码非常简单,效率也非常高,时间复杂度只有 O( log 10 n) 。 16 | * @date 2016年5月31日 上午9:25:47 17 | * @author yangengzhe 18 | */ 19 | public class code33 { 20 | //笨方法 21 | public int NumberOf1Between1AndN_Solution2(int n) { 22 | int count=0; 23 | while(n>0){ 24 | String str=String.valueOf(n); 25 | char [] chars=str.toCharArray(); 26 | for(int i=0;i 9) return 0; 41 | int high, low, curr, tmp, i = 1; 42 | high = n; 43 | int total = 0; 44 | while (high != 0) { 45 | high = n / (int) Math.pow(10, i);// 获取第i位的高位 46 | tmp = n % (int) Math.pow(10, i); 47 | curr = tmp / (int) Math.pow(10, i - 1);// 获取第i位 48 | low = tmp % (int) Math.pow(10, i - 1);// 获取第i位的低位 49 | if (curr == x) { 50 | total += high * (int) Math.pow(10, i - 1) + low + 1; 51 | } else if (curr < x) { 52 | total += high * (int) Math.pow(10, i - 1); 53 | } else { 54 | total += (high + 1) * (int) Math.pow(10, i - 1); 55 | } 56 | i++; 57 | } 58 | return total; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code34.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 把数组排成最小的数 ★★★ 7 | * 8 | * 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。 9 | * 10 | * 思路:利用int比较的话 会超出越界。所有用String来进行比较 11 | * @date 2016年5月31日 下午2:35:40 12 | * @author yangengzhe 13 | * 14 | */ 15 | public class code34 { 16 | //不正确 17 | // public String[] parseString(int[] numbers){ 18 | // String[] result = new String[numbers.length]; 19 | // int max_length = 0; 20 | // for(int i=0;i result[i].length()?max_length:result[i].length(); 23 | // } 24 | // for(int i=0;i list = new ArrayList(); 33 | list.add(1); 34 | int count = 1; 35 | int pos_2=0,pos_3=0,pos_5=0; 36 | while(count < index){ 37 | int ugly_2 = list.get(pos_2)*2; 38 | int ugly_3 = list.get(pos_3)*3; 39 | int ugly_5 = list.get(pos_5)*5; 40 | int cur_ugly = ugly_2>ugly_3?ugly_3:ugly_2; 41 | cur_ugly = cur_ugly>ugly_5?ugly_5:cur_ugly; 42 | 43 | list.add(cur_ugly); 44 | count++; 45 | 46 | while(list.get(pos_2)*2 <= cur_ugly) 47 | pos_2++; 48 | while(list.get(pos_3)*3 <= cur_ugly) 49 | pos_3++; 50 | while(list.get(pos_5)*5 <= cur_ugly) 51 | pos_5++; 52 | } 53 | return list.get(index-1); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code36.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | 6 | /** 7 | * 第一个只出现一次的字符位置 ★ 8 | * 9 | * 在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符的位置。若为空串,返回-1。位置索引从0开始 10 | * 11 | * 思路:利用数组节省时间的开销 12 | * 13 | * @date 2016年6月1日 下午5:53:52 14 | * @author yangengzhe 15 | * 16 | */ 17 | public class code36 { 18 | public int FirstNotRepeatingChar(String str) { 19 | int result = -1; 20 | if(str == null || str=="") return result; 21 | char[] array = str.toCharArray(); 22 | int[] count = new int[255]; 23 | for(int i=0;i=0;i--){ 23 | int j=i+1; 24 | int temp = 0; 25 | while(jarray[j] && temp map = new HashMap(); 26 | while(pHead1!=null){ 27 | map.put(pHead1, true); 28 | pHead1 = pHead1.next; 29 | } 30 | while(pHead2!=null){ 31 | if(map.containsKey(pHead2)) 32 | return pHead2; 33 | pHead2 = pHead2.next; 34 | } 35 | return null; 36 | } 37 | 38 | //思路3 39 | public ListNode FindFirstCommonNode3(ListNode pHead1, ListNode pHead2) { 40 | Stack stack1 = new Stack(); 41 | Stack stack2 = new Stack(); 42 | ListNode result = null; 43 | while(pHead1!=null){ 44 | stack1.push(pHead1); 45 | pHead1 = pHead1.next; 46 | } 47 | while(pHead2!=null){ 48 | stack2.push(pHead2); 49 | pHead2 = pHead2.next; 50 | } 51 | while(!stack1.isEmpty() && !stack2.isEmpty()){ 52 | if(!stack1.peek().equals(stack2.peek())) 53 | break; 54 | result = stack1.pop(); 55 | stack2.pop(); 56 | } 57 | return result; 58 | } 59 | 60 | //思路4 61 | public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { 62 | int countA = 0,countB = 0; 63 | 64 | ListNode result = null; 65 | ListNode temp = pHead1; 66 | while(pHead1!=null){ 67 | countA++; 68 | pHead1 = pHead1.next; 69 | } 70 | pHead1 = temp; 71 | temp = pHead2; 72 | while(pHead2!=null){ 73 | countB++; 74 | pHead2 = pHead2.next; 75 | } 76 | pHead2 = temp; 77 | while(countA>countB){ 78 | pHead1 = pHead1.next; 79 | countA--; 80 | } 81 | while(countAend) return -1; 18 | int mid = (start+end)/2; 19 | 20 | if(array[mid] < k){ 21 | return findFirst(array, k, mid+1, end); 22 | } 23 | else if(array[mid]>k){ 24 | return findFirst(array, k, start, mid-1); 25 | } 26 | else if(mid == 0 || array[mid-1] != k){ 27 | return mid; 28 | }else{ 29 | return findFirst(array, k, start, mid-1); 30 | } 31 | } 32 | public int findLast(int[] array,int k,int start,int end){ 33 | if(start<0 || start>end) return -1; 34 | int mid = (start+end)/2; 35 | 36 | if(array[mid] < k){ 37 | return findLast(array, k, mid+1, end); 38 | } 39 | else if(array[mid]>k){ 40 | return findLast(array, k, start, mid-1); 41 | } 42 | else if(mid == end || array[mid+1] != k){ 43 | return mid; 44 | }else{ 45 | return findLast(array, k, mid+1, end); 46 | } 47 | } 48 | public int GetNumberOfK(int [] array , int k) { 49 | int first = findFirst(array,k,0,array.length-1); 50 | int last = findLast(array,k,0,array.length-1); 51 | if(first<0) 52 | return 0; 53 | return last-first+1; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code4.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 替换空格 ★ 6 | * 7 | * 请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 8 | * 9 | * 思路:1. 遍历数组 查找空格个数。 2. 一个空格替换成3个字符,算出新数组长度。 3. 两个指针 一个尾部 一个字符串尾,逐渐复制后移对象,遇到空格就替换成%20,时间复杂度O(n) 10 | * @date 2016年4月23日 下午4:19:45 11 | * @author yangengzhe 12 | * 13 | */ 14 | public class code4 { 15 | public static void main(String args[]){ 16 | code4 c = new code4(); 17 | System.out.println(c.replaceSpace("new a")); 18 | } 19 | public String replaceSpace(String str) { 20 | byte[] s = new String(str).getBytes(); 21 | int spaceCount=0; 22 | for(int i=0;ileft?right+1:left+1; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code41.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 平衡二叉树 ★★★ 6 | * 7 | * 输入一棵二叉树,判断该二叉树是否是平衡二叉树。 8 | * 9 | * 思路:1, 计算深度,若左右子节点深度之差小于1 则是平衡的 10 | * 11 | * @date 2016年6月7日 下午12:18:00 12 | * @author yangengzhe 13 | * 14 | */ 15 | public class code41 { 16 | public int deepth(TreeNode root){ 17 | if(root == null) return 0; 18 | int right = deepth(root.right); 19 | int left = deepth(root.left); 20 | return right>left?right+1:left+1; 21 | } 22 | public boolean IsBalanced_Solution(TreeNode root) { 23 | if(root ==null)return true; 24 | int right = deepth(root.right); 25 | int left = deepth(root.left); 26 | if(Math.abs(right-left) <2) 27 | return true; 28 | else 29 | return false; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code42.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * 数组中只出现一次的数字 ★★★★ 7 | * 8 | * 一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。时间复杂度和空间复杂度O(n) 9 | * 10 | * 思路:1、java中利用队列进行两次标记,就可以筛选。 11 | * 方法2、异或的性质,两个相同数异或后为0. 数组全部异或后,结果必定两个不同的数的异或。肯定不为0.则肯定至少一位是1.根据为1的那位,进行分组,(肯定不同的两个数 那位不同 才能异或为1) 12 | * 13 | * @date 2016年4月23日 下午8:30:03 14 | * @author yangengzhe 15 | * 16 | */ 17 | public class code42 { 18 | public static void main(String args[]) { 19 | int array[]={2,4,3,6,3,2,5,5}; 20 | int num1[] = {0},num2[]={0}; 21 | code42 c = new code42(); 22 | c.FindNumsAppearOnce(array, num1, num2); 23 | } 24 | //num1,num2分别为长度为1的数组。传出参数 25 | //将num1[0],num2[0]设置为返回结果 26 | public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { 27 | int temp =0;num1[0]=0;num2[0]=0; 28 | if(array.length<2) return; 29 | for(int i=0;i>1; 35 | count++; 36 | } 37 | for(int i=0;i>count)&1)==1) 39 | num1[0] =num1[0]^array[i]; 40 | else 41 | num2[0] =num2[0]^array[i]; 42 | } 43 | } 44 | 45 | public void FindNumsAppearOnce2(int [] array,int num1[] , int num2[]) { 46 | num1[0]=0; 47 | num2[0]=0; 48 | if(array.length<2) return; 49 | ArrayList list = new ArrayList(); 50 | for(int i=0;i > FindContinuousSequence(int sum) { 18 | ArrayList > result = new ArrayList >(); 19 | int _sum = 3,small = 1,big = 2; 20 | while(smallsum){ 25 | _sum-=small; 26 | small++; 27 | }else{ 28 | ArrayList list = new ArrayList(); 29 | for(int i=small;i<=big;i++) 30 | list.add(i); 31 | result.add(list); 32 | big++; 33 | _sum+=big; 34 | } 35 | } 36 | return result; 37 | } 38 | 39 | public static void main(String args[]){ 40 | code43 c = new code43(); 41 | ArrayList > a = c.FindContinuousSequence(15); 42 | for(int i=0;i b=a.get(i); 44 | for(int j = 0;j FindNumbersWithSum(int [] array,int sum) { 18 | int small =0,big = array.length-1; 19 | ArrayList result = new ArrayList(); 20 | while(small sum){ 22 | big--; 23 | }else if(array[small]+array[big] < sum){ 24 | small++; 25 | }else{ 26 | result.add(array[small]); 27 | result.add(array[big]); 28 | return result; 29 | } 30 | } 31 | return result; 32 | } 33 | 34 | public static void main(String args[]){ 35 | code44 c = new code44(); 36 | int[] array = {1,2,4,7,11,15}; 37 | ArrayList r =c.FindNumbersWithSum(array, 15); 38 | System.out.println(r.get(0) +" "+r.get(1)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code45.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 左旋转字符串 ★★★ 6 | * 7 | * 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它! 8 | * 9 | * 思路:1. 左右分割,交换顺序 10 | * 2. 写一个反转函数,反转三次 。 hello word => word hello 单词按空格反转 可以看成是左移5位 11 | * 12 | * @date 2016年6月13日 下午6:52:39 13 | * @author yangengzhe 14 | * 15 | */ 16 | public class code45 { 17 | //反转函数 18 | public void fun(char[] str,int start,int end){ 19 | if(end numbers[i]) min = numbers[i]; 29 | 30 | if(num[numbers[i]] ==0) 31 | num[numbers[i]]=1; 32 | else 33 | return false; 34 | } 35 | if(max - min <5 && max-min+num[0]>=4) 36 | return true; 37 | return false; 38 | } 39 | //思路1 40 | public boolean isContinuous2(int [] numbers) { 41 | TreeSet set = new TreeSet<>(); 42 | int count = 0; 43 | for(int i=0;i= 4 && set.last() -set.first() <5) 50 | return true; 51 | return false; 52 | } 53 | 54 | public static void main(String args[]){ 55 | int[] numbers = {0,0,1,3,5}; 56 | code47 c = new code47(); 57 | System.out.println(c.isContinuous(numbers)); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code48.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 孩子们的游戏(圆圈中最后剩下的数) ★★★★★ 6 | * 7 | * 每年六一儿童节,NowCoder都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为NowCoder的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到NowCoder名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢? 8 | * 9 | * 思路:约瑟夫环 10 | * 1. 模拟环,利用链表或其他结构模拟。时间复杂度O(mn) 空间复杂度O(n) 11 | * 2. 找规律 12 | * f(n,m) = 0 n=1 13 | * = [f(n-1,m)+m]%n n>1 14 | * @date 2016年6月15日 下午5:41:08 15 | * @author yangengzhe 16 | * 17 | */ 18 | public class code48 { 19 | //思路2 20 | public int LastRemaining_Solution2(int n,int m){ 21 | if(n<1 ||m<1) 22 | return -1; 23 | int last = 0; 24 | for(int i=2;i<=n;i++){ 25 | last = (last+m)%i; 26 | } 27 | return last; 28 | } 29 | 30 | //思路1 31 | class Node{ 32 | int val; 33 | Node next; 34 | Node(int val){ 35 | this.val = val; 36 | } 37 | } 38 | public int LastRemaining_Solution(int n, int m) { 39 | if(n == 0) return -1; 40 | Node head = new Node(0); 41 | Node t_head = head; 42 | for(int i=1;i0)&&((sum+=Sum_Solution(n-1))>0); 19 | return sum; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code5.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Stack; 5 | 6 | /** 7 | * 从尾到头打印链表 ★ 8 | * 9 | * 输入一个链表,从尾到头打印链表每个节点的值。 10 | * 11 | * 思路:1、栈。2、递归 12 | * 13 | * @date 2016年4月23日 下午4:40:01 14 | * @author yangengzhe 15 | * 16 | */ 17 | 18 | class ListNode { 19 | int val; 20 | ListNode next = null; 21 | 22 | ListNode(int val) { 23 | this.val = val; 24 | } 25 | } 26 | 27 | public class code5 { 28 | //递归 29 | public ArrayList printListFromTailToHead(ListNode listNode) { 30 | ArrayList resulut = new ArrayList(); 31 | if(listNode!=null) 32 | fun(resulut, listNode); 33 | return resulut; 34 | } 35 | public void fun(ArrayList resulut ,ListNode listNode){ 36 | if(listNode.next !=null) 37 | fun(resulut,listNode.next); 38 | resulut.add(listNode.val); 39 | } 40 | 41 | //栈 42 | public ArrayList printListFromTailToHead2(ListNode listNode) { 43 | ArrayList resulut = new ArrayList(); 44 | Stack stack = new Stack(); 45 | if(listNode == null) 46 | return resulut; 47 | while(listNode!=null){ 48 | stack.push(listNode); 49 | listNode = listNode.next; 50 | } 51 | while(!stack.isEmpty()) 52 | resulut.add(stack.pop().val); 53 | return resulut; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code50.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 不用加减乘除做加法 ★★★ 6 | * 7 | * 写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。 8 | * 9 | * 思路:分为三步 10 | * 第一步:不进位加法。异或运算。 11 | * 第二步:计算进位。按位与 左移1位。 12 | * 第三步:相加求和。重复上两步 直到进位为0时 13 | * 14 | * @date 2016年6月17日 下午1:20:38 15 | * @author yangengzhe 16 | * 17 | */ 18 | public class code50 { 19 | public int Add(int num1,int num2) { 20 | int jinwei = 1; 21 | int sum=0; 22 | while(jinwei != 0) { 23 | jinwei = (num1 & num2)<<1; 24 | sum = num1 ^ num2; 25 | 26 | num1 = sum; 27 | num2 = jinwei; 28 | } 29 | return sum; 30 | } 31 | 32 | public static void main(String args[]){ 33 | code50 c = new code50(); 34 | System.out.println(c.Add(1, 2)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code51.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 把字符串转换成整数 ★★ 6 | * 7 | * 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 8 | * 9 | * 思路: 考虑程序的健全性。正负号,非数字等问题 10 | * 11 | * @date 2016年6月21日 下午7:03:28 12 | * @author yangengzhe 13 | * 14 | */ 15 | public class code51 { 16 | public int StrToInt(String str) 17 | { 18 | if (str.equals("") || str.length() == 0) 19 | return 0; 20 | char[] a = str.toCharArray(); 21 | int fuhao = 0; 22 | if (a[0] == '-') 23 | fuhao = 1; 24 | int sum = 0; 25 | for (int i = fuhao; i < a.length; i++) 26 | { 27 | if (a[i] == '+') 28 | continue; 29 | if (a[i] < 48 || a[i] > 57) 30 | return 0; 31 | sum = sum * 10 + a[i] - 48; 32 | } 33 | return fuhao == 0 ? sum : sum * -1; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code6.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 重建二叉树 ★★ 6 | * 7 | * 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。 8 | * 9 | * 思路:二叉树前中后序,知道任意两个,可求第三个。 10 | * 1. 前序 第一个元素 是当前根节点。(确定根节点) 11 | * 2. 中序,找到前序的第一个元素(根节点),左侧都是左子树,右侧都是右子树(找到左右子树的中序) 12 | * 3. 在中序找到左子树后,根据个数相同的原则,在前序中 从前往后可以找出左子树和右子树的前序序列。(找到左右子树的前序) 13 | * 14 | * @date 2016年4月25日 下午3:43:41 15 | * @author yangengzhe 16 | * 17 | */ 18 | class TreeNode { 19 | int val; 20 | TreeNode left; 21 | TreeNode right; 22 | TreeNode(int x) { val = x; } 23 | } 24 | public class code6 { 25 | public TreeNode findRoot(int[] pre,int s_p,int e_p,int[] in,int s_i,int e_i){ 26 | if(s_p>e_p || s_i>e_i) return null; 27 | TreeNode tree = new TreeNode(pre[s_p]); 28 | int i=s_i,count=0; 29 | for(;i<=e_i;i++){ 30 | if(pre[s_p] == in[i]) break; 31 | count++; 32 | } 33 | tree.left = findRoot(pre, s_p+1,s_p+1+count-1,in,s_i,s_i+count-1); 34 | tree.right = findRoot(pre, s_p+1+count, e_p, in, s_i+count+1, e_i); 35 | return tree; 36 | } 37 | public TreeNode reConstructBinaryTree(int [] pre,int [] in) { 38 | return findRoot(pre, 0, pre.length-1, in, 0, in.length-1); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code7.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * 用两个栈实现队列 ★★★ 7 | * 8 | * 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。 9 | * 10 | * 思路:一个栈是FILO,两个栈 通过逆序两次,实现队列FIFO 11 | * @date 2016年4月25日 下午6:00:46 12 | * @author yangengzhe 13 | * 14 | */ 15 | public class code7 { 16 | Stack stack1 = new Stack(); 17 | Stack stack2 = new Stack(); 18 | 19 | public void push(int node) { 20 | while(!stack2.empty()) 21 | stack1.push(stack2.pop()); 22 | stack1.push(node); 23 | } 24 | 25 | public int pop() { 26 | while(!stack1.empty()) 27 | stack2.push(stack1.pop()); 28 | return stack2.pop(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/code8.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer; 2 | 3 | 4 | /** 5 | * 旋转数组的最小数字 ★★★★ 6 | * 7 | * 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减序列的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 8 | * 9 | * 思路:方法一:遍历数组O(n)。方法二:二分查找。中间元素分别和头元素、尾元素比较,决定第二次的查找范围。 10 | * @date 2016年4月27日 下午4:00:43 11 | * @author yangengzhe 12 | * 13 | */ 14 | public class code8 { 15 | public int fun(int[] array,int start,int end){ 16 | if(array.length == 0) return 0; 17 | if(start == end || array[start]array[mid] ){ 24 | return fun(array, start, mid); 25 | } 26 | else{ 27 | int a = fun(array, start, mid-1); 28 | int b = fun(array,mid+1,end); 29 | return a>b?b:a; 30 | } 31 | } 32 | public int minNumberInRotateArray(int [] array) { 33 | return fun(array,0,array.length-1); 34 | } 35 | 36 | 37 | public int minNumberInRotateArray2(int [] array) { 38 | if(array==null || array.length==0) return 0; 39 | if(array[0]0;i--){ 45 | if(array[i]1){ 20 | c = a+b; 21 | a=b; 22 | b=c; 23 | n--; 24 | } 25 | return c; 26 | } 27 | //递归 28 | public int Fibonacci2(int n) { 29 | if(n<2) return n; 30 | else return Fibonacci(n-1)+Fibonacci(n-2); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/util/ListNode.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer.util; 2 | 3 | 4 | public class ListNode { 5 | public int val; 6 | public ListNode next = null; 7 | 8 | public ListNode(int val) { 9 | this.val = val; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/util/RandomListNode.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer.util; 2 | 3 | 4 | public class RandomListNode { 5 | public int label; 6 | public RandomListNode next = null; 7 | public RandomListNode random = null; 8 | 9 | public RandomListNode(int label) { 10 | this.label = label; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /nowcoder/src/nowcoder/剑指offer/util/TreeNode.java: -------------------------------------------------------------------------------- 1 | package nowcoder.剑指offer.util; 2 | 3 | 4 | public class TreeNode { 5 | int val = 0; 6 | TreeNode left = null; 7 | TreeNode right = null; 8 | 9 | public TreeNode(int val) { 10 | this.val = val; 11 | 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /nowcoder/src/practice/Binary.java: -------------------------------------------------------------------------------- 1 | package practice; 2 | 3 | public class Binary { 4 | 5 | public static int weishu(int a) { 6 | int count = 0; 7 | while (a != 1) { 8 | a = a / 2; 9 | count++; 10 | } 11 | return count + 1; 12 | } 13 | 14 | public static int[] fun(int a, int b) { 15 | // 1. 按位运算符 | & << >> 16 | int count_a = weishu(a);// 位数 17 | int count_b = weishu(b); 18 | int[] a_count = new int[count_a]; 19 | int[] b_count = new int[count_b]; 20 | int[] c_count = new int[count_a + count_b]; 21 | for (int i = count_a - 1; i >= 0; i--) { 22 | // (int)Math.pow(2, i-1)); 23 | if ((a & ((int) Math.pow(2, count_a - i - 1))) == Math.pow(2, count_a - i - 1)) 24 | 25 | a_count[i] = 1; 26 | else { 27 | a_count[i] = 0; 28 | } 29 | 30 | } 31 | for (int i = count_b - 1; i >= 0; i--) { 32 | if ((b & (int) Math.pow(2, count_b - i - 1)) == (Math.pow(2, count_b - i - 1))) b_count[i] = 1; 33 | else { 34 | b_count[i] = 0; 35 | } 36 | 37 | } 38 | if (count_a > count_b) { 39 | for (int j = count_a - 1; j >= 0; j--) { 40 | if (j >= count_b) { 41 | 42 | c_count[j] = a_count[j]; 43 | } else { 44 | if (a_count[j] == b_count[j]) c_count[j] = 0; 45 | else c_count[j] = 1; 46 | } 47 | 48 | } 49 | } else { 50 | for (int j = count_b - 1; j >= 0; j--) { 51 | if (j >= count_a) { 52 | 53 | c_count[j] = b_count[j]; 54 | } else { 55 | if (b_count[j] == a_count[j]) c_count[j] = 0; 56 | else c_count[j] = 1; 57 | } 58 | 59 | } 60 | } 61 | return c_count; 62 | } 63 | 64 | public static void main(String[] args) { 65 | int[] a = fun(1, 2); 66 | for (int i = 0; i < a.length; i++) 67 | System.out.print(a[i]); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /nowcoder/src/practice/MergeSort.java: -------------------------------------------------------------------------------- 1 | package practice; 2 | 3 | 4 | public class MergeSort { 5 | //将有二个有序数列a[first...mid]和a[mid...last]合并。 6 | void mergearray(int a[], int first, int mid, int last, int temp[]) 7 | { 8 | int i = first, j = mid + 1; 9 | int m = mid, n = last; 10 | int k = 0; 11 | 12 | while (i <= m && j <= n) 13 | { 14 | if (a[i] <= a[j]) 15 | temp[k++] = a[i++]; 16 | else 17 | temp[k++] = a[j++]; 18 | } 19 | 20 | while (i <= m) 21 | temp[k++] = a[i++]; 22 | 23 | while (j <= n) 24 | temp[k++] = a[j++]; 25 | 26 | for (i = 0; i < k; i++) 27 | a[first + i] = temp[i]; 28 | } 29 | void mergesort(int a[], int first, int last, int temp[]) 30 | { 31 | if (first < last) 32 | { 33 | int mid = (first + last) / 2; 34 | mergesort(a, first, mid, temp); //左边有序 35 | mergesort(a, mid + 1, last, temp); //右边有序 36 | mergearray(a, first, mid, last, temp); //再将二个有序数列合并 37 | } 38 | } 39 | 40 | boolean MergeSort(int a[], int n) 41 | { 42 | int[] p = new int[n]; 43 | mergesort(a, 0, n - 1, p); 44 | return true; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /nowcoder/src/practice/ThreadLocalp.java: -------------------------------------------------------------------------------- 1 | package practice; 2 | 3 | import java.util.Random; 4 | 5 | public class ThreadLocalp { 6 | 7 | class Bank{ 8 | //使用ThreadLocal类管理共享变量account 9 | private ThreadLocal account = new ThreadLocal(){ 10 | @Override 11 | protected Integer initialValue(){ 12 | return 100; 13 | } 14 | }; 15 | public void save(int money){ 16 | account.set(account.get()+money); 17 | } 18 | public int getAccount(){ 19 | return account.get(); 20 | } 21 | } 22 | 23 | class NewThread implements Runnable { 24 | 25 | private Bank bank; 26 | 27 | public NewThread(Bank bank){ 28 | this.bank = bank; 29 | } 30 | 31 | @Override 32 | public void run() { 33 | Random r = new Random(); 34 | for (int i = 0; i < 10; i++) { 35 | // bank.save1(10); 36 | int a = r.nextInt(10); 37 | bank.save(a); 38 | System.out.println(Thread.currentThread().getName()+ ", "+a+"账户余额为:" + bank.getAccount()); 39 | } 40 | } 41 | 42 | } 43 | 44 | /** 45 | * 建立线程,调用内部类 46 | */ 47 | public void useThread() { 48 | Bank bank = new Bank(); 49 | NewThread new_thread = new NewThread(bank); 50 | System.out.println("线程1"); 51 | Thread thread1 = new Thread(new_thread); 52 | thread1.start(); 53 | System.out.println("线程2"); 54 | Thread thread2 = new Thread(new_thread); 55 | thread2.start(); 56 | } 57 | 58 | public static void main(String[] args) { 59 | ThreadLocalp st = new ThreadLocalp(); 60 | st.useThread(); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /nowcoder/src/practice/quickSort.java: -------------------------------------------------------------------------------- 1 | package practice; 2 | 3 | 4 | public class quickSort { 5 | public static void main(String args[]){ 6 | int[] arr = {1,4,2,5}; 7 | qsort(arr, 0, arr.length-1); 8 | for (int i : arr) { 9 | System.out.println(i); 10 | } 11 | } 12 | private static void qsort(int[] arr, int low, int high){ 13 | if (low < high){ 14 | int pivot=partition(arr, low, high); //将数组分为两部分 15 | qsort(arr, low, pivot-1); //递归排序左子数组 16 | qsort(arr, pivot+1, high); //递归排序右子数组 17 | } 18 | } 19 | public static int partition(int arr[],int start,int end){ 20 | int pivot = arr[start]; 21 | while(start=pivot) end--; 23 | arr[start] = arr[end]; 24 | while(start set = new TreeSet(); 17 | int i=0; 18 | while(i n) 24 | System.out.println("mistake"); 25 | else if(array[array.length-1] - array[0] < n ){ 26 | if(array[0] == 1) 27 | System.out.println(array[array.length-1]+1); 28 | else 29 | System.out.println(array[0]-1 +" "+ (array[array.length-1]+1)); 30 | }else{ 31 | long c= array[0]; 32 | for(int j =0;j