diff --git a/README.md b/README.md index 5f2bfc6b4eb24ebe753765e04b52331d2de6ce4d..e986fba508baec368a41d398aef4a4595c704440 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -[![](http://www.hollischuang.com/wp-content/uploads/2018/10/Hollis.png)](https://www.hollischuang.com) - ## To Be Top Javaer - Java工程师成神之路 ![](https://img.shields.io/badge/version-v2.0.0-green.svg) ![](https://img.shields.io/badge/author-Hollis-yellow.svg) ![](https://img.shields.io/badge/license-GPL-blue.svg) @@ -7,993 +5,47 @@ | 主要版本 | 更新时间 | 备注 | | ---- | ---------- | -------------- | -| v1.0 | 2015-08-01 | 首次发布 | -| v1.1 | 2018-03-12 | 增加新技术知识、完善知识体系 | +| v3.0 | 2020-03-29 | 知识体系完善
通过GitHub Page搭建,便于阅读| | v2.0 | 2019-02-19 | 结构调整,更适合从入门到精通;
进一步完善知识体系;
新技术补充;| +| v1.1 | 2018-03-12 | 增加新技术知识、完善知识体系 | +| v1.0 | 2015-08-01 | 首次发布 | -欢迎关注[Java之道]公众号,最新内容均会在该公众号中同步发出! -![](pics/wechat.png) - - -[全套思维导图](/mind-map.md) - -## 一、基础篇 - -### 面向对象 - -#### 什么是面向对象 - -[面向对象、面向过程](/basics/java-basic/object-oriented-vs-procedure-oriented.md) - -[面向对象的三大基本特征](/basics/java-basic/characteristics.md)和[五大基本原则](/basics/java-basic/principle.md) - -#### 平台无关性 - -[Java如何实现的平台无关性的](/basics/java-basic/platform-independent.md) - -[JVM还支持哪些语言(Kotlin、Groovy、JRuby、Jython、Scala)](/basics/java-basic/jvm-language.md) - -#### 值传递 - -[值传递、引用传递](/basics/java-basic/java-pass-by.md) - -[为什么说Java中只有值传递](/basics/java-basic/java-pass-by.md) - -#### 封装、继承、多态 - -[什么是多态](/basics/java-basic/polymorphism.md)、[方法重写与重载](/basics/java-basic/overloading-vs-overriding.md) - -Java的继承与实现 - -[Java的继承与组合](/basics/java-basic/inheritance-composition.md) - -[构造函数与默认构造函数](/basics/java-basic/constructor.md) - -[类变量、成员变量和局部变量](/basics/java-basic/variable.md) - -[成员变量和方法作用域](/basics/java-basic/scope.md) - -### Java基础知识 - -#### 基本数据类型 - -[8种基本数据类型:整型、浮点型、布尔型、字符型](/basics/java-basic/basic-data-types.md) - -[整型中byte、short、int、long的取值范围](/basics/java-basic/integer-scope.md) - -[什么是浮点型?](/basics/java-basic/float.md) - -[什么是单精度和双精度?](/basics/java-basic/single-double-float.md) - -[为什么不能用浮点型表示金额?](/basics/java-basic/float-amount.md) - -#### 自动拆装箱 - -[什么是包装类型、什么是基本类型、什么是自动拆装箱](/basics/java-basic/boxing-unboxing.md) - -[Integer的缓存机制](/basics/java-basic/integer-cache.md) - -#### String - -[字符串的不可变性](/basics/java-basic/final-string.md) - -[JDK 6和JDK 7中substring的原理及区别](/basics/java-basic/substring.md) - -replaceFirst、replaceAll、replace区别、 - -[String对“+”的重载](/basics/java-basic/string-append.md) - -[字符串拼接的几种方式和区别](/basics/java-basic/string-concat.md) - -[String.valueOf和Integer.toString的区别](/basics/java-basic/value-of-vs-to-string.md) - -[switch对String的支持](/basics/java-basic/switch-string.md) - -字符串池、常量池(运行时常量池、Class常量池)、intern - -#### 熟悉Java中各种关键字 - -transient、instanceof、volatile、synchronized、final、static、const 原理及用法。 - -#### 集合类 - -常用集合类的使用 - -[ArrayList和LinkedList和Vector的区别](/basics/java-basic/arraylist-vs-linkedlist-vs-vector.md) - -[SynchronizedList和Vector的区别](/basics/java-basic/synchronizedlist-vector.md)、 - -[HashMap、HashTable、ConcurrentHashMap区别](/basics/java-basic/HashMap-HashTable-ConcurrentHashMap.md) - -[Set和List区别?](/basics/java-basic/set-vs-list.md) - -[Set如何保证元素不重复?](/basics/java-basic/set-repetition.md) - -[Java 8中stream相关用法](/basics/java-basic/stream.md)、 - -apache集合处理工具类的使用、 - -不同版本的JDK中HashMap的实现的区别以及原因 - -[Collection和Collections区别](/basics/java-basic/Collection-vs-Collections.md) - -[Arrays.asList获得的List使用时需要注意什么](/basics/java-basic/Arrays-asList.md) - -[Enumeration和Iterator区别](/basics/java-basic/Enumeration-vs-Iterator.md) - -[fail-fast 和 fail-safe](/basics/java-basic/fail-fast-vs-fail-safe.md) - -[CopyOnWriteArrayList](/basics/java-basic/CopyOnWriteArrayList.md) - -[ConcurrentSkipListMap](/basics/java-basic/ConcurrentSkipListMap.md) - -#### 枚举 - -[枚举的用法](/basics/java-basic/enum-usage.md) - -[枚举的实现](/basics/java-basic/enum-impl.md) - -[枚举与单例](/basics/java-basic/enum-singleton.md)、Enum类 - -[Java枚举如何比较](/basics/java-basic/enum-compare.md) - -[switch对枚举的支持](/basics/java-basic/enum-switch.md) - -[枚举的序列化如何实现](/basics/java-basic/enum-serializable.md) - -[枚举的线程安全性问题](/basics/java-basic/enum-thread-safe.md) - -#### IO - -[字符流、字节流](/basics/java-basic/byte-stream-vs-character-stream.md)、[输入流、输出流](/basics/java-basic/input-stream-vs-output-stream.md) - -[同步、异步](/basics/java-basic/synchronized-vs-asynchronization.md)、[阻塞、非阻塞](/basics/java-basic/block-vs-non-blocking.md)、[Linux 5种IO模型](/basics/java-basic/linux-io.md) - -[BIO、NIO和AIO的区别、三种IO的用法与原理](/basics/java-basic/bio-vs-nio-vs-aio.md)、netty - -#### Java反射与javassist - -[反射](/basics/java-basic/reflection.md)与工厂模式、 [反射有什么作用](/basics/java-basic/usage-of-reflection.md) - -[Class类](/basics/java-basic/Class.md) - -`java.lang.reflect.*` - -#### 动态代理 - -[静态代理](/basics/java-basic/static-proxy.md)、[动态代理](/basics/java-basic/dynamic-proxy.md) - -[动态代理和反射的关系](/basics/java-basic/dynamic-proxy-vs-reflection.md) - -[动态代理的几种实现方式](/basics/java-basic/dynamic-proxy-implementation.md) - -[AOP](/basics/java-basic/aop-vs-proxy.md) - -#### 序列化 - -[什么是序列化与反序列化](/basics/java-basic/serialize.md)、为什么序列化、[序列化底层原理](/basics/java-basic/serialize-principle.md)、[序列化与单例模式](/basics/java-basic/serialize-singleton.md)、protobuf、为什么说序列化并不安全 - -#### 注解 - -[元注解](/basics/java-basic/meta-annotation.md)、[自定义注解](/basics/java-basic/custom-annotation.md)、Java中常用注解使用、注解与反射的结合 - -[如何自定义一个注解?](/basics/java-basic/create-annotation.md) - -[Spring常用注解](/basics/java-basic/annotation-in-spring.md) - -#### JMS - -什么是Java消息服务、JMS消息传送模型 - -#### JMX - -`java.lang.management.*`、 `javax.management.*` - -#### 泛型 - -泛型与继承、类型擦除、[泛型中K T V E ? object等的含义](/basics/java-basic/k-t-v-e.md)、泛型各种用法 - -限定通配符和非限定通配符、上下界限定符extends 和 super - -[List和原始类型List之间的区别?](/basics/java-basic/genericity-list.md) - -[List和List之间的区别是什么?](/basics/java-basic/genericity-list-wildcard.md) - -#### 单元测试 - -junit、mock、mockito、内存数据库(h2) - -#### 正则表达式 - -`java.lang.util.regex.*` - -#### 常用的Java工具库 - -`commons.lang`, `commons.*...` `guava-libraries` `netty` - -#### API&SPI - -API、[API和SPI的关系和区别](/basics/java-basic/api-vs-spi.md) - -[如何定义SPI](/basics/java-basic/create-spi.md)、[SPI的实现原理](/basics/java-basic/spi-principle.md) - -#### 异常 - -异常类型、正确处理异常、自定义异常 - -Error和Exception - -异常链、try-with-resources - -finally和return的执行顺序 - -#### 时间处理 - -[时区](/basics/java-basic/time-zone.md)、[冬令时和夏令时](/basics/java-basic/StandardTime-vs-daylightSavingTime.md)、[时间戳](/basics/java-basic/timestamp.md)、Java中时间API - -[格林威治时间](/basics/java-basic/GMT.md)、[CET,UTC,GMT,CST几种常见时间的含义和关系](/basics/java-basic/CET-UTC-GMT-CST.md) - -[SimpleDateFormat的线程安全性问题](/basics/java-basic/simpledateformat-thread-safe.md) - -Java 8中的时间处理 - -如何在东八区的计算机上获取美国时间 - -#### 编码方式 - -什么是ASCII? - -[Unicode](/basics/java-basic/UNICODE.md)、[有了Unicode为啥还需要UTF-8](/basics/java-basic/why-utf8.md) - -[UTF8、UTF16、UTF32区别](/basics/java-basic/UTF8-UTF16-UTF32.md) - -有了UTF8为什么还需要GBK? - -[GBK、GB2312、GB18030之间的区别](/basics/java-basic/gbk-gb2312-gb18030.md) - -[URL编解码](/basics/java-basic/url-encode.md)、[Big Endian和Little Endian](/basics/java-basic/big-endian-vs-little-endian.md) - -如何解决乱码问题 - -#### 语法糖 - -[Java中语法糖原理、解语法糖](/basics/java-basic/syntactic-sugar.md) - -[语法糖:switch 支持 String 与枚举、泛型、自动装箱与拆箱、方法变长参数、枚举、内部类、条件编译、 断言、数值字面量、for-each、try-with-resource、Lambda表达式](/basics/java-basic/syntactic-sugar.md) - -### 阅读源代码 - -String、Integer、Long、Enum、BigDecimal、ThreadLocal、ClassLoader & URLClassLoader、ArrayList & LinkedList、 HashMap & LinkedHashMap & TreeMap & CouncurrentHashMap、HashSet & LinkedHashSet & TreeSet - -### Java并发编程 - -#### 并发与并行 - -什么是并发 - -什么是并行 - -并发与并行的区别 - -#### 线程 - -线程的实现、线程的状态、优先级、线程调度、创建线程的多种方式、守护线程 - -线程与进程的区别 - -#### 线程池 - -自己设计线程池、submit() 和 execute()、线程池原理 - -为什么不允许使用Executors创建线程池 - -#### 线程安全 - -[死锁?](/basics/java-basic/deadlock-java-level.md)、死锁如何排查、线程安全和内存模型的关系 - -#### 锁 - -CAS、乐观锁与悲观锁、数据库相关锁机制、分布式锁、偏向锁、轻量级锁、重量级锁、monitor、 - -锁优化、锁消除、锁粗化、自旋锁、可重入锁、阻塞锁、死锁 - -#### 死锁 - -死锁的原因 - -死锁的解决办法 - -#### synchronized - -[synchronized是如何实现的?](/basics/java-basic/synchronized.md) - -synchronized和lock之间关系、不使用synchronized如何实现一个线程安全的单例 - -synchronized和原子性、可见性和有序性之间的关系 - -#### volatile - -happens-before、内存屏障、编译器指令重排和CPU指令重排 - -volatile的实现原理 - -volatile和原子性、可见性和有序性之间的关系 - -有了symchronized为什么还需要volatile - -#### sleep 和 wait - -#### wait 和 notify - -#### notify 和 notifyAll - -#### ThreadLocal - -#### 写一个死锁的程序 - -#### 写代码来解决生产者消费者问题 - -### 并发包 - -#### 阅读源代码,并学会使用 - -Thread、Runnable、Callable、ReentrantLock、ReentrantReadWriteLock、Atomic*、Semaphore、CountDownLatch、、ConcurrentHashMap、Executors - -## 二、底层篇 - -### JVM - -#### JVM内存结构 - -class文件格式、运行时数据区:堆、栈、方法区、直接内存、运行时常量池、 - -堆和栈区别 - -[Java中的对象一定在堆上分配吗?](/basics/jvm/stack-alloc.md) - -#### Java内存模型 - -计算机内存模型、缓存一致性、MESI协议 - -可见性、原子性、顺序性、happens-before、 - -内存屏障、synchronized、volatile、final、锁 - -#### 垃圾回收 - -GC算法:标记清除、引用计数、复制、标记压缩、分代回收、增量式回收 - -GC参数、对象存活的判定、垃圾收集器(CMS、G1、ZGC、Epsilon) - -#### JVM参数及调优 - --Xmx、-Xmn、-Xms、Xss、-XX:SurvivorRatio、 - --XX:PermSize、-XX:MaxPermSize、-XX:MaxTenuringThreshold - -#### Java对象模型 - -oop-klass、对象头 - -#### HotSpot - -即时编译器、编译优化 - -#### 虚拟机性能监控与故障处理工具 - -jps, jstack, jmap、jstat, jconsole, jinfo, jhat, javap, btrace、TProfiler - -Arthas - -### 类加载机制 - -classLoader、类加载过程、双亲委派(破坏双亲委派)、模块化(jboss modules、osgi、jigsaw) - -### 编译与反编译 - -什么是编译(前端编译、后端编译)、什么是反编译 - -JIT、JIT优化(逃逸分析、栈上分配、标量替换、锁优化) - -编译工具:javac - -反编译工具:javap 、jad 、CRF - -## 三、 进阶篇 - -### Java底层知识 - -#### 字节码、class文件格式 - -#### CPU缓存,L1,L2,L3和伪共享 - -#### 尾递归 - -#### 位运算 - -用位运算实现加、减、乘、除、取余 - -### 设计模式 - -设计模式的六大原则: - -开闭原则(Open Close Principle)、里氏代换原则(Liskov Substitution Principle)、依赖倒转原则(Dependence Inversion Principle) - -接口隔离原则(Interface Segregation Principle)、迪米特法则(最少知道原则)(Demeter Principle)、合成复用原则(Composite Reuse Principle) - -#### 了解23种设计模式 - -创建型模式:单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。 - -结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。 - -行为型模式:模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)、访问者模式。 - -#### 会使用常用设计模式 - -单例的七种写法:懒汉——线程不安全、懒汉——线程安全、饿汉、饿汉——变种、静态内部类、枚举、双重校验锁 - -工厂模式、适配器模式、策略模式、模板方法模式、观察者模式、外观模式、代理模式等必会 - -#### 不用synchronized和lock,实现线程安全的单例模式 - -#### 实现AOP - -#### 实现IOC - -#### nio和reactor设计模式 - -### 网络编程知识 - -#### tcp、udp、http、https等常用协议 - -三次握手与四次关闭、流量控制和拥塞控制、OSI七层模型、tcp粘包与拆包 - -#### http/1.0 http/1.1 http/2之间的区别 - -http中 get和post区别 - -常见的web请求返回的状态码 - -404、302、301、500分别代表什么 - -#### http/3 - -#### Java RMI,Socket,HttpClient - -#### cookie 与 session - -cookie被禁用,如何实现session - -#### 用Java写一个简单的静态文件的HTTP服务器 - -#### 了解nginx和apache服务器的特性并搭建一个对应的服务器 - -#### 用Java实现FTP、SMTP协议 - -#### 进程间通讯的方式 - -#### 什么是CDN?如果实现? - -#### DNS? - -什么是DNS 、记录类型:A记录、CNAME记录、AAAA记录等 - -域名解析、根域名服务器 - -DNS污染、DNS劫持、公共DNS:114 DNS、Google DNS、OpenDNS - -#### 反向代理 - -正向代理、反向代理 - -反向代理服务器 - -### 框架知识 - -#### Servlet - -生命周期 - -线程安全问题 - -filter和listener - -web.xml中常用配置及作用 - -#### Hibernate - -什么是OR Mapping - -Hibernate的缓存机制 - -Hibernate的懒加载 - -Hibernate/Ibatis/MyBatis之间的区别 - -#### Spring - -Bean的初始化 - -AOP原理 - -实现Spring的IOC - -spring四种依赖注入方式 - -#### Spring MVC - -什么是MVC - -Spring mvc与Struts mvc的区别 - -#### Spring Boot - -Spring Boot 2.0、起步依赖、自动配置、 - -Spring Boot的starter原理,自己实现一个starter - -#### Spring Security - -### Spring Cloud - -服务发现与注册:Eureka、Zookeeper、Consul - -负载均衡:Feign、Spring Cloud Loadbalance - -服务配置:Spring Cloud Config - -服务限流与熔断:Hystrix - -服务链路追踪:Dapper - -服务网关、安全、消息 - -### 应用服务器知识 - -#### JBoss - -#### tomcat - -#### jetty - -#### Weblogic - -### 工具 - -#### git & svn - -#### maven & gradle - -#### Intellij IDEA - -常用插件:Maven Helper 、FindBugs-IDEA、阿里巴巴代码规约检测、GsonFormat - -Lombok plugin、.ignore、Mybatis plugin - -## 四、 高级篇 - -### 新技术 - -#### Java 8 - -lambda表达式、Stream API、时间API - -#### Java 9 - -Jigsaw、Jshell、Reactive Streams - -#### Java 10 - -局部变量类型推断、G1的并行Full GC、ThreadLocal握手机制 - -#### Java 11 - -ZGC、Epsilon、增强var、 - -#### Spring 5 - -响应式编程 - -#### Spring Boot 2.0 - -### http/2 - -### http/3 - -### 性能优化 - -使用单例、使用Future模式、使用线程池、选择就绪、减少上下文切换、减少锁粒度、数据压缩、结果缓存 - -### 线上问题分析 - -#### dump获取 - -线程Dump、内存Dump、gc情况 - -#### dump分析 - -分析死锁、分析内存泄露 - -#### dump分析及获取工具 - -jstack、jstat、jmap、jhat、Arthas - -#### 自己编写各种outofmemory,stackoverflow程序 - -HeapOutOfMemory、 Young OutOfMemory、MethodArea OutOfMemory、ConstantPool OutOfMemory、DirectMemory OutOfMemory、Stack OutOfMemory Stack OverFlow - -#### Arthas - -jvm相关、class/classloader相关、monitor/watch/trace相关、 - -options、管道、后台异步任务 - -文档:https://alibaba.github.io/arthas/advanced-use.html - -#### 常见问题解决思路 - -内存溢出、线程死锁、类加载冲突 - -#### 使用工具尝试解决以下问题,并写下总结 - -当一个Java程序响应很慢时如何查找问题、 - -当一个Java程序频繁FullGC时如何解决问题、 - -如何查看垃圾回收日志、 - -当一个Java应用发生OutOfMemory时该如何解决、 - -如何判断是否出现死锁、 - -如何判断是否存在内存泄露 - -使用Arthas快速排查Spring Boot应用404/401问题 - -使用Arthas排查线上应用日志打满问题 - -利用Arthas排查Spring Boot应用NoSuchMethodError - -### 编译原理知识 - -#### 编译与反编译 - -#### Java代码的编译与反编译 - -#### Java的反编译工具 - -javap 、jad 、CRF - -#### 即时编译器 - -#### 词法分析,语法分析(LL算法,递归下降算法,LR算法),语义分析,运行时环境,中间代码,代码生成,代码优化 - -### 操作系统知识 - -#### Linux的常用命令 - -#### 进程间通信 - -#### 进程同步 - -生产者消费者问题、哲学家就餐问题、读者写者问题 - -#### 缓冲区溢出 - -#### 分段和分页 - -#### 虚拟内存与主存 - -#### 虚拟内存管理 - -#### 换页算法 - -### 数据库知识 - -#### MySql 执行引擎 - -#### MySQL 执行计划 - -如何查看执行计划,如何根据执行计划进行SQL优化 - -#### 索引 - -Hash索引、B树索引(B+树、和B树、R树) - -普通索引、唯一索引 - -覆盖索引、最左前缀原则、索引下推 - -#### SQL优化 - -#### 数据库事务和隔离级别 - -事务的隔离级别、事务能不能实现锁的功能 - -#### 数据库锁 - -行锁、表锁、使用数据库锁实现乐观锁、 - -#### 连接 - -内连接,左连接,右连接 - -#### 数据库主备搭建 - -#### binlog - -#### redolog - -#### 内存数据库 - -h2 - -#### 分库分表 - -#### 读写分离 - -#### 常用的nosql数据库 - -redis、memcached - -#### 分别使用数据库锁、NoSql实现分布式锁 - -#### 性能调优 - -#### 数据库连接池 - -### 数据结构与算法知识 - -#### 简单的数据结构 - -栈、队列、链表、数组、哈希表、 - -栈和队列的相同和不同之处 - -栈通常采用的两种存储结构 - -#### 树 - -二叉树、字典树、平衡树、排序树、B树、B+树、R树、多路树、红黑树 - -#### 堆 - -大根堆、小根堆 - -#### 图 - -有向图、无向图、拓扑 - -#### 排序算法 - -稳定的排序:冒泡排序、插入排序、鸡尾酒排序、桶排序、计数排序、归并排序、原地归并排序、二叉排序树排序、鸽巢排序、基数排序、侏儒排序、图书馆排序、块排序 - -不稳定的排序:选择排序、希尔排序、Clover排序算法、梳排序、堆排序、平滑排序、快速排序、内省排序、耐心排序 - -各种排序算法和时间复杂度 - -#### 深度优先和广度优先搜索 - -#### 全排列、贪心算法、KMP算法、hash算法 - -#### 海量数据处理 - -分治,hash映射,堆排序,双层桶划分,Bloom Filter,bitmap,数据库索引,mapreduce等。 - -#### 两个栈实现队列,和两个队列实现栈 - -### 大数据知识 - -#### Zookeeper - -基本概念、常见用法 - -#### Solr,Lucene,ElasticSearch - -在linux上部署solr,solrcloud,,新增、删除、查询索引 - -#### Storm,流式计算,了解Spark,S4 - -在linux上部署storm,用zookeeper做协调,运行storm hello world,local和remote模式运行调试storm topology。 - -#### Hadoop,离线计算 - -HDFS、MapReduce - -#### 分布式日志收集flume,kafka,logstash - -#### 数据挖掘,mahout - -### 网络安全知识 - -#### XSS - -XSS的防御 - -#### CSRF - -#### 注入攻击 - -SQL注入、XML注入、CRLF注入 - -#### 文件上传漏洞 - -#### 加密与解密 - -对称加密、非对称加密、哈希算法、加盐哈希算法 - -MD5,SHA1、DES、AES、RSA、DSA - -彩虹表 - -#### DDOS攻击 - -DOS攻击、DDOS攻击 - -memcached为什么可以导致DDos攻击、什么是反射型DDoS - -如何通过Hash碰撞进行DOS攻击 - -#### SSL、TLS,HTTPS - -#### 用openssl签一个证书部署到apache或nginx - -## 五、架构篇 - -### 分布式 - -数据一致性、服务治理、服务降级 - -#### 分布式事务 - -2PC、3PC、CAP、BASE、 可靠消息最终一致性、最大努力通知、TCC - -#### Dubbo - -服务注册、服务发现,服务治理 - -http://dubbo.apache.org/zh-cn/ - -#### 分布式数据库 - -怎样打造一个分布式数据库、什么时候需要分布式数据库、mycat、otter、HBase - -#### 分布式文件系统 - -mfs、fastdfs - -#### 分布式缓存 - -缓存一致性、缓存命中率、缓存冗余 - -#### 限流降级 - -Hystrix、Sentinal - -#### 算法 - -共识算法、Raft协议、Paxos 算法与 Raft 算法、拜占庭问题与算法 - -2PC、3PC - -### 微服务 - -SOA、康威定律 - -#### ServiceMesh - -sidecar - -#### Docker & Kubernets - -#### Spring Boot - -#### Spring Cloud - -### 高并发 - -#### 分库分表 - -#### CDN技术 - -#### 消息队列 - -ActiveMQ - -### 监控 - -#### 监控什么 - -CPU、内存、磁盘I/O、网络I/O等 - -#### 监控手段 - -进程监控、语义监控、机器资源监控、数据波动 - -#### 监控数据采集 - -日志、埋点 - -#### Dapper - -### 负载均衡 - -tomcat负载均衡、Nginx负载均衡 - -四层负载均衡、七层负载均衡 - -### DNS - -DNS原理、DNS的设计 - -### CDN - -数据一致性 - -## 六、 扩展篇 - -### 云计算 - -IaaS、SaaS、PaaS、虚拟化技术、openstack、Serverlsess - -### 搜索引擎 - -Solr、Lucene、Nutch、Elasticsearch - -### 权限管理 - -Shiro +目前正在更新中... -### 区块链 +欢迎大家参与共建~ -哈希算法、Merkle树、公钥密码算法、共识算法、Raft协议、Paxos 算法与 Raft 算法、拜占庭问题与算法、消息认证码与数字签名 +### 在线阅读地址 -#### 比特币 +GitHub Pages 完整阅读:[进入](https://hollischuang.github.io/toBeTopJavaer/) -挖矿、共识机制、闪电网络、侧链、热点问题、分叉 +Gitee Pages 完整阅读:[进入](http://hollischuang.gitee.io/tobetopjavaer) (国内访问速度较快) -#### 以太坊 -#### 超级账本 +### 关于作者 -### 人工智能 +Hollis,阿里巴巴技术专家,51CTO专栏作家,CSDN博客专家,掘金优秀作者,《程序员的三门课》联合作者,《Java工程师成神之路》系列文章作者;热衷于分享计算机编程相关技术,博文全网阅读量上千万。 -数学基础、机器学习、人工神经网络、深度学习、应用场景。 -#### 常用框架 +### 开源协议 -TensorFlow、DeepLearning4J +本着互联网的开放精神,本项目采用开放的[GPL]协议进行许可。 -### IoT -### 量子计算 +### 参与共建 -### AR & VR +如果您对本项目中的内容有建议或者意见 -### 其他语言 +如果你对本项目中未完成的章节感兴趣 -Groovy、Python、Go、NodeJs、Swift、Rust +欢迎提出专业方面的修改建议及供稿,供稿只接受原创 -## 六、 推荐书籍 +请直接在[GitHub](https://github.com/hollischuang/toBeTopJavaer)上以issue或者PR的形式提出 -《深入理解Java虚拟机》 -《Effective Java》 -《深入分析Java Web技术内幕》 -《大型网站技术架构》 -《代码整洁之道》 -《架构整洁之道》 -《Head First设计模式》 -《maven实战》 -《区块链原理、设计与应用》 -《Java并发编程实战》 -《鸟哥的Linux私房菜》 -《从Paxos到Zookeeper》 -《架构即未来》 +如果本项目中的内容侵犯了您的任何权益,欢迎通过邮箱(hollischuang@gmail)与我联系 -------------- -扫描二维码,关注作者微信 +### 联系我们 -![](http://www.hollischuang.com/wp-content/uploads/2018/10/%E4%BA%8C%E7%BB%B4%E7%A0%81%E7%BE%8E%E5%8C%96-1.png) +欢迎关注作者的公众号,可以直接后台留言。 +![](/docs/contact/wechat-hollis.jpg) \ No newline at end of file diff --git a/basics/java-basic/basic-data-types.md b/basics/java-basic/basic-data-types.md deleted file mode 100644 index a4ea2d64246973179bdc70b86c65424c92bb7548..0000000000000000000000000000000000000000 --- a/basics/java-basic/basic-data-types.md +++ /dev/null @@ -1,11 +0,0 @@ -Java中有8种基本数据类型 -分为三大类。 - -字符型:char - -布尔型:boolean - -数值型: -1.整型:byte、short、int、long 2.浮点型:float、double - -String不是基本数据类型,是引用类型。 \ No newline at end of file diff --git a/basics/java-basic/data-structure/list.md b/basics/java-basic/data-structure/list.md deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/basics/jvm/java-object-model.md b/basics/jvm/java-object-model.md deleted file mode 100644 index 3319d3122a37ce7ab3a64a18c6f0c6258b55f0a6..0000000000000000000000000000000000000000 --- a/basics/jvm/java-object-model.md +++ /dev/null @@ -1,14 +0,0 @@ -> 本文是[《成神之路系列文章》](/catalog/catalog.md)中的一篇,主要是关于JVM的一些介绍。 -> -> 持续更新中 - -[JVM内存结构 VS Java内存模型 VS Java对象模型][2] - -[深入理解多线程(二)—— Java的对象模型][3] - -[深入理解多线程(三)—— Java的对象头][4] - - [1]: http://www.hollischuang.com/archives/1001 - [2]: http://www.hollischuang.com/archives/2509 - [3]: http://www.hollischuang.com/archives/1910 - [4]: http://www.hollischuang.com/archives/1953 \ No newline at end of file diff --git a/basics/jvm/jvm-memory-structure.md b/basics/jvm/jvm-memory-structure.md deleted file mode 100644 index 994b67d94806b8983422a57f2c794c290b553e62..0000000000000000000000000000000000000000 --- a/basics/jvm/jvm-memory-structure.md +++ /dev/null @@ -1,28 +0,0 @@ -## Java内存模型,Java内存管理,Java堆和栈,垃圾回收 - -> 本文是[《成神之路系列文章》](/catalog/catalog.md)中的一篇,主要是关于JVM的一些介绍。 -> -> 持续更新中 - -参考文章: - -[Java虚拟机的内存组成以及堆内存介绍][1] - -[Java堆和栈看这篇就够][2] - -[Java虚拟机的堆、栈、堆栈如何去理解?][3] - -[Java 内存之方法区和运行时常量池][4] - -[从0到1起步-跟我进入堆外内存的奇妙世界][5] - -[JVM内存结构 VS Java内存模型 VS Java对象模型][6] - -参考书籍:《深入理解Java虚拟机》 - - [1]: http://www.hollischuang.com/archives/80 - [2]: https://iamjohnnyzhuang.github.io/java/2016/07/12/Java%E5%A0%86%E5%92%8C%E6%A0%88%E7%9C%8B%E8%BF%99%E7%AF%87%E5%B0%B1%E5%A4%9F.html - [3]: https://www.zhihu.com/question/29833675 - [4]: https://mritd.me/2016/03/22/Java-%E5%86%85%E5%AD%98%E4%B9%8B%E6%96%B9%E6%B3%95%E5%8C%BA%E5%92%8C%E8%BF%90%E8%A1%8C%E6%97%B6%E5%B8%B8%E9%87%8F%E6%B1%A0/ - [5]: https://www.jianshu.com/p/50be08b54bee - [6]: http://www.hollischuang.com/archives/2509 diff --git a/catalog/catalog.md b/catalog/catalog.md deleted file mode 100644 index 86a23569012b7c011fd05f71f39f34a896e2d4d4..0000000000000000000000000000000000000000 --- a/catalog/catalog.md +++ /dev/null @@ -1,88 +0,0 @@ -[Java工程师成神之路](https://github.com/hollischuang/toBeTopJavaer)一文介绍了一个普通的Java工程师想要成神需要学习的所有相关知识点。很多内容介绍都是直接抛了一个链接,并且大部分都是英文文档或者相关技术的官网。 - -本系列文章主要从头开始总结[Java工程师成神之路](https://github.com/hollischuang/toBeTopJavaer)一文中介绍的所有知识点。 - -编程界有一句老话,叫做不要重复造轮子。虽然我并不完全认同这句话。但是本系列文章的原则类似:如果网上有人针对某知识点有十分详尽的介绍,那么就直接附上原文地址(绝对不做伸手党),如果实在没有写的好的文章,那么笔者就尝试着总结一下。 - -总结该系列文章的最主要目的就是和所有Javaer共同学习与进步。该系列文章的进展情况会在本文章和我的微信公众帐号中进行同步。希望和大家共同进步!每一个专题学习完之后欢迎大家通过微信公众号(Hollis)和我一起交流。 - -Here We Go! - -### 目录: - -[《成神之路-基础篇》JVM——JVM内存结构](/basics/jvm/jvm-memory-structure.md) - -[《成神之路-基础篇》JVM——Java内存模型](/basics/jvm/java-memory-model.md) - -[《成神之路-基础篇》JVM——Java对象模型](/basics/jvm/java-object-model.md) - -[《成神之路-基础篇》JVM——HotSpot][5] - -[《成神之路-基础篇》JVM——垃圾回收][6] - -[《成神之路-基础篇》JVM——JVM参数及调优][7] - -[《成神之路-基础篇》JVM——常用Java命令][8] - -[《成神之路-基础篇》编译与反编译][9] - -[《成神之路-基础篇》Java基础知识——阅读源代码][10] - -[《成神之路-基础篇》Java基础知识——String相关][11] - -[《成神之路-基础篇》Java基础知识——Java中各种关键字][12] - -[《成神之路-基础篇》Java基础知识——自动拆装箱][13] - -[《成神之路-基础篇》Java基础知识——枚举][14] - -[《成神之路-基础篇》Java基础知识——反射][15] - -[《成神之路-基础篇》Java基础知识——序列化][16] - -[《成神之路-基础篇》Java基础知识——JMS][17] - -[《成神之路-基础篇》Java基础知识——泛型][18] - -[《成神之路-基础篇》Java基础知识——常用的Java工具库][19] - -[《成神之路-基础篇》Java基础知识——单元测试][20] - -[《成神之路-进阶篇》设计模式——设计模式合集][21] - -[《成神之路-高级篇》Java并发编程——锁][22] - -[《成神之路-高级篇》大数据知识—— Zookeeper合集][23] - -[《成神之路-高级篇》网络安全知识—— 解决webx的xss和csrf漏洞][24] - -[《成神之路-进阶篇》网络编程知识——常用协议][25] - -[《成神之路-扩展篇》分布式—— 分布式合集][26] - - [1]: http://www.hollischuang.com/archives/489 - [2]: http://www.hollischuang.com/archives/2374 - [3]: http://www.hollischuang.com/archives/1003 - [4]: http://www.hollischuang.com/archives/2814 - [5]: http://www.hollischuang.com/archives/2822 - [6]: http://www.hollischuang.com/archives/2376 - [7]: http://www.hollischuang.com/archives/2378 - [8]: http://www.hollischuang.com/archives/1034 - [9]: http://www.hollischuang.com/archives/2817 - [10]: http://www.hollischuang.com/archives/1007 - [11]: http://www.hollischuang.com/archives/1330 - [12]: http://www.hollischuang.com/archives/1327 - [13]: http://www.hollischuang.com/archives/2700 - [14]: http://www.hollischuang.com/archives/2829 - [15]: http://www.hollischuang.com/archives/1163 - [16]: http://www.hollischuang.com/archives/1158 - [17]: http://www.hollischuang.com/archives/1226 - [18]: http://www.hollischuang.com/archives/1182 - [19]: http://www.hollischuang.com/archives/2836 - [20]: http://www.hollischuang.com/archives/category/%E7%BB%BC%E5%90%88%E5%BA%94%E7%94%A8/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95 - [21]: http://www.hollischuang.com/archives/category/%E7%BB%BC%E5%90%88%E5%BA%94%E7%94%A8/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F - [22]: http://www.hollischuang.com/archives/2842 - [23]: http://www.hollischuang.com/?s=Zookeeper - [24]: http://www.hollischuang.com/archives/69 - [25]: http://www.hollischuang.com/archives/2846 - [26]: http://www.hollischuang.com/archives/category/%E7%BB%BC%E5%90%88%E5%BA%94%E7%94%A8/%E5%88%86%E5%B8%83%E5%BC%8F diff --git a/docs/README.md b/docs/README.md index 3d17608bf6b6165c5a7794e161f71bb34b20aae0..27ab199e08d20ecc7a7471908787e84eade96cd2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,6 +5,45 @@ | 主要版本 | 更新时间 | 备注 | | ---- | ---------- | -------------- | -| v1.0 | 2015-08-01 | 首次发布 | -| v1.1 | 2018-03-12 | 增加新技术知识、完善知识体系 | +| v3.0 | 2020-03-29 | 知识体系完善
通过GitHub Page搭建,便于阅读| | v2.0 | 2019-02-19 | 结构调整,更适合从入门到精通;
进一步完善知识体系;
新技术补充;| +| v1.1 | 2018-03-12 | 增加新技术知识、完善知识体系 | +| v1.0 | 2015-08-01 | 首次发布 | + +目前正在更新中... + +欢迎大家参与共建~ + +### 关于作者 + +Hollis,阿里巴巴技术专家,51CTO专栏作家,CSDN博客专家,掘金优秀作者,《程序员的三门课》联合作者,《Java工程师成神之路》系列文章作者;热衷于分享计算机编程相关技术,博文全网阅读量上千万。 + + +### 开源协议 + +本着互联网的开放精神,本项目采用开放的[GPL]协议进行许可。 + + +### 参与共建 + +如果您对本项目中的内容有建议或者意见 + +如果你对本项目中未完成的章节感兴趣 + +欢迎提出专业方面的修改建议及供稿,供稿只接受原创 + +请直接在[GitHub](https://github.com/hollischuang/toBeTopJavaer)上以issue或者PR的形式提出 + +如果本项目中的内容侵犯了您的任何权益,欢迎通过邮箱(hollischuang@gmail)与我联系 + +### 在线阅读地址 + +GitHub Pages 完整阅读:[进入](https://hollischuang.github.io/toBeTopJavaer/) + +Gitee Pages 完整阅读:[进入](http://hollischuang.gitee.io/tobetopjavaer) (国内访问速度较快) + +### 联系我们 + +欢迎关注作者的公众号,可以直接后台留言。 + +![](contact/wechat-hollis.jpg) \ No newline at end of file diff --git a/docs/_coverpage.md b/docs/_coverpage.md index 0ba849282e9a62ad0e122d7500dee51fabde0861..41a33050726ad55499a8403cc21525bec9b76f8c 100644 --- a/docs/_coverpage.md +++ b/docs/_coverpage.md @@ -1,5 +1,3 @@ -
-

@@ -18,4 +16,4 @@ -Get Started

+开始阅读

diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 73240027fb4a919cbd722c61f947ce58305b3766..23ed0fe329e7fd98a93eca394b59c4954eb31468 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -1,12 +1,1349 @@ +* 基础篇 -## 一、基础篇 + * 面向对象 + + * 什么是面向对象 + + * [面向对象与面向过程](/basics/object-oriented/object-oriented-vs-procedure-oriented.md) + + * [面向对象的三大基本特征](/basics/object-oriented/characteristics.md) + + * [面向对象的五大基本原则](/basics/object-oriented/principle.md) + * 平台无关性 + + * [Java如何实现的平台无关性的](/basics/object-oriented/platform-independent.md) + + * [JVM还支持哪些语言](/basics/object-oriented/jvm-language.md) + + * 值传递 + + * [值传递、引用传递](/basics/object-oriented/java-pass-by.md) + + * [为什么说Java中只有值传递](/basics/object-oriented/why-pass-by-reference.md) + + * 封装、继承、多态 + * [什么是多态](/basics/object-oriented/polymorphism.md) + + * [方法重写与重载](/basics/object-oriented/overloading-vs-overriding.md) + * Java的继承与实现 + + * [Java的继承与组合](/basics/object-oriented/inheritance-composition.md) + + * [构造函数与默认构造函数](/basics/object-oriented/constructor.md) + + * [类变量、成员变量和局部变量](/basics/object-oriented/variable.md) + + * [成员变量和方法作用域](/basics/object-oriented/scope.md) + + * Java基础知识 + + * 基本数据类型 -### 面向对象 + * [8种基本数据类型](/basics/java-basic/basic-data-types.md) -#### 什么是面向对象 + * [整型中byte、short、int、long的取值范围](/basics/java-basic/integer-scope.md) -* [面向对象、面向过程](../basics/java-basic/object-oriented-vs-procedure-oriented.md) + * [什么是浮点型?](/basics/java-basic/float.md) -* [面向对象的三大基本特征](/basics/java-basic/characteristics.md) + * [什么是单精度和双精度?](/basics/java-basic/single-double-float.md) -* [五大基本原则](/basics/java-basic/principle.md) + * [为什么不能用浮点型表示金额?](/basics/java-basic/float-amount.md) + + * 自动拆装箱 + + * [自动拆装箱](/basics/java-basic/boxing-unboxing.md) + + * [Integer的缓存机制](/basics/java-basic/integer-cache.md) + + * String + + * [字符串的不可变性](/basics/java-basic/final-string.md) + + * [JDK 6和JDK 7中substring的原理及区别](/basics/java-basic/substring.md) + + * replaceFirst、replaceAll、replace区别 + + * [String对“+”的重载](/basics/java-basic/string-append.md) + + * [字符串拼接的几种方式和区别](/basics/java-basic/string-concat.md) + + * [String.valueOf和Integer.toString的区别](/basics/java-basic/value-of-vs-to-string.md) + + * [switch对String的支持](/basics/java-basic/switch-string.md) + * 字符串池 + * 常量池(运行时常量池、Class常量池) + * intern + * Java中各种关键字 + * transient + * instanceof + * volatile + * synchronized + * final + * static + * const + * 集合类 + + * 常用集合类的使用 + + * [ArrayList和LinkedList和Vector的区别](/basics/java-basic/arraylist-vs-linkedlist-vs-vector.md) + + * [SynchronizedList和Vector的区别](/basics/java-basic/synchronizedlist-vector.md) + + * [HashMap、HashTable、ConcurrentHashMap区别](/basics/java-basic/HashMap-HashTable-ConcurrentHashMap.md) + + * [Set和List区别?](/basics/java-basic/set-vs-list.md) + + * [Set如何保证元素不重复?](/basics/java-basic/set-repetition.md) + + * [Java 8中stream相关用法](/basics/java-basic/stream.md) + + * Apache集合处理工具类的使用 + + * 不同版本的JDK中HashMap的实现的区别以及原因 + + * [Collection和Collections区别](/basics/java-basic/Collection-vs-Collections.md) + + * [Arrays.asList获得的List使用时需要注意什么](/basics/java-basic/Arrays-asList.md) + + * [Enumeration和Iterator区别](/basics/java-basic/Enumeration-vs-Iterator.md) + + * [fail-fast 和 fail-safe](/basics/java-basic/fail-fast-vs-fail-safe.md) + + * [CopyOnWriteArrayList](/basics/java-basic/CopyOnWriteArrayList.md) + + * [ConcurrentSkipListMap](/basics/java-basic/ConcurrentSkipListMap.md) + + * 枚举 + + * [枚举的用法](/basics/java-basic/enum-usage.md) + + * [枚举的实现](/basics/java-basic/enum-impl.md) + + * [枚举与单例](/basics/java-basic/enum-singleton.md) + + * Enum类 + + * [Java枚举如何比较](/basics/java-basic/enum-compare.md) + + * [switch对枚举的支持](/basics/java-basic/enum-switch.md) + + * [枚举的序列化如何实现](/basics/java-basic/enum-serializable.md) + + * [枚举的线程安全性问题](/basics/java-basic/enum-thread-safe.md) + + * IO + + * [字符流、字节流](/basics/java-basic/byte-stream-vs-character-stream.md) + + * [输入流、输出流](/basics/java-basic/input-stream-vs-output-stream.md) + + * [同步、异步](/basics/java-basic/synchronized-vs-asynchronization.md) + + * [阻塞、非阻塞](/basics/java-basic/block-vs-non-blocking.md) + + * [Linux 5种IO模型](/basics/java-basic/linux-io.md) + + * [BIO、NIO和AIO的区别、三种IO的用法与原理](/basics/java-basic/bio-vs-nio-vs-aio.md) + + * netty + + * 反射 + + * [反射](/basics/java-basic/reflection.md)与工厂模式、 + + * [反射有什么作用](/basics/java-basic/usage-of-reflection.md) + + * [Class类](/basics/java-basic/Class.md) + + * `java.lang.reflect.*` + + * 动态代理 + + * [静态代理](/basics/java-basic/static-proxy.md) + + * [动态代理](/basics/java-basic/dynamic-proxy.md) + + * [动态代理和反射的关系](/basics/java-basic/dynamic-proxy-vs-reflection.md) + + * [动态代理的几种实现方式](/basics/java-basic/dynamic-proxy-implementation.md) + + * [AOP](/basics/java-basic/aop-vs-proxy.md) + + * 序列化 + + * [什么是序列化与反序列化](basics/java-basic/serialize.md) + * [Java如何实现序列化与反序列化](basics/java-basic/serialize-in-java.md) + * [Serializable 和 Externalizable 有何不同](basics/java-basic/diff-serializable-vs-externalizable.md) + * 为什么序列化 + * [serialVersionUID](basics/java-basic/serialVersionUID.md) + * [为什么serialVersionUID不能随便改](basics/java-basic/serialVersionUID-modify.md) + * [transient](basics/java-basic/transient.md) + * [序列化底层原理](basics/java-basic/serialize-principle.md) + * [序列化与单例模式](basics/java-basic/serialize-singleton.md) + * [protobuf](basics/java-basic/protobuf.md) + * 为什么说序列化并不安全 + + * 注解 + + * [元注解](/basics/java-basic/meta-annotation.md) + * [自定义注解](/basics/java-basic/custom-annotation.md) + * Java中常用注解使用 + * 注解与反射的结合 + + * [如何自定义一个注解?](/basics/java-basic/create-annotation.md) + + * [Spring常用注解](/basics/java-basic/annotation-in-spring.md) + * JMS + + * 什么是Java消息服务 + * JMS消息传送模型 + + * JMX + + * `java.lang.management.*` + * `javax.management.*` + + * 泛型 + + * [什么是泛型](/basics/java-basic/generics.md) + * [类型擦除](/basics/java-basic/type-erasue.md) + * [泛型带来的问题](/basics/java-basic/generics-problem.md) + * [泛型中K T V E ? object等的含义](/basics/java-basic/k-t-v-e.md) + * 泛型各种用法 + + * [限定通配符和非限定通配符](/basics/java-basic/Wildcard-Character.md) + * [上下界限定符extends 和 super](/basics/java-basic/extends-vs-super.md) + + * [`List`和原始类型`List`之间的区别?](/basics/java-basic/genericity-list.md) + + * [`List`和`List`之间的区别是什么?](/basics/java-basic/genericity-list-wildcard.md) + + * 单元测试 + + * junit + * mock + * mockito + * 内存数据库(h2) + + * 正则表达式 + + * `java.lang.util.regex.*` + + * 常用的Java工具库 + + * `commons.lang` + * `commons.*...` + * `guava-libraries` + * `netty` + + * API&SPI + + * API + * [API和SPI的关系和区别](/basics/java-basic/api-vs-spi.md) + + * [如何定义SPI](/basics/java-basic/create-spi.md) + * [SPI的实现原理](/basics/java-basic/spi-principle.md) + + * 异常 + + * [Error和Exception](/basics/java-basic/error-vs-exception.md) + * [异常类型](/basics/java-basic/exception-type.md) + * [异常相关关键字](/basics/java-basic/keyword-about-exception.md) + * [正确处理异常](/basics/java-basic/handle-exception.md) + * [自定义异常](/basics/java-basic/define-exception.md) + * [异常链](/basics/java-basic/exception-chain.md) + * [try-with-resources](/basics/java-basic/try-with-resources.md) + * [finally和return的执行顺序](/basics/java-basic/order-about-finllly-return.md) + + * 时间处理 + + * [时区](/basics/java-basic/time-zone.md) + * [冬令时和夏令时](/basics/java-basic/StandardTime-vs-daylightSavingTime.md) + * [时间戳](/basics/java-basic/timestamp.md) + * Java中时间API + + * [格林威治时间](/basics/java-basic/GMT.md) + * [CET,UTC,GMT,CST几种常见时间的含义和关系](/basics/java-basic/CET-UTC-GMT-CST.md) + + * [SimpleDateFormat的线程安全性问题](/basics/java-basic/simpledateformat-thread-safe.md) + + * [Java 8中的时间处理](/basics/java-basic/time-in-java8.md) + + * [如何在东八区的计算机上获取美国时间](/basics/java-basic/get-los_angeles-time.md) + + * [yyyy和YYYY有什么区别?](/basics/java-basic/YYYY-vs-yyyy.md) + + * 编码方式 + + * [什么是ASCII?](/basics/java-basic/ASCII.md) + + * [Unicode](/basics/java-basic/UNICODE.md) + + * [有了Unicode为啥还需要UTF-8](/basics/java-basic/why-utf8.md) + + * [UTF8、UTF16、UTF32区别](/basics/java-basic/UTF8-UTF16-UTF32.md) + + * 有了UTF8为什么还需要GBK? + + * [GBK、GB2312、GB18030之间的区别](/basics/java-basic/gbk-gb2312-gb18030.md) + + * [URL编解码](/basics/java-basic/url-encode.md) + * [Big Endian和Little Endian](/basics/java-basic/big-endian-vs-little-endian.md) + + * 如何解决乱码问题 + + * 语法糖 + + * [Java中语法糖原理、解语法糖](/basics/java-basic/syntactic-sugar.md) + + * [语法糖介绍](/basics/java-basic/syntactic-sugar.md) + + * 阅读源代码 + + * String + * Integer + * Long + * Enum + * BigDecimal + * ThreadLocal + * ClassLoader & URLClassLoader + * ArrayList & LinkedList + * HashMap & LinkedHashMap & TreeMap & CouncurrentHashMap + * HashSet & LinkedHashSet & TreeSet + + * Java并发编程 + + * 并发与并行 + + * [什么是并发](/basics/concurrent-coding/concurrent.md) + + * [什么是并行](/basics/concurrent-coding/parallel.md) + + * [并发与并行的区别](/basics/concurrent-coding/concurrent-vs-parallel.md) + + * 线程 + + * 线程的实现 + * 线程的状态 + * 线程优先级 + * 线程调度 + * 创建线程的多种方式 + * 守护线程 + * 线程与进程的区别 + + * 线程池 + + * 自己设计线程池 + * submit() 和 execute() + * 线程池原理 + * 为什么不允许使用Executors创建线程池 + + * 线程安全 + + * [死锁?](/basics/concurrent-coding/deadlock-java-level.md) + * 死锁如何排查 + * 线程安全和内存模型的关系 + + * 锁 + + * CAS + * 乐观锁与悲观锁 + * 数据库相关锁机制 + * 分布式锁 + * 偏向锁 + * 轻量级锁 + * 重量级锁 + * monitor + * 锁优化 + * 锁消除 + * 锁粗化 + * 自旋锁 + * 可重入锁 + * 阻塞锁 + + * 死锁 + + * 死锁的原因 + + * 死锁的解决办法 + + * synchronized + + * [synchronized是如何实现的?](/basics/concurrent-coding/synchronized.md) + + * synchronized和lock之间关系 + * 不使用synchronized如何实现一个线程安全的单例 + * synchronized和原子性、可见性和有序性之间的关系 + + * volatile + + * happens-before + * 内存屏障 + * 编译器指令重排和CPU指令重排 + + * volatile的实现原理 + + * volatile和原子性 + * 可见性和有序性之间的关系 + + * 有了symchronized为什么还需要volatile + + * sleep 和 wait + + * wait 和 notify + + * notify 和 notifyAll + + * ThreadLocal + + * 写一个死锁的程序 + + * 写代码来解决生产者消费者问题 + + * 并发包 + + * 阅读源代码,并学会使用 + + * Thread + * Runnable + * Callable + * ReentrantLock + * ReentrantReadWriteLock + * Atomic* + * Semaphore + * CountDownLatch + * ConcurrentHashMap + * Executors + +* 底层篇 + + * JVM + + * JVM内存结构 + + * class文件格式 + * 运行时数据区 + * 堆和栈区别 + * [Java中的对象一定在堆上分配吗?](/basement/jvm/stack-alloc.md) + + * Java内存模型 + + * 计算机内存模型 + * 缓存一致性 + * MESI协议 + + * 可见性 + * 原子性 + * 顺序性 + * happens-before + + * 内存屏障 + * synchronized + * volatile + * final + * 锁 + + * 垃圾回收 + + * GC算法:标记清除、引用计数、复制、标记压缩、分代回收、增量式回收 + + * GC参数 + * 对象存活的判定 + * 垃圾收集器(CMS、G1、ZGC、Epsilon) + + * JVM参数及调优 + + * -Xmx + * -Xmn + * -Xms + * Xss + * -XX:SurvivorRatio + + * -XX:PermSize + * -XX:MaxPermSize + * -XX:MaxTenuringThreshold + + * Java对象模型 + + * oop-klass + * 对象头 + + * HotSpot + + * 即时编译器 + * 编译优化 + + * 虚拟机性能监控与故障处理工具 + + * jps + * jstack + * jmap + * jstat + * jconsole + * jinfo + * jhat + * javap + * btrace + * TProfiler + * jlink + * Arthas + + * 类加载机制 + + * classLoader + * 类加载过程 + * 双亲委派(破坏双亲委派) + * 模块化(jboss modules、osgi、jigsaw) + + * 编译与反编译 + + * 什么是编译(前端编译、后端编译) + * 什么是反编译 + + * JIT + * JIT优化(逃逸分析、栈上分配、标量替换、锁优化) + + * 编译工具:javac + + * 反编译工具:javap 、jad 、CRF + +* 进阶篇 + * Java底层知识 + + * 字节码 + + * class文件格式 + + * CPU缓存,L1,L2,L3和伪共享 + + * 尾递归 + + * 位运算 + + 用位运算实现加、减、乘、除、取余 + + * 设计模式 + + * 设计模式的六大原则 + + * 开闭原则(Open Close Principle) + * 里氏代换原则(Liskov Substitution Principle) + * 依赖倒转原则(Dependence Inversion Principle) + * 接口隔离原则(Interface Segregation Principle) + * 迪米特法则(最少知道原则)(Demeter Principle) + * 合成复用原则(Composite Reuse Principle) + + * 了解23种设计模式 + + * 创建型模式 + * 单例模式 + * 抽象工厂模式 + * 建造者模式 + * 工厂模式 + * 原型模式 + + * 结构型模式 + * 适配器模式 + * 桥接模式 + * 装饰模式 + * 组合模式 + * 外观模式 + * 享元模式 + * 代理模式 + + * 行为型模式 + * 模版方法模式 + * 命令模式 + * 迭代器模式 + * 观察者模式 + * 中介者模式 + * 备忘录模式 + * 解释器模式 + * 状态模式 + * 策略模式 + * 责任链模式 + * 访问者模式 + + * 会使用常用设计模式 + + * 单例的七种写法 + * 懒汉——线程不安全 + * 懒汉——线程安全 + * 饿汉 + * 饿汉——变种 + * 静态内部类 + * 枚举 + * 双重校验锁 + + * 工厂模式 + * 适配器模式 + * 策略模式 + * 模板方法模式 + * 观察者模式 + * 外观模式 + * 代理模式 + + * 不用synchronized和lock,实现线程安全的单例模式 + + * 实现AOP + + * 实现IOC + + * nio和reactor设计模式 + + * 网络编程知识 + + * tcp、udp、http、https等常用协议 + + * 三次握手与四次关闭 + * 流量控制和拥塞控制 + * OSI七层模型 + * tcp粘包与拆包 + + * http/1.0 http/1.1 http/2之间的区别 + + * http中 get和post区别 + + * 常见的web请求返回的状态码 + + * 404、302、301、500分别代表什么 + + * http/2 + + * Java RMI,Socket,HttpClient + + * cookie 与 session + + * cookie被禁用,如何实现session + + * 用Java写一个简单的静态文件的HTTP服务器 + + * 了解nginx和apache服务器的特性并搭建一个对应的服务器 + + * 用Java实现FTP、SMTP协议 + + * 进程间通讯的方式 + + * 什么是CDN?如果实现? + + * DNS? + + * 什么是DNS + * 记录类型:A记录、CNAME记录、AAAA记录等 + + * 域名解析 + * 根域名服务器 + + * DNS污染 + * DNS劫持 + * 公共DNS:114 DNS、Google DNS、OpenDNS + + * 反向代理 + + * 正向代理 + * 反向代理 + + * 反向代理服务器 + + * 框架知识 + + * Servlet + + * 生命周期 + + * 线程安全问题 + + * filter和listener + + * web.xml中常用配置及作用 + + * Hibernate + + * 什么是OR Mapping + + * Hibernate的缓存机制 + + * Hibernate的懒加载 + + * Hibernate/Ibatis/MyBatis之间的区别 + + * Spring + + * Bean的初始化 + + * AOP原理 + + * 实现Spring的IOC + + * spring四种依赖注入方式 + + * Spring MVC + + * 什么是MVC + + * Spring mvc与Struts mvc的区别 + + * Spring Boot + + * Spring Boot 2.0 + * 起步依赖 + * 自动配置 + + * Spring Boot的starter原理 + * 自己实现一个starter + + * Spring Security + + * Spring Cloud + + * 服务发现与注册:Eureka、Zookeeper、Consul + + * 负载均衡:Feign、Spring Cloud Loadbalance + + * 服务配置:Spring Cloud Config + + * 服务限流与熔断:Hystrix + + * 服务链路追踪:Dapper + + * 服务网关、安全、消息 + + * 应用服务器知识 + + * JBoss + + * tomcat + + * jetty + + * Weblogic + + * 工具 + + * git & svn + + * maven & gradle + + * Intellij IDEA + + * 常用插件: + * Maven Helper + * FindBugs-IDEA + * 阿里巴巴代码规约检测 + * GsonFormat + + * Lombok plugin + * .ignore + * Mybatis plugin + +* 高级篇 + + * 新技术 + + * Java 8 + + * lambda表达式 + * Stream API + * 时间API + + * Java 9 + + * Jigsaw + * Jshell + * Reactive Streams + + * Java 10 + + * 局部变量类型推断 + * G1的并行Full GC + * ThreadLocal握手机制 + + * Java 11 + + * ZGC + * Epsilon + * 增强var + * Java 12 + + * Switch 表达式 + + * Java 13 + + * Text Blocks + * Dynamic CDS Archives + + * Java 14 + + * Java打包工具 + * 更有价值的NullPointerException + * record类型 + + * Spring 5 + + * 响应式编程 + + * Spring Boot 2.0 + + * http/2 + + * http/3 + + * 性能优化 + + * 使用单例 + * 使用Future模式 + * 使用线程池 + * 选择就绪 + * 减少上下文切换 + * 减少锁粒度 + * 数据压缩 + * 结果缓存 + + * 线上问题分析 + + * dump获取 + + * 线程Dump + * 内存Dump + * gc情况 + + * dump分析 + + * 分析死锁 + * 分析内存泄露 + + * dump分析及获取工具 + + * jstack + * jstat + * jmap + * jhat + * Arthas + + * 自己编写各种outofmemory,stackoverflow程序 + + * HeapOutOfMemory + * Young OutOfMemory + * MethodArea OutOfMemory + * ConstantPool OutOfMemory + * DirectMemory OutOfMemory + * Stack OutOfMemory Stack OverFlow + + * Arthas + + * jvm相关 + * class/classloader相关 + * monitor/watch/trace相关 + + * options + * 管道 + * 后台异步任务 + + * 常见问题解决思路 + + * 内存溢出 + * 线程死锁 + * 类加载冲突 + + * 使用工具尝试解决以下问题,并写下总结 + + * 当一个Java程序响应很慢时如何查找问题 + + * 当一个Java程序频繁FullGC时如何解决问题 + + * 如何查看垃圾回收日志 + + * 当一个Java应用发生OutOfMemory时该如何解决 + + * 如何判断是否出现死锁 + + * 如何判断是否存在内存泄露 + + * 使用Arthas快速排查Spring Boot应用404/401问题 + + * 使用Arthas排查线上应用日志打满问题 + + * 利用Arthas排查Spring Boot应用NoSuchMethodError + + * 编译原理知识 + + * 编译与反编译 + + * Java代码的编译与反编译 + + * Java的反编译工具 + + * javap + * jad + * CRF + + * 即时编译器 + + * 词法分析,语法分析(LL算法,递归下降算法,LR算法),语义分析,运行时环境,中间代码,代码生成,代码优化 + + * 操作系统知识 + + * Linux的常用命令 + + * 进程间通信 + + * 进程同步 + + * 生产者消费者问题 + * 哲学家就餐问题 + * 读者写者问题 + + * 缓冲区溢出 + + * 分段和分页 + + * 虚拟内存与主存 + + * 虚拟内存管理 + + * 换页算法 + + * 数据库知识 + + * MySql 执行引擎 + + * MySQL 执行计划 + + * 如何查看执行计划 + * 如何根据执行计划进行SQL优化 + + * 索引 + + * Hash索引 + * B树索引(B+树、和B树、R树) + + * 普通索引 + * 唯一索引 + + * 覆盖索引 + * 最左前缀原则 + * 索引下推 + + * SQL优化 + + * 数据库事务和隔离级别 + + * 事务的隔离级别 + * 事务能不能实现锁的功能 + + * 数据库锁 + + * 行锁 + * 表锁 + * 使用数据库锁实现乐观锁 + + * 连接 + + * 内连接 + * 左连接 + * 右连接 + + * 数据库主备搭建 + + * binlog + + * redolog + + * 内存数据库 + + * h2 + + * 分库分表 + + * 读写分离 + + * 常用的nosql数据库 + + * redis + * memcached + + * 分别使用数据库锁、NoSql实现分布式锁 + + * 性能调优 + + * 数据库连接池 + + * 数据结构与算法知识 + + * 简单的数据结构 + + * 栈 + * 队列 + * 链表 + * 数组* 哈希表 + + * 栈和队列的相同和不同之处 + + * 栈通常采用的两种存储结构 + + * 树 + + * 二叉树 + * 字典树 + * 平衡树 + * 排序树 + * B树 + * B+树 + * R树 + * 多路树 + * 红黑树 + + * 堆 + + * 大根堆 + * 小根堆 + + * 图 + + * 有向图 + * 无向图 + * 拓扑 + + * 排序算法 + + * 稳定的排序 + * 冒泡排序 + * 插入排序 + * 鸡尾酒排序 + * 桶排序 + * 计数排序 + * 归并排序 + * 原地归并排序 + * 二叉排序树排序 + * 鸽巢排序 + * 基数排序 + * 侏儒排序 + * 图书馆排序 + * 块排序 + + * 不稳定的排序 + * 选择排序 + * 希尔排序 + * Clover排序算法 + * 梳排序 + * 堆排序 + * 平滑排序 + * 快速排序 + * 内省排序 + * 耐心排序 + + * 各种排序算法和时间复杂度 + + * 深度优先和广度优先搜索 + + * 全排列 + * 贪心算法 + * KMP算法 + * hash算法 + + * 海量数据处理 + + * 分治 + * hash映射 + * 堆排序 + * 双层桶划分 + * Bloom Filter + * bitmap + * 数据库索引 + * mapreduce等。 + + * 两个栈实现队列,和两个队列实现栈 + + * 大数据知识 + + * Zookeeper + + * 基本概念 + * 常见用法 + + * Solr,Lucene,ElasticSearch + + * 在linux上部署solr + * solrcloud,新增、删除、查询索引 + + * Storm,流式计算,了解Spark,S4 + + * 在linux上部署storm + * 用zookeeper做协调 + * 运行storm hello world + * local和remote模式运行调试storm topology + + * Hadoop,离线计算 + + * HDFS + * MapReduce + + * 分布式日志收集flume,kafka,logstash + + * 数据挖掘,mahout + + * 网络安全知识 + + * XSS + + * XSS的防御 + + * CSRF + + * 注入攻击 + + * SQL注入 + * XML注入 + * CRLF注入 + + * 文件上传漏洞 + + * 加密与解密 + + * 对称加密 + * 非对称加密 + * 哈希算法 + * 加盐哈希算法 + + * MD5,SHA1、DES、AES、RSA、DSA + + * 彩虹表 + + * DDOS攻击 + + * DOS攻击 + * DDOS攻击 + + * memcached为什么可以导致DDos攻击 + * 什么是反射型DDoS + + * 如何通过Hash碰撞进行DOS攻击 + + * SSL、TLS,HTTPS + + * 用openssl签一个证书部署到apache或nginx + +* 架构篇 + + * 分布式 + + * 数据一致性 + * 服务治理 + * 服务降级 + * 分布式理论 + * 2PC + * 3PC + * CAP + * BASE + + * 分布式事务 + * 可靠消息最终一致性 + * 最大努力通知 + * TCC + + * Dubbo + + * 服务注册 + * 服务发现 + * 服务治理 + + * 分布式数据库 + + * 怎样打造一个分布式数据库 + * 什么时候需要分布式数据库 + * mycat + * otter + * HBase + + * 分布式文件系统 + + * mfs + * fastdfs + + * 分布式缓存 + + * 缓存一致性 + * 缓存命中率 + * 缓存冗余 + + * 限流降级 + + * Hystrix + * Sentinal + + * 算法 + + * 共识算法 + * Raft协议 + * Paxos 算法与 Raft 算法 + * 拜占庭问题与算法 + + * 2PC + * 3PC + + * 微服务 + + * SOA + * 康威定律 + + * ServiceMesh + + * sidecar + + * Docker & Kubernets + + * Spring Boot + + * Spring Cloud + + * 高并发 + + * 分库分表 + + * CDN技术 + + * 消息队列 + + * ActiveMQ + + * 监控 + + * 监控什么 + + * CPU + * 内存 + * 磁盘I/O + * 网络I/O等 + + * 监控手段 + + * 进程监控 + * 语义监控 + * 机器资源监控 + * 数据波动 + + * 监控数据采集 + + * 日志 + * 埋点 + + * Dapper + + * 负载均衡 + + * tomcat负载均衡 + * Nginx负载均衡 + + * 四层负载均衡 + * 七层负载均衡 + + * DNS + + * DNS原理 + * DNS的设计 + + * CDN + + * 数据一致性 + +* 扩展篇 + + * 云计算 + + * IaaS + * SaaS + * PaaS + * 虚拟化技术 + * openstack + * Serverlsess + + * 搜索引擎 + + * Solr + * Lucene + * Nutch + * Elasticsearch + + * 权限管理 + + * Shiro + + * 区块链 + + * 哈希算法 + * Merkle树 + * 公钥密码算法 + * 共识算法 + * Raft协议 + * Paxos 算法与 Raft 算法 + * 拜占庭问题与算法 + * 消息认证码与数字签名 + + * 比特币 + + * 挖矿 + * 共识机制 + * 闪电网络 + * 侧链 + * 热点问题 + * 分叉 + + * 以太坊 + + * 超级账本 + + * 人工智能 + + * 数学基础 + * 机器学习 + * 人工神经网络 + * 深度学习 + * 应用场景 + + * 常用框架 + + * TensorFlow + * DeepLearning4J + + * IoT + + * 量子计算 + + * AR & VR + + * 其他语言 + + * Groovy + * Kotlin + * Python + * Go + * NodeJs + * Swift + * Rust +* 推荐书籍 + + *《深入理解Java虚拟机》 + + *《Effective Java》 + + *《深入分析Java Web技术内幕》 + + *《大型网站技术架构》 + + *《代码整洁之道》 + + *《架构整洁之道》 + + *《Head First设计模式》 + + *《maven实战》 + + *《区块链原理、设计与应用》 + + *《Java并发编程实战》 + + *《鸟哥的Linux私房菜》 + + *《从Paxos到Zookeeper》 + + *《架构即未来》 diff --git a/docs/basement/_sidebar.md b/docs/basement/_sidebar.md new file mode 100644 index 0000000000000000000000000000000000000000..5129de0ee8503e29841a940b9ea8db8c9b5c3249 --- /dev/null +++ b/docs/basement/_sidebar.md @@ -0,0 +1,89 @@ +* JVM + + * JVM内存结构 + + * class文件格式 + * 运行时数据区 + * 堆和栈区别 + * [Java中的对象一定在堆上分配吗?](/basement/jvm/stack-alloc.md) + + * Java内存模型 + + * 计算机内存模型 + * 缓存一致性 + * MESI协议 + + * 可见性 + * 原子性 + * 顺序性 + * happens-before + + * 内存屏障 + * synchronized + * volatile + * final + * 锁 + + * 垃圾回收 + + * GC算法:标记清除、引用计数、复制、标记压缩、分代回收、增量式回收 + + * GC参数 + * 对象存活的判定 + * 垃圾收集器(CMS、G1、ZGC、Epsilon) + + * JVM参数及调优 + + * -Xmx + * -Xmn + * -Xms + * Xss + * -XX:SurvivorRatio + + * -XX:PermSize + * -XX:MaxPermSize + * -XX:MaxTenuringThreshold + + * Java对象模型 + + * oop-klass + * 对象头 + + * HotSpot + + * 即时编译器 + * 编译优化 + + * 虚拟机性能监控与故障处理工具 + + * jps + * jstack + * jmap + * jstat + * jconsole + * jinfo + * jhat + * javap + * btrace + * TProfiler + * jlink + * Arthas + +* 类加载机制 + + * classLoader + * 类加载过程 + * 双亲委派(破坏双亲委派) + * 模块化(jboss modules、osgi、jigsaw) + +* 编译与反编译 + + * 什么是编译(前端编译、后端编译) + * 什么是反编译 + + * JIT + * JIT优化(逃逸分析、栈上分配、标量替换、锁优化) + + * 编译工具:javac + + * 反编译工具:javap 、jad 、CRF \ No newline at end of file diff --git a/docs/basement/jvm/_sidebar.md b/docs/basement/jvm/_sidebar.md new file mode 100644 index 0000000000000000000000000000000000000000..57ba225ee6c395c5b0316daa5acff03f6b7da605 --- /dev/null +++ b/docs/basement/jvm/_sidebar.md @@ -0,0 +1,68 @@ +* JVM内存结构 + + * class文件格式 + * 运行时数据区 + * 堆和栈区别 + * [Java中的对象一定在堆上分配吗?](/basement/jvm/stack-alloc.md) + +* Java内存模型 + + * 计算机内存模型 + * 缓存一致性 + * MESI协议 + + * 可见性 + * 原子性 + * 顺序性 + * happens-before + + * 内存屏障 + * synchronized + * volatile + * final + * 锁 + +* 垃圾回收 + + * GC算法:标记清除、引用计数、复制、标记压缩、分代回收、增量式回收 + + * GC参数 + * 对象存活的判定 + * 垃圾收集器(CMS、G1、ZGC、Epsilon) + +* JVM参数及调优 + + * -Xmx + * -Xmn + * -Xms + * Xss + * -XX:SurvivorRatio + + * -XX:PermSize + * -XX:MaxPermSize + * -XX:MaxTenuringThreshold + +* Java对象模型 + + * oop-klass + * 对象头 + +* HotSpot + + * 即时编译器 + * 编译优化 + +* 虚拟机性能监控与故障处理工具 + + * jps + * jstack + * jmap + * jstat + * jconsole + * jinfo + * jhat + * javap + * btrace + * TProfiler + * jlink + * Arthas \ No newline at end of file diff --git a/basics/jvm/java-memory-model.md b/docs/basement/jvm/java-memory-model.md similarity index 100% rename from basics/jvm/java-memory-model.md rename to docs/basement/jvm/java-memory-model.md diff --git a/basics/java-basic/stack-alloc.md b/docs/basement/jvm/stack-alloc.md similarity index 100% rename from basics/java-basic/stack-alloc.md rename to docs/basement/jvm/stack-alloc.md diff --git a/docs/basics/_sidebar.md b/docs/basics/_sidebar.md new file mode 100644 index 0000000000000000000000000000000000000000..bd22850258860296c5d414bbf326a62ed3685710 --- /dev/null +++ b/docs/basics/_sidebar.md @@ -0,0 +1,415 @@ +* 面向对象 + + * 什么是面向对象 + + * [面向对象与面向过程](/basics/object-oriented/object-oriented-vs-procedure-oriented.md) + + * [面向对象的三大基本特征](/basics/object-oriented/characteristics.md) + + * [面向对象的五大基本原则](/basics/object-oriented/principle.md) + * 平台无关性 + + * [Java如何实现的平台无关性的](/basics/object-oriented/platform-independent.md) + + * [JVM还支持哪些语言](/basics/object-oriented/jvm-language.md) + + * 值传递 + + * [值传递、引用传递](/basics/object-oriented/java-pass-by.md) + + * [为什么说Java中只有值传递](/basics/object-oriented/why-pass-by-reference.md) + + * 封装、继承、多态 + * [什么是多态](/basics/object-oriented/polymorphism.md) + + * [方法重写与重载](/basics/object-oriented/overloading-vs-overriding.md) + * Java的继承与实现 + + * [Java的继承与组合](/basics/object-oriented/inheritance-composition.md) + + * [构造函数与默认构造函数](/basics/object-oriented/constructor.md) + + * [类变量、成员变量和局部变量](/basics/object-oriented/variable.md) + + * [成员变量和方法作用域](/basics/object-oriented/scope.md) + +* Java基础知识 + + * 基本数据类型 + + * [8种基本数据类型](/basics/java-basic/basic-data-types.md) + + * [整型中byte、short、int、long的取值范围](/basics/java-basic/integer-scope.md) + + * [什么是浮点型?](/basics/java-basic/float.md) + + * [什么是单精度和双精度?](/basics/java-basic/single-double-float.md) + + * [为什么不能用浮点型表示金额?](/basics/java-basic/float-amount.md) + + * 自动拆装箱 + + * [自动拆装箱](/basics/java-basic/boxing-unboxing.md) + + * [Integer的缓存机制](/basics/java-basic/integer-cache.md) + + * String + + * [字符串的不可变性](/basics/java-basic/final-string.md) + + * [JDK 6和JDK 7中substring的原理及区别](/basics/java-basic/substring.md) + + * replaceFirst、replaceAll、replace区别 + + * [String对“+”的重载](/basics/java-basic/string-append.md) + + * [字符串拼接的几种方式和区别](/basics/java-basic/string-concat.md) + + * [String.valueOf和Integer.toString的区别](/basics/java-basic/value-of-vs-to-string.md) + + * [switch对String的支持](/basics/java-basic/switch-string.md) + * 字符串池 + * 常量池(运行时常量池、Class常量池) + * intern + * Java中各种关键字 + * transient + * instanceof + * volatile + * synchronized + * final + * static + * const + * 集合类 + + * 常用集合类的使用 + + * [ArrayList和LinkedList和Vector的区别](/basics/java-basic/arraylist-vs-linkedlist-vs-vector.md) + + * [SynchronizedList和Vector的区别](/basics/java-basic/synchronizedlist-vector.md) + + * [HashMap、HashTable、ConcurrentHashMap区别](/basics/java-basic/HashMap-HashTable-ConcurrentHashMap.md) + + * [Set和List区别?](/basics/java-basic/set-vs-list.md) + + * [Set如何保证元素不重复?](/basics/java-basic/set-repetition.md) + + * [Java 8中stream相关用法](/basics/java-basic/stream.md) + + * Apache集合处理工具类的使用 + + * 不同版本的JDK中HashMap的实现的区别以及原因 + + * [Collection和Collections区别](/basics/java-basic/Collection-vs-Collections.md) + + * [Arrays.asList获得的List使用时需要注意什么](/basics/java-basic/Arrays-asList.md) + + * [Enumeration和Iterator区别](/basics/java-basic/Enumeration-vs-Iterator.md) + + * [fail-fast 和 fail-safe](/basics/java-basic/fail-fast-vs-fail-safe.md) + + * [CopyOnWriteArrayList](/basics/java-basic/CopyOnWriteArrayList.md) + + * [ConcurrentSkipListMap](/basics/java-basic/ConcurrentSkipListMap.md) + + * 枚举 + + * [枚举的用法](/basics/java-basic/enum-usage.md) + + * [枚举的实现](/basics/java-basic/enum-impl.md) + + * [枚举与单例](/basics/java-basic/enum-singleton.md) + + * Enum类 + + * [Java枚举如何比较](/basics/java-basic/enum-compare.md) + + * [switch对枚举的支持](/basics/java-basic/enum-switch.md) + + * [枚举的序列化如何实现](/basics/java-basic/enum-serializable.md) + + * [枚举的线程安全性问题](/basics/java-basic/enum-thread-safe.md) + + * IO + + * [字符流、字节流](/basics/java-basic/byte-stream-vs-character-stream.md) + + * [输入流、输出流](/basics/java-basic/input-stream-vs-output-stream.md) + + * [同步、异步](/basics/java-basic/synchronized-vs-asynchronization.md) + + * [阻塞、非阻塞](/basics/java-basic/block-vs-non-blocking.md) + + * [Linux 5种IO模型](/basics/java-basic/linux-io.md) + + * [BIO、NIO和AIO的区别、三种IO的用法与原理](/basics/java-basic/bio-vs-nio-vs-aio.md) + + * netty + + * 反射 + + * [反射](/basics/java-basic/reflection.md)与工厂模式、 + + * [反射有什么作用](/basics/java-basic/usage-of-reflection.md) + + * [Class类](/basics/java-basic/Class.md) + + * `java.lang.reflect.*` + + * 动态代理 + + * [静态代理](/basics/java-basic/static-proxy.md) + + * [动态代理](/basics/java-basic/dynamic-proxy.md) + + * [动态代理和反射的关系](/basics/java-basic/dynamic-proxy-vs-reflection.md) + + * [动态代理的几种实现方式](/basics/java-basic/dynamic-proxy-implementation.md) + + * [AOP](/basics/java-basic/aop-vs-proxy.md) + + * 序列化 + + * [什么是序列化与反序列化](basics/java-basic/serialize.md) + * [Java如何实现序列化与反序列化](basics/java-basic/serialize-in-java.md) + * [Serializable 和 Externalizable 有何不同](basics/java-basic/diff-serializable-vs-externalizable.md) + * 为什么序列化 + * [serialVersionUID](basics/java-basic/serialVersionUID.md) + * [为什么serialVersionUID不能随便改](basics/java-basic/serialVersionUID-modify.md) + * [transient](basics/java-basic/transient.md) + * [序列化底层原理](basics/java-basic/serialize-principle.md) + * [序列化与单例模式](basics/java-basic/serialize-singleton.md) + * [protobuf](basics/java-basic/protobuf.md) + * 为什么说序列化并不安全 + + * 注解 + + * [元注解](/basics/java-basic/meta-annotation.md) + * [自定义注解](/basics/java-basic/custom-annotation.md) + * Java中常用注解使用 + * 注解与反射的结合 + + * [如何自定义一个注解?](/basics/java-basic/create-annotation.md) + + * [Spring常用注解](/basics/java-basic/annotation-in-spring.md) + * JMS + + * 什么是Java消息服务 + * JMS消息传送模型 + + * JMX + + * `java.lang.management.*` + * `javax.management.*` + + * 泛型 + + * [什么是泛型](/basics/java-basic/generics.md) + * [类型擦除](/basics/java-basic/type-erasue.md) + * [泛型带来的问题](/basics/java-basic/generics-problem.md) + * [泛型中K T V E ? object等的含义](/basics/java-basic/k-t-v-e.md) + * 泛型各种用法 + + * [限定通配符和非限定通配符](/basics/java-basic/Wildcard-Character.md) + * [上下界限定符extends 和 super](/basics/java-basic/extends-vs-super.md) + + * [`List`和原始类型`List`之间的区别?](/basics/java-basic/genericity-list.md) + + * [`List`和`List`之间的区别是什么?](/basics/java-basic/genericity-list-wildcard.md) + + * 单元测试 + + * junit + * mock + * mockito + * 内存数据库(h2) + + * 正则表达式 + + * `java.lang.util.regex.*` + + * 常用的Java工具库 + + * `commons.lang` + * `commons.*...` + * `guava-libraries` + * `netty` + + * API&SPI + + * API + * [API和SPI的关系和区别](/basics/java-basic/api-vs-spi.md) + + * [如何定义SPI](/basics/java-basic/create-spi.md) + * [SPI的实现原理](/basics/java-basic/spi-principle.md) + + * 异常 + + * [Error和Exception](/basics/java-basic/error-vs-exception.md) + * [异常类型](/basics/java-basic/exception-type.md) + * [异常相关关键字](/basics/java-basic/keyword-about-exception.md) + * [正确处理异常](/basics/java-basic/handle-exception.md) + * [自定义异常](/basics/java-basic/define-exception.md) + * [异常链](/basics/java-basic/exception-chain.md) + * [try-with-resources](/basics/java-basic/try-with-resources.md) + * [finally和return的执行顺序](/basics/java-basic/order-about-finllly-return.md) + + * 时间处理 + + * [时区](/basics/java-basic/time-zone.md) + * [冬令时和夏令时](/basics/java-basic/StandardTime-vs-daylightSavingTime.md) + * [时间戳](/basics/java-basic/timestamp.md) + * Java中时间API + + * [格林威治时间](/basics/java-basic/GMT.md) + * [CET,UTC,GMT,CST几种常见时间的含义和关系](/basics/java-basic/CET-UTC-GMT-CST.md) + + * [SimpleDateFormat的线程安全性问题](/basics/java-basic/simpledateformat-thread-safe.md) + + * [Java 8中的时间处理](/basics/java-basic/time-in-java8.md) + + * [如何在东八区的计算机上获取美国时间](/basics/java-basic/get-los_angeles-time.md) + + * [yyyy和YYYY有什么区别?](/basics/java-basic/YYYY-vs-yyyy.md) + + * 编码方式 + + * [什么是ASCII?](/basics/java-basic/ASCII.md) + + * [Unicode](/basics/java-basic/UNICODE.md) + + * [有了Unicode为啥还需要UTF-8](/basics/java-basic/why-utf8.md) + + * [UTF8、UTF16、UTF32区别](/basics/java-basic/UTF8-UTF16-UTF32.md) + + * 有了UTF8为什么还需要GBK? + + * [GBK、GB2312、GB18030之间的区别](/basics/java-basic/gbk-gb2312-gb18030.md) + + * [URL编解码](/basics/java-basic/url-encode.md) + * [Big Endian和Little Endian](/basics/java-basic/big-endian-vs-little-endian.md) + + * 如何解决乱码问题 + + * 语法糖 + + * [Java中语法糖原理、解语法糖](/basics/java-basic/syntactic-sugar.md) + + * [语法糖介绍](/basics/java-basic/syntactic-sugar.md) + + * 阅读源代码 + + * String + * Integer + * Long + * Enum + * BigDecimal + * ThreadLocal + * ClassLoader & URLClassLoader + * ArrayList & LinkedList + * HashMap & LinkedHashMap & TreeMap & CouncurrentHashMap + * HashSet & LinkedHashSet & TreeSet + +* Java并发编程 + + * 并发与并行 + + * [什么是并发](/basics/concurrent-coding/concurrent.md) + + * [什么是并行](/basics/concurrent-coding/parallel.md) + + * [并发与并行的区别](/basics/concurrent-coding/concurrent-vs-parallel.md) + + * 线程 + + * 线程的实现 + * 线程的状态 + * 线程优先级 + * 线程调度 + * 创建线程的多种方式 + * 守护线程 + * 线程与进程的区别 + + * 线程池 + + * 自己设计线程池 + * submit() 和 execute() + * 线程池原理 + * 为什么不允许使用Executors创建线程池 + + * 线程安全 + + * [死锁?](/basics/concurrent-coding/deadlock-java-level.md) + * 死锁如何排查 + * 线程安全和内存模型的关系 + + * 锁 + + * CAS + * 乐观锁与悲观锁 + * 数据库相关锁机制 + * 分布式锁 + * 偏向锁 + * 轻量级锁 + * 重量级锁 + * monitor + * 锁优化 + * 锁消除 + * 锁粗化 + * 自旋锁 + * 可重入锁 + * 阻塞锁 + + * 死锁 + + * 死锁的原因 + + * 死锁的解决办法 + + * synchronized + + * [synchronized是如何实现的?](/basics/concurrent-coding/synchronized.md) + + * synchronized和lock之间关系 + * 不使用synchronized如何实现一个线程安全的单例 + * synchronized和原子性、可见性和有序性之间的关系 + + * volatile + + * happens-before + * 内存屏障 + * 编译器指令重排和CPU指令重排 + + * volatile的实现原理 + + * volatile和原子性 + * 可见性和有序性之间的关系 + + * 有了symchronized为什么还需要volatile + + * sleep 和 wait + + * wait 和 notify + + * notify 和 notifyAll + + * ThreadLocal + + * 写一个死锁的程序 + + * 写代码来解决生产者消费者问题 + +* 并发包 + + * 阅读源代码,并学会使用 + + * Thread + * Runnable + * Callable + * ReentrantLock + * ReentrantReadWriteLock + * Atomic* + * Semaphore + * CountDownLatch + * ConcurrentHashMap + * Executors + \ No newline at end of file diff --git a/docs/basics/concurrent-coding/_sidebar.md b/docs/basics/concurrent-coding/_sidebar.md new file mode 100644 index 0000000000000000000000000000000000000000..c0144d9251edb7bf21eceb27e7c68a8a4d6ed6a6 --- /dev/null +++ b/docs/basics/concurrent-coding/_sidebar.md @@ -0,0 +1,102 @@ +* 并发与并行 + + * [什么是并发](/basics/concurrent-coding/concurrent.md) + + * [什么是并行](/basics/concurrent-coding/parallel.md) + + * [并发与并行的区别](/basics/concurrent-coding/concurrent-vs-parallel.md) + +* 线程 + + * 线程的实现 + * 线程的状态 + * 线程优先级 + * 线程调度 + * 创建线程的多种方式 + * 守护线程 + * 线程与进程的区别 + +* 线程池 + + * 自己设计线程池 + * submit() 和 execute() + * 线程池原理 + * 为什么不允许使用Executors创建线程池 + +* 线程安全 + + * [死锁?](/basics/concurrent-coding/deadlock-java-level.md) + * 死锁如何排查 + * 线程安全和内存模型的关系 + +* 锁 + + * CAS + * 乐观锁与悲观锁 + * 数据库相关锁机制 + * 分布式锁 + * 偏向锁 + * 轻量级锁 + * 重量级锁 + * monitor + * 锁优化 + * 锁消除 + * 锁粗化 + * 自旋锁 + * 可重入锁 + * 阻塞锁 + +* 死锁 + + * 死锁的原因 + + * 死锁的解决办法 + +* synchronized + + * [synchronized是如何实现的?](/basics/concurrent-coding/synchronized.md) + + * synchronized和lock之间关系 + * 不使用synchronized如何实现一个线程安全的单例 + * synchronized和原子性、可见性和有序性之间的关系 + +* volatile + + * happens-before + * 内存屏障 + * 编译器指令重排和CPU指令重排 + + * volatile的实现原理 + + * volatile和原子性 + * 可见性和有序性之间的关系 + + * 有了symchronized为什么还需要volatile + +* sleep 和 wait + +* wait 和 notify + +* notify 和 notifyAll + +* ThreadLocal + +* 写一个死锁的程序 + +* 写代码来解决生产者消费者问题 + +* 并发包 + +* 阅读源代码,并学会使用 + + * Thread + * Runnable + * Callable + * ReentrantLock + * ReentrantReadWriteLock + * Atomic* + * Semaphore + * CountDownLatch + * ConcurrentHashMap + * Executors + \ No newline at end of file diff --git a/docs/basics/concurrent-coding/concurrent-vs-parallel.md b/docs/basics/concurrent-coding/concurrent-vs-parallel.md new file mode 100644 index 0000000000000000000000000000000000000000..d815168d1a3428d66bcc481da5fdcd1c4768b4e6 --- /dev/null +++ b/docs/basics/concurrent-coding/concurrent-vs-parallel.md @@ -0,0 +1,7 @@ +Erlang 之父 Joe Armstrong 用一张比较形象的图解释了并发与并行的区别: + +![](http://www.hollischuang.com/wp-content/uploads/2018/12/CON.jpg) + +并发是两个队伍交替使用一台咖啡机。并行是两个队伍同时使用两台咖啡机。 + +映射到计算机系统中,上图中的咖啡机就是CPU,两个队伍指的就是两个进程。 diff --git a/docs/basics/concurrent-coding/concurrent.md b/docs/basics/concurrent-coding/concurrent.md new file mode 100644 index 0000000000000000000000000000000000000000..4f14ebbfce4e5abdc409b7c5c15ad1375afa9a6e --- /dev/null +++ b/docs/basics/concurrent-coding/concurrent.md @@ -0,0 +1,13 @@ +并发(Concurrent),在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。 + +那么,操作系统视如何实现这种并发的呢? + +现在我们用到操作系统,无论是Windows、Linux还是MacOS等其实都是**多用户多任务分时操作系统**。使用这些操作系统的用户是可以“同时”干多件事的。 + +但是实际上,对于单CPU的计算机来说,在CPU中,同一时间是只能干一件事儿的。为了看起来像是“同时干多件事”,分时操作系统是把CPU的时间划分成长短基本相同的时间区间,即”时间片”,通过操作系统的管理,把这些时间片依次轮流地分配给各个用户使用。 + +如果某个作业在时间片结束之前,整个任务还没有完成,那么该作业就被暂停下来,放弃CPU,等待下一轮循环再继续做.此时CPU又分配给另一个作业去使用。 + +由于计算机的处理速度很快,只要时间片的间隔取得适当,那么一个用户作业从用完分配给它的一个时间片到获得下一个CPU时间片,中间有所”停顿”,但用户察觉不出来,好像整个系统全由它”独占”似的。 + +所以,在单CPU的计算机中,我们看起来“同时干多件事”,其实是通过CPU时间片技术,并发完成的。 diff --git a/basics/java-basic/deadlock-java-level.md b/docs/basics/concurrent-coding/deadlock-java-level.md similarity index 100% rename from basics/java-basic/deadlock-java-level.md rename to docs/basics/concurrent-coding/deadlock-java-level.md diff --git a/docs/basics/concurrent-coding/parallel.md b/docs/basics/concurrent-coding/parallel.md new file mode 100644 index 0000000000000000000000000000000000000000..2ab6b0d0aa66ec74c1b318fbd28193408fd2eb00 --- /dev/null +++ b/docs/basics/concurrent-coding/parallel.md @@ -0,0 +1,2 @@ + +并行(Parallel),当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。 \ No newline at end of file diff --git a/basics/java-basic/synchronized.md b/docs/basics/concurrent-coding/synchronized.md similarity index 100% rename from basics/java-basic/synchronized.md rename to docs/basics/concurrent-coding/synchronized.md diff --git a/docs/basics/java-basic/ASCII.md b/docs/basics/java-basic/ASCII.md new file mode 100644 index 0000000000000000000000000000000000000000..ddfe639f6736e20f6ecfb0dc8cdb5241b9f35e5d --- /dev/null +++ b/docs/basics/java-basic/ASCII.md @@ -0,0 +1,16 @@ +ASCII( American Standard Code for InformationInterchange, 美国信息交换标准代码) 是基于拉丁字母的⼀套电脑编码系统, 主要⽤于显⽰现代英语和其他西欧语⾔。 + +它是现今最通⽤的单字节编码系统, 并等同于国际标准ISO/IEC646。 + +标准ASCII 码也叫基础ASCII码, 使⽤7 位⼆进制数( 剩下的1位⼆进制为0) 来表⽰所有的⼤写和⼩写字母, 数字0 到9、 标点符号, 以及在美式英语中使⽤的特殊控制字符。 + + +其中: + +0~31及127(共33个)是控制字符或通信专⽤字符( 其余为可显⽰字符) , 如控制符: LF( 换⾏) 、 CR( 回车) 、 FF( 换页) 、 DEL( 删除) 、 BS( 退格)、 BEL( 响铃) 等; 通信专⽤字符: SOH( ⽂头) 、 EOT( ⽂尾) 、 ACK( 确认) 等; + +ASCII值为8、 9、 10 和13 分别转换为退格、 制表、 换⾏和回车字符。 它们并没有特定的图形显⽰, 但会依不同的应⽤程序,⽽对⽂本显⽰有不同的影响 + +32~126(共95个)是字符(32是空格) , 其中48~57为0到9⼗个阿拉伯数字。 + +65~90为26个⼤写英⽂字母, 97~122号为26个⼩写英⽂字母, 其余为⼀些标点符号、 运算符号等。 \ No newline at end of file diff --git a/basics/java-basic/Arrays-asList.md b/docs/basics/java-basic/Arrays-asList.md similarity index 100% rename from basics/java-basic/Arrays-asList.md rename to docs/basics/java-basic/Arrays-asList.md diff --git a/basics/java-basic/CET-UTC-GMT-CST.md b/docs/basics/java-basic/CET-UTC-GMT-CST.md similarity index 100% rename from basics/java-basic/CET-UTC-GMT-CST.md rename to docs/basics/java-basic/CET-UTC-GMT-CST.md diff --git a/basics/java-basic/Class.md b/docs/basics/java-basic/Class.md similarity index 100% rename from basics/java-basic/Class.md rename to docs/basics/java-basic/Class.md diff --git a/basics/java-basic/Collection-vs-Collections.md b/docs/basics/java-basic/Collection-vs-Collections.md similarity index 100% rename from basics/java-basic/Collection-vs-Collections.md rename to docs/basics/java-basic/Collection-vs-Collections.md diff --git a/basics/java-basic/ConcurrentSkipListMap.md b/docs/basics/java-basic/ConcurrentSkipListMap.md similarity index 100% rename from basics/java-basic/ConcurrentSkipListMap.md rename to docs/basics/java-basic/ConcurrentSkipListMap.md diff --git a/basics/java-basic/CopyOnWriteArrayList.md b/docs/basics/java-basic/CopyOnWriteArrayList.md similarity index 100% rename from basics/java-basic/CopyOnWriteArrayList.md rename to docs/basics/java-basic/CopyOnWriteArrayList.md diff --git a/basics/java-basic/Enumeration-vs-Iterator.md b/docs/basics/java-basic/Enumeration-vs-Iterator.md similarity index 100% rename from basics/java-basic/Enumeration-vs-Iterator.md rename to docs/basics/java-basic/Enumeration-vs-Iterator.md diff --git a/basics/java-basic/GMT.md b/docs/basics/java-basic/GMT.md similarity index 100% rename from basics/java-basic/GMT.md rename to docs/basics/java-basic/GMT.md diff --git a/basics/java-basic/HashMap-HashTable-ConcurrentHashMap.md b/docs/basics/java-basic/HashMap-HashTable-ConcurrentHashMap.md similarity index 100% rename from basics/java-basic/HashMap-HashTable-ConcurrentHashMap.md rename to docs/basics/java-basic/HashMap-HashTable-ConcurrentHashMap.md diff --git a/docs/basics/java-basic/README.md b/docs/basics/java-basic/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e6fef94538f84abe34ee3487a738343196f16655 --- /dev/null +++ b/docs/basics/java-basic/README.md @@ -0,0 +1,12 @@ +## To Be Top Javaer - Java工程师成神之路 + +![](https://img.shields.io/badge/version-v2.0.0-green.svg) ![](https://img.shields.io/badge/author-Hollis-yellow.svg) ![](https://img.shields.io/badge/license-GPL-blue.svg) + + +| 主要版本 | 更新时间 | 备注 | +| ---- | ---------- | -------------- | +| v1.0 | 2015-08-01 | 首次发布 | +| v1.1 | 2018-03-12 | 增加新技术知识、完善知识体系 | +| v2.0 | 2019-02-19 | 结构调整,更适合从入门到精通;
进一步完善知识体系;
新技术补充;| + +Java 基础 \ No newline at end of file diff --git a/basics/java-basic/StandardTime-vs-daylightSavingTime.md b/docs/basics/java-basic/StandardTime-vs-daylightSavingTime.md similarity index 100% rename from basics/java-basic/StandardTime-vs-daylightSavingTime.md rename to docs/basics/java-basic/StandardTime-vs-daylightSavingTime.md diff --git a/basics/java-basic/UNICODE.md b/docs/basics/java-basic/UNICODE.md similarity index 100% rename from basics/java-basic/UNICODE.md rename to docs/basics/java-basic/UNICODE.md diff --git a/basics/java-basic/UTF8-UTF16-UTF32.md b/docs/basics/java-basic/UTF8-UTF16-UTF32.md similarity index 100% rename from basics/java-basic/UTF8-UTF16-UTF32.md rename to docs/basics/java-basic/UTF8-UTF16-UTF32.md diff --git a/docs/basics/java-basic/Wildcard-Character.md b/docs/basics/java-basic/Wildcard-Character.md new file mode 100644 index 0000000000000000000000000000000000000000..b9e2a1b005f30d3bb723d7eff7a62ef76f168236 --- /dev/null +++ b/docs/basics/java-basic/Wildcard-Character.md @@ -0,0 +1,10 @@ +`限定通配符`对类型进⾏限制, 泛型中有两种限定通配符: + +表示类型的上界,格式为:<? extends T>,即类型必须为T类型或者T子类 +表示类型的下界,格式为:<? super T>,即类型必须为T类型或者T的父类 + +泛型类型必须⽤限定内的类型来进⾏初始化,否则会导致编译错误。 + + + +`⾮限定通配符`表⽰可以⽤任意泛型类型来替代,类型为 \ No newline at end of file diff --git a/docs/basics/java-basic/YYYY-vs-yyyy.md b/docs/basics/java-basic/YYYY-vs-yyyy.md new file mode 100644 index 0000000000000000000000000000000000000000..cfc552872282e4d9c962c7ff2d636e2055898e59 --- /dev/null +++ b/docs/basics/java-basic/YYYY-vs-yyyy.md @@ -0,0 +1,57 @@ +在使用SimpleDateFormat的时候,需要通过字母来描述时间元素,并组装成想要的日期和时间模式。常用的时间元素和字母的对应表(JDK 1.8)如下: + +![](http://www.hollischuang.com/wp-content/uploads/2020/01/15781278483147.jpg) + +可以看到,*y表示Year ,而Y表示Week Year* + + + +### 什么是Week Year + +我们知道,不同的国家对于一周的开始和结束的定义是不同的。如在中国,我们把星期一作为一周的第一天,而在美国,他们把星期日作为一周的第一天。 + +同样,如何定义哪一周是一年当中的第一周?这也是一个问题,有很多种方式。 + +比如下图是2019年12月-2020年1月的一份日历。 + +![](http://www.hollischuang.com/wp-content/uploads/2020/01/15781286552869.jpg) + + + +到底哪一周才算2020年的第一周呢?不同的地区和国家,甚至不同的人,都有不同的理解。 + +* 1、1月1日是周三,到下周三(1月8日),这7天算作这一年的第一周。 +* 2、因为周日(周一)才是一周的第一天,所以,要从2020年的第一个周日(周一)开始往后推7天才算这一年的第一周。 +* 3、因为12.29、12.30、12.31是2019年,而1.1、1.2、1.3才是2020年,而1.4周日是下一周的开始,所以,第一周应该只有1.1、1.2、1.3这三天。 + +#### ISO 8601 + +因为不同人对于日期和时间的表示方法有不同的理解,于是,大家就共同制定了了一个国际规范:ISO 8601 。 + +国际标准化组织的国际标准ISO 8601是日期和时间的表示方法,全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》。 + +在 ISO 8601中。对于一年的第一个日历星期有以下四种等效说法: +* 1,本年度第一个星期四所在的星期; +* 2,1月4日所在的星期; +* 3,本年度第一个至少有4天在同一星期内的星期; +* 4,星期一在去年12月29日至今年1月4日以内的星期; + +根据这个标准,我们可以推算出: + +2020年第一周:2019.12.29-2020.1.4 + +所以,根据ISO 8601标准,2019年12月29日、2019年12月30日、2019年12月31日这两天,其实不属于2019年的最后一周,而是属于2020年的第一周。 + + +#### JDK针对ISO 8601提供的支持 + +根据ISO 8601中关于日历星期和日表示法的定义,2019.12.29-2020.1.4是2020年的第一周。 + +我们希望输入一个日期,然后程序告诉我们,根据ISO 8601中关于日历日期的定义,这个日期到底属于哪一年。 + +比如我输入2019-12-20,他告诉我是2019;而我输入2019-12-30的时候,他告诉我是2020。 + +为了提供这样的数据,Java 7引入了「YYYY」作为一个新的日期模式来作为标识。使用「YYYY」作为标识,。再通过SimpleDateFormat就可以得到一个日期所属的周属于哪一年了 + + +所以,当我们要表示日期的时候,一定要使用 yyyy-MM-dd 而不是 YYYY-MM-dd ,这两者的返回结果大多数情况下都一样,但是极端情况就会有问题了。 \ No newline at end of file diff --git a/docs/basics/java-basic/_sidebar.md b/docs/basics/java-basic/_sidebar.md new file mode 100644 index 0000000000000000000000000000000000000000..7b28c6ca73374207d05a817a3dc8fb05211ddd2f --- /dev/null +++ b/docs/basics/java-basic/_sidebar.md @@ -0,0 +1,274 @@ +* 基本数据类型 + + * [8种基本数据类型](/basics/java-basic/basic-data-types.md) + + * [整型中byte、short、int、long的取值范围](/basics/java-basic/integer-scope.md) + + * [什么是浮点型?](/basics/java-basic/float.md) + + * [什么是单精度和双精度?](/basics/java-basic/single-double-float.md) + + * [为什么不能用浮点型表示金额?](/basics/java-basic/float-amount.md) + +* 自动拆装箱 + + * [自动拆装箱](/basics/java-basic/boxing-unboxing.md) + + * [Integer的缓存机制](/basics/java-basic/integer-cache.md) + +* String + + * [字符串的不可变性](/basics/java-basic/final-string.md) + + * [JDK 6和JDK 7中substring的原理及区别](/basics/java-basic/substring.md) + + * replaceFirst、replaceAll、replace区别 + + * [String对“+”的重载](/basics/java-basic/string-append.md) + + * [字符串拼接的几种方式和区别](/basics/java-basic/string-concat.md) + + * [String.valueOf和Integer.toString的区别](/basics/java-basic/value-of-vs-to-string.md) + + * [switch对String的支持](/basics/java-basic/switch-string.md) + * 字符串池 + * 常量池(运行时常量池、Class常量池) + * intern +* Java中各种关键字 + * transient + * instanceof + * volatile + * synchronized + * final + * static + * const +* 集合类 + + * 常用集合类的使用 + + * [ArrayList和LinkedList和Vector的区别](/basics/java-basic/arraylist-vs-linkedlist-vs-vector.md) + + * [SynchronizedList和Vector的区别](/basics/java-basic/synchronizedlist-vector.md) + + * [HashMap、HashTable、ConcurrentHashMap区别](/basics/java-basic/HashMap-HashTable-ConcurrentHashMap.md) + + * [Set和List区别?](/basics/java-basic/set-vs-list.md) + + * [Set如何保证元素不重复?](/basics/java-basic/set-repetition.md) + + * [Java 8中stream相关用法](/basics/java-basic/stream.md) + + * Apache集合处理工具类的使用 + + * 不同版本的JDK中HashMap的实现的区别以及原因 + + * [Collection和Collections区别](/basics/java-basic/Collection-vs-Collections.md) + + * [Arrays.asList获得的List使用时需要注意什么](/basics/java-basic/Arrays-asList.md) + + * [Enumeration和Iterator区别](/basics/java-basic/Enumeration-vs-Iterator.md) + + * [fail-fast 和 fail-safe](/basics/java-basic/fail-fast-vs-fail-safe.md) + + * [CopyOnWriteArrayList](/basics/java-basic/CopyOnWriteArrayList.md) + + * [ConcurrentSkipListMap](/basics/java-basic/ConcurrentSkipListMap.md) + +* 枚举 + + * [枚举的用法](/basics/java-basic/enum-usage.md) + + * [枚举的实现](/basics/java-basic/enum-impl.md) + + * [枚举与单例](/basics/java-basic/enum-singleton.md) + + * Enum类 + + * [Java枚举如何比较](/basics/java-basic/enum-compare.md) + + * [switch对枚举的支持](/basics/java-basic/enum-switch.md) + + * [枚举的序列化如何实现](/basics/java-basic/enum-serializable.md) + + * [枚举的线程安全性问题](/basics/java-basic/enum-thread-safe.md) + +* IO + + * [字符流、字节流](/basics/java-basic/byte-stream-vs-character-stream.md) + + * [输入流、输出流](/basics/java-basic/input-stream-vs-output-stream.md) + + * [同步、异步](/basics/java-basic/synchronized-vs-asynchronization.md) + + * [阻塞、非阻塞](/basics/java-basic/block-vs-non-blocking.md) + + * [Linux 5种IO模型](/basics/java-basic/linux-io.md) + + * [BIO、NIO和AIO的区别、三种IO的用法与原理](/basics/java-basic/bio-vs-nio-vs-aio.md) + + * netty + +* 反射 + + * [反射](/basics/java-basic/reflection.md)与工厂模式、 + + * [反射有什么作用](/basics/java-basic/usage-of-reflection.md) + + * [Class类](/basics/java-basic/Class.md) + + * `java.lang.reflect.*` + +* 动态代理 + + * [静态代理](/basics/java-basic/static-proxy.md) + + * [动态代理](/basics/java-basic/dynamic-proxy.md) + + * [动态代理和反射的关系](/basics/java-basic/dynamic-proxy-vs-reflection.md) + + * [动态代理的几种实现方式](/basics/java-basic/dynamic-proxy-implementation.md) + + * [AOP](/basics/java-basic/aop-vs-proxy.md) + +* 序列化 + + * [什么是序列化与反序列化](basics/java-basic/serialize.md) + * [Java如何实现序列化与反序列化](basics/java-basic/serialize-in-java.md) + * [Serializable 和 Externalizable 有何不同](basics/java-basic/diff-serializable-vs-externalizable.md) + * 为什么序列化 + * [serialVersionUID](basics/java-basic/serialVersionUID.md) + * [为什么serialVersionUID不能随便改](basics/java-basic/serialVersionUID-modify.md) + * [transient](basics/java-basic/transient.md) + * [序列化底层原理](basics/java-basic/serialize-principle.md) + * [序列化与单例模式](basics/java-basic/serialize-singleton.md) + * [protobuf](basics/java-basic/protobuf.md) + * 为什么说序列化并不安全 + +* 注解 + + * [元注解](/basics/java-basic/meta-annotation.md) + * [自定义注解](/basics/java-basic/custom-annotation.md) + * Java中常用注解使用 + * 注解与反射的结合 + + * [如何自定义一个注解?](/basics/java-basic/create-annotation.md) + + * [Spring常用注解](/basics/java-basic/annotation-in-spring.md) +* JMS + + * 什么是Java消息服务 + * JMS消息传送模型 + +* JMX + + * `java.lang.management.*` + * `javax.management.*` + +* 泛型 + + * [什么是泛型](/basics/java-basic/generics.md) + * [类型擦除](/basics/java-basic/type-erasue.md) + * [泛型带来的问题](/basics/java-basic/generics-problem.md) + * [泛型中K T V E ? object等的含义](/basics/java-basic/k-t-v-e.md) + * 泛型各种用法 + + * [限定通配符和非限定通配符](/basics/java-basic/Wildcard-Character.md) + * [上下界限定符extends 和 super](/basics/java-basic/extends-vs-super.md) + + * [`List`和原始类型`List`之间的区别?](/basics/java-basic/genericity-list.md) + + * [`List`和`List`之间的区别是什么?](/basics/java-basic/genericity-list-wildcard.md) + +* 单元测试 + + * junit + * mock + * mockito + * 内存数据库(h2) + +* 正则表达式 + + * `java.lang.util.regex.*` + +* 常用的Java工具库 + + * `commons.lang` + * `commons.*...` + * `guava-libraries` + * `netty` + +* API&SPI + + * API + * [API和SPI的关系和区别](/basics/java-basic/api-vs-spi.md) + + * [如何定义SPI](/basics/java-basic/create-spi.md) + * [SPI的实现原理](/basics/java-basic/spi-principle.md) + +* 异常 + + * [Error和Exception](/basics/java-basic/error-vs-exception.md) + * [异常类型](/basics/java-basic/exception-type.md) + * [异常相关关键字](/basics/java-basic/keyword-about-exception.md) + * [正确处理异常](/basics/java-basic/handle-exception.md) + * [自定义异常](/basics/java-basic/define-exception.md) + * [异常链](/basics/java-basic/exception-chain.md) + * [try-with-resources](/basics/java-basic/try-with-resources.md) + * [finally和return的执行顺序](/basics/java-basic/order-about-finllly-return.md) + +* 时间处理 + + * [时区](/basics/java-basic/time-zone.md) + * [冬令时和夏令时](/basics/java-basic/StandardTime-vs-daylightSavingTime.md) + * [时间戳](/basics/java-basic/timestamp.md) + * Java中时间API + + * [格林威治时间](/basics/java-basic/GMT.md) + * [CET,UTC,GMT,CST几种常见时间的含义和关系](/basics/java-basic/CET-UTC-GMT-CST.md) + + * [SimpleDateFormat的线程安全性问题](/basics/java-basic/simpledateformat-thread-safe.md) + + * [Java 8中的时间处理](/basics/java-basic/time-in-java8.md) + + * [如何在东八区的计算机上获取美国时间](/basics/java-basic/get-los_angeles-time.md) + + * [yyyy和YYYY有什么区别?](/basics/java-basic/YYYY-vs-yyyy.md) + +* 编码方式 + + * [什么是ASCII?](/basics/java-basic/ASCII.md) + + * [Unicode](/basics/java-basic/UNICODE.md) + + * [有了Unicode为啥还需要UTF-8](/basics/java-basic/why-utf8.md) + + * [UTF8、UTF16、UTF32区别](/basics/java-basic/UTF8-UTF16-UTF32.md) + + * 有了UTF8为什么还需要GBK? + + * [GBK、GB2312、GB18030之间的区别](/basics/java-basic/gbk-gb2312-gb18030.md) + + * [URL编解码](/basics/java-basic/url-encode.md) + * [Big Endian和Little Endian](/basics/java-basic/big-endian-vs-little-endian.md) + + * 如何解决乱码问题 + +* 语法糖 + + * [Java中语法糖原理、解语法糖](/basics/java-basic/syntactic-sugar.md) + + * [语法糖介绍](/basics/java-basic/syntactic-sugar.md) + +* 阅读源代码 + + * String + * Integer + * Long + * Enum + * BigDecimal + * ThreadLocal + * ClassLoader & URLClassLoader + * ArrayList & LinkedList + * HashMap & LinkedHashMap & TreeMap & CouncurrentHashMap + * HashSet & LinkedHashSet & TreeSet + \ No newline at end of file diff --git a/basics/java-basic/annotation-in-spring.md b/docs/basics/java-basic/annotation-in-spring.md similarity index 100% rename from basics/java-basic/annotation-in-spring.md rename to docs/basics/java-basic/annotation-in-spring.md diff --git a/basics/java-basic/aop-vs-proxy.md b/docs/basics/java-basic/aop-vs-proxy.md similarity index 100% rename from basics/java-basic/aop-vs-proxy.md rename to docs/basics/java-basic/aop-vs-proxy.md diff --git a/basics/java-basic/api-vs-spi.md b/docs/basics/java-basic/api-vs-spi.md similarity index 100% rename from basics/java-basic/api-vs-spi.md rename to docs/basics/java-basic/api-vs-spi.md diff --git a/basics/java-basic/arraylist-vs-linkedlist-vs-vector.md b/docs/basics/java-basic/arraylist-vs-linkedlist-vs-vector.md similarity index 100% rename from basics/java-basic/arraylist-vs-linkedlist-vs-vector.md rename to docs/basics/java-basic/arraylist-vs-linkedlist-vs-vector.md diff --git a/docs/basics/java-basic/basic-data-types.md b/docs/basics/java-basic/basic-data-types.md new file mode 100644 index 0000000000000000000000000000000000000000..a54b406b89e370977b430032c1d7a68889e26f13 --- /dev/null +++ b/docs/basics/java-basic/basic-data-types.md @@ -0,0 +1,17 @@ +Java中有8种基本数据类型分为三大类。 + +### 字符型 + +char + +### 布尔型 + +boolean + +### 数值型 + +1.整型:byte、short、int、long + +2.浮点型:float、double + +*String不是基本数据类型,是引用类型。* \ No newline at end of file diff --git a/basics/java-basic/big-endian-vs-little-endian.md b/docs/basics/java-basic/big-endian-vs-little-endian.md similarity index 100% rename from basics/java-basic/big-endian-vs-little-endian.md rename to docs/basics/java-basic/big-endian-vs-little-endian.md diff --git a/basics/java-basic/bio-vs-nio-vs-aio.md b/docs/basics/java-basic/bio-vs-nio-vs-aio.md similarity index 100% rename from basics/java-basic/bio-vs-nio-vs-aio.md rename to docs/basics/java-basic/bio-vs-nio-vs-aio.md diff --git a/basics/java-basic/block-vs-non-blocking.md b/docs/basics/java-basic/block-vs-non-blocking.md similarity index 100% rename from basics/java-basic/block-vs-non-blocking.md rename to docs/basics/java-basic/block-vs-non-blocking.md diff --git a/basics/java-basic/boxing-unboxing.md b/docs/basics/java-basic/boxing-unboxing.md similarity index 100% rename from basics/java-basic/boxing-unboxing.md rename to docs/basics/java-basic/boxing-unboxing.md diff --git a/basics/java-basic/byte-stream-vs-character-stream.md b/docs/basics/java-basic/byte-stream-vs-character-stream.md similarity index 100% rename from basics/java-basic/byte-stream-vs-character-stream.md rename to docs/basics/java-basic/byte-stream-vs-character-stream.md diff --git a/basics/java-basic/constructor.md b/docs/basics/java-basic/constructor.md similarity index 100% rename from basics/java-basic/constructor.md rename to docs/basics/java-basic/constructor.md diff --git a/basics/java-basic/create-annotation.md b/docs/basics/java-basic/create-annotation.md similarity index 100% rename from basics/java-basic/create-annotation.md rename to docs/basics/java-basic/create-annotation.md diff --git a/basics/java-basic/create-spi.md b/docs/basics/java-basic/create-spi.md similarity index 100% rename from basics/java-basic/create-spi.md rename to docs/basics/java-basic/create-spi.md diff --git a/basics/java-basic/custom-annotation.md b/docs/basics/java-basic/custom-annotation.md similarity index 100% rename from basics/java-basic/custom-annotation.md rename to docs/basics/java-basic/custom-annotation.md diff --git a/docs/basics/java-basic/define-exception.md b/docs/basics/java-basic/define-exception.md new file mode 100644 index 0000000000000000000000000000000000000000..489811f631260942e7daa9fc3120a044024f858b --- /dev/null +++ b/docs/basics/java-basic/define-exception.md @@ -0,0 +1,6 @@ +⾃定义异常就是开发⼈员⾃⼰定义的异常, ⼀般通过继承`Exception`的⼦类的⽅式实现。 + + +编写⾃定义异常类实际上是继承⼀个API标准异常类, ⽤新定义的异常处理信息覆盖原有信息的过程。 + +这种⽤法在Web开发中也⽐较常见, ⼀般可以⽤来⾃定义业务异常。 如余额不⾜、 重复提交等。 这种⾃定义异常有业务含义, 更容易让上层理解和处理 \ No newline at end of file diff --git a/docs/basics/java-basic/diff-serializable-vs-externalizable.md b/docs/basics/java-basic/diff-serializable-vs-externalizable.md new file mode 100644 index 0000000000000000000000000000000000000000..5b2ed9a73c5b37c86abc656aa2f664f70fb3a487 --- /dev/null +++ b/docs/basics/java-basic/diff-serializable-vs-externalizable.md @@ -0,0 +1,17 @@ +Java中的类通过实现 `java.io.Serializable` 接口以启⽤其序列化功能。 未实现此接⼜的类将⽆法使其任何状态序列化或反序列化。 + +可序列化类的所有⼦类型本⾝都是可序列化的。 + +序列化接⼜没有⽅法或字段, 仅⽤于标识可序列化的语义。 + +当试图对⼀个对象进⾏序列化的时候, 如果遇到不⽀持`Serializable` 接口的对象。 在此情况下, 将抛`NotSerializableException`。 + +如果要序列化的类有⽗类, 要想同时将在⽗类中定义过的变量持久化下来, 那么⽗类也应该集成`java.io.Serializable`接口。 + +`Externalizable`继承了`Serializable`, 该接⼜中定义了两个抽象⽅法:`writeExternal()`与`readExternal()`。 当使⽤`Externalizable`接口来进⾏序列化与反序列化的时候需要开发⼈员重写writeExternal()与readExternal()⽅法。 + +如果没有在这两个⽅法中定义序列化实现细节, 那么序列化之后, 对象内容为空。 + +实现`Externalizable`接⼜的类必须要提供⼀个`public`的⽆参的构造器。 + +所以, 实现`Externalizable`, 并实现`writeExternal()`和`readExternal()`⽅法可以指定序列化哪些属性。 diff --git a/basics/java-basic/dynamic-proxy-implementation.md b/docs/basics/java-basic/dynamic-proxy-implementation.md similarity index 100% rename from basics/java-basic/dynamic-proxy-implementation.md rename to docs/basics/java-basic/dynamic-proxy-implementation.md diff --git a/basics/java-basic/dynamic-proxy-vs-reflection.md b/docs/basics/java-basic/dynamic-proxy-vs-reflection.md similarity index 100% rename from basics/java-basic/dynamic-proxy-vs-reflection.md rename to docs/basics/java-basic/dynamic-proxy-vs-reflection.md diff --git a/basics/java-basic/dynamic-proxy.md b/docs/basics/java-basic/dynamic-proxy.md similarity index 100% rename from basics/java-basic/dynamic-proxy.md rename to docs/basics/java-basic/dynamic-proxy.md diff --git a/basics/java-basic/enum-compare.md b/docs/basics/java-basic/enum-compare.md similarity index 100% rename from basics/java-basic/enum-compare.md rename to docs/basics/java-basic/enum-compare.md diff --git a/basics/java-basic/enum-impl.md b/docs/basics/java-basic/enum-impl.md similarity index 100% rename from basics/java-basic/enum-impl.md rename to docs/basics/java-basic/enum-impl.md diff --git a/basics/java-basic/enum-serializable.md b/docs/basics/java-basic/enum-serializable.md similarity index 100% rename from basics/java-basic/enum-serializable.md rename to docs/basics/java-basic/enum-serializable.md diff --git a/basics/java-basic/enum-singleton.md b/docs/basics/java-basic/enum-singleton.md similarity index 100% rename from basics/java-basic/enum-singleton.md rename to docs/basics/java-basic/enum-singleton.md diff --git a/basics/java-basic/enum-switch.md b/docs/basics/java-basic/enum-switch.md similarity index 100% rename from basics/java-basic/enum-switch.md rename to docs/basics/java-basic/enum-switch.md diff --git a/basics/java-basic/enum-thread-safe.md b/docs/basics/java-basic/enum-thread-safe.md similarity index 100% rename from basics/java-basic/enum-thread-safe.md rename to docs/basics/java-basic/enum-thread-safe.md diff --git a/basics/java-basic/enum-usage.md b/docs/basics/java-basic/enum-usage.md similarity index 100% rename from basics/java-basic/enum-usage.md rename to docs/basics/java-basic/enum-usage.md diff --git a/docs/basics/java-basic/error-vs-exception.md b/docs/basics/java-basic/error-vs-exception.md new file mode 100644 index 0000000000000000000000000000000000000000..0e13030b483fbab04abb2c46a5cf1a1ca0d39090 --- /dev/null +++ b/docs/basics/java-basic/error-vs-exception.md @@ -0,0 +1,6 @@ +Exception和 Error, ⼆者都是 Java异常处理的重要⼦类, 各⾃都包含⼤量⼦类。均继承自Throwable类。 + + +Error表⽰系统级的错误, 是java运⾏环境内部错误或者硬件问题, 不能指望程序来处理这样的问题, 除了退出运⾏外别⽆选择, 它是Java虚拟机抛出的。 + +Exception 表⽰程序需要捕捉、 需要处理的常, 是由与程序设计的不完善⽽出现的问题, 程序必须处理的问题。 \ No newline at end of file diff --git a/docs/basics/java-basic/exception-chain.md b/docs/basics/java-basic/exception-chain.md new file mode 100644 index 0000000000000000000000000000000000000000..44e6e32a3d83104d6dc576eccd9aaba6566779e7 --- /dev/null +++ b/docs/basics/java-basic/exception-chain.md @@ -0,0 +1,26 @@ +“异常链”是Java中⾮常流⾏的异常处理概念, 是指在进⾏⼀个异常处理时抛出了另外⼀个异常, 由此产⽣了⼀个异常链条。 + +该技术⼤多⽤于将“ 受检查异常” ( checked exception) 封装成为“⾮受检查异常”( unchecked exception)或者RuntimeException。 + +顺便说⼀下, 如果因为因为异常你决定抛出⼀个新的异常, 你⼀定要包含原有的异常, 这样, 处理程序才可以通过getCause()和initCause()⽅法来访问异常最终的根源。 + +从 Java 1.4版本开始,几乎所有的异常都支持异常链。 + +以下是Throwable中支持异常链的方法和构造函数。 + + Throwable getCause() + Throwable initCause(Throwable) + Throwable(String, Throwable) + Throwable(Throwable) + +initCause和Throwable构造函数的Throwable参数是导致当前异常的异常。 getCause返回导致当前异常的异常,initCause设置当前异常的原因。 + +以下示例显示如何使用异常链。 + + try { + + } catch (IOException e) { + throw new SampleException("Other IOException", e); + } + +在此示例中,当捕获到IOException时,将创建一个新的SampleException异常,并附加原始的异常原因,并将异常链抛出到下一个更高级别的异常处理程序。 \ No newline at end of file diff --git a/docs/basics/java-basic/exception-type.md b/docs/basics/java-basic/exception-type.md new file mode 100644 index 0000000000000000000000000000000000000000..7e8de55c4e9a86b2dcbf4a695b8117d91cda13e0 --- /dev/null +++ b/docs/basics/java-basic/exception-type.md @@ -0,0 +1,20 @@ +Java中的异常, 主要可以分为两⼤类, 即受检异常( checked exception) 和 ⾮受检异常( unchecked exception) + +### 受检异常 +对于受检异常来说, 如果⼀个⽅法在声明的过程中证明了其要有受检异常抛出: + + public void test() throw new Exception{ } + +那么,当我们在程序中调⽤他的时候, ⼀定要对该异常进⾏处理( 捕获或者向上抛出) , 否则是⽆法编译通过的。 这是⼀种强制规范。 + +这种异常在IO操作中⽐较多。 ⽐如FileNotFoundException , 当我们使⽤IO流处理⼀个⽂件的时候, 有⼀种特殊情况, 就是⽂件不存在, 所以, 在⽂件处理的接⼜定义时他会显⽰抛出FileNotFoundException, ⽬的就是告诉这个⽅法的调⽤者,我这个⽅法不保证⼀定可以成功, 是有可能找不到对应的⽂件 +的, 你要明确的对这种情况做特殊处理哦。 + +所以说, 当我们希望我们的⽅法调⽤者, 明确的处理⼀些特殊情况的时候, 就应该使⽤受检异常。 + +### 非受检异常 +对于⾮受检异常来说, ⼀般是运⾏时异常, 继承⾃RuntimeException。 在编写代码的时候, 不需要显⽰的捕获,但是如果不捕获, 在运⾏期如果发⽣异常就会中断程序的执⾏。 + +这种异常⼀般可以理解为是代码原因导致的。 ⽐如发⽣空指针、 数组越界等。 所以, 只要代码写的没问题, 这些异常都是可以避免的。 也就不需要我们显⽰的进⾏处理。 + +试想⼀下, 如果你要对所有可能发⽣空指针的地⽅做异常处理的话, 那相当于你的所有代码都需要做这件事。 \ No newline at end of file diff --git a/docs/basics/java-basic/extends-vs-super.md b/docs/basics/java-basic/extends-vs-super.md new file mode 100644 index 0000000000000000000000000000000000000000..e52fcbee3c3e898c66c49a6e44f99cbfafcfa1cf --- /dev/null +++ b/docs/basics/java-basic/extends-vs-super.md @@ -0,0 +1,48 @@ +``和``是Java泛型中的“通配符(Wildcards)”和“边界(Bounds)”的概念。 + +``:是指 “上界通配符(Upper Bounds Wildcards)”,即泛型中的类必须为当前类的子类或当前类。 + +``:是指 “下界通配符(Lower Bounds Wildcards)”,即泛型中的类必须为当前类或者其父类。 + + +先看一个列子: + + public class Food {} + public class Fruit extends Food {} + public class Apple extends Fruit {} + public class Banana extends Fruit{} + + public class GenericTest { + + public void testExtends(List list){ + + //报错,extends为上界通配符,只能取值,不能放. + //因为Fruit的子类不只有Apple还有Banana,这里不能确定具体的泛型到底是Apple还是Banana,所以放入任何一种类型都会报错 + //list.add(new Apple()); + + //可以正常获取 + Fruit fruit = list.get(1); + } + + public void testSuper(List list){ + + //super为下界通配符,可以存放元素,但是也只能存放当前类或者子类的实例,以当前的例子来讲, + //无法确定Fruit的父类是否只有Food一个(Object是超级父类) + //因此放入Food的实例编译不通过 + list.add(new Apple()); + // list.add(new Food()); + + Object object = list.get(1); + } + } + +在testExtends方法中,因为泛型中用的是extends,在向list中存放元素的时候,我们并不能确定List中的元素的具体类型,即可能是Apple也可能是Banana。因此调用add方法时,不论传入new Apple()还是new Banana(),都会出现编译错误。 + + +理解了extends之后,再看super就很容易理解了,即我们不能确定testSuper方法的参数中的泛型是Fruit的哪个父类,因此在调用get方法时只能返回Object类型。结合extends可见,在获取泛型元素时,使用extends获取到的是泛型中的上边界的类型(本例子中为Fruit),范围更小。 + +在使用泛型时,存取元素时用super,获取元素时,用extends。 + +频繁往外读取内容的,适合用上界Extends。经常往里插入的,适合用下界Super。 + +本文来源:https://juejin.im/post/5c653fe06fb9a049e3089d88 \ No newline at end of file diff --git a/basics/java-basic/fail-fast-vs-fail-safe.md b/docs/basics/java-basic/fail-fast-vs-fail-safe.md similarity index 100% rename from basics/java-basic/fail-fast-vs-fail-safe.md rename to docs/basics/java-basic/fail-fast-vs-fail-safe.md diff --git a/basics/java-basic/final-string.md b/docs/basics/java-basic/final-string.md similarity index 100% rename from basics/java-basic/final-string.md rename to docs/basics/java-basic/final-string.md diff --git a/basics/java-basic/float-amount.md b/docs/basics/java-basic/float-amount.md similarity index 100% rename from basics/java-basic/float-amount.md rename to docs/basics/java-basic/float-amount.md diff --git a/basics/java-basic/float.md b/docs/basics/java-basic/float.md similarity index 100% rename from basics/java-basic/float.md rename to docs/basics/java-basic/float.md diff --git a/basics/java-basic/gbk-gb2312-gb18030.md b/docs/basics/java-basic/gbk-gb2312-gb18030.md similarity index 100% rename from basics/java-basic/gbk-gb2312-gb18030.md rename to docs/basics/java-basic/gbk-gb2312-gb18030.md diff --git a/basics/java-basic/genericity-list-wildcard.md b/docs/basics/java-basic/genericity-list-wildcard.md similarity index 100% rename from basics/java-basic/genericity-list-wildcard.md rename to docs/basics/java-basic/genericity-list-wildcard.md diff --git a/basics/java-basic/genericity-list.md b/docs/basics/java-basic/genericity-list.md similarity index 100% rename from basics/java-basic/genericity-list.md rename to docs/basics/java-basic/genericity-list.md diff --git a/docs/basics/java-basic/generics-problem.md b/docs/basics/java-basic/generics-problem.md new file mode 100644 index 0000000000000000000000000000000000000000..ccbd2ab6742f44e9054af9a1f82adb51b33c36c4 --- /dev/null +++ b/docs/basics/java-basic/generics-problem.md @@ -0,0 +1,42 @@ + + +###一、当泛型遇到重载 + + public class GenericTypes { + + public static void method(List list) { + System.out.println("invoke method(List list)"); + } + + public static void method(List list) { + System.out.println("invoke method(List list)"); + } + } + + +上面这段代码,有两个重载的函数,因为他们的参数类型不同,一个是`List`另一个是`List` ,但是,这段代码是编译通不过的。因为我们前面讲过,参数`List`和`List`编译之后都被擦除了,变成了一样的原生类型List,擦除动作导致这两个方法的特征签名变得一模一样。 + +### 二、当泛型遇到catch + +如果我们自定义了一个泛型异常类GenericException,那么,不要尝试用多个catch取匹配不同的异常类型,例如你想要分别捕获GenericException、GenericException,这也是有问题的。 + +### 三、当泛型内包含静态变量 + + public class StaticTest{ + public static void main(String[] args){ + GT gti = new GT(); + gti.var=1; + GT gts = new GT(); + gts.var=2; + System.out.println(gti.var); + } + } + class GT{ + public static int var=0; + public void nothing(T x){} + } + + +答案是——2! + +由于经过类型擦除,所有的泛型类实例都关联到同一份字节码上,泛型类的所有静态变量是共享的。 diff --git a/docs/basics/java-basic/generics.md b/docs/basics/java-basic/generics.md new file mode 100644 index 0000000000000000000000000000000000000000..2ba7a3ecd02865601e72c6610efa80eb185d69d8 --- /dev/null +++ b/docs/basics/java-basic/generics.md @@ -0,0 +1,5 @@ +Java泛型( generics) 是JDK 5中引⼊的⼀个新特性, 允许在定义类和接⼜的时候使⽤类型参数( type parameter) 。 + +声明的类型参数在使⽤时⽤具体的类型来替换。 泛型最主要的应⽤是在JDK 5中的新集合类框架中。 + +泛型最⼤的好处是可以提⾼代码的复⽤性。 以List接⼜为例,我们可以将String、 Integer等类型放⼊List中, 如不⽤泛型, 存放String类型要写⼀个List接口, 存放Integer要写另外⼀个List接口, 泛型可以很好的解决这个问题。 \ No newline at end of file diff --git a/docs/basics/java-basic/get-los_angeles-time.md b/docs/basics/java-basic/get-los_angeles-time.md new file mode 100644 index 0000000000000000000000000000000000000000..2517a9e5af01c87becbe091cb1d222f0e2b60342 --- /dev/null +++ b/docs/basics/java-basic/get-los_angeles-time.md @@ -0,0 +1,52 @@ +了解Java8 的朋友可能都知道,Java8提供了一套新的时间处理API,这套API比以前的时间处理API要友好的多。 + +Java8 中加入了对时区的支持,带时区的时间为分别为:`ZonedDate`、`ZonedTime`、`ZonedDateTime`。 + +其中每个时区都对应着 ID,地区ID都为 “{区域}/{城市}”的格式,如`Asia/Shanghai`、`America/Los_Angeles`等。 + +在Java8中,直接使用以下代码即可输出美国洛杉矶的时间: + + LocalDateTime now = LocalDateTime.now(ZoneId.of("America/Los_Angeles")); + System.out.println(now); + + + +为什么以下代码无法获得美国时间呢? + + System.out.println(Calendar.getInstance(TimeZone.getTimeZone("America/Los_Angeles")).getTime()); + +当我们使用System.out.println来输出一个时间的时候,他会调用Date类的toString方法,而该方法会读取操作系统的默认时区来进行时间的转换。 + + public String toString() { + // "EEE MMM dd HH:mm:ss zzz yyyy"; + BaseCalendar.Date date = normalize(); + ... + } + + private final BaseCalendar.Date normalize() { + ... + TimeZone tz = TimeZone.getDefaultRef(); + if (tz != cdate.getZone()) { + cdate.setZone(tz); + CalendarSystem cal = getCalendarSystem(cdate); + cal.getCalendarDate(fastTime, cdate); + } + return cdate; + } + + static TimeZone getDefaultRef() { + TimeZone defaultZone = defaultTimeZone; + if (defaultZone == null) { + // Need to initialize the default time zone. + defaultZone = setDefaultZone(); + assert defaultZone != null; + } + // Don't clone here. + return defaultZone; + } + +主要代码如上。也就是说如果我们想要通过`System.out.println`输出一个Date类的时候,输出美国洛杉矶时间的话,就需要想办法把`defaultTimeZone`改为`America/Los_Angeles` + +但是,通过阅读Calendar的源码,我们可以发现,getInstance方法虽然有一个参数可以传入时区,但是并没有将默认时区设置成传入的时区。 + +而在Calendar.getInstance.getTime后得到的时间只是一个时间戳,其中未保留任何和时区有关的信息,所以,在输出时,还是显示的是当前系统默认时区的时间。 \ No newline at end of file diff --git a/docs/basics/java-basic/handle-exception.md b/docs/basics/java-basic/handle-exception.md new file mode 100644 index 0000000000000000000000000000000000000000..ec5c24d20347e55eca08535d98adfe857c446237 --- /dev/null +++ b/docs/basics/java-basic/handle-exception.md @@ -0,0 +1,6 @@ +异常的处理⽅式有两种。 1、 ⾃⼰处理。 2、 向上抛, 交给调⽤者处理。 + + +异常, 千万不能捕获了之后什么也不做。 或者只是使⽤`e.printStacktrace`。 + +具体的处理⽅式的选择其实原则⽐较简明: ⾃⼰明确的知道如何处理的, 就要处理掉。 不知道如何处理的, 就交给调⽤者处理。 \ No newline at end of file diff --git a/basics/java-basic/inheritance-composition.md b/docs/basics/java-basic/inheritance-composition.md similarity index 100% rename from basics/java-basic/inheritance-composition.md rename to docs/basics/java-basic/inheritance-composition.md diff --git a/basics/java-basic/input-stream-vs-output-stream.md b/docs/basics/java-basic/input-stream-vs-output-stream.md similarity index 100% rename from basics/java-basic/input-stream-vs-output-stream.md rename to docs/basics/java-basic/input-stream-vs-output-stream.md diff --git a/basics/java-basic/integer-cache.md b/docs/basics/java-basic/integer-cache.md similarity index 100% rename from basics/java-basic/integer-cache.md rename to docs/basics/java-basic/integer-cache.md diff --git a/basics/java-basic/integer-scope.md b/docs/basics/java-basic/integer-scope.md similarity index 100% rename from basics/java-basic/integer-scope.md rename to docs/basics/java-basic/integer-scope.md diff --git a/basics/java-basic/k-t-v-e.md b/docs/basics/java-basic/k-t-v-e.md similarity index 100% rename from basics/java-basic/k-t-v-e.md rename to docs/basics/java-basic/k-t-v-e.md diff --git a/docs/basics/java-basic/keyword-about-exception.md b/docs/basics/java-basic/keyword-about-exception.md new file mode 100644 index 0000000000000000000000000000000000000000..1a4163046855df999d53403dc0ab56f2086acd03 --- /dev/null +++ b/docs/basics/java-basic/keyword-about-exception.md @@ -0,0 +1,11 @@ +throws、 throw、 try、 catch、 finally + +try⽤来指定⼀块预防所有异常的程序; + +catch⼦句紧跟在try块后⾯, ⽤来指定你想要捕获的异常的类型; + +finally为确保⼀段代码不管发⽣什么异常状况都要被执⾏; + +throw语句⽤来明确地抛出⼀个异常; + +throws⽤来声明⼀个⽅法可能抛出的各种异常; \ No newline at end of file diff --git a/basics/java-basic/linux-io.md b/docs/basics/java-basic/linux-io.md similarity index 100% rename from basics/java-basic/linux-io.md rename to docs/basics/java-basic/linux-io.md diff --git a/basics/java-basic/meta-annotation.md b/docs/basics/java-basic/meta-annotation.md similarity index 100% rename from basics/java-basic/meta-annotation.md rename to docs/basics/java-basic/meta-annotation.md diff --git a/docs/basics/java-basic/order-about-finllly-return.md b/docs/basics/java-basic/order-about-finllly-return.md new file mode 100644 index 0000000000000000000000000000000000000000..6f9de9932bd83d6ecebd971d56ce4f69db4d64e6 --- /dev/null +++ b/docs/basics/java-basic/order-about-finllly-return.md @@ -0,0 +1,6 @@ + + + `try()` ⾥⾯有⼀个`return`语句, 那么后⾯的`finally{}`⾥⾯的code会不会被执⾏, 什么时候执⾏, 是在`return`前还是`return`后? + + +如果try中有return语句, 那么finally中的代码还是会执⾏。因为return表⽰的是要整个⽅法体返回, 所以,finally中的语句会在return之前执⾏。 \ No newline at end of file diff --git a/docs/basics/java-basic/protobuf.md b/docs/basics/java-basic/protobuf.md new file mode 100644 index 0000000000000000000000000000000000000000..f8c8738ce011c8444b42d46d48b3f2e1f7cb3dae --- /dev/null +++ b/docs/basics/java-basic/protobuf.md @@ -0,0 +1,9 @@ + +Protocol Buffer (简称Protobuf) 是Google出品的性能优异、跨语言、跨平台的序列化库。 + +2001年初,Protobuf首先在Google内部创建, 我们把它称之为 proto1,一直以来在Google的内部使用,其中也不断的演化,根据使用者的需求也添加很多新的功能,一些内部库依赖它。几乎每个Google的开发者都会使用到它。 + +Google开始开源它的内部项目时,因为依赖的关系,所以他们决定首先把Protobuf开源出去。 + +目前Protobuf的稳定版本是3.9.2,于2019年9月23日发布。由于很多公司很早的就采用了Protobuf,所以很多项目还在使用proto2协议,目前是proto2和proto3同时在使用的状态。 + diff --git a/basics/java-basic/reflection.md b/docs/basics/java-basic/reflection.md similarity index 100% rename from basics/java-basic/reflection.md rename to docs/basics/java-basic/reflection.md diff --git a/basics/java-basic/scope.md b/docs/basics/java-basic/scope.md similarity index 100% rename from basics/java-basic/scope.md rename to docs/basics/java-basic/scope.md diff --git a/docs/basics/java-basic/serialVersionUID-modify.md b/docs/basics/java-basic/serialVersionUID-modify.md new file mode 100644 index 0000000000000000000000000000000000000000..6b1e26ac11f225551b2d24503a1e7f7029d6f1bd --- /dev/null +++ b/docs/basics/java-basic/serialVersionUID-modify.md @@ -0,0 +1,278 @@ +关于`serialVersionUID` 。这个字段到底有什么用?如果不设置会怎么样?为什么《阿里巴巴Java开发手册》中有以下规定: + +![-w934][4] + +### 背景知识 + +**Serializable 和 Externalizable** + +类通过实现 `java.io.Serializable` 接口以启用其序列化功能。**未实现此接口的类将无法进行序列化或反序列化。**可序列化类的所有子类型本身都是可序列化的。 + +如果读者看过`Serializable`的源码,就会发现,他只是一个空的接口,里面什么东西都没有。**Serializable接口没有方法或字段,仅用于标识可序列化的语义。**但是,如果一个类没有实现这个接口,想要被序列化的话,就会抛出`java.io.NotSerializableException`异常。 + +它是怎么保证只有实现了该接口的方法才能进行序列化与反序列化的呢? + +原因是在执行序列化的过程中,会执行到以下代码: + + if (obj instanceof String) { + writeString((String) obj, unshared); + } else if (cl.isArray()) { + writeArray(obj, desc, unshared); + } else if (obj instanceof Enum) { + writeEnum((Enum) obj, desc, unshared); + } else if (obj instanceof Serializable) { + writeOrdinaryObject(obj, desc, unshared); + } else { + if (extendedDebugInfo) { + throw new NotSerializableException( + cl.getName() + "\n" + debugInfoStack.toString()); + } else { + throw new NotSerializableException(cl.getName()); + } + } + + +在进行序列化操作时,会判断要被序列化的类是否是`Enum`、`Array`和`Serializable`类型,如果都不是则直接抛出`NotSerializableException`。 + +Java中还提供了`Externalizable`接口,也可以实现它来提供序列化能力。 + +`Externalizable`继承自`Serializable`,该接口中定义了两个抽象方法:`writeExternal()`与`readExternal()`。 + +当使用`Externalizable`接口来进行序列化与反序列化的时候需要开发人员重写`writeExternal()`与`readExternal()`方法。否则所有变量的值都会变成默认值。 + +**transient** + +`transient` 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,`transient` 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。 + +**自定义序列化策略** + +在序列化过程中,如果被序列化的类中定义了`writeObject` 和 `readObject` 方法,虚拟机会试图调用对象类里的 `writeObject` 和 `readObject` 方法,进行用户自定义的序列化和反序列化。 + +如果没有这样的方法,则默认调用是 `ObjectOutputStream` 的 `defaultWriteObject` 方法以及 `ObjectInputStream` 的 `defaultReadObject` 方法。 + +用户自定义的 `writeObject` 和 `readObject` 方法可以允许用户控制序列化的过程,比如可以在序列化的过程中动态改变序列化的数值。 + +所以,对于一些特殊字段需要定义序列化的策略的时候,可以考虑使用transient修饰,并自己重写`writeObject` 和 `readObject` 方法,如`java.util.ArrayList`中就有这样的实现。 + +我们随便找几个Java中实现了序列化接口的类,如String、Integer等,我们可以发现一个细节,那就是这些类除了实现了`Serializable`外,还定义了一个`serialVersionUID` ![][5] + +那么,到底什么是`serialVersionUID`呢?为什么要设置这样一个字段呢? + +### 什么是serialVersionUID + +序列化是将对象的状态信息转换为可存储或传输的形式的过程。我们都知道,Java对象是保存在JVM的堆内存中的,也就是说,如果JVM堆不存在了,那么对象也就跟着消失了。 + +而序列化提供了一种方案,可以让你在即使JVM停机的情况下也能把对象保存下来的方案。就像我们平时用的U盘一样。把Java对象序列化成可存储或传输的形式(如二进制流),比如保存在文件中。这样,当再次需要这个对象的时候,从文件中读取出二进制流,再从二进制流中反序列化出对象。 + +虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致,这个所谓的序列化ID,就是我们在代码中定义的`serialVersionUID`。 + +### 如果serialVersionUID变了会怎样 + +我们举个例子吧,看看如果`serialVersionUID`被修改了会发生什么? + + public class SerializableDemo1 { + public static void main(String[] args) { + //Initializes The Object + User1 user = new User1(); + user.setName("hollis"); + //Write Obj to File + ObjectOutputStream oos = null; + try { + oos = new ObjectOutputStream(new FileOutputStream("tempFile")); + oos.writeObject(user); + } catch (IOException e) { + e.printStackTrace(); + } finally { + IOUtils.closeQuietly(oos); + } + } + } + + class User1 implements Serializable { + private static final long serialVersionUID = 1L; + private String name; + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + } + + +我们先执行以上代码,把一个User1对象写入到文件中。然后我们修改一下User1类,把`serialVersionUID`的值改为`2L`。 + + class User1 implements Serializable { + private static final long serialVersionUID = 2L; + private String name; + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + } + + +然后执行以下代码,把文件中的对象反序列化出来: + + public class SerializableDemo2 { + public static void main(String[] args) { + //Read Obj from File + File file = new File("tempFile"); + ObjectInputStream ois = null; + try { + ois = new ObjectInputStream(new FileInputStream(file)); + User1 newUser = (User1) ois.readObject(); + System.out.println(newUser); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } finally { + IOUtils.closeQuietly(ois); + try { + FileUtils.forceDelete(file); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + +执行结果如下: + + java.io.InvalidClassException: com.hollis.User1; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2 + + +可以发现,以上代码抛出了一个`java.io.InvalidClassException`,并且指出`serialVersionUID`不一致。 + +这是因为,在进行反序列化时,JVM会把传来的字节流中的`serialVersionUID`与本地相应实体类的`serialVersionUID`进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是`InvalidCastException`。 + +这也是《阿里巴巴Java开发手册》中规定,在兼容性升级中,在修改类的时候,不要修改`serialVersionUID`的原因。**除非是完全不兼容的两个版本**。所以,**`serialVersionUID`其实是验证版本一致性的。** + +如果读者感兴趣,可以把各个版本的JDK代码都拿出来看一下,那些向下兼容的类的`serialVersionUID`是没有变化过的。比如String类的`serialVersionUID`一直都是`-6849794470754667710L`。 + +但是,作者认为,这个规范其实还可以再严格一些,那就是规定: + +如果一个类实现了`Serializable`接口,就必须手动添加一个`private static final long serialVersionUID`变量,并且设置初始值。 + +### 为什么要明确定一个serialVersionUID + +如果我们没有在类中明确的定义一个`serialVersionUID`的话,看看会发生什么。 + +尝试修改上面的demo代码,先使用以下类定义一个对象,该类中不定义`serialVersionUID`,将其写入文件。 + + class User1 implements Serializable { + private String name; + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + } + + +然后我们修改User1类,向其中增加一个属性。在尝试将其从文件中读取出来,并进行反序列化。 + + class User1 implements Serializable { + private String name; + private int age; + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public int getAge() { + return age; + } + public void setAge(int age) { + this.age = age; + } + } + + +执行结果: `java.io.InvalidClassException: com.hollis.User1; local class incompatible: stream classdesc serialVersionUID = -2986778152837257883, local class serialVersionUID = 7961728318907695402` + +同样,抛出了`InvalidClassException`,并且指出两个`serialVersionUID`不同,分别是`-2986778152837257883`和`7961728318907695402`。 + +从这里可以看出,系统自己添加了一个`serialVersionUID`。 + +所以,一旦类实现了`Serializable`,就建议明确的定义一个`serialVersionUID`。不然在修改类的时候,就会发生异常。 + +`serialVersionUID`有两种显示的生成方式: +一是默认的1L,比如:`private static final long serialVersionUID = 1L;` +二是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如: +`private static final long serialVersionUID = xxxxL;` + +后面这种方式,可以借助IDE生成,后面会介绍。 + +### 背后原理 + +知其然,要知其所以然,我们再来看看源码,分析一下为什么`serialVersionUID`改变的时候会抛异常?在没有明确定义的情况下,默认的`serialVersionUID`是怎么来的? + +为了简化代码量,反序列化的调用链如下: + +`ObjectInputStream.readObject -> readObject0 -> readOrdinaryObject -> readClassDesc -> readNonProxyDesc -> ObjectStreamClass.initNonProxy` + +在`initNonProxy`中 ,关键代码如下: + +![][6] + +在反序列化过程中,对`serialVersionUID`做了比较,如果发现不相等,则直接抛出异常。 + +深入看一下`getSerialVersionUID`方法: + + public long getSerialVersionUID() { + // REMIND: synchronize instead of relying on volatile? + if (suid == null) { + suid = AccessController.doPrivileged( + new PrivilegedAction() { + public Long run() { + return computeDefaultSUID(cl); + } + } + ); + } + return suid.longValue(); + } + + +在没有定义`serialVersionUID`的时候,会调用`computeDefaultSUID` 方法,生成一个默认的`serialVersionUID`。 + +这也就找到了以上两个问题的根源,其实是代码中做了严格的校验。 + +### IDEA提示 + +为了确保我们不会忘记定义`serialVersionUID`,可以调节一下Intellij IDEA的配置,在实现`Serializable`接口后,如果没定义`serialVersionUID`的话,IDEA(eclipse一样)会进行提示: ![][7] + +并且可以一键生成一个: + +![][8] + +当然,这个配置并不是默认生效的,需要手动到IDEA中设置一下: + +![][9] + +在图中标号3的地方(Serializable class without serialVersionUID的配置),打上勾,保存即可。 + +### 总结 + +`serialVersionUID`是用来验证版本一致性的。所以在做兼容性升级的时候,不要改变类中`serialVersionUID`的值。 + +如果一个类实现了Serializable接口,一定要记得定义`serialVersionUID`,否则会发生异常。可以在IDE中通过设置,让他帮忙提示,并且可以一键快速生成一个`serialVersionUID`。 + +之所以会发生异常,是因为反序列化过程中做了校验,并且如果没有明确定义的话,会根据类的属性自动生成一个。 + + [1]: http://www.hollischuang.com/archives/1150 + [2]: http://www.hollischuang.com/archives/1140 + [3]: http://www.hollischuang.com/archives/1144 + [4]: http://www.hollischuang.com/wp-content/uploads/2018/12/15455608799770.jpg + [5]: http://www.hollischuang.com/wp-content/uploads/2018/12/15455622116411.jpg + [6]: http://www.hollischuang.com/wp-content/uploads/2018/12/15455655236269.jpg + [7]: http://www.hollischuang.com/wp-content/uploads/2018/12/15455657868672.jpg + [8]: http://www.hollischuang.com/wp-content/uploads/2018/12/15455658088098.jpg + [9]: http://www.hollischuang.com/wp-content/uploads/2018/12/15455659620042.jpg \ No newline at end of file diff --git a/docs/basics/java-basic/serialVersionUID.md b/docs/basics/java-basic/serialVersionUID.md new file mode 100644 index 0000000000000000000000000000000000000000..dc5331810bf4d2961a20bb535db39802cd4381c0 --- /dev/null +++ b/docs/basics/java-basic/serialVersionUID.md @@ -0,0 +1,21 @@ +序列化是将对象的状态信息转换为可存储或传输的形式的过程。 + +我们都知道, Java对象是保存在JVM的堆内存中的, 也就是说, 如果JVM堆不存在了, 那么对象也就跟着消失了。 + +⽽序列化提供了⼀种⽅案, 可以让你在即使JVM停机的情况下也能把对象保存下来的⽅案。 就像我们平时⽤的U盘⼀样。 把Java对象序列化成可存储或传输的形式( 如⼆进制流) , ⽐如保存在⽂件中。 这样, 当再次需要这个对象的时候, 从⽂件中读取出⼆进制流, 再从⼆进制流中反序列化出对象。 + + +但是, 虚拟机是否允许反序列化, 不仅取决于类路径和功能代码是否⼀致, ⼀个⾮常重要的⼀点是两个类的序列化 ID 是否⼀致, 即`serialVersionUID`要求⼀致。 + + +在进⾏反序列化时, JVM会把传来的字节流中的`serialVersionUID`与本地相应实体类的`serialVersionUID`进⾏⽐较, 如果相同就认为是⼀致的, 可以进⾏反序列化, 否则就会出现序列化版本不⼀致的异常, 即是`InvalidCastException`。 + +这样做是为了保证安全, 因为⽂件存储中的内容可能被篡改。 + + +当实现`java.io.Serializable`接口的类没有显式地定义⼀个`serialVersionUID`变量时候, Java序列化机制会根据编译的Class⾃动⽣成⼀个`serialVersionUID`作序列化版本⽐较⽤, 这种情况下, 如果Class⽂件没有发⽣变化, 就算再编译多 +次, serialVersionUID也不会变化的。 + +但是, 如果发⽣了变化,那么这个⽂件对应的`serialVersionUID`也就会发⽣变化。 + +基于以上原理, 如果我们⼀个类实现了Serializable接口, 但是没有定义`serialVersionUID`, 然后序列化。 在序列化之后, 由于某些原因, 我们对该类做了变更, 重新启动应⽤后, 我们相对之前序列化过的对象进⾏反序列化的话就会报错 \ No newline at end of file diff --git a/basics/java-basic/serialize-principle.md b/docs/basics/java-basic/serialize-in-java.md similarity index 78% rename from basics/java-basic/serialize-principle.md rename to docs/basics/java-basic/serialize-in-java.md index 31a4a1c4f0002f3b5251598d42faabce855f4249..bf982c84fceb5414df96c24ff55970ffeb8daf57 100644 --- a/basics/java-basic/serialize-principle.md +++ b/docs/basics/java-basic/serialize-in-java.md @@ -1,6 +1,3 @@ -## 序列化与反序列化 - -序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。一般将一个对象存储至一个储存媒介,例如档案或是记亿体缓冲等。在网络传输过程中,可以是字节或是XML等格式。而字节的或XML编码格式可以还原完全相等的对象。这个相反的过程又称为反序列化。 ## Java对象的序列化与反序列化 @@ -135,7 +132,6 @@ Java为了方便开发人员将Java对象进行序列化及反序列化提供了 //User{name='hollis', age=23} -更多关于Serializable的使用,请参考[代码实例][2] ## Externalizable接口 @@ -319,37 +315,6 @@ Externalizable继承了Serializable,该接口中定义了两个抽象方法: > 如果User类中没有无参数的构造函数,在运行时会抛出异常:`java.io.InvalidClassException` -更多Externalizable接口使用实例请参考[代码实例][3] - -## ObjectOutput和ObjectInput 接口 - -ObjectInput接口 扩展自 DataInput 接口以包含对象的读操作。 - -> DataInput 接口用于从二进制流中读取字节,并根据所有 Java 基本类型数据进行重构。同时还提供根据 UTF-8 修改版格式的数据重构 String 的工具。 -> -> 对于此接口中的所有数据读取例程来说,如果在读取所需字节数之前已经到达文件末尾 (end of file),则将抛出 EOFException(IOException 的一种)。如果因为到达文件末尾以外的其他原因无法读取字节,则将抛出 IOException 而不是 EOFException。尤其是,在输入流已关闭的情况下,将抛出 IOException。 - -ObjectOutput 扩展 DataOutput 接口以包含对象的写入操作。 - -> DataOutput 接口用于将数据从任意 Java 基本类型转换为一系列字节,并将这些字节写入二进制流。同时还提供了一个将 String 转换成 UTF-8 修改版格式并写入所得到的系列字节的工具。 -> -> 对于此接口中写入字节的所有方法,如果由于某种原因无法写入某个字节,则抛出 IOException。 - -## ObjectOutputStream类和ObjectInputStream类 - -通过前面的代码片段中我们也能知道,我们一般使用ObjectOutputStream的`writeObject`方法把一个对象进行持久化。再使用ObjectInputStream的`readObject`从持久化存储中把对象读取出来。 - -更多关于ObjectInputStream和ObjectOutputStream的相关知识欢迎阅读我的另外两篇博文:[深入分析Java的序列化与反序列化][4]、[单例与序列化的那些事儿][5] - -## Transient 关键字 - -Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。关于Transient 关键字的拓展知识欢迎阅读[深入分析Java的序列化与反序列化][4] - -## 序列化ID - -虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 `private static final long serialVersionUID`) - -序列化 ID 在 Eclipse 下提供了两种生成策略,一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具生成),在这里有一个建议,如果没有特殊需求,就是用默认的 1L 就可以,这样可以确保代码一致时反序列化成功。那么随机生成的序列化 ID 有什么作用呢,有些时候,通过改变序列化 ID 可以用来限制某些用户的使用。 ## 参考资料 diff --git a/docs/basics/java-basic/serialize-principle.md b/docs/basics/java-basic/serialize-principle.md new file mode 100644 index 0000000000000000000000000000000000000000..993ae5b3ba01ad7aefbd421a5cd80e620311fa97 --- /dev/null +++ b/docs/basics/java-basic/serialize-principle.md @@ -0,0 +1,397 @@ +序列化是一种对象持久化的手段。普遍应用在网络传输、RMI等场景中。本文通过分析ArrayList的序列化来介绍Java序列化的相关内容。主要涉及到以下几个问题: + +> 怎么实现Java的序列化 +> +> 为什么实现了java.io.Serializable接口才能被序列化 +> +> transient的作用是什么 +> +> 怎么自定义序列化策略 +> +> 自定义的序列化策略是如何被调用的 +> +> ArrayList对序列化的实现有什么好处 + +## Java对象的序列化 + +Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能。 + +使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的"状态",即它的成员变量。由此可知,**对象序列化不会关注类中的静态变量**。 + +除了在持久化对象时会用到对象序列化之外,当使用RMI(远程方法调用),或在网络中传递对象时,都会用到对象序列化。Java序列化API为处理对象序列化提供了一个标准机制,该API简单易用。 + +## 如何对Java对象进行序列化与反序列化 + +在Java中,只要一个类实现了`java.io.Serializable`接口,那么它就可以被序列化。这里先来一段代码: + +code 1 创建一个User类,用于序列化及反序列化 + + package com.hollis; + import java.io.Serializable; + import java.util.Date; + + /** + * Created by hollis on 16/2/2. + */ + public class User implements Serializable{ + private String name; + private int age; + private Date birthday; + private transient String gender; + private static final long serialVersionUID = -6849794470754667710L; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public Date getBirthday() { + return birthday; + } + + public void setBirthday(Date birthday) { + this.birthday = birthday; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + @Override + public String toString() { + return "User{" + + "name='" + name + '\'' + + ", age=" + age + + ", gender=" + gender + + ", birthday=" + birthday + + '}'; + } + } + + +code 2 对User进行序列化及反序列化的Demo + + package com.hollis; + import org.apache.commons.io.FileUtils; + import org.apache.commons.io.IOUtils; + import java.io.*; + import java.util.Date; + + /** + * Created by hollis on 16/2/2. + */ + public class SerializableDemo { + + public static void main(String[] args) { + //Initializes The Object + User user = new User(); + user.setName("hollis"); + user.setGender("male"); + user.setAge(23); + user.setBirthday(new Date()); + System.out.println(user); + + //Write Obj to File + ObjectOutputStream oos = null; + try { + oos = new ObjectOutputStream(new FileOutputStream("tempFile")); + oos.writeObject(user); + } catch (IOException e) { + e.printStackTrace(); + } finally { + IOUtils.closeQuietly(oos); + } + + //Read Obj from File + File file = new File("tempFile"); + ObjectInputStream ois = null; + try { + ois = new ObjectInputStream(new FileInputStream(file)); + User newUser = (User) ois.readObject(); + System.out.println(newUser); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } finally { + IOUtils.closeQuietly(ois); + try { + FileUtils.forceDelete(file); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + } + //output + //User{name='hollis', age=23, gender=male, birthday=Tue Feb 02 17:37:38 CST 2016} + //User{name='hollis', age=23, gender=null, birthday=Tue Feb 02 17:37:38 CST 2016} + + +## 序列化及反序列化相关知识 + +1、在Java中,只要一个类实现了`java.io.Serializable`接口,那么它就可以被序列化。 + +2、通过`ObjectOutputStream`和`ObjectInputStream`对对象进行序列化及反序列化 + +3、虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 `private static final long serialVersionUID`) + +4、序列化并不保存静态变量。 + +5、要想将父类对象也序列化,就需要让父类也实现`Serializable` 接口。 + +6、Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。 + +7、服务器端给客户端发送序列化对象数据,对象中有一些数据是敏感的,比如密码字符串等,希望对该密码字段在序列化时,进行加密,而客户端如果拥有解密的密钥,只有在客户端进行反序列化时,才可以对密码进行读取,这样可以一定程度保证序列化对象的数据安全。 + +## ArrayList的序列化 + +在介绍ArrayList序列化之前,先来考虑一个问题: + +> **如何自定义的序列化和反序列化策略** + +带着这个问题,我们来看`java.util.ArrayList`的源码 + +code 3 + + public class ArrayList extends AbstractList + implements List, RandomAccess, Cloneable, java.io.Serializable + { + private static final long serialVersionUID = 8683452581122892189L; + transient Object[] elementData; // non-private to simplify nested class access + private int size; + } + + +笔者省略了其他成员变量,从上面的代码中可以知道ArrayList实现了`java.io.Serializable`接口,那么我们就可以对它进行序列化及反序列化。因为elementData是`transient`的,所以我们认为这个成员变量不会被序列化而保留下来。我们写一个Demo,验证一下我们的想法: + +code 4 + + public static void main(String[] args) throws IOException, ClassNotFoundException { + List stringList = new ArrayList(); + stringList.add("hello"); + stringList.add("world"); + stringList.add("hollis"); + stringList.add("chuang"); + System.out.println("init StringList" + stringList); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("stringlist")); + objectOutputStream.writeObject(stringList); + + IOUtils.close(objectOutputStream); + File file = new File("stringlist"); + ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file)); + List newStringList = (List)objectInputStream.readObject(); + IOUtils.close(objectInputStream); + if(file.exists()){ + file.delete(); + } + System.out.println("new StringList" + newStringList); + } + //init StringList[hello, world, hollis, chuang] + //new StringList[hello, world, hollis, chuang] + + +了解ArrayList的人都知道,ArrayList底层是通过数组实现的。那么数组`elementData`其实就是用来保存列表中的元素的。通过该属性的声明方式我们知道,他是无法通过序列化持久化下来的。那么为什么code 4的结果却通过序列化和反序列化把List中的元素保留下来了呢? + +### writeObject和readObject方法 + +在ArrayList中定义了来个方法: `writeObject`和`readObject`。 + +这里先给出结论: + +> 在序列化过程中,如果被序列化的类中定义了writeObject 和 readObject 方法,虚拟机会试图调用对象类里的 writeObject 和 readObject 方法,进行用户自定义的序列化和反序列化。 +> +> 如果没有这样的方法,则默认调用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法。 +> +> 用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程,比如可以在序列化的过程中动态改变序列化的数值。 + +来看一下这两个方法的具体实现: + +code 5 + + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + elementData = EMPTY_ELEMENTDATA; + + // Read in size, and any hidden stuff + s.defaultReadObject(); + + // Read in capacity + s.readInt(); // ignored + + if (size > 0) { + // be like clone(), allocate array based upon size not capacity + ensureCapacityInternal(size); + + Object[] a = elementData; + // Read in all elements in the proper order. + for (int i=0; i