ArrayList 与 LinkedList 区别
因为 Array 是基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的。Array 获取数据的时间复杂度是 O(1),但是要删除数据却是开销很大的,因为这需要重排数组中的所有数据。 相对于 ArrayList,LinkedList 插入是更快的。因为 LinkedList 不像 ArrayList 一样,不需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重新装入一个新的数组,这是 ArrayList 最坏的一种情况,时间复杂度是 O(n),而 LinkedList 中插入或删除的时间复杂度仅为 O(1)。ArrayList 在插入数据时还需要更新索引(除了插入数组的尾部)。 类似于插入数据,删除数据时,LinkedList 也优于 ArrayList。 LinkedList 需要更多的内存,因为 ArrayList 的每个索引的位置是实际的数据,而 LinkedList 中的每个节点中存储的是实际的数据和前后节点的位置。 你的应用不会随机访问数据。因为如果你需要 LinkedList 中的第 n 个元素的时候,你需要从第一个元素顺序数到第 n ...
List 和 Set 区别
List, Set 都是继承自 Collection 接口 List 特点:元素有放入顺序,元素可重复。Set 特点:元素无放入顺序,元素不可重复(注意:元素虽然无放入顺序,但是元素在 set 中的位置是有该元素的 HashCode 决定的,其位置其实是固定的) List 接口有三个实现类:LinkedList,ArrayList,Vector。Set 接口有两个实现类:HashSet(底层由 HashMap 实现),LinkedHashSet 三条特点之外,真正决定选型的是底层数据结构带来的复杂度差异,以及”去重/判含”这类操作在两种集合里的成本天壤之别。本文按语义、实现、复杂度、选型四层展开。 语义差异:有序可重 vs 唯一性 List:序列语义。保留插入顺序、允许重复、支持按索引访问(get(i))——对应”一批有先后关系的记录” Set:集合语义。元素唯一、不承诺顺序(HashSet)、无索引访问——对应”一个成员资格集合” “Set 无序但位置固定”那句注记的准确解释:HashSet 的迭代顺序由元素 hashCode 与桶分布决定,对同一组元素是...
equals 与 == 的区别
== 与equals 的主要区别是:== 常用于比较原生类型,而 equals() 方法用于检查对象的相等性。 另一个不同的点是:如果 == 和 equals() 用于比较对象,当两个引用地址相同,== 返回 true。而 equals() 可以返回 true 或者 false 主要取决于重写实现。最常见的一个例子,字符串的比较,不同情况 == 和 equals() 返回不同的结果。 两点结论正确但偏薄。要答出深度,需要补三块:字符串常量池这个经典案例的完整推演、equals 重写必须连带重写 hashCode 的契约、以及 Integer 缓存这类包装类的陷阱。 语义层:值比较 vs 引用比较 == 是运算符:基本类型比较值;引用类型比较引用(地址)——即”是不是同一个对象” equals 是 Object 的方法:默认实现就是 this == obj(比引用);语义由重写者定义,String、Integer、LocalDate 等都重写为”内容相等” 所以”equals 比内容”不是语言保证,而是类的契约承诺;自己写的类不重写 equals,equals 就退化为 ...
MVC 设计思想
MVC 是三个单词的首字母缩写,它们是 Model(模型)、View(视图)和 Controller(控制)。 这个模式认为,程序不论简单或复杂,从结构上看,都可以分成三层: 最上面的一层,是直接面向最终用户的”视图层”(View)。它是提供给用户的操作界面,是程序的外壳。 最底下的一层,是核心的”数据层”(Model),也就是程序需要操作的数据或信息。 中间的一层,就是”控制层”(Controller),它负责根据用户从”视图层”输入的指令,选取”数据层”中的数据,然后对其进行相应的操作,产生最终结果。 三层划分只是 MVC 的静态面貌。真正让它成为”思想”而非”目录结构”的,是依赖方向与变化隔离:View 与 Model 互不直接依赖,Controller 做中间调度,于是”界面变化”与”数据/业务变化”可以独立演进。本文补上交互流程、Spring MVC 的落地映射、以及 MVC 的变体与误用。 交互流程:一次请求的三角关系经典 MVC 的交互(以 Web 应用为例): 用户操作 View(提交表单/点击链接)→ 请求进入 Controller C...
JDBC 流程
向 DriverManager 类注册驱动数据库驱动程序 调用 DriverManager.getConnection 方法, 通过 JDBC URL,用户名,密码取得数据库连接的 Connection 对象。 获取 Connection 后, 便可以通过 createStatement 创建 Statement 用以执行 SQL 语句。 有时候会得到查询结果,比如 select,得到查询结果,查询(SELECT)的结果存放于结果集(ResultSet)中。 关闭数据库语句,关闭数据库连接。 五步流程背下来只要十秒,但每一步背后都有一个”为什么这样设计”:驱动为什么要注册、Statement 三种形态的区别、资源为什么要按序关闭。把这些补齐,JDBC 就从流程变成机制。 完整代码与五步对应// 1. 注册驱动(JDBC4 之后 SPI 自动加载,此行可省略)Class.forName("com.mysql.cj.jdbc.Driver");// 2. 获取连接try (Connection conn = DriverManager.getConn...
Session 分布式处理
Session 复制在支持 Session 复制的 Web 服务器上,通过修改 Web 服务器的配置,可以实现将 Session 同步到其它 Web 服务器上,达到每个 Web 服务器上都保存一致的 Session。 优点:代码上不需要做支持和修改。 缺点:需要依赖支持的 Web 服务器,一旦更换成不支持的 Web 服务器就不能使用了,在数据量很大的情况下不仅占用网络资源,而且会导致延迟。 适用场景:只适用于Web服务器比较少且 Session 数据量少的情况。 可用方案:开源方案 tomcat-redis-session-manager,暂不支持 Tomcat8。 Session 粘滞将用户的每次请求都通过某种方法强制分发到某一个 Web 服务器上,只要这个 Web 服务器上存储了对应 Session 数据,就可以实现会话跟踪。 优点:使用简单,没有额外开销。 缺点:一旦某个 Web 服务器重启或宕机,相对应的 Session 数据将会丢失,而且需要依赖负载均衡机制。 适用场景:对稳定性要求不是很高的业务情景。 Session 集中管理在单独的服务器或服务器集群上使用缓...
Session 与 Cookie 区别
Cookie 数据存放在客户的浏览器上,Session 数据放在服务器上。 Cookie 不是很安全,别人可以分析存放在本地的 Cookie 并进行 Cookie 欺骗,考虑到安全应当使用 Session。 Session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用 Cookie。 单个 Cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 Cookie。 这四条是区别清单,但清单回答不了两个更深的问题:Session 为什么需要 Cookie 配合(它们不是对立关系而是协作关系),以及分布式环境下 Session 怎么办。把这两点补上,这个题目才算答完。 本质:HTTP 无状态与状态保持HTTP 是无状态协议:服务器处理完请求就忘记你是谁。但购物车、登录态都需要”记住你”。两种记忆路线: Cookie:把状态记在客户端。服务器通过 Set-Cookie 响应头下发数据,浏览器存储并在后续请求自动携带 Cookie 头 Session:把状态记在服务端。服务器为每个会话创建一块...
HTTP 请求的 GET 与 POST 方式的区别
根据 HTTP 规范,GET 用于信息获取,而且应该是安全的和幂等的。 根据 HTTP 规范,POST 表示可能修改变服务器上资源的请求。 首先是 “GET 方式提交的数据最多只能是 1024 字节”,因为 GET 是通过 URL 提交数据,那么 GET 可提交的数据量就跟 URL 的长度有直接关系了。而实际上,URL 不存在参数上限的问题,HTTP 协议规范没有对 URL 长度进行限制。这个限制是特定的浏览器及服务器对它的限制。IE 对 URL 长度的限制是 2083 字节(2K+35)。对于其他浏览器,如 Netscape、FireFox 等,理论上没有长度限制,其限制取决于操作系统的支持。注意这是限制是整个 URL 长度,而不仅仅是你的参数值数据长度。 POST 是没有大小限制的,HTTP 协议规范也没有进行大小限制 以上为标准答案,实际回答时可增加如下两条: 首先是语义区别,GET 为获取,POST 为提交;(分清语义区别是为了更好的实现 RESTFul 风格 API) 其次是 GET 请求只请求服务器一次,但 POST 会请求两次,第一次是 OPTIONS 方式请...
说说自定义注解的场景及实现
登陆、权限拦截、日志处理,以及各种 Java 框架,如 Spring,Hibernate,JUnit 提到注解就不能不说反射,Java 自定义注解是通过运行时靠反射获取注解。实际开发中,例如我们要获取某个方法的调用日志,可以通过 AOP(动态代理机制)给方法添加切面,通过反射来获取方法包含的注解,如果包含日志注解,就进行日志记录。反射的实现在 Java 应用层面上讲,是通过对 Class 对象的操作实现的,Class 对象为我们提供了一系列方法对类进行操作。在 JVM 这个角度来说,Class 文件是一组以 8 位字节为基础单位的二进制流,各个数据项目按严格的顺序紧凑的排列在 Class 文件中,里面包含了类、方法、字段等等相关数据。通过对 Class 数据流的处理我们即可得到字段、方法等数据。 以上是注解机制的骨架。下面补全三块实战中最需要的内容:注解本身的定义要素、运行时读取的完整链路、以及一个可运行的自定义注解实现。 定义注解的四个要素@Target(ElementType.METHOD) // 能标在哪里:方法/类/字段/参数@Retention(Ret...
说说反射的用途及实现
反射的用途Java 反射机制是一个非常强大的功能,在很多的项目比如 Spring,MyBatis 都都可以看到反射的身影。通过反射机制,我们可以在运行期间获取对象的类型信息。利用这一点我们可以实现工厂模式和代理模式等设计模式,同时也可以解决 Java 泛型擦除等令人苦恼的问题。 把”用途”落到具体框架行为上会更直观: Spring IoC:读取 XML/注解中的类名 → Class.forName 加载 → 反射构造器实例化 → 反射 setter/字段注入依赖。没有反射,容器就无法在”不知道具体类”的前提下创建对象 MyBatis:把 ResultSet 的列映射到 POJO 字段、把 #{param} 绑定到方法参数,全靠反射读写属性 JDK 动态代理:Proxy.newProxyInstance 在运行期生成类并转发调用,AOP 的基石 泛型擦除补偿:运行期通过 getGenericReturnType 等取回声明时的泛型信息(Jackson 反序列化 List<User> 就依赖它) 测试与工具:JUnit 反射调用测...















