<commit_before> <h2>阿里 Java 面经 :memo: </h2> 
 
 > 牛客上扒的，具体出处不详。如有侵权，联系必删。赠人玫瑰，手留余香，向大佬致敬。
 
```html
1.Java 的四个基本特性(抽象、封装、继承、多态)，对多态的理解(多态的实现方式)以及在项目中哪些地方用到多态？
  1) Java 的四个基本特性:
   (1) 抽象：抽象是将一类对象的共同特征总结出来构造类的过程，包括数据抽象和行为抽象两方面。
抽象只关注对象有哪些属性和行为，并不关注这些行为的细节是什么。
   (2) 继承：继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类)；
得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性，同时继承也是封装程序中可变因素的重要手段。
   (3) 封装：通常认为封装是把数据和操作数据的方法绑定起来，对数据的访问只能通过已定义的接口。
面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装；
我们编写一个类就是对数据和数据操作的封装。可以说，封装就是隐藏一切可隐藏的东西，只向外界提供最简单的编程接口。
   (4) 多态性是指允许不同子类型的对象对同一消息作出不同的响应。

  2) 多态的理解(多态的实现方式)。
   (1) 方法重载(overload): 实现的是编译时的多态性(也称为前绑定)。
   (2) 方法重写(override): 实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西。
   (3) 要实现多态需要做两件事：
     ① 方法重写(子类继承父类并重写父类中已有的或抽象的方法)；
     ② 对象造型(用父类型引用引用子类型对象，这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。

  3) 项目中对多态的应用。
   举一个简单的例子，在物流信息管理系统中，有两种用户：订购客户和卖房客户，两个客户都可以登录系统，他们有相
同的方法 Login，但登陆之后他们会进入到不同的页面，也就是在登录的时候会有不同的操作，两种客户都继承父类的
Login 方法，但对于不同的对象，拥有不同的操作。

2.面向对象和面向过程的区别？用面向过程可以实现面向对象吗？那是不是不能面向对象？
  面向对象和面向过程的区别：
   (1) 面向过程就像是一个细心的管家，事无具细的都要考虑到。而面向对象就像是个家用电器，你只需要知道他的功能，
不需要知道它的工作原理。
   (2) "面向过程" 是一种是事件为中心的编程思想。就是分析出解决问题所需的步骤，然后用函数把这些步骤实现，
并按顺序调用。面向对象是以“对象”为中心的编程思想。
   (3) 简单的举个例子：汽车发动、汽车到站。
    这对于“面向过程”来说，是两个事件，汽车启动是一个事件，汽车到站是另一个事件，面向过程编程的过程中我们关心的是事件，
而不是汽车本身。针对上述两个事件，形成两个函数，之后依次调用。
    然而这对于面向对象来说，我们关心的是汽车这类对象，两个事件只是这类对象所具有的行为。
而且对于这两个行为的顺序没有强制要求。

3.重载和重写，如何确定调用哪个函数？
   (1) 重载：重载发生在同一个类中，同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载。
   (2) 重写：重写发生在子类与父类之间，重写要求子类被重写方法与父类被重写方法有相同的返回类型，比父类被重写方法更好
访问，不能比父类被重写方法声明更多的异常(里氏代换原则)。根据不同的子类对象确定调用的那个方法。

4.面向对象开发的六个基本原则(单一职责、开放封闭、里氏替换、依赖倒置、合成聚合复用、接口隔离)，迪米特法则。
在项目中用过哪些原则?
  1) 六个基本原则：
   (1) 单一职责：一个类只做它该做的事情(高内聚)。在面向对象中，如果只让一个类完成它该做的事，而不涉及与它无关的
领域就是践行了高内聚的原则，这个类就只有单一职责。
   (2) 开放封闭：软件实体应当对扩展开放，对修改关闭。要做到开闭有两个要点：
     ① 抽象是关键，一个系统中如果没有抽象类或接口系统就没有扩展点；
     ② 封装可变性，将系统中的各种可变因素封装到一个继承结构中，如果多个可变因素混杂在一起，系统将变得复杂而换乱。
   (3) 里氏替换：任何时候都可以用子类型替换掉父类型。子类一定是增加父类的能力而不是减少父类的能力，因为子类比父
类的能力更多，把能力多的对象当成能力少的对象来用当然没有任何问题。
   (4) 依赖倒置：面向接口编程。(该原则说得直白和具体一些就是声明方法的参数类型、方法的返回类型、变量的引用类型时，
尽可能使用抽象类型而不用具体类型，因为抽象类型可以被它的任何一个子类型所替代)。
   (5) 合成聚和复用：优先使用聚合或合成关系复用代码。
   (6) 接口隔离：接口要小而专，绝不能大而全。臃肿的接口是对接口的污染，既然接口表示能力，那么一个接口只应该描述
一种能力，接口也应该是高度内聚的。
  2) 迪米特法则：迪米特法则又叫最少知识原则，一个对象应当对其他对象有尽可能少的了解。
  3) 项目中用到的原则: 单一职责、开放封闭、合成聚合复用(最简单的例子就是 String 类)、接口隔离。

5.static 和 final 的区别和用途？
  (1) static
   修饰变量：静态变量随着类加载时被完成初始化，内存中只有一个，且 JVM 也只会为它分配一次内存，所有类共享静态变量。
   修饰方法：在类加载的时候就存在，不依赖任何实例；static 方法必须实现，不能用 abstract 修饰。
   修饰代码块：在类加载完之后就会执行代码块中的内容。
   父类静态代码块 -> 子类静态代码块 -> 父类非静态代码块 -> 父类构造方法 -> 子类非静态代码块 -> 子类构造方法
  (2) final
   修饰变量：
     编译期常量：类加载的过程完成初始化，编译后带入到任何计算式中。只能是基本类型。
     运行时常量：基本数据类型或引用数据类型。引用不可变，但引用的对象内容可变。
     修饰方法：不能被继承，不能被子类修改。
     修饰类：不能被继承。
     修饰形参：final 形参不可变。

6.Hash Map 和 Hash Table 的区别，Hash Map 中的 key 可以是任何对象或数据类型吗？HashTable 是线程安全的么？
   (1) Hash Map 和 Hash Table 的区别：
    Hashtable 的方法是同步的，HashMap 未经同步，所以在多线程场合要手动同步 HashMap 这个区别就像 Vector 和
ArrayList 一样。
    Hashtable 不允许 null 值( key 和 value 都不可以)，HashMap 允许 null 值( key 和 value 都可以)。
    两者的遍历方式大同小异，Hashtable 仅仅比 HashMap 多一个 elements 方法。
    Hashtable 和 HashMap 都能通过 values() 方法返回一个 Collection，然后进行遍历处理。
    两者也都可以通过 entrySet() 方法返回一个 Set， 然后进行遍历处理。
    HashTable 使用 Enumeration，HashMap 使用 Iterator。
    哈希值的使用不同，Hashtable 直接使用对象的 hashCode。而 HashMap 重新计算 hash 值，而且用于代替求模。
    Hashtable 中 hash 数组默认大小是 11，增加的方式是 old*2 + 1。HashMap 中 hash 数组的默认大小是 16，
而且一定是 2 的指数。
    HashTable 基于 Dictionary 类，而 HashMap 基于 AbstractMap 类。
   (2) Hash Map 中的 key 可以是任何对象或数据类型吗?
    可以为 null，但不能是可变对象，如果是可变对象的话，对象中的属性改变，则对象 HashCode 也进行相应的改变，
导致下次无法查找到已存在 Map 中的数据。
    如果可变对象在 HashMap 中被用作键，那就要小心在改变对象状态的时候，不要改变它的哈希值了。我们只需要保证
成员变量的改变能保证该对象的哈希值不变即可。
   (3) HashTable 是线程安全的么？
    HashTable 是线程安全的，其实现是在对应的方法上添加了 synchronized 关键字进行修饰，由于在执行此方法的时候
需要获得对象锁，则执行起来比较慢。所以现在如果为了保证线程安全的话，使用 ConcurrentHashMap。
```<commit_msg>Update AlibabaJavaInterview.md<commit_after> <h2>阿里 Java 面经 :memo: </h2> 
 
 > 牛客上扒的，具体出处不详。如有侵权，联系必删。赠人玫瑰，手留余香，向大佬致敬。
 
```html
1.Java 的四个基本特性(抽象、封装、继承、多态)，对多态的理解(多态的实现方式)以及在项目中哪些地方用到多态？
  1) Java 的四个基本特性:
   (1) 抽象：抽象是将一类对象的共同特征总结出来构造类的过程，包括数据抽象和行为抽象两方面。
抽象只关注对象有哪些属性和行为，并不关注这些行为的细节是什么。
   (2) 继承：继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类)；
得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性，同时继承也是封装程序中可变因素的重要手段。
   (3) 封装：通常认为封装是把数据和操作数据的方法绑定起来，对数据的访问只能通过已定义的接口。
面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装；
我们编写一个类就是对数据和数据操作的封装。可以说，封装就是隐藏一切可隐藏的东西，只向外界提供最简单的编程接口。
   (4) 多态性是指允许不同子类型的对象对同一消息作出不同的响应。

  2) 多态的理解(多态的实现方式)。
   (1) 方法重载(overload): 实现的是编译时的多态性(也称为前绑定)。
   (2) 方法重写(override): 实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西。
   (3) 要实现多态需要做两件事：
     ① 方法重写(子类继承父类并重写父类中已有的或抽象的方法)；
     ② 对象造型(用父类型引用引用子类型对象，这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。

  3) 项目中对多态的应用。
   举一个简单的例子，在物流信息管理系统中，有两种用户：订购客户和卖房客户，两个客户都可以登录系统，他们有相
同的方法 Login，但登陆之后他们会进入到不同的页面，也就是在登录的时候会有不同的操作，两种客户都继承父类的
Login 方法，但对于不同的对象，拥有不同的操作。

2.面向对象和面向过程的区别？用面向过程可以实现面向对象吗？那是不是不能面向对象？
  面向对象和面向过程的区别：
   (1) 面向过程就像是一个细心的管家，事无具细的都要考虑到。而面向对象就像是个家用电器，你只需要知道他的功能，
不需要知道它的工作原理。
   (2) "面向过程" 是一种是事件为中心的编程思想。就是分析出解决问题所需的步骤，然后用函数把这些步骤实现，
并按顺序调用。面向对象是以“对象”为中心的编程思想。
   (3) 简单的举个例子：汽车发动、汽车到站。
    这对于“面向过程”来说，是两个事件，汽车启动是一个事件，汽车到站是另一个事件，面向过程编程的过程中我们关心的是事件，
而不是汽车本身。针对上述两个事件，形成两个函数，之后依次调用。
    然而这对于面向对象来说，我们关心的是汽车这类对象，两个事件只是这类对象所具有的行为。
而且对于这两个行为的顺序没有强制要求。

3.重载和重写，如何确定调用哪个函数？
   (1) 重载：重载发生在同一个类中，同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载。
   (2) 重写：重写发生在子类与父类之间，重写要求子类被重写方法与父类被重写方法有相同的返回类型，比父类被重写方法更好
访问，不能比父类被重写方法声明更多的异常(里氏代换原则)。根据不同的子类对象确定调用的那个方法。

4.面向对象开发的六个基本原则(单一职责、开放封闭、里氏替换、依赖倒置、合成聚合复用、接口隔离)，迪米特法则。
在项目中用过哪些原则?
  1) 六个基本原则：
   (1) 单一职责：一个类只做它该做的事情(高内聚)。在面向对象中，如果只让一个类完成它该做的事，而不涉及与它无关的
领域就是践行了高内聚的原则，这个类就只有单一职责。
   (2) 开放封闭：软件实体应当对扩展开放，对修改关闭。要做到开闭有两个要点：
     ① 抽象是关键，一个系统中如果没有抽象类或接口系统就没有扩展点；
     ② 封装可变性，将系统中的各种可变因素封装到一个继承结构中，如果多个可变因素混杂在一起，系统将变得复杂而换乱。
   (3) 里氏替换：任何时候都可以用子类型替换掉父类型。子类一定是增加父类的能力而不是减少父类的能力，因为子类比父
类的能力更多，把能力多的对象当成能力少的对象来用当然没有任何问题。
   (4) 依赖倒置：面向接口编程。(该原则说得直白和具体一些就是声明方法的参数类型、方法的返回类型、变量的引用类型时，
尽可能使用抽象类型而不用具体类型，因为抽象类型可以被它的任何一个子类型所替代)。
   (5) 合成聚和复用：优先使用聚合或合成关系复用代码。
   (6) 接口隔离：接口要小而专，绝不能大而全。臃肿的接口是对接口的污染，既然接口表示能力，那么一个接口只应该描述
一种能力，接口也应该是高度内聚的。
  2) 迪米特法则：迪米特法则又叫最少知识原则，一个对象应当对其他对象有尽可能少的了解。
  3) 项目中用到的原则: 单一职责、开放封闭、合成聚合复用(最简单的例子就是 String 类)、接口隔离。

5.static 和 final 的区别和用途？
  (1) static
   修饰变量：静态变量随着类加载时被完成初始化，内存中只有一个，且 JVM 也只会为它分配一次内存，所有类共享静态变量。
   修饰方法：在类加载的时候就存在，不依赖任何实例；static 方法必须实现，不能用 abstract 修饰。
   修饰代码块：在类加载完之后就会执行代码块中的内容。
   父类静态代码块 -> 子类静态代码块 -> 父类非静态代码块 -> 父类构造方法 -> 子类非静态代码块 -> 子类构造方法
  (2) final
   修饰变量：
     编译期常量：类加载的过程完成初始化，编译后带入到任何计算式中。只能是基本类型。
     运行时常量：基本数据类型或引用数据类型。引用不可变，但引用的对象内容可变。
     修饰方法：不能被继承，不能被子类修改。
     修饰类：不能被继承。
     修饰形参：final 形参不可变。

6.Hash Map 和 Hash Table 的区别，Hash Map 中的 key 可以是任何对象或数据类型吗？HashTable 是线程安全的么？
   (1) Hash Map 和 Hash Table 的区别：
    Hashtable 的方法是同步的，HashMap 未经同步，所以在多线程场合要手动同步 HashMap 这个区别就像 Vector 和
ArrayList 一样。
    Hashtable 不允许 null 值( key 和 value 都不可以)，HashMap 允许 null 值( key 和 value 都可以)。
    两者的遍历方式大同小异，Hashtable 仅仅比 HashMap 多一个 elements 方法。
    Hashtable 和 HashMap 都能通过 values() 方法返回一个 Collection，然后进行遍历处理。
    两者也都可以通过 entrySet() 方法返回一个 Set， 然后进行遍历处理。
    HashTable 使用 Enumeration，HashMap 使用 Iterator。
    哈希值的使用不同，Hashtable 直接使用对象的 hashCode。而 HashMap 重新计算 hash 值，而且用于代替求模。
    Hashtable 中 hash 数组默认大小是 11，增加的方式是 old*2 + 1。HashMap 中 hash 数组的默认大小是 16，
而且一定是 2 的指数。
    HashTable 基于 Dictionary 类，而 HashMap 基于 AbstractMap 类。
   (2) Hash Map 中的 key 可以是任何对象或数据类型吗?
    可以为 null，但不能是可变对象，如果是可变对象的话，对象中的属性改变，则对象 HashCode 也进行相应的改变，
导致下次无法查找到已存在 Map 中的数据。
    如果可变对象在 HashMap 中被用作键，那就要小心在改变对象状态的时候，不要改变它的哈希值了。我们只需要保证
成员变量的改变能保证该对象的哈希值不变即可。
   (3) HashTable 是线程安全的么？
    HashTable 是线程安全的，其实现是在对应的方法上添加了 synchronized 关键字进行修饰，由于在执行此方法的时候
需要获得对象锁，则执行起来比较慢。所以现在如果为了保证线程安全的话，使用 ConcurrentHashMap。

7.HashMap 和 ConcurrentHashMap 的区别，ConcurrentHashMap 线程安全吗? ConcurrentHashMap 如何保证线程安全？
   (1) HashMap 和 ConcurrentHashMap 区别？
    HashMap 是非线程安全的，CurrentHashMap 是线程安全的。
    ConcurrentHashMap 将整个 Hash 桶进行了分段 Segment，也就是将这个大的数组分成了几个小的片段 Segment，
而且每个小的片段 Segment 上面都有锁存在，那么在插入元素的时候就需要先找到应该插入到哪一个片段 Segment，
然后再在这个片段上面进行插入，而且这里还需要获取 Segment 锁。
    ConcurrentHashMap 让锁的粒度更精细一些，并发性能更好。
   (2) ConcurrentHashMap 线程安全吗，ConcurrentHashMap 如何保证线程安全？
    HashTable 容器在竞争激烈的并发环境下表现出效率低下的原因是所有访问 HashTable 的线程都必须竞争同一把锁，
那假如容器里有多把锁，每一把锁用于锁容器其中一部分数据，那么当多线程访问容器里不同数据段的数据时，线程间就
不会存在锁竞争，从而可以有效的提高并发访问效率，这就是 ConcurrentHashMap 所使用的锁分段技术，首先将数据
分成一段一段的存储，然后给每一段数据配一把锁，当一个线程占用锁访问其中一个段数据的时候，其他段的数据也能
被其他线程访问。
    get 操作的高效之处在于整个 get 过程不需要加锁，除非读到的值是空的才会加锁重读。get 方法里将要使用的共享变量
都定义成 volatile，如用于统计当前 Segement 大小的 count 字段和用于存储值的 HashEntry 的 value。
定义成 volatile 的变量，能够在线程之间保持可见性，能够被多线程同时读，并且保证不会读到过期的值，
但是只能被单线程写(有一种情况可以被多线程写，就是写入的值不依赖于原值)，
在 get 操作里只需要读不需要写共享变量 count 和 value，所以可以不用加锁。
    put 方法首先定位到 Segment，然后在 Segment 里进行插入操作。插入操作需要经历两个步骤，第一步判断是否需要
对 Segment 里的 HashEntry 数组进行扩容，第二步定位添加元素的位置然后放在 HashEntry 数组里。

8.因为别人知道源码怎么实现的，故意构造相同 hash 的字符串进行攻击，怎么处理？那 jdk7 怎么办？
   1) 怎么处理构造相同 hash 的字符串进行攻击?
    当客户端提交一个请求并附带参数的时候，Web 应用服务器会把我们的参数转化成一个 HashMap 存储，
这个 HashMap 的逻辑结构如下：key1 --> value1;
    但是物理存储结构是不同的，key 值会被转化成 hashcode，这个 hashcode 会被转成数组的下标：0 --> value1；
    不同的 string 就会产生相同 hashcode 而导致碰撞，碰撞后的物理存储结构可能如下：0 --> value1 --> value2;
   2) 怎么处理？
     (1) 限制 Post 和 Get 的参数个数，越少越好;
     (2) 限制 Post 数据包的大小;
     (3) WAF。
   3) Jdk7 如何处理 hashcode 字符串攻击？
    HashMap 会动态的使用一个专门的 treemap 实现来替换掉它。
```
{'fraction_non_alphanumeric': 0.08925279253877019, 'fraction_numerical': 0.01160394751111593, 'mean_word_length': 6.815254237288135, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '11422', 'n_tokens_mistral': 7542, 'n_tokens_neox': 8670, 'n_words': 628}