Java基础
一. 数据类型
1. Java8基本数据类型以及包装类型
| 基本数据类型 / 包装类型 | 字节数 |
|---|---|
| boolean / Boolean | 没有规定 |
| byte / Byte | 1 |
| char / Character | 2 |
| short / Short | 2 |
| int / Integer | 4 |
| long / Long | 8 |
| fload / Float | 4 |
| double / Double | 8 |
**为什么boolean没有规定字节数?
在java中没有具体规定boolean所占用的字节数,boolean在jvm虚拟机中会宽化处理为int类型,但是如果我们声明了一个boolean的数组,将会被编码成byte数组,这个时候占用一个字节,所以可以认为boolean类型占了单独使用是4个字节,在数组中又是1个字节。
2.缓冲池
①什么是缓冲池?
②哪些包装类具有缓冲池?
- Byte
- Short
- Character
- Integer
- Long
**缓冲池范围一般都是[-128,127],除了Character
3.String相关
①String的改变
在java8中String使用char数组存储数据。
在java9中String使用byte数组存储字符串,并且同时使用coder来标识使用了哪种编码。
②String为什么被声明为final(声明为final的好处?)
对于Map容器来说要求key不可变,所以字符串常量池要求String不可变。
③什么是StringPool(StringTable)?
StringTable又称为StringPool,字符串常量池,其存在于堆中(jdk1.7之后改的)。最重要的一点,String table中存储的并不是String类型的对象,存储的而是指向String对象的索引,真实对象还是存储在堆中。
④StringBuilder
线程不安全,可以被改变
⑤StringBuffer
线程安全,内部被synchronized同步
二.运算
switch支持的类型
byte和Byte
char和Character
short和Short
int和Integer
String
enum
注意:从java7开始才能使用char(Character)和String
三.关键字
final
①可以声明的位置:
类 (该类不能被继承)
方法(该方法不能被重写)
数据:
(基本类型:使数值不能够被修改)
(引用类型:引用不能变,但是被引用变量的对象本身可以被修改)
②final修饰的变量也可以被修改
使用java提供的反射技术,并且关闭安全校验也可以修改其值
static
①可以声明的位置:
类
方法
成员变量
②静态代码块
初始化顺序
静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。
1.父类(静态变量,静态代码块)
2.子类(静态变量,静态代码块)
3.父类(实例变量,普通代码块)
4.父类构造方法
5.子类(实例变量,普通代码块)
6.子类构造方法
四.继承
访问权限
private 类访问
default 包访问
protected 继承访问(这个修饰符在继承体系中成员对于子类可见,但是这个修饰符对于类没有意义)
public
----补充:
**private和protected不能修饰外部类的原因
使用private修饰,表示该类的成员只能在类的内部访问。
使用protected修饰,表示该类的成员可以被类的内部、同包下的其它类以及该类的子类访问。
从组织结构来分析:
类的成员(包过变量、方法、内部类等)的上层结构是类,而类的上层结构是包。
如果类可以使用private来修饰,表示该包下的这个类不能被其它类访问,那么该类也失去了存在的意义,所以不能使用private来修饰类。
如果类A用protected修饰,与类A不同包的类B想要访问类A的话,类B就必须是继承类A的(或者说类B必须为类A的子类),但是类B继承类A的前提又是类B可以访问到类A,仔细想想会发现这里是冲突的,其实这就说明了为什么不能用protected来修饰外部类。
重写
①子类只能够重写父类非私有的的,非静态的方法
子类重写父类的静态方法,那不叫重写,因为不能使用Override注解,所以那叫叫覆盖,因为这样会导致父类的静态方法失效
②子类重写父类的方法可以扩大访问权限
③子类方法抛出的异常类型必须是父类抛出异常类型或为其子类型。
五.抽象类和接口
1.接口
①新特性:
在java8中接口可以有default方法,也可以有静态方法
但是静态方法不能够被重写,default方法可以被重写
②接口中的方法默认都是public的,并且不允许定义为其他的
③接口中的字段都是static和final的
2.抽象类
抽象类和抽象方法都使用 abstract 关键字进行声明。如果一个类中包含抽象方法,那么这个类必须声明为抽象类。
抽象类不能被实例化,只能被继承。
六.异常
1.分类
java中异常都有一个共同的祖先Throwable
①Error:
OutOfMemoryError
StackOverflowError
ThreadDeath
②Exception:
运行时异常都是 RuntimeException 类及其子类异常。
非运行时异常是指 RuntimeException以外的异常,类型上都属于 Exception 类及其子类。
2.Exception和Error的区别?
Error一般由jvm抛出,Error是java程序不能够处理的错误,Exception是java程序能够处理的异常。
七.泛型(参数化类型)
1.分类
①泛型类
class Father < T >{
public T get(T e){
return e;
}
}
//这就是一个泛型类,但是要注意的是get方法并不是泛型方法
如果一个类继承了一个泛型类,要么在子类的泛型声明上上声明父类泛型参数,要么指定父类泛型的具体类型。
//1
class Father < T >{
}
class Son<E> extends Father< E >{//要是E,子类和父类必须都是E,要是T,必须都是T
}
//2
class Father < T >{
}
class Son< E,T > extends Father< E >{//虽然新加入了一个T,但是子类和父类的泛型标识要一致
}
//3
class Father < T >{
}
class Son< E > extends Father< String >{//这样子类就可以不用事先声明父类的泛型类型了,原因是已经知道了父类泛型类型
}
②泛型方法
class Father < T >{
public < E,T > E getValue(T para){
E rel=null;
return rel;
}
}
//只有在方法的返回值和方法的访问权限修饰符中间声明的泛型的参数才算泛型方法.
③泛型接口
class Father < T >{
public < E,T > E getValue(T para){
E rel=null;
return rel;
}
}
//只有在方法的返回值和方法的访问权限修饰符中间声明的泛型的参数才算泛型方法.
值得注意的是,泛型方法可以声明为静态的,前提是不能使用到类的非静态方法和非静态变量。
④泛型抽象类
2.泛型的通配符和泛型的上限和下限
①在使用”?“只能接收,不能修改。
②上边界通配符会导致修改失效,但是获取有效
③下边界通配符会导致获取有效,但是修改失效
④原因:
##①设置泛型上限后无法添加/修改元素,原因:子类分支间不兼容(无共同下限类型),若加入新元素排序时(Set/Map)存在 新元素无已存元素的成员属性导致无法比较的问题
②设置泛型下限后可添加/修改下限类型元素,原因:超类间兼容(存在共同下限类型),加入的新元素(被限定为共同下限类型)都包含已存元素的成员属性,新元素排序时(Set/Map)不存在已存元素比较方法由于新元素无指定成员属性导致无法比较的问题,为什么不能获取呢?因为设置下限后在获取的时候不能明确的知道里面的元素到底是什么类型的元素,以至于所有的元素只能当做object类型,那样对象就会损失信息,这样的话获取还有什么意义呢?##
八.容器
1.Collection(单列集合)
- List
- ArrarList
- 动态数组实现
- 初始容量10(只有在第一次添加的时候才会真正分配初始容量),每次扩 容1.5倍,如果扩容1.5倍还不够就会使用最小容量
- 线程不安全
- 实现了RandomAccess接口,支持快速随机访问
- LinkedList
- 双向链表
- 线程不安全
- 插入和删除时间复杂度几乎为O(1)
- 不支持快速随机访问
- 空间消耗比ArrayList消耗更大(因为每个节点都比ArrayList多了两个引用)
- Vector
- 动态数组实现
- 线程安全
- 初始容量10,每次扩容2倍,并且可以指定每次容量的增量
- 可以理解为加了synchronized的ArrayList
- CopyOnWriteArrayList
- 原理
- 写入时复制
- 特点
- 适合大量读操作,但是不适合大量的写操作
- 可以读写分离,但并不是读写锁实现的
- 线程安全
- 初始容量0,每次写入的时候容量扩容,新的容量=插入容量+旧容量
- 原理
- ArrarList
- Set
- TreeSet
- TreeMap换皮
- HashSet
- HashSet换皮
- LinkedHashSet
- LinkedHashSet换皮
- CopyOnWriteSet
- 和CopyOnWriteArrayList原理一样
- TreeSet
- Queue
- Deque(双端队列)
- ArrayDeque(常用子类)
- BlockingQueue(阻塞队列,线程安全)
- LinkedBlockingQueue(常用子类)
- ArrayBlockingQueue(常用子类)
- AbstractQueue(非阻塞队列)
- 四组常用API
- 抛出异常
- add
- remove
- element
- 有返回值,不会抛出异常
- offer
- poll
- peek
- 阻塞等待
- put
- take
- 超时等待
- offer(,)
- poll(,)
- 抛出异常
- 使用阻塞队列实现生产者和消费者模型
- Deque(双端队列)

2.Map(双列集合)
- HashMap
- 升级
- 在JDK1.7中HashMap使用数组加链表来实现
- 在JDK1.8中HashMap使用数组+链表+红黑树实现
- JDK1.8原理
- 初始容量16(第一次插入才会真正分配)
- 每次扩容2倍
- 如果当前桶的容量大于装填因子*总容量就触发扩容
- 如果一个链表的节点个数超过8个,并且桶的长度超过64个则链表升级为红黑树,如果没有超过64个则单纯扩容2倍
- 首先先把hash值高16位和低16位按位与计算,然后计算桶位置算法是 index = (n - 1) & hash相当于index=hash%n
- 如果一颗红黑树的节点小于6个则红黑树退化为链表
- 线程不安全
- 可以存NULL
- 升级
- HashTable
- 线程安全
- 默认初始容量11,装填因子0.75
- 每次扩容容量是2倍+1
- 直接使用hasoCode的值作为hash值
- TreeMap
- 红黑树实现
- key自动排序
- LinkedHashMap
- 链表实现
- 应用场景
- HashMap是无序的,当我们希望有顺序地去存储key-value时,就需要使用LinkedHashMap
- 线程不安全
- ConcurrentHashMap(高性能线程安全map)
- JDK1.7
- 实现
- 分段锁 segment,锁的粒度更加精细
分段的数组+链表的形式
- 分段锁 segment,锁的粒度更加精细
- 原理
- get
- get不需要加锁,采取volatile修饰共享变量
这样每次get的时候都可以获取最新的结构更新
由于遍历不需要加锁的原因是因为next是final。要么
是不为空返回,为空的话就加锁重读
- get不需要加锁,采取volatile修饰共享变量
- put
- 1.二阶段hash,第一阶段是定位到哪个segment
第二阶段是定位到哪个entry - 2.entry中,除了value,还有key,hash和next都是final修饰
意味着不能从中心或者尾部添加或者删除节点,一律添加到头部 - 3.通过count来统计段内的数据个数,只有新增和删除
会修改这个值,每次都是在上述俩个步骤的最后一步进行修改
- 1.二阶段hash,第一阶段是定位到哪个segment
- remove
- 由于是final,所以删除节点的时候会删除某个节点
然后那个节点之上都复制,然后最后一个节点指向
被删节点的下一个节点
- 由于是final,所以删除节点的时候会删除某个节点
- resize
- 扩容只会对段扩容而非整个桶
跟HashMap不同的是,段是先判断
是否需要扩容再put,而hashmap是
先put再判断是否要扩容
- 扩容只会对段扩容而非整个桶
- size
- 先尝试不锁住segment的方式来统计segment的大小
如果统计过程中,容器的count发生变化则采取加锁的方式
- 先尝试不锁住segment的方式来统计segment的大小
- get
- 实现
- JDK1.8
- 取消了分段锁,而是采取了cas和synchronized来保证并发安全,
synchronized只锁住当前链表或者红黑二叉树的首节点,只要hash
不冲突,就不会产生并发,效率很高 - 可以认为是JDK1.8版本你的HashMap+CAS和synchronized实现的
- 取消了分段锁,而是采取了cas和synchronized来保证并发安全,
- JDK1.7
有问题欢迎指出,感谢观看!
本文详细介绍了Java的基础知识,包括数据类型的字节数、包装类的缓冲池、String的特性和StringPool、运算中的switch支持类型、关键字final和static的使用、继承的访问权限、重写规则。此外,还探讨了抽象类和接口、异常分类、泛型的各类应用、以及集合容器如ArrayList、LinkedList、Vector、Map等的特性与实现。最后,文章涵盖了Map的实现,如HashMap、HashTable和ConcurrentHashMap的内部工作机制。





