未经允许所有内容都可都可都可转载,不对的地方欢迎指正
String
1.String s1 = “a”;String s2 = “a”; a==b? s1.equals(s2)?
- String 字符串时常量,常量存储在方法区的常量池。
- 进入常量池规则,如果没有,创建,如果有,不再创建通过地址指向即可。
- 所以,s1 = “a”, 会在常量池创建一个字符串常量 “abc”,地址给了s1
- 当s2 = “a” 时,常量池已经有了整个字符串对象,所以将地址给了s2.
- 两个引用指向了同一个地址,所以a==b 返回true.
- String类重写了equals方法。先比较了长度,后转char数组每位逐一比较,比较的是属性值,所以equals也是相等的。
2.下面这句话创建了几个对象?String s = new String(“abc”);
- 如果常量池有 “abc” 整个字符串,创建了一个对象。即堆中创建了一个String对象。 堆中对象地址与常量池中不同。
- 如果常量池没有 “abc”,则创建了两个对象,先在常量池创建了字符串对象,在再堆中创建了String对象。
3.String s1 = “abc”. s2 = new String(abc) 判断是否相等。
- s1 == s2 // false. 结合1.2 略
- s1.equals(s2) // ture. 同上略
4. 如下,+ 号的底层是什么的理解?
- s2 == s3 ture, 单纯的字符串相加已经在编译器完成了常量池的指向。
- s2 == s4 false, s1 + b, s1本身不是字符串常量,而是字符串的引用。而+号实际上是通过StringBuffer 或者 StringBuilder的append方法拼接后转化为String对象,对象在堆中。
@Testpublic void testStr(){String s1 = "a";String s2 = "ab";String s3 = "a"+"b";String s4 = s1 + "b";System.out.println(s2 == s3); // tureSystem.out.println(s2 == s4); // false}
5.String ,StringBuffer, StringBuilder的区别
略。
6. intern方法
- 如问题4 String s4 = (s1 + “b”).intern(); s2 == s4 为true.
- 当intern方法被调用时,如果常量池中有一个字符串和当前调用方法的字符串equals相等,name就返回常量池中字符串引用,如果池中没有,放入,返归引用。
7.为什么使用HashMap时总是使用String做key?
- 因为Stirng时不可变的,当创建字符串时,他的hashcode被缓存下来,不需要再次计算。
- HashMap内部实现时通过key的hasCode来确定Value的位置。所以相比使用其他key计算更快。
8 String和byte ,char的互转。
ArrayList
1、讲讲ArrayList? — arrayList实现了List接口,继承与AbstarctList、底层数据结构为动态数组。线程不安全。 2、说说ArrayList默认长度? —指定正整数为指定数据长度,空构造长度为0,第一次添加元素时初始化,默认大小为10. 3、ArrayList的扩容? — 原大小的1.5倍和添加元素后的长度做比较。取大的。 4、ArrayList为什么增删慢? — 底层为数组,内存空间连续,需要动态改变数组大小,调用System.arrayCopy且需要移动其他元素位置。频繁地增删建议使用LinkedList. 5、线程安全吗? —线程不安全,使用Vector替代,或者使用 SynchronizedList 、CopyonWriteArrayList 6、modCout作用? —-迭代时next方法中会校验 modCount和expectModCount大小,如果改变抛出ConcurrentModificationException异常。 7、如何拷贝一个arrayList数组至另外一个ArrayList? —7.1 直接new = old.clone(); 浅拷贝 7.2 new ArrayList(old); 浅拷贝 7.3 Collection.copy 身拷贝 8、什么时候使用ArrayList,什么时候使用LinkedList? arrayList 增加删除慢。LinkedList 查询慢。
== 和 equals 的区别?
== 比较的是栈中的值, 基本数据类型比较的是变量值。 引用类型比较的是堆中的地址。 equals : Object类中默认也是通过 == 比较,通常会重写。
重载和重写?
重写 override 发生在子父类中,方法名,参数名必须与父类相同, 返回值范围小于等于父类,异常小于等于父类。访问修饰符大于等于父类,如果父类访问修饰符为private,则不能重写。 重载 overload 发生在同一个类中,方法名必须相同、 参数类型不同、个数不同、顺序不同。 返回值和修饰符可以不同。发生在编译时。
什么是面向对象
做一件事情,面向过程更注重每一个步骤和顺序。 面向对象更注重做一件事情需要哪些参与者。即这些参与者需要做什么。 举例说明(洗衣服):
- 面向过程: 打开洗衣机—> 放衣服 —> 放洗衣粉—> 清洗衣服 —> 烘干
- 面向对象: 人(对象): 打开洗衣机 放衣服 放洗衣粉 都是人的方法, 洗衣机(对象): 清洗衣服 烘干 都是洗衣机的方法
面向对象的三大特性
- 封装
将一系列的功能封装成方法对外可见, 内部的实现细节外部无需关注。 同时也可以通过修饰符 限定封装的方法对谁可用。
- 继承
继承父类方法,做出自己的改变和扩展。 子类共性的方法或者属性,直接定义在父类,无需自己再定义。只需要根据自身特性扩展。
- 多态
基于对象所属类的不同,调用同一个方法,实际执行的逻辑不同。
抽象类和接口的区别
- 基础
1) 抽象类中可以存在普通函数、接口中1.7前只能是public abstract方法,1.8后可以有静态和default方法。 2) 抽象类中成员变量可以是各种类型的。而接口中的成员变量只能是publice static final的。 3) 抽象类只能继承一个,而接口可以多实现。
- 高级
1) 接口 like a的关系。 2) 抽象类 is a 的关系。 3) 比如: 飞行物可以是一个接口 可以定义fly这个方法, 而鸟就是实现了这个接口的抽象类,可以定义鸟的名称、大小、颜色等属性, 而飞机也是实现了 飞行物接口的,可以定义型号、生产地、邮箱大小等属性。
数据类型
数据结构
线性
数组
链表
Stack栈(Vector子类,底层为数组):
- 是什么
- 一种特殊线性数据结构
- 只允许从在固定的一端(栈顶)插入和删除元素。
- FILO first in last out: 先进后出
- 类关系图

- 构造方法:默认大小:10,扩容机制同Vector

- 常用方法:
队列
- 类关系图

- 特点: 先进先出 FILI
- 非阻塞队列:ConcurrentLinkedQueue
- 阻塞队列:
树形
二叉树简介:
数的基本术语
若一个结点有子树,那么该结点称为子树根的“双亲”,子树的根称为该结点的“孩子”。有相同双亲的结点互为“兄弟”。一个结点的所有子树上的任何结点都是该结点的后裔。从根结点到某个结点的路径上的所有结点都是该结点的祖先。
满二叉树
高度为h,并且由2h-1个结点组成的二叉树,称为满二叉树
完全二叉树
定义:一棵二叉树中,只有最下面两层结点的度可以小于2,并且最下层的叶结点集中在靠左的若干位置上,这样的二叉树称为完全二叉树。
特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。
二叉搜索树(BST):
如果左子树存在,则其左子树中的每个节点的值都小于该节点的值 如果右子树存在,则其右子树的每个节点的值都大于该节点值 树在插入的时候会导致倾斜,不同的插入顺序导致树的高度不一致。比如:

每次插入,如果大于跟节点,从右边找位置,小于从左边。 从右边一直找到大于当前值的节点,左边没节点放左边,左边有节点和左边比,最终插入的原则,左小右大,一条树线性上右边小到大,左边大到小。
高度平衡树(AVL)
BST不同的插入顺序会导致树的高度不一样,而树的高度直接影响了查询效率。最坏的情况下所有节点都在一条线上。 平衡树在插入和删除的时候会将高度保持在LogN上。 具有二叉搜索树的全部特点,而且左右高度差不超过1
2-3-4 树
红黑树
集合框架
Colleciton类关系图
ArrayList(不安全,效率高)
Vector(线程安全,效率不高)
ArrayList 和 Vector区别:
HashMap
脑图整理: https://www.processon.com/mindmap/612211871e08534545453e07 有空回来补充。
IO
javaIO体系
- inputStream

- outputStream

- Reader

- Writer
java中有几种类型的流?
字节流和字符流
- 字节流继承自inputStream和OutPutStream.
- 字节流继承自Reader和Writer
谈谈javaIO里面常见类,字节流,字符流,接口,实现类,方法阻塞
- 输入流就是指从外部文件输入到内存,输出流指从内存输出到文件。
- 字节流主要是InputStream和OutputStream和他们的子类FileInputStream,FileOutputStream,BufferedOutputStream等。
- 字符流主要是Reader和Writer和他们的子类。BufferedReader、FileReader等。
- 他们都实现了Closeable,Flushable,Appendable这些接口。
- java中的阻塞式方法是指程序程序在调用该方法时,必须等待输入数据可用,或者检测到输入结束,参会继续往下执行,否则一致会停留在该语句上。比如read()方法和readLine()方法。
字符流和字节流有什么区别
- 字节流在操作的时候本身是不会用到缓冲区的,是直接操作的文件。字符流在字符流操作的时候使用到了缓冲区。
- 字节流在操作文件时,即使不关闭资源,即不调用close方法,文件也能输入,因为是直接操作的文件。而字符流用的是缓冲区,需要flush,close才能真正的刷新缓冲区输出内容。
- InputStream,read方法返回int,因为字节流每次读取的是1一个字节,占位8bit,范围在0——28-1. 如果读取到流末尾返回-1.
- Reader,read方法范围int,因为字符流每次读取的是2个字节,占位16bit,范围在0——216-1,如果读取到行末尾返回-1.
反射
序列化
什么是序列化
序列化是指将对象持久化为可以存储或者传输的形式的过程。 将持久化存储转化为对象的过程称为反序列化。
JAVA相关类
示例代码
- 方式一:
- 实现serializable
- 通过ObjectOutputStream的write和ObjectInputStrem的read实现。

- 方式二
- 继承Externalizable
- 必须设置无参构造方法
- 复写writeExternal和readExternal可以指定需要序列化和反序列化的属性。
- 读取数据类型一致,读取顺序一致
泛型
泛型中的extends和super的区别。
<? extend T>表示包括T在内的任何T的子类 <? super T>表示包括T在内的任何T的父类。
String
String、StringBuffer、StringBuiler区别
- Stirng是final修饰的。不可变,每次操作都会产生新的对象。
- StringBuilder和StringBuffer都是在原对象上操作。
- StirngBuffer是线程安全的,StringBuilder是线程不安全的。
- StirngBuffer的每个方法都synchronized修饰的。
- 性能 StirngBuilder > StringBuffer > String
- 优先使用StringBuilder,多线程共享变量时使用StringBuffer.
7种单例
深拷贝浅拷贝
什么是深拷贝、什么是浅拷贝
- 一个对象中,存在两种类型的属性,一种是基本数据类型。一种是引用数据类型。
- 浅拷贝是指,只会拷贝基本数据类型的值,以及示例对象的引用,并不会复制一份引用地址所指向的对象。即浅拷贝出来的对象,内部指向的是同一个对象。
- 深拷贝既会拷贝基本数据类型的值,也会针对实例对象的引用地址所指向的对象进行复制,即最后指向的是一个新的对象。
实现深拷贝的两种方式
- 实现Cloneable方法,并覆盖object中的clone方法。设置作用域为public。
- 实现序列或接口Serializbale,通过反序列化来生成新对象。
List扩容是深拷贝还是浅拷贝
- 地从使用的是 Arrays.copyof 和 System.arrayCopy.
- 对于数组来说,是深拷贝。相当于拷贝了一份新的数组空间。
- 对用数组元素来说,只有基本数据类型和String时,是深拷贝。
- 引用数据类型都是浅拷贝。
值传递引用传递
- 基本数据类型是值传递,对形参的修改不会影响实参。
- 引用数据类型是引用传递,形参和实参指向内存中同一个地址。所以对形参的修改会影响实际的对象。
- String和Ingteger、Double等封装类型可以理解为值传递,对形参的修改不会影响实参对象。
JDK8新特性
ConcurrentHashMap
JAVA中的异常体系

- 所有的异常都继承自Throwable. 分为两个子类ERROR 和 Exception.
- ERROR一旦发生,就只有一个结果,那就是程序终止,JVM退出,ERROR是不可处理的。比如OutOFMemoryError 和 StackOverflowError.
- Exception下面有很多内容,大概分为两个部部分,RuntimeException和Exception的直接子类。
- RuntimeException被称为运行时异常,运行时异常,在编写程序的时候,可以选择处理,也可以不处理。 运行时异常都是写代码过程中,能避免的,比如NumberFormatException,ArrayIndexoutOfBoundsException等。
- Exception的直接子类,都被称为编译时异常,编译时异常并不是在编译阶段发生的。是表示在编写程序的时候必须预先对这种异常进行处理,不处理编译器会报错。比如IOException. ClassNotFoundException.
final
修饰方法
- 表示方法不可被子类覆盖,即不能使用override从写,
- final修饰的方法可以重写。
修饰变量
表示变量一旦被赋值,就不可以更改它的值。
- 修饰成员变量
- 如果final修饰的是类变量,即static修饰,赋值必须在
- 声明时赋值
- 静态代码块中赋值
- 如果final修饰的成员变量,即没有static修饰,赋值必须在
- 声明时赋值
- 非静态代码块赋值
- 构造器中赋值
- 修饰局部变量
- 系统不会为局部变量初始化,这句话的意思是
- 比如成员变量,在创建对象的时候会初始化属性
- 比如类变量,随着类的加载而初始化
- 都是系统做的初始化。
- final修饰的成员变量,可以在声明的时候初始化,也可以不初始化。
- 如果声明的时候没有初始化,后面的代码中可以对final的变量赋值,但是只能赋值一次。
- 修饰基本数据类型和引用数据类型
- 如果修饰的是基本数据类型,初始化后数值不能修改。
- 如果是引用数据类型,初始化后不能再指向其他对象,但是可以修改其属性。
为什么局部内部类只能访问局部final变量
- 编译后会生成两个class文件,因此内部类和外部类是同级的。
- 内部类不会因为定义在方法中就会随着方法的执行完毕被销毁。
- 当外部类的方法执行结束时,局部变量就销毁掉了。
- 但是,局部内部类对象可能还存在,比如内部类是在外部类方法新启动线程执行的。
- 这样就出现了一个问题,内部类引用了一个不存在的变量。
- 为了解决这个问题,就将外部类的局部变量复制了一份作为内部类的成员变量,这样当外部方法执行结束后,内部类还可以正常访问这个变量。延迟了局部变量的声明周期。
- 将局部变量复制为内部类成员变量时,必须保证是一样的。 如果不设置为final。内部类中如果修改了,外部类没有办法感知到。
hashCode和equals.
hashcode介绍
- hashcode的作用是获取对象的哈希码,也称为散列码。
- 实际上返回的是一个整数,作用是确定该对对象在hash表中的索引位置。
- Object的方法,任意对象都有hashcode方法,作用是能根据索引快速找到堆中的位置。












