题目小计

简历

项目简介:

非科班出身 –> 影响较大

偏向于问八股, 问基本功

专业技能方向应该把微服务 大数据、抽练一下,阐述含金量的优化点

亮点: 人大金仓 微服务全流程 一定会问死

项目写的不行,就这么 第一个放在第二个
第二个项目 重写 放在第一位。
项目的基本概述 ,技术栈罗列出来, 职责描述,
技术亮点1、2、3、4、把智慧办案 的进行重写
一个很重权重 的面试点;

平均水平,有亮点但是不多

上八股,打实在基础

java

@Autowired 与@Resource的区别

https://blog.csdn.net/weixin_40423597/article/details/80643990

权限修饰符可用来修饰

属性、方法、构造器、内部类

区分方法的重写和重载

https://www.yuanql.top/2023/01/05/03_java%E5%9F%BA%E7%A1%80%E7%BC%96%E7%A8%8B/05_%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E4%B8%AD/%E6%96%B9%E6%B3%95%E7%9A%84%E9%87%8D%E5%86%99/#5-%E9%9D%A2%E8%AF%95%E9%A2%98%EF%BC%9A

super可以调用 属性、方法、构造器

static可以用来修饰 属性、方法、代码块、内部类

final可以用来修饰:类、方法、变量

abstract可以用来修饰:类、方法
abstract不能用来修饰:属性、构造器等结构
abstract不能用来修饰私方法、静态方法、final的方法、final的类

Thread

# Java线程的6种状态及切换(透彻讲解)

初始化和扩容

StringBuffer、StringBuilder 的初始化和扩容

此两个类都继承了AbstractStringBuilder类,实现了Serializable, CharSequence接口,其初始化和扩容都是一样的

初始化:

1
2
3
4
5
6
7
public StringBuffer() {  super(16); }

public StringBuffer(int capacity) { super(capacity); }

public StringBuffer(String str) { super(str.length() + 16); append(str); }

public StringBuffer(CharSequence seq) { this(seq.length() + 16); append(seq); }

扩容:

当不能够完全存下的时候,则进行扩容:
1、先尝试扩大到 原本的数组长度 * 2 + 2 (value.length << 1) + 2 ,判断数组大小是否可以使用,如果还不够用
2、直接扩大到 需要加入数值长度 + 原有占用参数的长度(即lenth()返回的长度。)。

ArrayList

java 7

ArrayList list = new ArrayList();//底层创建了长度是10的Object[]数组elementData

list.add(123);//elementData[0] = new Integer(123);

list.add(11);//如果此次的添加导致底层elementData数组容量不够,则扩容。
默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中。

java 8

初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}

public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray();
if ((size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
}
}

底层Object[] elementData初始化为{}.并没创建长度为10的数组

扩容:

1
2
3
4
5
6
7
8
9
10
11
private void grow(int minCapacity) {  
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容的大小
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}

因为jdk8中的ArrayList的对象的创建类似于单例的懒汉式,延迟了数组的创建。所以在初始创建的时候,其在添加第一个数据的时候就涉及到了扩容,最终现象未初始化了一个长度为10的数组。

当数据装不下的时候进行扩容,扩容的大小为 1.5 倍原数组,如果还装不下,直接等于相加之后的长度。并且把原有的数据copy过去。

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

HashSet

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public HashSet() {
map = new HashMap<>();
}

public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}

public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}

public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}

HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

向Set(主要指:HashSet、LinkedHashSet)中添加的数据,其所在的类一定要重写hashCode()和equals()

HashMap

jdk7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HashMap map = new HashMap():
* 在实例化以后,底层创建了长度是16的一维数组Entry[] table。
* ...可能已经执行过多次put...
* map.put(key1,value1):
* 首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。
* 如果此位置上的数据为空,此时的key1-value1添加成功。 ----情况1
* 如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
* 如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。----情况2
* 如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals(key2)方法,比较:
* 如果equals()返回false:此时key1-value1添加成功。----情况3
* 如果equals()返回true:使用value1替换value2。
*
* 补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储。
*
* 在不断的添加过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空)时,扩容。默认的扩容方式:扩容为原来容量的2倍,并将原的数据复制过来。

jdk8中相较于jdk7在底层实现方面的不同

  1. new HashMap():底层没创建一个长度为16的数组
  2. jdk 8底层的数组是:Node[],而非Entry[]
  3. 首次调用put()方法时,底层创建长度为16的数组
  4. jdk7底层结构只:数组+链表。jdk8中底层结构:数组+链表+红黑树。
    4.1 形成链表时,七上八下(jdk7:新的元素指向旧的元素。jdk8:旧的元素指向新的元素)
    4.2 当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且 当前数组的长度 > 64时,此时此索引位置上的所数据改为使用红黑树存储。
1
2
3
4
5
DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16
DEFAULT_LOAD_FACTOR:HashMap的默认加载因子:0.75
threshold:扩容的临界值,=容量*填充因子:16 * 0.75 => 12
TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树:8
MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64

jdk 注解:

## Java 注解(Annotation)

内置的注解

Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。

作用在代码的注解是

  • @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
  • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
  • @SuppressWarnings - 指示编译器去忽略注解中声明的警告。

作用在其他注解的注解(或者说 元注解)是:

  • @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
  • @Documented - 标记这些注解是否包含在用户文档中。
  • @Target - 标记这个注解应该是哪种 Java 成员。
  • @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

从 Java 7 开始,额外添加了 3 个注解:

  • @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
  • @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
  • @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

JVM

-Xss 设置栈的大小
“-Xms”用于表示堆空间(年轻代+老年代)的起始内存
“-Xmx”则用于表示堆空间(年轻代+老年代)的最大内存

配置新生代与老年代在堆结构的占比。

  • 默认-XX:NewRatio=2,表示新生代占 1,老年代占 2,新生代占整个堆的 1/3
  • 可以修改-XX:NewRatio=4,表示新生代占 1,老年代占 4,新生代占整个堆的 1/5

在 HotSpot 中,Eden 空间和另外两个 survivor 空间缺省所占的比例是 8:1:1
当然开发人员可以通过选项“-XX:SurvivorRatio”调整这个空间比例。比如-XX:SurvivorRatio=8

-XX:-UseAdaptivesizePolicy : 关闭自适应的内存分配策略

-Xmn“设置新生代最大内存大小
当同时设置了”-Xmn“与-XX:NewRatio=2,将以”-Xmn“设置的参数为准。
-Xmn“一般不设置,一般使用-XX:NewRatio=2进行设置。

养老区呢?可以设置次数。默认是 15 次。

  • 可以设置参数:-Xx:MaxTenuringThreshold= N进行设置

堆空间的参数设置
官网地址:https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 详细的参数内容会在JVM下篇:性能监控与调优篇中进行详细介绍,这里先熟悉下
-XX:+PrintFlagsInitial //查看所有的参数的默认初始值
-XX:+PrintFlagsFinal //查看所有的参数的最终值(可能会存在修改,不再是初始值)
具体查看某个参数的指令:
jps //查看当前运行中的进程
jinfo -flag SurvivorRatio 进程id
-Xms //初始堆空间内存(默认为物理内存的1/64)
-Xmx //最大堆空间内存(默认为物理内存的1/4)
-Xmn //设置新生代的大小。(初始值及最大值)
-XX:NewRatio //配置新生代与老年代在堆结构的占比
-XX:SurvivorRatio //设置新生代中Eden和S0/S1空间的比例
-XX:MaxTenuringThreshold //设置新生代垃圾的最大年龄
-XX:+PrintGCDetails //输出详细的GC处理日志
//打印gc简要信息:①-Xx:+PrintGC ② - verbose:gc
-XX:HandlePromotionFalilure://是否设置空间分配担保
  • 参数-server:启动 Server 模式,因为在 server 模式下,才可以启用逃逸分析。
  • 参数-XX:+DoEscapeAnalysis:启用逃逸分析
  • 参数-Xmx10m:指定了堆空间最大为 10MB
  • 参数-XX:+PrintGC:将打印 Gc 日志
  • 参数-XX:+EliminateAllocations:开启了标量替换(默认打开),允许将对象打散分配在栈上,比如对象拥有 id 和 name 两个字段,那么这两个字段将会被视为两个独立的局部变量进行分配

方法区
jdk7 及以前

  • 通过-XX:Permsize来设置永久代初始分配空间。默认值是 20.75M
  • 通过-XX:MaxPermsize来设定永久代最大可分配空间。32 位机器默认是 64M,64 位机器模式是 82M
  • 当 JVM 加载的类信息容量超过了这个值,会报异常OutOfMemoryError:PermGen space

JDK8 以后

  • 元数据区大小可以使用参数 -XX:MetaspaceSize-XX:MaxMetaspaceSize指定
  • 默认值依赖于平台。windows 下,-XX:MetaspaceSize=21M -XX:MaxMetaspaceSize=-1//即没有限制
  • 与永久代不同,如果不指定大小,默认情况下,虚拟机会耗尽所有的可用系统内存。如果元数据区发生溢出,虚拟机一样会抛出异常OutOfMemoryError:Metaspace
  • -XX:MetaspaceSize:设置初始的元空间大小。对于一个 64 位的服务器端 JVM 来说,其默认的-XX:MetaspaceSize值为 21MB。这就是初始的高水位线,一旦触及这个水位线,Full GC 将会被触发并卸载没用的类(即这些类对应的类加载器不再存活),然后这个高水位线将会重置。新的高水位线的值取决于 GC 后释放了多少元空间。如果释放的空间不足,那么在不超过MaxMetaspaceSize时,适当提高该值。如果释放空间过多,则适当降低该值。
  • 如果初始化的高水位线设置过低,上述高水位线调整情况会发生很多次。通过垃圾回收器的日志可以观察到 Full GC 多次调用。为了避免频繁地 GC,建议将-XX:MetaspaceSize设置为一个相对较高的值。

回收器

  • 新生代收集器:Serial、ParNew、Parallel Scavenge;
  • 老年代收集器:Serial Old、Parallel Old、CMS;
  • 整堆收集器:G1;

Serial 收集器采用复制算法串行回收和”stop-the-World“机制的方式执行内存回收
Serial Old 收集器同样也采用了串行回收和 “ Stop the World “ 机制,只不过内存回收算法使用的是标记-压缩算法

ParNew 收集器则是 Serial 收集器的多线程版本;ParNew 收集器除了采用并行回收的方式执行内存回收外,两款垃圾收集器之间几乎没有任何区别。ParNew 收集器在年轻代中同样也是采用复制算法、”Stop-the-World”机制

Parallel Scavenge 收集器同样也采用了复制算法、并行回收和”Stop the World”机制

  • 和 ParNew 收集器不同,ParallelScavenge 收集器的目标则是达到一个可控制的吞吐量(Throughput),它也被称为吞吐量优先的垃圾收集器。
  • 自适应调节策略也是 Parallel Scavenge 与 ParNew 一个重要区别。

Parallel Old 收集器采用了标记-压缩算法,但同样也是基于并行回收和”Stop-the-World”机制

CMS 收集器的关注点是尽可能缩短垃圾收集时用户线程的停顿时间
CMS 的垃圾收集算法采用标记-清除算法,并且也会”Stop-the-World”

G1 将内存划分为一个个的 region。内存的回收是以 region 作为基本单位的。Region 之间是复制算法,但整体上实际可看作是标记-压缩(Mark-Compact)算法,两种算法都可以避免内存碎片。

垃圾收集器 分类 作用位置 使用算法 特点 适用场景
Serial 串行运行 作用于新生代 复制算法 响应速度优先 适用于单 CPU 环境下的 client 模式
ParNew 并行运行 作用于新生代 复制算法 响应速度优先 多 CPU 环境 Server 模式下与 CMS 配合使用
Parallel 并行运行 作用于新生代 复制算法 吞吐量优先 适用于后台运算而不需要太多交互的场景
Serial Old 串行运行 作用于老年代 标记-压缩算法 响应速度优先 适用于单 CPU 环境下的 Client 模式
Parallel Old 并行运行 作用于老年代 标记-压缩算法 吞吐量优先 适用于后台运算而不需要太多交互的场景
CMS 并发运行 作用于老年代 标记-清除算法 响应速度优先 适用于互联网或 B/S 业务
G1 并发、并行运行 作用于新生代、老年代 标记-压缩算法、复制算法 响应速度优先 面向服务端应用

题目小计
http://yuanql.top/2022/01/16/题目小计/
作者
Qingli Yuan
发布于
2022年1月16日
许可协议