├── designpattern-principle └── readme.md ├── fundamentals └── readme.md ├── jvm ├── Java进程JVM参数调优指导.pdf ├── code │ ├── FinalizeEscapeGC.java │ ├── MinorGC.java │ ├── testMaxTenuringThreshold.java │ ├── testMaxTenuringThreshold_dynamic.java │ └── testPretenureSizeThreshold.java └── 深入理解java虚拟机笔记.xmind ├── readme.md └── sort-algorithm ├── BubbleSort.java └── SelectionSort.java /designpattern-principle/readme.md: -------------------------------------------------------------------------------- 1 | 说明 2 | ======= 3 | 4 | 这个目录用来汇总学习设计模式时的各种资料,欢迎 issue + PR,一起丰富。 5 | 6 | ------------ 7 | 8 | 9 | 下面的综述介绍来自 [@guohongjun](https://github.com/guohongjun) 的 repo [DesignPattern-principle](https://github.com/guohongjun/DesignPattern-principle/blob/master/README.md) ,感谢作者的整理,在此借用下。 10 | 11 | # DesignPattern-principle 12 | 13 | 关于设计模式原则,有的按照solid原则总结,有的说六原则,大家都总结的都不一致。学习了这位[仁兄](http://my.csdn.net/zhengzhb)的文章基础上,今天这里把我理解的设计模式几大原则给大家分享一下: 14 | 15 | >* 单一职责原则 16 | >* 开闭原则 17 | >* 接口分离原则 18 | >* 里氏代换原则 19 | >* 依赖倒置原则 20 | >* 迪米特原则 21 | >* 优先使用组合,而不是使用继承 22 | 23 | ## 单一职责原则 24 | -------------------- 25 | 26 | > 定义:不要存在多于一个导致类变更的原因。通俗的说,即单一职责是说一个类或者一个方法,只做一件事,或者完成一个任务。 27 | 28 | 问题由来:类T负责两个不同的职责:职责Z1,职责Z2。当由于职责Z1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责Z2功能发生故障。 29 | 30 | 解决:遵循单一职责原则。分别建立两个类T1、T2,使T1完成职责Z1功能,T2完成职责Z2功能。这样,当修改类T1时,不会使职责Z2发生故障风险;同理,当修改T2时,也不会使职责Z1发生故障风险。 31 | 32 | 举例说明: 用一个类描述动物行走的 33 | 34 | ```java 35 | public class Animal { 36 | public void run(String str) { 37 | System.out.println("行走 " + str); 38 | } 39 | } 40 | public class Client { 41 | public static void main(String[] args) { 42 | Animal animal = new Animal(); 43 | animal.run("牛"); 44 | animal.run("羊"); 45 | } 46 | } 47 | ``` 48 | 49 | 运行了一下后,发现不对哈。鱼等水生的动物是不能行走的,那么怎么办呢?所以我们要修改一下,遵循单一职责原则,让陆生动物使用 Terrestrial 这个类;而水生动物使用 Aquatic 这个类。 50 | 51 | ```java 52 | class Terrestrial{ 53 | public void run(String animal){ 54 | System.out.println(animal+"陆地行走"); 55 | } 56 | } 57 | class Aquatic{ 58 | public void run(String animal){ 59 | System.out.println(animal+"水中游行"); 60 | } 61 | } 62 | public class Client { 63 | public static void main(String[] args) { 64 | Terrestrial terrestrial = new Terrestrial(); 65 | terrestrial.breathe("牛"); 66 | terrestrial.breathe("羊"); 67 | terrestrial.breathe("猪"); 68 | 69 | Aquatic aquatic = new Aquatic(); 70 | aquatic.breathe("鱼"); 71 | } 72 | } 73 | ``` 74 | 75 | 遵循单一职责原的优点有: 76 | 77 | >* 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多; 78 | >* 提高类的可读性,提高系统的可维护性; 79 | >* 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。 80 | >* 需要说明的一点是单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。 81 | 82 | ## 开闭原则 83 | -------------------- 84 | 85 | > 定义:是说软件实体(类、模块、函数等等)应该可以扩展,但是不可修改。 86 | 开闭原则的核心是:对扩展开放,对修改关闭。 87 | 88 | **“可变性的封装原则”意味着两点:** 89 | 90 | - 一种可变性不应当散落在代码的很多角落里,而应当被封装到一个对象里面。继承应当被看做是封装变化的方法,而不应当被认为是从一般的对象生成特殊的对象方法。 91 | - 一种可变性不应当与另一种可变性混合在一起。所有的类图的继承结构一般不会超过两层,不然就意味着将两种不同的可变性混合在一起。 92 | 93 | 此处我借鉴了[花郎V](http://www.cnblogs.com/loulijun/archive/2012/03/14/2394055.html)这个仁兄的文章,很感谢哈。 94 | 95 | ```java 96 | public interface IBoy { 97 | // 年龄 98 | public int getAge(); 99 | 100 | // 姓名 101 | public String getName(); 102 | 103 | // 长相 104 | public String getFace(); 105 | 106 | } 107 | 108 | 109 | public class StrongerBoy implements IBoy { 110 | private String name; 111 | private int age; 112 | private String face; 113 | 114 | public StrongerBoy(String name, int age, String face, String figure) { 115 | this.name = name; 116 | this.age = age; 117 | this.face = face; 118 | } 119 | 120 | @Override 121 | public int getAge() { 122 | return age; 123 | } 124 | 125 | @Override 126 | public String getFace() { 127 | return face; 128 | } 129 | 130 | @Override 131 | public String getName() { 132 | return name; 133 | } 134 | } 135 | 136 | public class Mans { 137 | private final static ArrayList boys = new ArrayList(); 138 | // 静态初始化块 139 | static { 140 | boy.add(new StrongerBoy("谢霆锋", 30, "帅气")); 141 | boy.add(new StrongerBoy("冯小刚", 60, "成熟")); 142 | } 143 | 144 | public static void main(String args[]) { 145 | System.out.println("----------美女在这里----------"); 146 | for (IBoy boy : boys) { 147 | System.out.println("姓名:" + boy.getName() + " 年龄:" 148 | + boy.getAge() + " 长相:" + boy.getFace()); 149 | } 150 | } 151 | } 152 | } 153 | 154 | ``` 155 | 156 | 这个程序写的不错哈,我运行了一下,感觉不错。此时问题来了,如果要加个外国名人怎么办?修改 Iboy 这个接口吗,这样做就符合不了开闭原则了。所以,我这里想到了扩展,但是如何扩展呢? 157 | 可以定义一个 IForeigner 接口继承自 IBoy,在 IForeigner 接口中添加国籍属性 getCountry(),然后实现这个接口即可,然后就只需要在场景类中做稍微修改就可以了。 158 | 159 | ```java 160 | 161 | public interface IForeigner extends IBoy { 162 | // 国籍 163 | public String getCountry(); 164 | } 165 | 166 | public class ForeignerBoy implements IForeigner { 167 | private String name; 168 | private int age; 169 | private String country; 170 | private String face; 171 | private String figure; 172 | 173 | public ForeignerBoy(String name, int age, String country, String face, String figure) 174 | { 175 | this.name = name; 176 | this.age = age; 177 | this.country = country; 178 | this.face =face; 179 | this.figure = figure; 180 | } 181 | @Override 182 | public String getCountry() { 183 | // TODO Auto-generated method stub 184 | return country; 185 | } 186 | 187 | @Override 188 | public int getAge() { 189 | // TODO Auto-generated method stub 190 | return age; 191 | } 192 | 193 | @Override 194 | public String getFace() { 195 | // TODO Auto-generated method stub 196 | return face; 197 | } 198 | 199 | @Override 200 | public String getName() { 201 | // TODO Auto-generated method stub 202 | return name; 203 | } 204 | 205 | } 206 | boys.add(new ForeignerBoy("richale",28,"美国","阳光")); 207 | ``` 208 | 209 | 设计原则是死的,也要根据实际的需求,我们要灵活使用这个开闭原则。 210 | 211 | 212 | ## 接口分离原则 213 | -------------------- 214 | 215 | > 定义:客户端不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口上。 216 | 217 | 通俗的说就是:接口中的方法要尽量的少,不要使接口过于臃肿,不要有过多不相关的逻辑方法。参考于[李天炜](http://tianweili.github.io/blog/2015/02/10/interface-segregation-principle/)的文章 218 | 219 | ```java 220 | public interface I { 221 | public void method1(); 222 | public void method2(); 223 | public void method3(); 224 | } 225 | public class B implements I{ 226 | 227 | @Override 228 | public void method1() { 229 | System.out.println("类B实现了接口I的方法1"); 230 | } 231 | 232 | @Override 233 | public void method2() { 234 | System.out.println("类B实现了接口I的方法2"); 235 | } 236 | 237 | @Override 238 | public void method3() {//类B并不需要接口I的方法3功能,但是由于实现接口I,所以不得不实现方法3 239 | //在这里写一个空方法 240 | } 241 | } 242 | public class D implements I{ 243 | 244 | @Override 245 | public void method2() { 246 | System.out.println("类D实现了接口I的方法2"); 247 | } 248 | 249 | @Override 250 | public void method3() { 251 | System.out.println("类D实现了接口I的方法3"); 252 | } 253 | 254 | @Override 255 | public void method1() {//类D并不需要接口I的方法1功能,但是由于实现接口I,所以不得不实现方法1 256 | //在这里写一个空方法 257 | } 258 | } 259 | //类A通过接口I依赖类B 260 | public class A { 261 | public void depend1(I i){ 262 | i.method1(); 263 | } 264 | } 265 | //类C通过接口I依赖类D 266 | public class C { 267 | public void depend1(I i){ 268 | i.method3(); 269 | } 270 | } 271 | public class Client { 272 | public static void main(String[] args) { 273 | A a = new A(); 274 | I i1 = new B(); 275 | a.depend1(i1); 276 | 277 | C c = new C(); 278 | I i2 = new D(); 279 | c.depend1(i2); 280 | } 281 | } 282 | ``` 283 | 284 | 运行结果: 285 | 286 | ``` java 287 | 类B实现了接口I的方法1 288 | 类D实现了接口I的方法3 289 | ``` 290 | 291 | 从以上代码可以看出,如果接口过于臃肿,不同业务逻辑的抽象方法都放在一个接口内,则会造成它的实现类必须实现自己并不需要的方法,这种设计方式显然是不妥当的。所以我们要修改上述设计方法,把接口I拆分成3个接口,使得实现类只需要实现自己需要的接口即可。只贴出修改后的接口和实现类的代码,修改代码如下: 292 | 293 | ```java 294 | public interface I1 { 295 | public void method1(); 296 | } 297 | public interface I2 { 298 | public void method2(); 299 | } 300 | public interface I3 { 301 | public void method3(); 302 | } 303 | 304 | public class B implements I1,I2{ 305 | @Override 306 | public void method1() { 307 | System.out.println("类B实现了接口I的方法1"); 308 | } 309 | 310 | @Override 311 | public void method2() { 312 | System.out.println("类B实现了接口I的方法2"); 313 | } 314 | } 315 | 316 | public class D implements I2,I3{ 317 | @Override 318 | public void method2() { 319 | System.out.println("类D实现了接口I的方法2"); 320 | } 321 | 322 | @Override 323 | public void method3() { 324 | System.out.println("类D实现了接口I的方法3"); 325 | } 326 | } 327 | ``` 328 | 329 | ### 与单一职责原则的区别 330 | 331 | 到了这里,有些人可能觉得接口隔离原则与单一职责原则很相似,其实不然。 332 | 333 | 1. 单一职责原则注重的是职责;而接口隔离原则注重对接口依赖的隔离。 334 | 335 | 2. 单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口,主要针对抽象,针对程序整体框架的构建。 336 | 3. 接口尽量小 337 | 4. 接口高内聚 338 | 5. 接口设计是有限度的 339 | 340 | **注意事项:** 341 | 342 | > 原则是软件大师们经验的总结,在软件设计中具有一定的指导作用,但不能按部就班哈。对于接口隔离原则来说,接口尽量小,但是也要有限度。对接口进行细化可以提高程序设计灵活性是不争的事实,但是如果过小,则会造成接口数量过多,使设计复杂化,所以一定要适度。 343 | 344 | 345 | ## 里氏代换原则 346 | -------------------- 347 | 348 | 里氏代换原则是由麻省理工学院(MIT)计算机科学实验室的Liskov女士,在1987年的OOPSLA大会上发表的一篇文章《[Data Abstraction and Hierarchy](http://www.rendezvouswithdestiny.net/index_files/LiskovSub.pdf)》里面提出来的,主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中的蕴涵的原理。2002年,软件工程大师Robert C. Martin,出版了一本《[Agile Software Development Principles Patterns and Practices](http://book.douban.com/subject/1459003/)》,在文中他把里氏代换原则最终简化为一句话:"Subtypes must be substitutable for their base types",也就是说,子类必须能够替换成它们的基类。 349 | 350 | >定义1:如果对每一个类型为 T1的对象 Object1,都有类型为 T2 的对象Object2,使得以 T1定义的所有程序 P 在所有的对象 Object1 都代换成 Object2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。 351 | 352 | >定义2:所有引用父类的地方必须能正常地使用其子类的对象。 353 | 354 | 问题由来:有一功能P1,由类Superclass完成。现需要将功能P1进行扩展,扩展后的功能为P,其中P由原有功能P1与新功能P2组成。新功能P由类Superclass的子类Subclass来完成,则子类B在完成新功能P2的同时,有可能会导致原有功能P1发生故障。 355 | 356 | 解决方案:当使用继承时,遵循里氏替换原则。类Subclass继承类Superclass时,除添加新的方法完成新增功能P2外,尽量不要重写父类Superclass的方法,也尽量不要重载父类Superclass的方法。 357 | 358 | 不说没用营养的了,上代码: 359 | 360 | ``` java 361 | public class Superclass { 362 | public int subtraction(int a, int b) { 363 | return a - b; 364 | } 365 | } 366 | public class Subclass extends Superclass { 367 | public int subtraction(int a, int b) { 368 | return a - b - 1; 369 | } 370 | } 371 | public class Client { 372 | public static void main(String[] args) { 373 | Subclass subclass = new Subclass(); 374 | SuperClass supuerClass = new SuperClass(); 375 | System.out.println("SuperClass + " 376 | + SuperClass.subtraction(10 - 5)); 377 | System.out.println("subclass + "+subclass.subtraction(10 - 5)); 378 | } 379 | } 380 | ``` 381 | 382 | 大家看一下上面的代码中子类可以代替父类,而不使原来的父类的计算功能不变吗?答案是否定的。 383 | 里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义: 384 | 385 | 1. 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。 386 | 2. 子类中可以增加自己特有的方法。 387 | 3. 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。 388 | 4. 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。 389 | 390 | ## 依赖倒置原则 391 | -------------------- 392 | 393 | > 定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。编程应该依赖抽象,不应该依赖细节。 394 | 395 | 问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。 396 | 397 | 解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。 398 | 399 | 依赖倒置原则的核心思想是面向接口编程,我们依旧用一个例子来说明面向接口编程比相对于面向实现编程好在什么地方。场景是这样的,母亲给孩子讲故事,只要给她一本书,她就可以照着书给孩子讲故事了。举个例子说明一下: 400 | 401 | ```java 402 | class Book { 403 | public String getContent() { 404 | return "这个是一个关于毛主席的故事……"; 405 | } 406 | } 407 | 408 | class Mother { 409 | public void read(Book book) { 410 | System.out.println("妈妈开始讲故事"); 411 | System.out.println(book.getContent()); 412 | } 413 | } 414 | 415 | public class Client { 416 | public static void main(String[] args) { 417 | Mother mother = new Mother(); 418 | mother.read(new Book()); 419 | } 420 | } 421 | ``` 422 | 423 | 运行结果: 424 | 425 | ``` java 426 | 妈妈开始讲故事 427 | 428 | 这个是一个关于毛主席的故事…… 429 | ``` 430 | 431 | 运行良好,假如有一天,需求变成这样:不是给书而是给一份报纸,让这位母亲讲一下报纸上的故事,报纸的代码如下: 432 | 433 | ```java 434 | class NewsPaper { 435 | public String getContent() { 436 | return "中国篮球超人姚明……"; 437 | } 438 | } 439 | 440 | ``` 441 | 442 | 这位母亲就办不到,因为她居然不会读报纸上的故事,这太荒唐了,只是将书换成报纸,居然必须要修改Mother才能读。假如以后需求换成杂志呢?换成网页呢?还要不断地修改Mother,这显然不是好的设计。原因就是Mother与Book之间的耦合性太高了,必须降低他们之间的耦合度才行。 443 | 444 | 我们引入一个抽象的接口IReader。读物,只要是带字的都属于读物: 445 | 446 | ```java 447 | public Interface IReader{ 448 | public String getContent(); 449 | } 450 | ``` 451 | Mother类与接口IReader发生依赖关系,而Book和Newspaper都属于读物的范围,它们各自都去实现IReader接口,这样就符合依赖倒置原则了,代码修改为: 452 | 453 | ```java 454 | class Newspaper implements IReader { 455 | public String getContent() { 456 | return "中国篮球超人姚明……"; 457 | } 458 | } 459 | 460 | class Book implements IReader { 461 | public String getContent() { 462 | return "这个是一个关于毛主席的故事……"; 463 | } 464 | } 465 | 466 | class Mother { 467 | public void read(IReader reader) { 468 | System.out.println("妈妈开始讲故事"); 469 | System.out.println(reader.getContent()); 470 | } 471 | } 472 | 473 | public class Client { 474 | public static void main(String[] args) { 475 | Mother mother = new Mother(); 476 | mother.read(new Book()); 477 | mother.read(new Newspaper()); 478 | } 479 | } 480 | ``` 481 | 482 | 这样以后,妈妈就是万能的了,主要是读物,妈妈都可以讲给我了。 483 | 484 | 这样修改后,无论以后怎样扩展Client类,都不需要再修改Mother类了。这只是一个简单的例子,实际情况中,代表高层模块的Mother类将负责完成主要的业务逻辑,一旦需要对它进行修改,引入错误的风险极大。所以遵循依赖倒置原则可以降低类之间的耦合性,提高系统的稳定性,降低修改程序造成的风险。 485 | 486 | 采用依赖倒置原则给多人并行开发带来了极大的便利,比如上例中,原本Mother类与Book类直接耦合时,Mother类必须等Book类编码完成后才可以进行编码,因为Mother类依赖于Book类。修改后的程序则可以同时开工,互不影响,因为Mother与Book类一点关系也没有。参与协作开发的人越多、项目越庞大,采用依赖导致原则的意义就越重大。现在很流行的TDD开发模式就是依赖倒置原则最成功的应用。 487 | 488 | 传递依赖关系有三种方式,以上的例子中使用的方法是接口传递,另外还有两种传递方式:构造方法传递和setter方法传递,相信用过Spring框架的,对依赖的传递方式一定不会陌生。 489 | 490 | 在实际编程中,我们一般需要做到如下3点: 491 | 492 | 1. 低层模块尽量都要有抽象类或接口,或者两者都有。 493 | 2. 变量的声明类型尽量是抽象类或接口。 494 | 3. 使用继承时遵循里氏替换原则。 495 | 496 | 依赖倒置原则的核心就是要我们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。 497 | 498 | 499 | ## 迪米特原则 500 | -------------------- 501 | 502 | > 定义:也叫最少知道原则,如果两个类不必彼此直接通信,那么这两个类就不应放生直接的互相作用。如果其中一个类需要调用另一个类的某个方法的化,可以用使用第三者转发这个调用。 503 | 504 | 强调的前提:在类的结构设计上,每一个类都应当尽量降低成员的访问权限,也就是说,一个类包装好自己的private状态,不需要让别的类知道的字段或行为就不要公开。 505 | 506 | 根本思想是:强调类之间的松耦合,类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。 507 | 508 | ```java 509 | public class A { 510 | public B getB(String str) { 511 | return new B(str); 512 | } 513 | 514 | public void work() { 515 | B b = getB("李同学"); 516 | C c = b.getC("谢霆锋"); 517 | c.work(); 518 | } 519 | } 520 | 521 | public class B { 522 | public String name; 523 | 524 | public B() { 525 | 526 | } 527 | 528 | public B(String name) { 529 | this.name = name; 530 | } 531 | 532 | public C getC(String name) { 533 | return new C(name); 534 | } 535 | } 536 | 537 | public class C { 538 | 539 | public String name; 540 | 541 | public C(String name) { 542 | this.name = name; 543 | } 544 | 545 | public void work() { 546 | System.out.println(name + "帮我把这件事做好了"); 547 | } 548 | } 549 | public class Client { 550 | public static void main(String[] args) { 551 | A a = new A("王同学"); 552 | a.work(); 553 | } 554 | } 555 | ``` 556 | 557 | 运行结果是: 558 | 559 | ``` java 560 | 谢霆锋帮我把这件事做好了。 561 | ``` 562 | 563 | 运行结果正常,但是我们发现一个问题,A类与B类有关联,而A类与C类没有什么关联。C类出现在A类中是不是有点不合时宜呢? 564 | 看到这里很多人都会明白,这种场景在实际开发中是非常常见的一种情况。对象A需要调用对象B的方法,对象B有需要调用对象C的方法……就是常见的`getXXX().getXXX().getXXX()`……类似于这种代码。如果你发现你的代码中也有这样的代码,那就考虑下是不是违反迪米特法则,是不是要重构一下了。 565 | 566 | 修改一下该例子: 567 | 568 | ```java 569 | 570 | public class A { 571 | pubic A(){ 572 | 573 | } 574 | public B getB(String str) { 575 | return new B(str); 576 | } 577 | 578 | public void work() { 579 | B b = getB("王同学"); 580 | b.work(); 581 | } 582 | } 583 | 584 | public class B { 585 | public String name; 586 | 587 | public B() { 588 | 589 | } 590 | public B(String name) { 591 | this.name = name; 592 | } 593 | public void work(){ 594 | C c= getC(“谢霆锋”); 595 | c.work; 596 | } 597 | public C getC(String name) { 598 | return new C(name); 599 | } 600 | } 601 | 602 | public class C { 603 | public String name; 604 | public C(String name) { 605 | this.name = name; 606 | } 607 | public void work() { 608 | System.out.println(name + "帮我把这件事做好了"); 609 | } 610 | } 611 | public class Client { 612 | public static void main(String[] args) { 613 | A a = new A("王同学"); 614 | a.work(); 615 | } 616 | } 617 | ``` 618 | 619 | 运行结果如下: 620 | 621 | ``` java 622 | 谢霆锋帮我把这件事做好了 623 | ``` 624 | 625 | 上面代码只是修改了下类A和B的work方法,使之符合了迪米特法则: 626 | 627 | - 类A只与最直接的朋友类B通信,不与类C通信; 628 | - 类A只调用类B提供的方法即可,不用关心类B内部是如何实现的(至于B是怎么调用的C,这些A都不用关心)。 629 | 630 | ## 优先使用组合,而不是使用继承 631 | -------------------- 632 | 633 | 定义:这个就不用解释了吧,学习过面向对象编程的同学,都应该知道这个事。 634 | 635 | ** 组合:** 636 | >通过创建一个由其他对象组合的对象来获得新功能的重用方法 637 | 新功能的获得是通过调用组合对象的功能实现的,有时又叫聚合。 638 | 639 | 例如: 640 | 一个对象拥有或者对另外一个对象负责并且两个对象有相同的生命周期。(GOF) 641 | 一个对象包含另一个对象集合 642 | 被包含对象对其他对象是不可见的并且只能从包含它的对象中访问的特殊组合形式 643 | 组合的优缺点 644 | 645 | **优点** 646 | 647 | - 被包含对象通过包含他们的类来访问 648 | - 黑盒重用,因为被包含对象的内部细节是不可见的 649 | - 很好的封装 650 | - 每个类专注于一个任务 651 | - 通过获得和被包含对象的类型相同的对象引用,可以在运行时动态定义组合的方式 652 | 653 | **缺点** 654 | 655 | - 结果系统可能会包含更多的对象 656 | - 为了使组合时可以使用不同的对象,必须小心的定义接口 657 | 658 | **继承:** 659 | > 通过扩展已实现的对象来获得新功能的重用方法 660 | > 基类有用通用的属性和方法 661 | > 子类提供更多的属性和方法来扩展基类 662 | 663 | 664 | **优点** 665 | 666 | - 新的实现很容易,因为大部分是继承而来的 667 | - 很容易修改和扩展已有的实现 668 | 669 | **缺点** 670 | 671 | - 打破了封装,因为基类向子类暴露了实现细节 672 | - 白盒重用,因为基类的内部细节通常对子类是可见的 673 | - 当父类的实现改变时可能要相应的对子类做出改变 674 | - 不能在运行时改变由父类继承来的实现 675 | 676 | 由此可见,组合比继承具有更大的灵活性和更稳定的结构,一般情况下应该优先考虑组合。只有当下列条件满足时才考虑使用继承: 677 | 678 | - 子类是一种特殊的类型,而不只是父类的一个角色 679 | - 子类的实例不需要变成另一个类的对象 680 | - 子类扩展,而不是覆盖或者使父类的功能失效 681 | 682 | 实例 683 | 参见Effective Java第四章第14条 684 | -------------------------------------------------------------------------------- /fundamentals/readme.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 3 | 本目录汇总 Java 基础学习的资料 ,欢迎 PR,丰富更多的内容。 4 | 5 | # 规范 6 | - [Java 语言、虚拟机规范 - Java Language and Virtual Machine Specifications](http://docs.oracle.com/javase/specs/) Java SE6/7/8 每个版本中的语言规范、虚拟机规范进行说明。 7 | - [Google 代码规范 - Google Code Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javaguide.html) 中文翻译版本[Google Java 编程风格指南](http://www.hawstein.com/posts/google-java-style.html) -------------------------------------------------------------------------------- /jvm/Java进程JVM参数调优指导.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xirong/my-java/a72919dd6f2d565be5584ad57647d3fffa56ccfe/jvm/Java进程JVM参数调优指导.pdf -------------------------------------------------------------------------------- /jvm/code/FinalizeEscapeGC.java: -------------------------------------------------------------------------------- 1 | /** 2 | * description: 3 | * 对象无引用链后,需要进行标记和筛选后才行回收; 4 | * 5 | * 1. 演示对象可以在GC时候进行自我拯救,通过Finalize()方法; 6 | * 2. 不过只有一种机会,一个对象的finalize()方法只能执行一次 7 | * 8 | * 9 | * 10 | * author: xirong 11 | * date: 2015-07-30 12 | * version: 1.0 13 | */ 14 | public class FinalizeEscapeGC { 15 | public static FinalizeEscapeGC SAVE_INSTANCE = null; 16 | 17 | public void isAlive() { 18 | System.out.println("yes, i am still alive !"); 19 | 20 | } 21 | 22 | @Override 23 | protected void finalize() throws Throwable{ 24 | super.finalize(); 25 | System.out.println("finalize method has been invoked !"); 26 | // 拯救自我 27 | FinalizeEscapeGC.SAVE_INSTANCE =this; 28 | } 29 | 30 | public static void main(String[] args) throws InterruptedException { 31 | SAVE_INSTANCE =new FinalizeEscapeGC(); 32 | 33 | // 对象第一次拯救自我 34 | SAVE_INSTANCE =null; 35 | System.gc(); 36 | 37 | Thread.sleep(1000); // finalize方法的优先级低,等待1秒后 38 | if(SAVE_INSTANCE !=null){ 39 | SAVE_INSTANCE.isAlive(); 40 | }else { 41 | System.out.println("no ,i am dead !"); 42 | } 43 | 44 | // 执行过一次后,被回收 45 | SAVE_INSTANCE =null; 46 | System.gc(); 47 | 48 | Thread.sleep(1000); 49 | if(SAVE_INSTANCE !=null){ 50 | SAVE_INSTANCE.isAlive(); 51 | }else { 52 | System.out.println("no ,i am dead !"); 53 | } 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /jvm/code/MinorGC.java: -------------------------------------------------------------------------------- 1 | /** 2 | * description: 3 | * 对象优先分配在Eden空间,当不足时,发生Minor GC的操作 4 | * author: xirong 5 | * date: 2015-07-30 6 | * version: 1.0 7 | * copyright 2015 ,all rights reserved. 8 | */ 9 | public class MinorGC { 10 | private static final int _1MB=1024*1024; 11 | 12 | /* 13 | vm : -verbose:gc -Xmx20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 14 | */ 15 | public static void main(String[] args){ 16 | byte[] a1,a2,a3,a4; 17 | a1 =new byte[2*_1MB]; 18 | a2 =new byte[2*_1MB]; 19 | a3 =new byte[2*_1MB]; 20 | a4 =new byte[4*_1MB]; 21 | 22 | System.out.println("main is over!"); 23 | } 24 | } 25 | 26 | /* 27 | 28 | [GC[DefNew: 7495K->382K(9216K), 0.0072260 secs] 7495K->6526K(19456K), 0.0072610 secs] [Times: user=0.00 sys=0.01, real=0.01 secs] 29 | main is over! 30 | Heap 31 | def new generation total 9216K, used 4984K [0x00000007f9a00000, 0x00000007fa400000, 0x00000007fa400000) 32 | eden space 8192K, 56% used [0x00000007f9a00000, 0x00000007f9e7e8c8, 0x00000007fa200000) 33 | from space 1024K, 37% used [0x00000007fa300000, 0x00000007fa35fa88, 0x00000007fa400000) 34 | to space 1024K, 0% used [0x00000007fa200000, 0x00000007fa200000, 0x00000007fa300000) 35 | tenured generation total 10240K, used 6144K [0x00000007fa400000, 0x00000007fae00000, 0x00000007fae00000) 36 | the space 10240K, 60% used [0x00000007fa400000, 0x00000007faa00030, 0x00000007faa00200, 0x00000007fae00000) 37 | compacting perm gen total 21248K, used 2930K [0x00000007fae00000, 0x00000007fc2c0000, 0x0000000800000000) 38 | the space 21248K, 13% used [0x00000007fae00000, 0x00000007fb0dca68, 0x00000007fb0dcc00, 0x00000007fc2c0000) 39 | No shared spaces configured. 40 | 41 | */ -------------------------------------------------------------------------------- /jvm/code/testMaxTenuringThreshold.java: -------------------------------------------------------------------------------- 1 | /** 2 | * description: 3 | * 当对象的age熬过指定年龄时,将进入老年代 4 | * author: xirong 5 | * date: 2015-07-30 6 | * version: 1.0 7 | * copyright 2015 ,all rights reserved. 8 | */ 9 | public class testMaxTenuringThreshold { 10 | private static final int _1MB = 1024*1024; 11 | 12 | /* 13 | vm :-verbose:gc -Xmx20M -Xms20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 14 | -XX:MaxTenuringThreshold=1 15 | -XX:MaxTenuringThreshold=15 尝试下 不同 16 | -XX:+PrintTenuringDistribution 17 | */ 18 | public static void main(String[] args){ 19 | /* 20 | eden space 8192K, 21 | from space 1024K, 22 | to space 1024K, 23 | */ 24 | 25 | // //-XX:MaxTenuringThreshold=1 运行注释 26 | // byte[] a1,a2,a3; 27 | // a1 =new byte[_1MB/4]; 28 | // a2=new byte[4*_1MB]; 29 | // // 对象优先存储在Eden,4M放不下,minor gc start 30 | // // a1 存储在from ,a2 from、to都无法放下,进入老年代 31 | // a3=new byte[4*_1MB]; 32 | // a3 =null; //上一句分配的对象无引用,下次GC即可回收掉 33 | // // Eden空间中保存着上一个 4M,新对象无法存储,Minor GC开始,from 空间 age=1的 a1对象要到老年代去了 34 | // a3=new byte[4*_1MB]; 35 | // // 最终,a3的4M在 Eden区,a1+a2进入老年代 36 | 37 | 38 | //-XX:MaxTenuringThreshold=15 运行注释 39 | byte[] a1,a2,a3; 40 | a1 =new byte[_1MB/4]; 41 | a2=new byte[4*_1MB]; 42 | // 对象优先存储在Eden,4M放不下,minor gc start 43 | // a1 存储在from ,a2 from、to都无法放下,进入老年代 44 | a3=new byte[4*_1MB]; 45 | a3 =null; //上一句分配的对象无引用,下次GC即可回收掉 46 | // Eden空间中保存着上一个 4M,新对象无法存储,Minor GC开始, 47 | // from 空间 age=1的 a1对象不到年龄仍然留在 from 空间 48 | a3=new byte[4*_1MB]; 49 | // 最终,a3的4M在 Eden区,a1+a2进入老年代 50 | } 51 | } 52 | 53 | /* 54 | -XX:MaxTenuringThreshold=1 的时候结果如下: 55 | 56 | [GC[DefNew 57 | Desired survivor size 524288 bytes, new threshold 1 (max 1) 58 | - age 1: 615792 bytes, 615792 total 59 | : 5556K->601K(9216K), 0.0056710 secs] 5556K->4697K(19456K), 0.0056960 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 60 | [GC[DefNew 61 | Desired survivor size 524288 bytes, new threshold 1 (max 1) 62 | - age 1: 256 bytes, 256 total 63 | : 4945K->0K(9216K), 0.0017150 secs] 9041K->4693K(19456K), 0.0017390 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 64 | Heap 65 | def new generation total 9216K, used 4178K [0x00000007f9a00000, 0x00000007fa400000, 0x00000007fa400000) 66 | eden space 8192K, 51% used [0x00000007f9a00000, 0x00000007f9e14820, 0x00000007fa200000) 67 | from space 1024K, 0% used [0x00000007fa200000, 0x00000007fa200100, 0x00000007fa300000) 68 | to space 1024K, 0% used [0x00000007fa300000, 0x00000007fa300000, 0x00000007fa400000) 69 | tenured generation total 10240K, used 4693K [0x00000007fa400000, 0x00000007fae00000, 0x00000007fae00000) 70 | the space 10240K, 45% used [0x00000007fa400000, 0x00000007fa895548, 0x00000007fa895600, 0x00000007fae00000) 71 | compacting perm gen total 21248K, used 2623K [0x00000007fae00000, 0x00000007fc2c0000, 0x0000000800000000) 72 | the space 21248K, 12% used [0x00000007fae00000, 0x00000007fb08ffa0, 0x00000007fb090000, 0x00000007fc2c0000) 73 | No shared spaces configured. 74 | */ -------------------------------------------------------------------------------- /jvm/code/testMaxTenuringThreshold_dynamic.java: -------------------------------------------------------------------------------- 1 | /** 2 | * description: 3 | * 当对象的age熬过指定年龄时,将进入老年代 4 | * author: xirong 5 | * date: 2015-07-30 6 | * version: 1.0 7 | * copyright 2015 ,all rights reserved. 8 | */ 9 | public class testMaxTenuringThreshold_dynamic { 10 | private static final int _1MB = 1024*1024; 11 | 12 | /* 13 | vm :-verbose:gc -Xmx20M -Xms20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 14 | -XX:MaxTenuringThreshold=1 15 | -XX:MaxTenuringThreshold=15 尝试下 不同 16 | -XX:+PrintTenuringDistribution 17 | */ 18 | public static void main(String[] args){ 19 | /* 20 | eden space 8192K, 21 | from space 1024K, 22 | to space 1024K, 23 | */ 24 | 25 | //-XX:MaxTenuringThreshold=15 运行注释 26 | byte[] a1,a2,a3,a4; 27 | a1 =new byte[_1MB/4]; 28 | a4=new byte[_1MB/4]; 29 | a2=new byte[4*_1MB]; 30 | // 对象优先存储在Eden,4M放不下,minor gc start 31 | // a1 存储在from ,a2 from、to都无法放下,进入老年代 32 | a3=new byte[4*_1MB]; 33 | a3 =null; //上一句分配的对象无引用,下次GC即可回收掉 34 | // Eden空间中保存着上一个 4M,新对象无法存储,Minor GC开始, 35 | // from 空间 age=1的 a1对象不到年龄仍然留在 from 空间 36 | a3=new byte[4*_1MB]; 37 | // 最终,a3的4M在 Eden区,a1+a2进入老年代 38 | } 39 | } 40 | 41 | /* 42 | [GC[DefNew 43 | Desired survivor size 524288 bytes, new threshold 1 (max 15) 44 | - age 1: 920088 bytes, 920088 total 45 | : 5959K->898K(9216K), 0.0073310 secs] 5959K->4994K(19456K), 0.0073630 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 46 | [GC[DefNew 47 | Desired survivor size 524288 bytes, new threshold 15 (max 15) 48 | - age 1: 256 bytes, 256 total 49 | : 5242K->0K(9216K), 0.0029150 secs] 9338K->4975K(19456K), 0.0029450 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 50 | Heap 51 | def new generation total 9216K, used 4178K [0x00000007f9a00000, 0x00000007fa400000, 0x00000007fa400000) 52 | eden space 8192K, 51% used [0x00000007f9a00000, 0x00000007f9e14820, 0x00000007fa200000) 53 | from space 1024K, 0% used [0x00000007fa200000, 0x00000007fa200100, 0x00000007fa300000) 54 | to space 1024K, 0% used [0x00000007fa300000, 0x00000007fa300000, 0x00000007fa400000) 55 | tenured generation total 10240K, used 4975K [0x00000007fa400000, 0x00000007fae00000, 0x00000007fae00000) 56 | the space 10240K, 48% used [0x00000007fa400000, 0x00000007fa8dbe18, 0x00000007fa8dc000, 0x00000007fae00000) 57 | compacting perm gen total 21248K, used 2985K [0x00000007fae00000, 0x00000007fc2c0000, 0x0000000800000000) 58 | the space 21248K, 14% used [0x00000007fae00000, 0x00000007fb0ea4d8, 0x00000007fb0ea600, 0x00000007fc2c0000) 59 | No shared spaces configured. 60 | */ -------------------------------------------------------------------------------- /jvm/code/testPretenureSizeThreshold.java: -------------------------------------------------------------------------------- 1 | /** 2 | * description: 3 | * 大对象直接分配在老年大,参数 -XX:PretenureSizeThreshold 4 | * author: xirong 5 | * date: 2015-07-30 6 | * version: 1.0 7 | * copyright 2015 ,all rights reserved. 8 | */ 9 | public class testPretenureSizeThreshold { 10 | private static final int _1MB = 1024*1024; 11 | 12 | /* 13 | vm :-verbose:gc -Xmx20M -Xms20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 14 | -XX:PretenureSizeThreshold=3145728 15 | */ 16 | public static void main(String[] args){ 17 | byte[] a4; 18 | a4 =new byte[4*_1MB]; // 大于3M直接分配在老年代 19 | 20 | } 21 | } 22 | 23 | /* 24 | Heap 25 | def new generation total 9216K, used 1515K [0x00000007f9a00000, 0x00000007fa400000, 0x00000007fa400000) 26 | eden space 8192K, 18% used [0x00000007f9a00000, 0x00000007f9b7af08, 0x00000007fa200000) 27 | from space 1024K, 0% used [0x00000007fa200000, 0x00000007fa200000, 0x00000007fa300000) 28 | to space 1024K, 0% used [0x00000007fa300000, 0x00000007fa300000, 0x00000007fa400000) 29 | tenured generation total 10240K, used 4096K [0x00000007fa400000, 0x00000007fae00000, 0x00000007fae00000) 30 | the space 10240K, 40% used [0x00000007fa400000, 0x00000007fa800010, 0x00000007fa800200, 0x00000007fae00000) 31 | compacting perm gen total 21248K, used 2979K [0x00000007fae00000, 0x00000007fc2c0000, 0x0000000800000000) 32 | the space 21248K, 14% used [0x00000007fae00000, 0x00000007fb0e8cf8, 0x00000007fb0e8e00, 0x00000007fc2c0000) 33 | No shared spaces configured. 34 | 35 | 对象直接分配在 tenured generation 里面了 36 | */ -------------------------------------------------------------------------------- /jvm/深入理解java虚拟机笔记.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xirong/my-java/a72919dd6f2d565be5584ad57647d3fffa56ccfe/jvm/深入理解java虚拟机笔记.xmind -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | # java 语言 3 | 4 | ## 规范 5 | - [Java 语言、虚拟机规范 - Java Language and Virtual Machine Specifications](http://docs.oracle.com/javase/specs/) Java SE6/7/8 每个版本中的语言规范、虚拟机规范进行说明。 6 | - [Google 代码规范 - Google Code Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javaguide.html) 中文翻译版本[Google Java 编程风格指南](http://www.hawstein.com/posts/google-java-style.html) 7 | - [Reasons, Tips and Tricks for Better Java Documentation - 写更好的 Java 文档注释](http://zeroturnaround.com/rebellabs/reasons-tips-and-tricks-for-better-java-documentation/) 写一个类、方法前思考清楚她的职责,多多使用 @Author/@Version/@Since/@Value 等注解来进行说明。中文翻译版本参考[ImportNew - 改善 Java 文档的理由、建议和技巧](http://www.importnew.com/16459.html) 8 | 9 | 10 | ## 常见问题 11 | - [深入理解 HashMap](https://github.com/guohongjun/HashMap-System-Learning) HashMap 的结构是怎样的,又是怎样处理 Hash 冲突的。 12 | 13 | ## 并发编程 14 | - [java.util.concurrent - Java Concurrency Utilities](http://tutorials.jenkov.com/java-util-concurrent/index.html) 15 | 16 | ## Java8 学习 17 | - [Java Platform, Standard Edition (Java SE) 8 Documentation](http://docs.oracle.com/javase/8/) 18 | 19 | ## Java9 前沿 20 | 21 | 22 | # JVM 虚拟机 23 | 24 | - [Understanding Java Garbage Collection](http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/) 阅读完《[深入理解Java虚拟机第二版](https://github.com/xirong/my-java/blob/master/jvm/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3java%E8%99%9A%E6%8B%9F%E6%9C%BA%E7%AC%94%E8%AE%B0.xmind)》后,感觉没有形成一个大局观,这篇文章介绍的很详细,每个收集器的区别等。 25 | - [HotspotOverview.pdf](https://www.cs.princeton.edu/picasso/mats/HotspotOverview.pdf) 基于SE6,Compilation、Synchronization、Garbage Collection、A Performance Future几个部分来介绍。最权威的介绍 Hotspot 还是看 Oracle 官方[Java SE HotSpot at a Glance] 26 | - [How to Monitor Java Garbage Collection](http://www.cubrid.org/blog/dev-platform/how-to-monitor-java-garbage-collection/) 如何利用系统自带的监控工具进行监控 GC 的状态 27 | - [How to Tune Java Garbage Collection](http://www.cubrid.org/blog/dev-platform/how-to-tune-java-garbage-collection/) 28 | - [Jvm 性能监控及故障排查命令行、图形化工具介绍及相应使用方法](http://www.ixirong.com/2015/08/01/jvm-monitor-tools/) 29 | - Jvm Tuning Resources (Jvm 调优实践) 30 | - [Start with Jvm :heap,stack,-Xss,-Xmn,-Xmx,-Xms Overview](http://www.avricot.com/blog/?post/2010/05/03/Get-started-with-java-JVM-memory-(heap%2C-stack%2C-xss-xms-xmx-xmn...)) 介绍几个详细参数的确切含义 31 | - [Java 进程 Jvm 参数调优指导 -- 各个参数介绍及实践经验](jvm/Java进程JVM参数调优指导.pdf) 介绍 Heap、Stack、Perm各个区及相应的优化参数,满满的都是实战经验。 32 | - [Tuning Garbage Collection Outline](http://www.petefreitag.com/articles/gctuning/) 33 | - [Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning](http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html) 34 | - [Gabage First(G1) Collector in Jdk 7 - from Stackoverflow.com](http://stackoverflow.com/questions/8111310/java-7-jdk-7-garbage-collection-and-documentation) G1 收集器的一些介绍 35 | - [All Java HotSpot VM Options](http://www.oracle.com/technetwork/articles/java/vmoptions-jsp-140102.html) 所有的配置参数介绍 36 | - [Java HotSpot Garbage Collection Whiterpapers](http://www.oracle.com/technetwork/articles/java/index-jsp-140228.html) 包括内存管理、收集器技术、收集Tuning、常见错误解决方法、G1 介绍等。 37 | 38 | jvm 的测试代码及一些参考资料见[目录jvm](jvm/) 39 | 40 | # 数据结构及算法 41 | 42 | ## 排序算法 43 | 复习数据结构算法进行的练习,整节来源于书籍《[大话数据结构](http://book.douban.com/subject/6424904/)》 44 | 45 | - [冒泡排序及其改进](http://www.ixirong.com/2015/07/16/sort-algorithm-bubblesort/) ,源码地址[BubbleSort](sort-algorithm/BubbleSort.java) 46 | - [简单选择排序](http://www.ixirong.com/2015/07/19/sort-algorithm-selectionsort/) ,源码地址[SelectionSort](sort-algorithm/SelectionSort.java) 47 | - [直接插入排序](http://www.ixirong.com/2015/07/19/sort-algorithem-insertsort/),源码地址[SelectionSort](sort-algorithm/SelectionSort.java) 48 | - 希尔排序 49 | - 堆排序 50 | - 归并排序 51 | - 快速排序 52 | - 桶排序 53 | -------------------------------------------------------------------------------- /sort-algorithm/BubbleSort.java: -------------------------------------------------------------------------------- 1 | /** 2 | * description: 3 | * author: xirong 4 | * date: 2015-07-16 5 | * version: 1.0 6 | * copyright 2015 ,all rights reserved. 7 | */ 8 | public class BubbleSort { 9 | 10 | // 原始冒泡排序 11 | // 外循环为总共遍历的次数,内循环从最后开始,若小于前者,则往前移动顺序即可 12 | public static void OriginalBubbleSort(int[] array){ 13 | for(int i=1;i<=array.length;i++){ 14 | for(int j=array.length-1;j>=i;j--){ 15 | if(array[j-1]>array[j]){ 16 | Swap(array,j-1,j); 17 | } 18 | } 19 | } 20 | } 21 | 22 | // 改善效率的冒泡 23 | // 比如{2,1,3,4,5,6,7,8,9} 第一次循环即可将数组排好顺序,剩下的8次循环是可以不用进行的 24 | public static void ImprovedBubbleSort(int[] array){ 25 | boolean loop=true; 26 | for(int i=1;i<=array.length && loop;i++){ 27 | loop =false; 28 | for(int j=array.length-1;j>=i;j--){ 29 | if(array[j-1] > array[j]){ 30 | Swap(array,j-1,j); 31 | loop =true; 32 | } 33 | } 34 | } 35 | } 36 | 37 | // 交换数组位置 38 | public static void Swap(int[] array,int start,int end){ 39 | int temp=array[start]; 40 | array[start] = array[end]; 41 | array[end] =temp; 42 | } 43 | 44 | public static void PrintArray(int[] array){ 45 | StringBuilder sb=new StringBuilder(); 46 | for(int i=0;i array[j]){ 22 | minIndex =j; 23 | } 24 | } 25 | // 如果存在比 arr[minIndex] 小的记录,则进行交换 26 | if(minIndex !=i){ 27 | Swap(array,minIndex,i); 28 | } 29 | } 30 | } 31 | 32 | /** 33 | * 直接插入排序 34 | * 在待排序的列表中 35 | * @param array 36 | */ 37 | public static void InsertionSort(int[] array){ 38 | int temp,j; 39 | for(int i=1;i= 0 && temp < array[j]){ 44 | array[j+1]=array[j]; 45 | j--; 46 | } 47 | array[j+1]=temp; 48 | } 49 | } 50 | 51 | // 交换数组位置 52 | public static void Swap(int[] array,int start,int end){ 53 | int temp=array[start]; 54 | array[start] = array[end]; 55 | array[end] =temp; 56 | } 57 | 58 | public static void PrintArray(int[] array){ 59 | StringBuilder sb=new StringBuilder(); 60 | for(int i=0;i