琐碎知识点
1、Java 中浮点数的精度丢失问题以及解决方案
在 Java 中写入new BigDecimal(0.1) 所创建的 BigDecimal 正好等于 0.1,但是它实际上等于 0.1000000000000000055511151231257827021181583404541015625
Java 的浮点数只能用来进行科学计算或工程计算,在大多数的商业计算中,一般采用java.math.BigDecimal 类来进行精确计算.
使用步骤:
- 用 float 或者 double 变量构建 BigDecimal 对象。通常使用 BigDecimal 的构造方法或者静态方法的 valueOf() 方法把基本类型的变量构建成 BigDecimal 对象。
- 通过调用 BigDecimal 的加,减,乘,除等相应的方法进行算术运算。
- 把 BigDecimal 对象转换成 float,double,int 等类型。
BigDecimal 类 的构造函数:
1 | BigDecimal(int var) //创建一个具有参数所指定整数值的对象。 |
BigDecimal 类的加,减,乘,除等相应的方法:
1 | BigDecimal add(BigDecimal augend) //加法运算 |
1 |
|
总结
(1)需要精确的表示两位小数时我们需要把他们转换为 BigDecimal 对象,然后再进行运算。
(2)使用 BigDecimal(double val) 构造函数时仍会存在精度丢失问题,建议使用 BigDecimal(String val)。
2、Java反射中getMethods()与getDeclaredMethods()区别
getMethods()获取的是所有public方法,包括:
getMethods() 无法获取当前类中被声明为private的方法
- 类自身声明的public方法、
- 父类中的public方法、
- 实现的接口方法。
getDeclaredMethods()获取的是类中所有方法,也就是源文件中有哪些方法,就会获取到哪些,包括:
- 类自身的方法、
- 重写的父类的方法、
- 实现的接口方法。
遇到的问题
使用getMethods() 方法无法获取到 Servlet中 被声明为==private== 的crud的方法,
导致for循环遍历methods[] 无法匹配到 与operate 相同的method(), 例如 operate=“del” ,method(): del()
出现==throw new RuntimeException(“operate值非法”);== 的问题
将getMethods()改成 getDeclaredMethods() 即可
1 |
|
3、java Stack 类
注意:Java堆栈Stack类已经过时,Java官方推荐使用Deque替代Stack使用。Deque堆栈操作方法:push()、pop()、peek()。
- 栈是Vector的一个子类,它实现了一个标准的后进先出的栈。
- 堆栈只定义了默认构造函数,用来创建一个空栈。 堆栈除了包括由Vector定义的所有方法,也定义了自己的一些方法。
| 序号 | 方法描述 |
|---|---|
| 1 | boolean empty() 测试堆栈是否为空。 |
| 2 | Object peek( ) 查看堆栈顶部的对象,但不从堆栈中移除它。 |
| 3 | Object pop( ) 移除堆栈顶部的对象,并作为此函数的值返回该对象。 |
| 4 | Object push(Object element) 把项压入堆栈顶部。 |
| 5 | int search(Object element) 返回对象在堆栈中的位置,以 1 为基数。 |
5、System.arraycopy()
复制数组
- 它是一个静态本地方法,由虚拟机实现,效率自然比用java一个个复制高。
1 | public static void arraycopy(Object src,int srcPos, Object dest,int destPos, int length); |
参数
- Object src:the source array. 源数组
- int srcPos:starting position in the source array. 在源数组中,开始复制的位置
- Object dest:the destination array. 目标数组
- int destPos:starting position in the destination data. 在目标数组中,开始赋值的位置
- int length:the number of array elements to be copied. 被复制的数组元素的数量
一、深度复制和浅度复制的区别
Java数组的复制操作可以分为深度复制和浅度复制,简单来说深度复制,可以将对象的值和对象的内容复制;浅复制是指对对象引用的复制。
二、System.arraycopy()方法实现复制
1、System中提供了一个native静态方法arraycopy(),可以使用这个方法来实现数组之间的复制。
-
对于一维数组来说,这种复制属性值传递,修改副本不会影响原来的值。
-
对于二维或者一维数组中存放的是对象时,复制结果是一维的引用变量传递给副本的一维数组,修改副本时,会影响原来的数组。
一维数组非引用类型不会影响原来的值,
二维数组或者 元素是引用类型的一维数组 复制的结果知识对对象引用的复制,会影响原来的数组
6、java队列(Queue)
1 | public interface Queue<E> extends Collection<E> {} |
- 先进先出
队列是一种特殊的线性表,它只允许在表的前端进行删除操作,而在表的后端进行插入操作。
LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用。
1 | import java.util.LinkedList; |
7、java双端队列(Deque)
1 | public interface Deque<E> extends Queue<E> {} |
-
Deque是一个双端队列接口,继承自Queue接口,Deque的实现类是
LinkedList、ArrayDeque、LinkedBlockingDeque,其中
LinkedList是最常用的。
Deque有三种用途:
- 普通队列(一端进另一端出):
Queue queue = new LinkedList()或Deque deque = new LinkedList() - 双端队列(两端都可进出)
Deque deque = new LinkedList() - 堆栈
Deque deque = new LinkedList()
注意:Java堆栈Stack类已经过时,Java官方推荐使用Deque替代Stack使用。Deque堆栈操作方法:push()、pop()、peek()。
此接口定义在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。插入操作的后一种形式是专为使用有容量限制的 Deque 实现设计的;在大多数实现中,插入操作不能失败。
| 第一个元素 (头部) | 最后一个元素 (尾部) | |||
|---|---|---|---|---|
| 抛出异常 | 特殊值 | 抛出异常 | 特殊值 | |
| 插入 | addFirst(e) | offerFirst(e) | addLast(e) | offerLast(e) |
| 删除 | removeFirst() | pollFirst() | removeLast() | pollLast() |
| 检查 | getFirst() | peekFirst() | getLast() | peekLast() |
Deque 中有下面几种添加元素的方法:
add():可以使用 Deque的addFirst()方法在Deque的头部添加元素, 如果Deque不能添加元素,addFirst()方法会抛异常, offerFirst()方法则返回 false。addLast()addLast()方法也可以在 Deque的尾部添加元素,这是Deque接口与从Queue接口继承的add()方法等效addFirst()可以使用 Deque的addFirst()方法在Deque的头部添加元素offer()offer()方法可以在Deque的尾部添加元素,如果元素没满则添加成功返回true,否则返回falseofferFirst()offerFirst()方法是在 Deque 的头部添加元素,如果添加成功返回true,否则返回falseofferLast()offerLast()方法在Deque的尾部添加元素push()push()方法是在Deque的头部添加元素,如果Deque中的元素满了,则会抛异常,
可以查看Deque中的元素
可以查看Deque中的第一个或者最后一个元素,查看元素意味着获取元素的引用而不是移除元素,有下面几种方法:
-
peek()Deque中的第一个元素并且不删除,如果Deque是空则返回null -
peekFirst()返回第一个元素并且不删除,如果Deque是空则返回null,这和 peek()非常相似 -
peekLast()返回最后一个元素并且不删除,如果Deque是空则返回null -
getFirst()getFirst()方法获取Deque的第一个元素并且不删除,如果Deque是空则抛异常 -
getLast()getLast()获取Deque的最后一个元素并且不删除,如果Deque是空则返回null
Deque接口扩展(继承)了 Queue 接口。在将双端队列用作队列时,将得到 FIFO(先进先出)行为。将元素添加到双端队列的末尾,从双端队列的开头移除元素。从 Queue 接口继承的方法完全等效于 Deque 方法,
| Queue方法 | 等效Deque方法 |
|---|---|
| add(e) | addLast(e) |
| offer(e) | offerLast(e) |
| remove() | removeFirst() |
| poll() | pollFirst() |
| element() | getFirst() |
| peek() | peekFirst() |
双端队列也可用作 LIFO(后进先出)堆栈。应优先使用此接口而不是遗留 Stack 类。在将双端队列用作堆栈时,元素被推入双端队列的开头并从双端队列开头弹出。堆栈方法完全等效于 Deque 方法,如下表所示:
| 堆栈方法 | 等效Deque方法 |
|---|---|
| push(e) | addFirst(e) |
| pop() | removeFirst() |
| peek() | peekFirst() |
Deque的使用场景
在一般情况,不涉及到并发的情况下,有两个实现类,可根据其自身的特性进行选择,分别是:
- LinkedList 大小可变的链表双端队列,允许元素为插入null。
- ArrayDeque 大下可变的数组双端队列,不允许插入null。
- ConcurrentLinkedDeque 大小可变且线程安全的链表双端队列,非阻塞,不允许插入null。
- LinkedBlockingDeque 为线程安全的双端队列,在队列为空的情况下,获取操作将会阻塞,直到有元素添加。
注意:LinkedList 和 ArrayDeque 是线程不安全的容器。
8、java中的list为空(size==0)与list为null的区别
-
举个例子,我有一个空着的水杯(list),而你没有,那你是null,我的size为0。你想装水就需要自己去买个水杯(new ArrayList();),\
但是我就可以直接装水(list.add(水))。你要是没有杯子直接倒水,水就流出去(
NullPointerException)。
isEmpty() 或者(list.size() == 0)用于判断List内容是否为空,即表里一个元素也没有, 但是使用isEmpty()和size()的前提是,list是一个空集合,而不是null,所以为了避免异常,建议在使用或赋值list集合之前,做一次空集合创建处理,进行内存空间分配,
实测isEmpty速度要比size慢
- null
list==null,其实就是没有为这个list 分配空间 , 如果直接使用就会NullPointerException
例子:
1 |
|
- 直接运行
list1.get(0)的异常是java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0list2.get(0)的异常是java.lang.NullPointerException










