目录
1.接口和抽象类的区别
2.重载和重写的区别
3.==和equals的区别
4.异常处理机制
5.HashMap原理
6.想要线程安全的HashMap怎么办?
7.ConcurrentHashMap原如何保证的线程安全?
8.HashTable与HashMap的区别
9.ArrayList和LinkedList的区别
10.如何保证ArrayList的线程安全?
11.String、StringBuffer、StringBuilder的区别
12.hashCode和equals
13.面向对象和面向过程的区别
4.深拷贝和浅拷贝
15.多态的作用
16.什么是反射?
17.Java创建对象得五种方式?
相似点:
① 接口和抽象类都不能被实例化
② 实现接口或继承抽象类的普通子类都
必须实现这些抽象方法
不同点:
① 抽象类可以包含普通方法和代码块,
接口里只能包含抽象方法,静态方法
和默认方法
② 抽象类可以有构造方法,而接口没有
③ 抽象类中的成员变量可以是各种类型
的,接口的成员变量只能是 public
static final 类型的,并且必须赋值
① 重载发生在同一个类中,方法名相同、
参数列表、返回类型、权限修饰符可以
不同
② 重写发生在子类中,方法名相、参数列
表、返回类型都相同,权限修饰符要大
于父类方法,声明异常范围要小于父类
方法,但是 final 和 private 修饰的方法
不可重写
① == 比较基本类型,比较的是值,== 比
较引用类型,比较的是内存地址
② equlas 是 Object 类的方法,本质上与
== 一样,但是有些类重写了 equals 方
法,比如 String 的 equals 被重写后,
比较的是字符值,另外重写了 equlas
后,也必须重写 hashcode() 方法
① 使用 try、catch、finaly 捕获异常,finaly
中的代码一定会执行,捕获异常后程序会
继续执行
② 使用 throws 声明该方法可能会抛出的异
常类型,出现异常后,程序终止
(1) HashMap
在 Jdk1.8 以后是基于数组+链表+红黑树来实
现的,特点是,key 不能重复,可以为 null,
线程不安全
(2) HashMap 的扩容机制:
HashMap 的默认容量为 16,默认的负载因子
为 0.75,当 HashMap 中元素个数超过容量乘
以负载因子的个数时,就创建一个大小为前一
次两倍的新数组,再将原来数组中的数据复制
到新数组中,当数组长度到达 64 且链表长度
大于 8 时,链表转为红黑树
(3) HashMap存取原理:
① 计算 key 的 hash 值,然后进行二次 hash,
根据二次 hash 结果找到对应的索引位置
② 如果这个位置有值,先进行 equals 比较,
若结果为 true 则取代该元素,若结果为 false,
就使用高低位平移法将节点插入链表 (JDK 8
以前使用头插法,但是头插法在并发扩容时可
能会造成环形链表或数据丢失,而高低位平移
发会发生数据覆盖的情况)
① 使用 ConcurrentHashMap
② 使用 HashTable
③ Collections.synchronizedHashMap() 方法
JDK 1.7:使用分段锁,将一个 Map 分为了
16 个段,每个段都是一个小的 hashmap,
每次操作只对其中一个段加锁
JDK 1.8:采用 CAS + Synchronized 保证线
程安全,每次插入数据时判断在当前数组下
标是否是第一次插入,是就通过 CAS 方式插
入,然后判断 f.hash 是否等于 -1,是的话就
说明其他线程正在进行扩容,当前线程也会
参与扩容;删除方法用了 synchronized 修饰,
保证并发下移除元素安全
① HashTable 的每个方法都用 synchronized
修饰,因此是线程安全的,但同时读写效率
很低
② HashTable 的 Key 不允许为 null
③ HashTable 只对 key 进行一次 hash,
HashMap 进行了两次 Hash
④ HashTable 底层使用的数组加链表
ArratList 的底层使用动态数组,默认容量为
10,当元素数量到达容量时,生成一个新的
数组,大小为前一次的 1.5 倍,然后将原来
的数组 copy 过来;因为数组在内存中是连
续的地址,所以 ArrayList 查找数据更快,
由于扩容机制添加数据效率更低
LinkedList 的底层使用链表,在内存中是离
散的,没有扩容机制;LinkedList 在查找数
据时需要从头遍历,所以查找慢,但是添加
数据效率更高
① 使用 collentions.synchronizedList() 方法
为 ArrayList 加锁
② 使用 Vector,Vector 底层与 Arraylist 相
同,但是每个方法都由 synchronized 修
饰,速度很慢
③ 使用 juc 下的 CopyOnWriterArrayList,
该类实现了读操作不加锁,写操作时为
list 创建一个副本,期间其它线程读取的
都是原本 list,写操作都在副本中进行,
写入完成后,再将指针指向副本
① String 由 char[] 数组构成,使用了 final
修饰,对 String 进行改变时每次都会新
生成一个 String 对象,然后把指针指向
新的引用对象
② StringBuffer 可变并且线程安全
③ StringBuiler 可变但线程不安全
① 操作少量字符数据用 String;
② 单线程操作大量数据用 StringBuilder;
③ 多线程操作大量数据用 StringBuffer
hashCode() 和 equals() 都是 Object 类的
方法,hashCode() 默认是通过地址来计算
hash 码,但是可能被重写过用内容来计算
hash 码,equals() 默认通过地址判断两个
对象是否相等,但是可能被重写用内容来
比较两个对象,两个对象相等,他们的
hashCode 和 equals 一定相等,但是
hashCode 相等的两个对象未必相等
如果重写 equals() 必须重写 hashCode(),
比如在 HashMap 中,key 如果是 String
类型,String 如果只重写了 equals() 而没
有重写 hashcode() 的话,则两个 equals()
比较为 true 的 key,因为 hashcode 不同
导致两个 key 没有出现在一个索引上,就
会出现 map 中存在两个相同的 key
面向对象有封装、继承、多态性的特性,所
以相比面向过程易维护、易复用、易扩展,
但是因为类调用时要实例化,所以开销大性
能比面向过程低
浅拷贝:浅拷贝只复制某个对象的引用,而
不复制对象本身,新旧对象还是共享同一块
内存
深拷贝:深拷贝会创造一个一摸一样的对象,新对象和原对象不共享内存,修改新对象不
会改变原对对象
多态的实现要有继承、重写,父类引用指向
子类对象,它的好处是可以消除类型之间的
耦合关系,增加类的可扩充性和灵活性。
反射是通过获取类的 class 对象,然后动态
的获取到这个类的内部结构,动态的去操作
类的属性和方法
应用场景:
要操作权限不够的类属性和方法时、实现自定
义注解时、动态加载第三方 jar 包时、按需加
载类,节省编译和初始化时间;
获取 class 对象的方法有:
① class.forName(类路径)
② 类.class()
③ 对象的 getClass()
(1) new关键字
(2) Class.newInstance
(3) Constructor.newInstance
(4) Clone方法
(5) 反序列化