自己创建的网站怎么做流量,代理网店童装,设计师个人作品集网站,wordpress 过滤词目录
Arrays.sort的底层实现
BigDecimal(double)和BigDecimal(String)有什么区别
Char可以存储一个汉字吗
Java中的Timer定时调度任务是咋实现的
Java中的序列化机制是咋实现的
Java中的注解是干嘛的 Arrays.sort的底层实现
Arrays.sort是Java中提供的对数组进行排序的…目录
Arrays.sort的底层实现
BigDecimal(double)和BigDecimal(String)有什么区别
Char可以存储一个汉字吗
Java中的Timer定时调度任务是咋实现的
Java中的序列化机制是咋实现的
Java中的注解是干嘛的 Arrays.sort的底层实现
Arrays.sort是Java中提供的对数组进行排序的方法根据参数类型不同它提供了很多重载方法
public static void sort(Object[] a)
public static void sort(byte[] a)
public static void sort(float[] a)
public static void sort(int[] a)
因此对于不同的数据类型底层采用的排序算法也是不同的
如果是基本数据类型int、double、char等的数组则采用的是“双轴快速排序”算法来实现的
public static void sort(int[] a) {DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);}
双轴快速排序是对传统快速排序的改进它通过选择两个轴值来划分数组并在每个划分区域中进行递归排序。这种算法通常比传统的快速排序更快特别是在大量重复元素的情况下。双轴快速排序算法是在JDK7中引入的并在后续版本中进行了优化和改进。
而对象数组类型的话则采用的就是归并排序和TimSort
// 1.7以前
public static void sort(Object[] a) {Object[] aux (Object[])a.clone();mergeSort(aux, a, 0, a.length, 0);
}// 1.7以后
public static void sort(Object[] a) {if (LegacyMergeSort.userRequested)legacyMergeSort(a);elseComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}/** To be removed in a future release. */
private static void legacyMergeSort(Object[] a) {Object[] aux a.clone();mergeSort(aux, a, 0, a.length, 0);
}
TimSort 是一种混合排序算法结合了归并排序Merge Sort和插入排序Insertion Sort的特点。
BigDecimal(double)和BigDecimal(String)有什么区别
首先我们来看一下阿里巴巴Java开发手册的提示 其实我们可以看到double本身就是不准确的表示一个值取得是一个近似值例如new BigDecimal(0.1) 但是创建出来的值并不是0.1而是0.100000000000000000055555555......等但是new BigDecimal(0.1)时创建出来的值正是0.1值是很准确的。当我们去看BigDecimal源码时可以发现他的实现主要是用的是个无标度值和标度来表示的。所以在使用double时创建的是一个不准确的值那么如何创建一个准确的小数值呢采用的就是BigDecimal(String)它可以完整的表示一个小数的精度
但是需要注意的是new BigDecimal(0.10000)和new BigDecimal(0.1)这两个数的标度分别是5和1如果使用BigDecimal的equals方法比较得到的结果是false。
public class BigDecimal extends Number implements ComparableBigDecimal {private final BigInteger intVal;private final int scale; private final transient long intCompact;
}
因为计算机采用二进制处理数据但是很多小数如0.1的二进制是一个无限循环小数而这种数字在计算机中是无法精确表示的。所以人们采用了一种通过近似值的方式在计算机中表示于是就有了单精度浮点数和双精度浮点数等。所以作为单精度浮点数的float和双精度浮点数的double在表示小数的时候只是近似值并不是真实值。
所以当使用BigDecimal(Double)创建一个的时候得到的BigDecimal是损失了精度的。而使用一个损失了精度的数字进行计算得到的结果也是不精确的。
想要避免这个问题可以通过BigDecimal(String)的方式创建BigDecimal这样的情况下0.1就会被精确的表示出来。
Char可以存储一个汉字吗
在Java中使用的是编码时Unicode因此char类型使用16位来表示可以存储任何在Unicode字符集出现的字符。Unicode字符集包含了几乎所有的字符包括常见字符、生僻字、罕见字以及其他语言的字符。所以用char类型其实是可以存储生僻字的。
Java中的Timer定时调度任务是咋实现的
在JDK源码中是这样定义Timer类的
public class Timer {/*** The timer task queue. This data structure is shared with the timer* thread. The timer produces tasks, via its various schedule calls,* and the timer thread consumes, executing timer tasks as appropriate,* and removing them from the queue when theyre obsolete.*/private final TaskQueue queue new TaskQueue();/*** The timer thread.*/private final TimerThread thread new TimerThread(queue);
}
可以看到最主要的是两个变量TaskQueue和TimerThread TaskQueue一个任务队列用于存储已计划的定时任务。任务队列按照任务的执行时间进行排序确保最早执行的任务排在队列前面。在队列中的任务可能是一次性的也可能是周期性的。TimerThreadTimer 内部的后台线程它负责扫描 TaskQueue 中的任务检查任务的执行时间然后在执行时间到达时执行任务的 run() 方法。TimerThread 是一个守护线程因此当所有非守护线程完成时它会随之终止 任务调度的核心代码如下
class TimerThread extends Thread {boolean newTasksMayBeScheduled true;/*** 存储 TimerTask 的队列*/private TaskQueue queue;TimerThread(TaskQueue queue) {this.queue queue;}public void run() {try {mainLoop();} finally {synchronized (queue) {newTasksMayBeScheduled false;queue.clear(); }}}/*** 主要的计时器循环。 */private void mainLoop() {while (true) {try {TimerTask task;boolean taskFired;synchronized (queue) {// 等待队列变为非空while (queue.isEmpty() newTasksMayBeScheduled)queue.wait();if (queue.isEmpty())break; // 队列为空将永远保持为空线程终止// 队列非空查看第一个事件并执行相应操作long currentTime, executionTime;task queue.getMin();synchronized (task.lock) {if (task.state TimerTask.CANCELLED) {queue.removeMin();continue; // 无需执行任何操作再次轮询队列}currentTime System.currentTimeMillis();executionTime task.nextExecutionTime;if (taskFired (executionTime currentTime)) {if (task.period 0) { // 非重复移除queue.removeMin();task.state TimerTask.EXECUTED;} else { // 重复任务重新安排queue.rescheduleMin(task.period 0 ? currentTime - task.period: executionTime task.period);}}}if (!taskFired) // 任务尚未触发等待queue.wait(executionTime - currentTime);}if (taskFired) // 任务触发运行它不持有锁task.run();} catch (InterruptedException e) {}}}
}
TimerThread的实际是在运行mainLoop方法这个方法一进来就是一个while(true)的循环他在循环中不断地从TaskQueue中取出第一个任务然后判断他是否到达执行时间了如果到了就触发任务执行。否则就继续等一会再次执行。如此往复的重复执行。
使用 Timer定时调度有哪些优缺点呢
优点实现简单啊因为是JDK内置的定时调度任务因此体量是比较小的只需要在需要使用的地方调用方法即可
缺点
1、Timer内部是单线程执行任务的如果某个任务执行时间较长会影响后续任务的执行。 2、如果任务抛出未捕获异常将导致整个 Timer 线程终止影响其他任务的执行。 3、Timer 无法提供高精度的定时任务。因为系统调度和任务执行时间的不确定性可能导致任务执行的时间不准确。因此需要准时和高性能的定时任务采集时常采用xxl-job定时任务框架来完成。 4、虽然可以使用 cancel 方法取消任务但这仅仅是将任务标记为取消状态仍然会在任务队列中占用位置无法释放资源。这可能导致内存泄漏。 5、当有大量任务时Timer 的性能可能受到影响因为它在每次扫描任务队列时都要进行时间比较。 6、Timer执行任务完全基于JVM内存一旦应用重启那么队列中的任务就都没有了
Java中的序列化机制是咋实现的
序列化是将对象转换为可传输格式的过程。 是一种数据的持久化手段。一般广泛应用于网络传输RMI和RPC等场景中。 几乎所有的商用编程语言都有序列化的能力不管是数据存储到硬盘还是通过网络的微服务传输都需要序列化能力。
在Java的序列化机制中如果是String枚举或者实现了Serializable接口的类均可以通过Java的序列化机制将类序列化为符合编码的数据流然后通过InputStream和OutputStream将内存中的类持久化到硬盘或者网络中同时也可以通过反序列化机制将磁盘中的字节码再转换成内存中的类。
**如果一个类想被序列化需要实现Serializable接口。**否则将抛出NotSerializableException异常。Serializable接口没有方法或字段仅用于标识可序列化的语义。
自定义类通过实现Serializable接口做标识进而在IO中实现序列化和反序列化具体的执行路径如下 #writeObject - #writeObject0(判断类是否是自定义类) - #writeOrdinaryObject(区分Serializable和Externalizable) - writeSerialData(序列化fields) - invokeWriteObject(反射调用类自己的序列化策略) 其中在invokeWriteObject的阶段系统就会处理自定义类的序列化方案。这是因为在序列化操作过程中会对类型进行检查要求被序列化的类必须属于Enum、Array和Serializable类型其中的任何一种。
Java中的注解是干嘛的
Java 注解用于为 Java 代码提供元数据。作为元数据注解不直接影响你的代码执行但也有一些类型的注解实际上可以用于这一目的。Java 注解是从 Java5 开始添加到 Java 的。
Java的注解可以说是一种标识标识一个类或者一个字段常常是和反射AOP结合起来使用。中间件一般会定义注解如果某些类或字段符合条件就执行某些能力。
元注解
Target(ElementType.METHOD)
Retention(RetentionPolicy.SOURCE)
public interface Override {
}
这里面的TargetRetention就是元注解。 元注解有四个:Target表示该注解可以用于什么地方、Retention表示在什么级别保存该注解信息、Documented将此注解包含在javadoc中、Inherited允许子类继承父类中的注解。
一般Target是被用的最多的。
Retention指定被修饰的注解的生命周期即注解在源代码、编译时还是运行时保留。它有三个可选的枚举值SOURCE、CLASS和RUNTIME。默认为CLASS。
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;Retention(RetentionPolicy.RUNTIME)
public interface MyRuntimeAnnotation {// some elements and values
}
Target指定被修饰的注解可以应用于的元素类型如类、方法、字段等。这样可以限制注解的使用范围避免错误使用。
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;Target({ElementType.TYPE, ElementType.METHOD})
public interface MyTargetAnnotation {// some elements and values
}
Documented用于指示注解是否会出现在生成的Java文档中。如果一个注解被Documented元注解修饰则该注解的信息会出现在API文档中方便开发者查阅。
import java.lang.annotation.Documented;Documented
public interface MyDocumentedAnnotation {// some elements and values
}
Inherited指示被该注解修饰的注解是否可以被继承。默认情况下注解不会被继承即子类不会继承父类的注解。但如果将一个注解用Inherited修饰那么它就可以被子类继承。
import java.lang.annotation.Inherited;Inherited
public interface MyInheritedAnnotation {// some elements and values
}