文章字数:19,阅读全文大约需要1分钟
1 | Inter i = new Inter(){//多态 |
文章字数:19,阅读全文大约需要1分钟
1 | Inter i = new Inter(){//多态 |
文章字数:495,阅读全文大约需要1分钟
-31代表负数,0代表正数。后面的二进制代表绝对值,例如-3的机器数就是10000011[1111 1111, 0111 1111]即[-127, 127]0的情况(因为存在符号位,所以有一个+0和-0)[-2^8, (2^8)-1]即[-127, +127]1 | class Solution { |
文章字数:473,阅读全文大约需要1分钟
Atom不可分割的意思,CAS是一种替换操作,不是锁。
cpu带来死锁等问题CAS操作,直到成功(自旋)。A被改成了B又被改回了A。对于一个线程来说,检测到值为A就以为没有改动过,其实有可能是再次被改回来了。cpu会不断循环| 类型 | jdk类 | 备注 |
|---|---|---|
| 基本类型 | AtomicBoolean AtomicInteger AtomicLong |
常用getAndIncrement()先获取后累加,incrementAndGet()先累加再获取之类的方法。 |
| 数组 | AtomicIntegerArray AtomicLongArray AtomicReferenceArray |
可以理解为数组的引用类型 |
| 引用类型 | AtomicReference AtomicMarkableReference AtomicStampedReference |
AtomicReference包装一个类,然后调用compareAndSet进行原子操作替换成另一个类。可以进行整个类的CAS原子操作。另外两个主要关系ABA问题,mark关心是否被动过,stamped关心动过几次 |
| 原子更新字段类 | AtomicReferenceFieldUpdater AtomicIntegerFieldUpdater AtomicLongFieldUpdater |
比较麻烦,可以用上一个替代 |
文章字数:115,阅读全文大约需要1分钟
怀疑人生,去掉输出程序执行错误(时好时坏)
1 | //把密码加密再提交表单 |
原来提交之前输出md5字符串的值,之后去掉了。结果提交的密码就成了明文???
可能加密或者val()存在异步操作,程序直接进入下一步。
1 | var md5Pwd=hex_md5(pwd); |
文章字数:711,阅读全文大约需要2分钟
整理自原文
Method#invoke方法会对参数做封装和解封操作invoke方法参数是Object[]类型,如果方法的参数是简单类型,那么需要先包装成Object类型。例如long需要装换成Long。此时产生了多余的Long类型的Objec。生成动态字节码,并加载到jvm的方法MethodAccessorGenerator#emitInvoke会将参数恢复到之前的类型,同时做参数校验。
反射调用的时候可能会将参数进行多余的封装和解封,产生不必要的内存浪费。调用次数过多甚至会导致GC(感觉有点夸张)
需要检测方法可见性
反射每次调用都必须检查方法的可见性(Method.invoke)
需要校验参数
反射必须检查每个实际参数和形式参数的类型匹配(在NativeMethodAccessorImpl.invoke0 里或者生成的 Java 版 MethodAccessor.invoke 里)
方法难以内联Method.invoke()自身难以被内联到方法调用。
JIT无法优化
反射涉及到动态加载的类型,无法优化。
文章没给,但是自己能想到几个
Method等对象缓存下来,这样在下次调用的时候可以减少生成的开销。getMethod / getDeclaredMethod
调用反射时现需要创建Class对象(Class.forName),然后获取Method对象(getMethod / getDeclaredMethod),最后才是invoke调用。
相同:getMethod和getDeclaredMethod的内部结构都是检查方法权限、获取方法、返回方法的拷贝。
不同:getMethod检查和获取的方法可以是自身的也可以是父类的,getDeclaredMethod获取的方法只能是自身的。
checkMemberAccess
第一步,检查方法权限。getMethod的传入值之一是Member.PUBLIC,getDeclaredMethod是Member.DECLARED。一个检查父类和自身,另一个只有自身方法。
getMethod0getMethod方法检查完方法权限后调用getMethod0获取方法
getMechodsRecursive
递归查找父类方法
privateGetDeclaredMethods
获取自身方法
Method#copy
文章字数:174,阅读全文大约需要1分钟
原文
1 | @RestControllerAdvice(basePackages = {"com.rudecrab.demo.controller"}) // 注意哦,这里要加上需要扫描的包 |
1 | @RestControllerAdvice |
文章字数:204,阅读全文大约需要1分钟
响应式编程有三个组成部分 变化传递
propagation of change、 数据流data stream、 申明式declarative。
在响应式编程中,一个模块数据产生变动,相应模块的数据也会变化。(vue的数据绑定)
生产者生成发送 数据/事件,消费者监听并负责处理数据变化传递的方式。
响应式编程中的数据是以数据流的形式发出的,相应的方法监听数据流,对于数据流的元素一次处理。
数据流中说到的监听数据流的方法中对于数据流应该如何处理的定义就是声明。预先定义好将如何对数据流进行处理就是声明式。
文章字数:359,阅读全文大约需要1分钟
回文子串指的是从前向后和从后向前读是一样的字符串,比如
abba或者abcba。
以下是我自己写的,思路如下:
实现是:
1 | class Solution { |
时间复杂度O(n^3)
为了直观,现将String转成char[]再操作,多占了内存。将char[]的操作改成直接操作String可以达到空间复杂度O(1)
在leetcode官方讲解中看到的一个解决方法,时间复杂度O(n^2),空间复杂度O(1)
思路:
每个回文子串都有个中心,abba的中心就是bb。abcba的中心是c。
通过中心向外扩散,即可得到整个回文子串。
实现
1 | public String longestPalindrome(String s) { |
文章字数:265,阅读全文大约需要1分钟
基数排序适用于整形排序,将数据按照位数切割成不同的数字,按照权重依次桶排序。
第一次排序,位数最大的在后面,小的在前面。
第二次排序十位上的大的向后
第三次百位大的向后
…
越在后面进行的排序作用就越大,因为可以推翻之前的排序结果。位数越靠前代表的值也越大,所以从个位开始到最高位。
本质上是桶排序的增强版,不需要那么多的桶。
1 | public static void sort(int[] arr){ |
文章字数:511,阅读全文大约需要2分钟
1 | public String encryptToBase64(String filePath) { |
Files、Paths类是JDK7里加入的,读取文件不再需要调用IO包里的FileInputStream,简单便捷。字符串参数filePath是文件的路径。
首先是将文件读成二进制码,然后通过Base64.getEncoder().encodeToString()方法将二进制码转换为Base64值。
1 | public String decryptByBase64(String base64, String filePath) { |
Files.write()方法轻松将文件写入指定位置
1.7之后引入了
java.nio.file包取代原来基于java.io.File的文件IO操作
位置:
java.nio.file.Filesjava.nio.file.Path获取path
1 | Path path; |
File和Path转换
1 | File file = new file("c:\\xxx.txt"); |
Path信息
1 | Path path = Paths.get("D:\\demo\text.txt"); |
文件是否存在
1 | Path path = Paths.get("D:\\demo.txt"); |
创建文件/文件夹
1 | Path target2 = Paths.get("C:\\demo.txt"); |
Files.createDirectory()创建文件夹,上级目录不存在报错Files.createDirectorys()创建文件夹,上级目录不存在则创建上级目录
删除文件或目录
1 | Path path = Paths.get("data/subdir/logging-moved.properties"); |
复制文件到另一个位置
1 | Path sourcePath = Paths.get("data/logging.properties"); |
还可以直接覆盖目标文件
1 | Files.copy(sourcePath, destinationPath, |
获取文件属性
1 | Path path = Paths.get("D:\\XMind\\bcl-java.txt"); |
遍历一个文件夹
1 | Path dir = Paths.get("D:\\Java"); |
遍历整个文件目录
walkFileTree接受一个path和FileVisitor,path是遍历的目录,FileVistor则是一个接口,每次遍历都会被调用,需要自己实现。
SimpleFileVisitor是默认实现类,将接口所有方法都做了空实现。
1 | //地址 |
FindJavaVisitor.java
1 | public class FindJavaVisitor extends SimpleFileVisitor<Path>{ |