Java入门
二、八、十六进制
2018-09-18
表示方法
- 2进制 (
0b开头):0b101表示十进制的5 - 8进制 (
0开头):011表示十进制的9 - 16进制 (
0x开头):0x11表示十进制的17
转为对应String
- 2进制: Integer.toBinaryString(int i)
- 8进制: Integer.toOctalString(int i)
- 16进制: Integer.toHexString(int i)
- n进制: Integer.toString(int i, int radix)
从String转为对应Int
支持2~36进制,10个数字+26个字母
- 10进制: Integer.valueOf(i)
- 2进制: Integer.valueOf(i, 2)
- 8进制: Integer.valueOf(i, 8)
- 16进制: Integer.valueOf(i, 16)
- n进制: Integer.valueOf(i, n)
String加法
2018-09-16
在我们编写Java代码过程中,经常有拼接字符串的需求,通常有三种方法:
- 直接使用
"+"操作 - 使用
StringBuilder - 使用
StringBuffer
首先介绍一下
StringBuilder
StringBuilder
先看一下如何使用StringBuilder
1 | StringBuilder sb = new StringBuilder(); |
通过append操作拼接字符串,最后通过toString方法得到最终的字符串。
StringBuffer
StringBuffer和StringBuilder的使用方法差不多。
1 | StringBuffer sb = new StringBuffer(); |
既然差不多,为什么还要另搞一个StringBuffer呢?查看源码可以看到,StringBuffer的操作都是有synchronized关键字的,也就是说是线程安全的。
StringBuilder 和 StringBuffer 比较
所以我们可以总结,
- 当为单线程时,直接使用
StringBuilder,比StringBuffer要快,免去加锁操作。 - 对于多线程,我们可以使用
StringBuffer保证线程安全。
可以直接使用"+"吗?
当然可以,不然发明它干吗~~
假如,我们编写以下程序,直接相加2个字符串
1 | String ret = str1 + str2; |
build后查看class文件,发现是这样的:
1 | String ret = (new StringBuilder()).append(str1).append(str2).toString()) |
也就是说,如果直接采用+进行字符串的合并,编译器会将其转为StringBuilder,所以放心使用String的加法吧~
只是
如果你要写下面的代码
1 | String ret = ""; |
看看build后的结果
1 | String ret = ""; |
显然,这将会产生n多个StringBuilder,大大增加了gc开销,这个时候,StringBuilder和StringBuffer便派上用场了,所以,知道该怎么做了吗。
基本类型及其数组类型
2019-03-12
| 基本类型 | class名(=本身) | 对应数组class名 |
|---|---|---|
byte | byte | [B |
int | int | [i |
long | long | [J |
float | float | [F |
double | double | [D |
boolean | boolean | [z |
下面以byte为例说明这个问题
1 | System.out.println(byte.class.getName()); // byte |
反射
2019-04-09
有时,现有的类库接口不能满足我们的需求(它们往往封装的过好,隐藏了内部细节,以至于把这些细节都设为了private方法)。我们确实需要主动执行这些内部方法,以达到某种目的。大多数时候,这种需求会添加在该库的未来的版本中,但我们由于各种各样的原因不能升级,需要在当前版本满足我们的需求,问题来了,如何主动执行受保护的方法,答案是,反射。
有以下类A,我们要在外部访问它的 private 字段,执行它的 private 方法。
1 | public class A { |
访问私有字段
1 | A a = new A(1); |
访问私有方法
1 | A a = new A(1); |
访问静态私有方法
1 | Method staticMethod = A.class.getDeclaredMethod("of", int.class); // 第一个是方法名,第二个是函数参数的类型 |
Java集合
2023-01-16
Queue
- 先进先出
单线程实现
LinkedListPriorityQueue
多线程实现
BlockingQueue接口ArrayBlockingQueueLinkedBlockingQueue
Deque
- 双端队列
- 包括
Queue、Stack等接口
单线程实现
ArrayDeque:循环数组实现LinkedList
多线程实现
BlockingDeque接口- 只有
LinkedBlockingDeque
- 只有
ConcurrentLinkedDeque
SortedMap / NavigableMap
排序Map / 可导航Map
单线程实现
TreeMap:红黑树实现
多线程实现
ConcurrentSkipListMap
SortedSet / NavigableSet
基于 SortedMap / NavigableMap
ArrayList和LinkedList的原理和使用场景
2023-02-23
ArrayList
- 默认大小为
10,每次扩大为1.5倍 - 数组扩容时需要复制旧数组内容到新数组
- 预分配内存,效率高
- 适合绝大多数场景(顺序添加、遍历、随机访问等)。当你需要一个
List时,就选它
LinkedList
- 每个节点对应一个
Node对象,保存前后指针,增加了内存占用 - 查找指定位置时会先计算与头部和尾部的距离,哪个近就从哪里开始遍历(双向链表)
- 实现了
Deque接口,当你需要双向队列或经常变动头部节点时,就选它
实现和复杂度对比
| 类型 | ArrayList | LinkedList |
|---|---|---|
| 实现方式 | 动态数组 | 双向链表 |
| 内存分步 | 连续 | 不连续 |
| 查询效率 | O(n) | O(n) |
| 随机访问效率 | ***O(1)***,下标访问 | *O(n)*,遍历至指定位置 |
| 随机增加/删除效率 | *O(n)*,需移动数组,但很快 | *O(n)*,遍历找到节点 |
| 头部添加删除效率 | *O(n)*,需移动后续数组 | O(1) |
| 尾部添加删除效率 | *O(1)*,添加时可能需要扩容数组 | O(1) |
数字的大小比较
1 | assert 1.00f == 1.000f; |