Java基础复习
1、== 与equals方法
对于八种基本数据类型来说(byte short int long float double boolean char) == 是比较的值 而八种基本数据类型 是没有equals方法的
对于引用数据类型来说 == 比较的是对象的内存地址 而equals比较的字面值(例:String类型)
2、Synchronized关键字
作用
- 原子性:所谓原子性就是指一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。被
synchronized
修饰的类或对象的所有操作都是原子的,因为在执行操作之前必须先获得类或对象的锁,直到执行完才能释放。 - 可见性:**可见性是指多个线程访问一个资源时,该资源的状态、值信息等对于其他线程都是可见的。 **synchronized和volatile都具有可见性,其中synchronized对一个类或对象加锁时,一个线程如果要访问该类或对象必须先获得它的锁,而这个锁的状态对于其他任何线程都是可见的,并且在释放锁之前会将对变量的修改刷新到共享内存当中,保证资源变量的可见性。
- 有序性:有序性值程序执行的顺序按照代码先后执行。 synchronized和volatile都具有有序性,Java允许编译器和处理器对指令进行重排,但是指令重排并不会影响单线程的顺序,它影响的是多线程并发执行的顺序性。synchronized保证了每个时刻都只有一个线程访问同步代码块,也就确定了线程执行同步代码块是分先后顺序的,保证了有序性。
Synchronized主要有三种用法:
- 修饰实例方法: 作用于当前对象实例加锁,进入同步代码前要获得 当前对象实例的锁
1 | synchronized void method() { |
- 修饰静态方法: 也就是给当前类加锁,会作用于类的所有对象实例 ,进入同步代码前要获得 当前 class 的锁。因为静态成员不属于任何一个实例对象,是类成员( static 表明这是该类的一个静态资源,不管 new 了多少个对象,只有一份)。所以,如果一个线程 A 调用一个实例对象的非静态
synchronized
方法,而线程 B 需要调用这个实例对象所属类的静态synchronized
方法,是允许的,不会发生互斥现象,因为访问静态synchronized
方法占用的锁是当前类的锁,而访问非静态synchronized
方法占用的锁是当前实例对象锁。
1 | synchronized void staic method() { |
- 修饰代码块 :指定加锁对象,对给定对象/类加锁。
synchronized(this|object)
表示进入同步代码库前要获得给定对象的锁。synchronized(类.class)
表示进入同步代码前要获得 当前 class 的锁
1 | synchronized(this) { |
3.Java容器
一、Collection
简单来说就是单个集合的元素
分为List、Set、Queue三大类
List有ArrayList(底层由数组组成 查找快 支持随机访问) LinkedList(底层由双向链表组成 修改快 还可以做栈 队列 以及双向队列) 以及Vector(线程安全 但是效率低 很少用)
List
ArrayList
JDK 7 以无参数构造方法创建 ArrayList 时,直接创建了长度是10的Object[]数组elementData 。
JDK 8 以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为 10。
底层为一个Object类型的数组 初始长度为0;若采用了泛型 ArrayList
则生成的是String[]类型的数组 初始长度为0
扩容
当初始长度为10已经加入了十个元素之后,我们需要再加一个元素的时候,我们就需要扩容
1 | private void add(E e, Object[] elementData, int s) { |
这段源代码就是ArrayList的add()方法 如果添加的元素已经满了 则调用grow()函数 很明显 这是一个扩容函数
grow函数有两个 一个有参函数 一个无参函数
无参参数会调用有参参数 进行1.5倍的扩容
1 | ArrayList list1 = new ArrayList(23); |
这表示着生成了一个初始长度为23的ArrayList数组
Vector
和ArrayList数组类似 线程安全 效率低 用的很少
但是我们用的Stack(栈)则是基于Vector设计的
实现栈
Stack继承Vector 是Vector的子类
LinkedList
基于双向链表实现 增删元素效率高 查询效率低
LinkedList可以用作栈 队列 以及双向队列
Set
集合 无序可去重的集合
TreeSet
无序 不可重复 自动排序 相当于存放在TreeMap的Key部分
HashSet
无序 不可重复 支持快速查找 存放在HashMap中相当于key部分
LinkedHashSet
基于双向链表实现,具有HashSet的查找效率
Queue
LinkedList
可以用他来实现双向队列
PriorityQueue
用于堆实现 可以用它实现优先队列
二、Map
映射类型 Key - Value类型结构、
HashMap
比如最为常见的HashMap
JDK 1.7 底层是数组+链表
JDK 1.8 底层是数组+链表+红黑树 加入红黑树的目的是增加HashMap的插入和查询速率
HaashMap通过key进行hashcode与 与运算 得到下标。
HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。
HashMap 实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步。
HashMap 是无序的,即不会记录插入的顺序。
HashMap 继承于AbstractMap,实现了 Map、Cloneable、java.io.Serializable 接口。
1 | public class Main { |
起初我验证Map的无序的时候 输出的总是有序的 增加了样本之后才变得无序
但是输入 它内部就有机构形成 无论你是输出十遍还是一百遍 他都是输出一样的顺序
这就是HashMap的无序性和有序性
采用拉链法解决哈希冲突
JDK1.7采用头插法,有可能形成回路
JDK1.8以后采用尾插法
HashMap的默认初始容量为16
必须是 2 的次幂,这也是 jdk 官⽅推荐的
这是因为达到散列均匀,为了提⾼ HashMap 集合的存取效率,所必须的
HashMap 默认加载因⼦:0.75
数组容器达到 3/4 时,开始扩容
JDK 8 之后,对 HashMap 底层数据结构(单链表)进⾏了改进
如果单链表元素超过8个,则将单链表转变为红⿊树;
如果红⿊树节点数量⼩于6时,会将红⿊树重新变为单链表。
hashcode() :通过调用Hashcode()方法得到key的哈希值
通过哈希函数/哈希算法 转换成数组的下表
重写Hashcode()和equals()的原因是
需要达到散列分布均匀
4.JVM,JRE,JDK的区别
总的来说 JVM包括JRE JRE包括JVM
Java 虚拟机(JVM)是运行 Java 字节码的虚拟机。JVM 有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。字节码和不同系统的 JVM 实现是 Java 语言“一次编译,随处可以运行”的关键所在。