
Java
文章平均质量分 91
Java基础相关知识
程序员Seven
欢迎到访在线网站:www.seven97.top
展开
-
Java中到底有哪些锁
读锁是共享锁,写锁是独享锁。在代码进入同步块的时候,如果同步对象锁状态为无锁状态(锁标志位为“01”状态,是否为偏向锁为“0”),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝,然后拷贝对象头中的Mark Word复制到锁记录中。如果轻量级锁的更新操作失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是就说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块继续执行,否则说明多个线程竞争锁。原创 2024-09-25 23:50:43 · 1239 阅读 · 0 评论 -
线程状态转换?创建线程的几种方式?线程如何停止?
线程状态转换新建(New)NEW:初始状态,线程被构建,但是还没有调用start()方法。可运行(Runnable)RUNNABLE:可运行状态,可运行状态可以包括:运行中状态和就绪状态。也就是 可能正在运行,也可能正在等待 CPU 时间片。包含了操作系统线程状态中的 Running 和 Ready。阻塞(Blocking)等待获取一个排它锁,如果其线程释放了锁就会结束此状态。new Thread(new BlockedDemo(),"Blocked-Demo-1").start();n原创 2024-09-24 23:23:23 · 1122 阅读 · 0 评论 -
一文夯实并发编程的理论基础
java内存模型(即 java Memory Model,简称JMM),不存在的东西,是一个概念,约定主要分成两部分来看,一部分叫做主内存,另一部分叫做工作内存。java当中的共享变量;都放在主内存当中,如类的成员变量(实例变量),还有静态的成员变量(类变量),都是存储在主内存中的。每一个线程都可以访问主内存;每一个线程都有其自己的工作内存,当线程要执行代码的时候,就必须在工作内存中完成。原创 2024-09-23 22:22:44 · 1118 阅读 · 0 评论 -
ConcurrentLinkedQueue详解(图文并茂)
是基于链接节点的无界线程安全队列。此队列按照FIFO(先进先出)原则对元素进行排序。队列的头部是队列中存在时间最长的元素,而队列的尾部则是最近添加的元素。新的元素总是被插入到队列的尾部,而队列的获取操作(例如poll或peek)则是从队列头部开始。与传统的LinkedList不同,使用了一种高效的非阻塞算法,被称为无锁编程(Lock-Free programming),它通过原子变量和CAS(Compare-And-Swap)操作来保证线程安全,而不是通过传统的锁机制。原创 2024-09-22 19:45:17 · 1005 阅读 · 0 评论 -
深入理解ConcurrentHashMap
concurrentHashMap是一个支持高并发更新与查询的哈希表(基于HashMap)。hashtable该类不依赖于synchronization去保证线程操作的安全。Collections.synchronizedMap()也可以将map转成线程安全的。而concurrentHashMap在保证安全的前提下,进行get不需要锁定。HashTable: 使用了synchronized关键字对put等操作进行加锁;ConcurrentHashMap JDK1.7: 使用分段锁机制实现;原创 2024-09-19 22:13:12 · 1065 阅读 · 0 评论 -
一文搞定WeakHashMap
在缓存场景下,由于内存是有限的,不能缓存所有对象,因此就需要一定的删除机制,淘汰掉一些对象。这个时候可能很快就想到了各种Cache数据过期策略,目前也有一些优秀的包提供了功能丰富的Cache,比如Google的,它支持数据定期过期、LRU、LFU等策略,但它仍然有可能会导致有用的数据被淘汰,没用的数据迟迟不淘汰(如果策略使用得当的情况下这都是小概率事件)。现在有种机制,可以让Cache里不用的key数据自动清理掉,用的还留着,不会出现误删除。原创 2024-09-18 21:23:05 · 667 阅读 · 0 评论 -
为什么在EffectiveJava中建议用EnumSet替代位字段,以及使用EnumMap替换序数索引
在中的第 36条中建议 用 EnumSet 替代位字段,在第37条中建议 用EnumMap替换序数索引,为什么?原创 2024-09-13 21:18:14 · 1044 阅读 · 0 评论 -
LinkedHashMap原理详解—从LRU缓存机制说起
从一道Leetcode题目说起146.LRU缓存机制,题目描述如下:请你设计并实现一个满足LRU (最近最少使用) 缓存约束的数据结构。实现LRUCache以正整数作为容量capacity初始化 LRU 缓存如果关键字key存在于缓存中,则返回关键字的值,否则返回-1。如果关键字key已经存在,则变更其数据值value;如果不存在,则向缓存中插入该组key-value。如果插入操作导致关键字数量超过capacity,则应该逐出最久未使用的关键字。函数get和put必须以O(1)原创 2024-09-12 20:27:20 · 990 阅读 · 0 评论 -
TreeMap源码详解—彻底搞懂红黑树的平衡操作
TreeSet和TreeMap在Java里有着相同的实现,前者仅仅是对后者做了一层包装,也就是说TreeSet里面有一个TreeMap(适配器模式)。JavaTreeMap实现了SortedMap接口,也就是说会按照key的大小顺序对Map中的元素进行排序,key大小的评判可以通过其本身的自然顺序(natural ordering),也可以通过构造时传入的比较器(Comparator)。TreeMap底层通过红黑树(Red-Black tree)实现。原创 2024-09-11 20:41:48 · 1047 阅读 · 0 评论 -
为什么Java已经不推荐使用Stack了?
Java里有一个叫做Stack的类,却没有叫做Queue的类(它是个接口名字)。当需要使用栈时,Java已不推荐使用Stack,而是推荐使用更高效的ArrayDeque;既然Queue只是一个接口,当需要使用队列时也就首选ArrayDeque了(次选是LinkedList)。原创 2024-09-10 22:15:24 · 1152 阅读 · 0 评论 -
深入剖析HashMap:理解Hash、底层实现与扩容机制
Key的存储方式是基于哈希表的HashMap是 Map 接口 使用频率最高的实现类。允许使用null键和null值,与HashSet一样,不保证映射的顺序。所有的key构成的集合是无序的、唯一不可重复的。所以,key所在的类要重写:equals()和hashCode()所有的value构成的集合是Collection:无序的、可以重复的。所以,value所在的类要重写:equals()一个key-value构成一个entry所有的entry构成的集合是Set:无序的、不可重复的。原创 2024-09-07 14:58:27 · 1474 阅读 · 0 评论 -
优先级队列PriorityQueue(图文并茂)
介绍优先级队列的作用是能保证每次取出的元素都是队列中权值最小(或最大)的。这里元素大小的评判可以通过元素本身的自然顺序(natural ordering),也可以通过构造时传入的比较器(Comparator)。Java中PriorityQueue实现了Queue接口,不允许放入null元素;其通过堆实现,具体说是通过完全二叉树(complete binary tree)实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值),也就意味着可以通过数组来作为PriorityQueue的底层实现。原创 2024-09-05 21:06:45 · 727 阅读 · 0 评论 -
Linkedlist源码详解
LinkedList同时实现了List接口和Deque接口,也就是说它既可以看作一个顺序容器,又可以看作一个队列(Queue),同时又可以看作一个栈(Stack这样看来,LinkedList简直就是个全能冠军。当你需要使用栈或者队列时,可以考虑使用LinkedList,一方面是因为Java官方已经声明不建议使用Stack类,更遗憾的是,Java里根本没有一个叫做Queue的类(它是个接口名字,无法直接创建)。关于栈或队列,现在的首选是ArrayDeque,它有着比LinkedList。原创 2024-09-04 21:58:50 · 998 阅读 · 0 评论 -
深入浅出Stream流
Stream是一个接口,它定义了对Stream的操作,它继承自BaseStream,BaseStream是最顶端的接口类,定义了流的基本接口方法,最主要的方法为 spliterator、isParallel。Stream主要可分为中间操作与终结操作,中间操作对流进行转化,定义了映射(map)过滤(filter)排序(sorted)等行为。终结操作启动流水线,获取结果数据(collect)。AbstractPipline是一个抽象类,定义了流水线节点的常用属性sourceStage:指向流水线首节点。原创 2024-09-03 21:34:32 · 1318 阅读 · 0 评论 -
解耦利器 - Java中的SPI机制
SPI(Service Provider Interface),是JDK内置的一种 服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用,例如数据库中的java.sql.Driver接口,不同的厂商可以针对同一接口做出不同的实现,如下图所示,MySQL和PostgreSQL都有不同的实现提供给用户。而Java的SPI机制可以为某个接口寻找服务实现,Java中SPI机制主要思想是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要,其核心思想就是解耦。原创 2024-09-02 21:08:16 · 1368 阅读 · 0 评论 -
最常用集合 - ArrayList详解
ArrayList实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现。除该类未实现同步外,其余跟Vector大致相同。每个ArrayList都有一个容量(capacity),表示底层数组的实际大小,容器内存储元素的个数不能多于当前容量。当向容器中添加元素时,如果容量不足,容器会自动增大底层数组的大小。JDK1.7:像饿汉式,直接创建一个初始容量为10的数组。原创 2024-08-30 22:28:53 · 1403 阅读 · 0 评论 -
一篇文章讲清楚Java中的反射
每个类都有一个Class对象,包含了与类有关的信息。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。类加载相当于 Class 对象的加载。类在第一次使用时才动态加载到 JVM 中,可以使用 Class.forName(“com.mysql.jdbc.Driver”) 这种方式来控制类的加载,该方法会返回一个 Class 对象。反射可以提供运行时的类信息,并且这个类可以在运行时才加载进来,甚至在编译时期该类的 .class 不存在也可以加载进来。原创 2024-08-29 21:46:48 · 945 阅读 · 1 评论 -
什么是枚举?实现原理?
/...各个常量的值可能会一样,出现混淆,例如不小心把TUESDAY 定义为0使用起来并不是很方便,例如想要获取某一种枚举的所有枚举值列表,根名称获取值等,还要去编码实现并不是很安全,例如反射修改常量的值,MONDAY 的值可能被修改为1方式并不是很优雅为了不重复造轮子,Java在JDK1.5的时候,引入了枚举enum关键字(enum就是enumeration的缩写),我们可以定义枚举类型。访问修饰符 enum 枚举类型名称{原创 2024-08-29 21:36:05 · 1278 阅读 · 0 评论 -
Java异常详解(全文干货)
Throwable 是 Java 语言中所有错误与异常的超类。Throwable 包含两个子类:Error(错误)和 Exception(异常),它们通常用于指示发生了异常情况。Throwable 包含了其线程创建时线程执行堆栈的快照,它提供了 printStackTrace() 等接口用于获取堆栈跟踪数据等信息。无论try中是否有return,是否有异常,finally都一定会执行。如果try中有异常发生,会执行catch中的句子,try中异常后续的位置的语句不会再被执行。原创 2024-08-28 21:21:06 · 1478 阅读 · 0 评论 -
注解是如何实现的?
注意,注解的解析和处理用的是反射,所以注解定义时要用RententionPolicy.RUNTIME,否则用反射是拿不到注解信息的,因为反射是在运行时(Runtime)。区别于注解的继承,被注解的子类继承父类注解可以用@Inherited: 如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。虽然反编译后发现注解继承了Annotation接口,但即使Java的接口可以实现多继承,但定义注解时依然无法使用extends关键字继承@interface。原创 2024-08-27 20:45:33 · 649 阅读 · 0 评论 -
注解的优点?元注解?
注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包、类、接口、字段、方法参数、局部变量等进行注解。主要作用如下:编写文档——通过注解中标识的元数据可以生成doc文档,这是最常见的,也是java 最早提供的注解。常用的有@param @return 等代码分析——通过注解中标识元数据对代码进行分析。跟踪代码依赖性,实现替代配置文件功能。编译检查——通过注解中标识的元数据,让编译器能够实现基本的编译检查,例如@Override重写,如果这个方法并不是覆盖了超类方法,则编译时就能检查出。原创 2024-08-27 20:39:56 · 880 阅读 · 0 评论 -
知道泛型擦除会造成多态的冲突吗?
类型擦除会造成多态的冲突,而JVM的解决方法就是泛型的。原创 2024-08-26 21:07:07 · 1032 阅读 · 0 评论 -
了解泛型的类型擦除吗?
java.lang.reflect.Type是Java中所有类型的公共高级接口, 代表了Java中的所有类型. Type体系中类型的包括:数组类型(GenericArrayType)、参数化类型(ParameterizedType)、类型变量(TypeVariable)、通配符类型(WildcardType)、原始类型(Class)、基本类型(Class), 以上这些类型都实现Type接口。泛型的本质是参数化类型,即给类型指定一个参数,然后在使用时再指定此参数具体的值,那样这个类型就可以在使用时决定了。原创 2024-08-26 20:54:11 · 549 阅读 · 0 评论 -
讲讲Java的序列化反序列化?
如果不显示指定 serialVersionUID,JVM 在序列化时会根据属性自动生成一个 serialVersionUID,然后与属性一起序列化,再进行持久化或网络传输. 在反序列化时,JVM 会再根据属性自动生成一个新版 serialVersionUID,然后将这个新版 serialVersionUID 与序列化时生成的旧版 serialVersionUID 进行比较,如果相同则反序列化成功,否则报错.所以在实际开发中,都会显示指定一个 serialVersionUID。不同序列化工具的权衡。原创 2024-08-24 21:20:43 · 736 阅读 · 0 评论 -
一文讲清楚static关键字
子类会继承父类的静态方法和静态变量,但是无法对静态方法进行重写子类中可以直接调用父类的静态方法和静态变量子类可以直接修改(如果父类中没有将静态变量设为private)静态变量,但这是子类自己的静态变量。子类可以拥有和父类同名的,同参数的静态方法,但是这并不是对父类静态方法的重写,是子类自己的静态方法,子类只是把父类的静态方法隐藏了。原创 2024-08-23 21:01:12 · 510 阅读 · 0 评论 -
讲讲深拷贝浅拷贝
值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量。引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本,并不是原对象本身,两者指向同一片内存空间。所以对引用对象进行操作会同时改变原对象。java中不存在引用传递,只有值传递。即不存在变量a指向变量b,变量b指向对象的这种情况。原创 2024-08-23 20:53:33 · 1019 阅读 · 0 评论 -
解决哈希冲突的三种方法
HashMap,HashSet其实都是采用的拉链法来解决哈希冲突的,就是在每个位桶实现的时候,采用链表(jdk1.8之后采用链表+红黑树)的数据结构来去存取发生哈希冲突的输入域的关键字(也就是被哈希函数映射到同一个位桶上的关键字)它的实现是在插入一个元素的时候,先通过哈希函数进行判断,若是发生哈希冲突,就以当前地址为基准,根据再寻址的方法(探查序列),去寻找下一个地址,若发生冲突再去寻找,直至找到一个为空的地址为止。我们知道,在使用Map,Set这些集合时,都会重写hashcode方法,但Java中的。原创 2024-08-22 20:50:51 · 1259 阅读 · 0 评论 -
为什么重写hashCode一定也要重写equals方法?
*对于普通判断对象是否相等来说,只equals是可以完成需求的,但是如果使用set,map这种需要用到hash值的集合时,不重写hashCode方法,是无法满足需求的。**尽管如此,也一般建议两者都要重写,几乎没有见过只重写一个的情况。原创 2024-08-22 20:40:49 · 1260 阅读 · 0 评论 -
数组到底是不是对象
Arrays.sort()默认是升序排序,如果要降序排序,需要自定义比较器//报错报错显示:需要的是int类型,但提供的是T类型的这是因为Arrays.sort方法有多个重载版本,其中针对基本类型数组(如int[])的版本不接受自定义比较器。你尝试传入一个自定义比较器给int[]数组的方法,因此会导致编译错误。具体来说,:用于排序int数组,按自然顺序排序,不接受比较器。:用于排序泛型对象数组,按自定义比较器排序。因此如果试图将一个自定义比较器传入int数组的。原创 2024-08-21 21:34:49 · 470 阅读 · 0 评论 -
能否自定义一个String类使用
可以自定义包名不为java.lang的String类,并区别包名正常使用自定义包名为java.lang的String类String类下写main方法:由于双亲委派模型,在加载String类时,会最终委派给Bootstrap ClassLoader去加载,加载的是rt.jar包中的那个java.lang.String,而rt.jar包中的String类是没有main方法的,因此报错误。原创 2024-08-21 21:25:54 · 1151 阅读 · 0 评论 -
String, StringBuffer 和 StringBuilder之间的区别
StringBuilder快就快在,相比String,他在运算的时候分配内存次数小,所以拷贝次数和内存占用也随之减少,当有大量字符串拼接时,StringBuilder创建char[]的次数会少很多。由于GC的机制,即使原来的char[]没有引用了,那么也得等到GC触发的时候才能回收,String运算过多的时候就会产生大量垃圾,消耗内存。创建s1的时候其实就是创建了第一个不可变的char[]数组,创建s2的时候创建了第二个不可变的char[]数组。无论放入是否成功,都会返回串池中的字符串对象。原创 2024-08-20 21:42:11 · 928 阅读 · 0 评论 -
String究竟能存储多少字符?
因此,主要的还是看编译器对常量池的限制,使得byte数组的最大长度不能超过65535;以及JVM的内存限制补充:JDK9以后对String的存储进行了优化。底层不再使用char数组存储字符串,而是使用byte数组。对于LATIN1字符的字符串可以节省一倍的内存空间。详情请看Java9 - string字符串的变化。原创 2024-08-20 21:14:19 · 1211 阅读 · 0 评论 -
String真的不可变吗?
Java中的String是不可变对象在面向对象及函数编程语言中,不可变对象(英语:Immutable object)是一种对象,在被创造之后,它的状态就不可以被改变。至于状态可以被改变的对象,则被称为可变对象(英语:mutable object)。-- 来自百度百科。原创 2024-08-20 21:01:13 · 470 阅读 · 0 评论 -
金融、支付行业的开发者不得不知道的float、double计算误差问题
BigDecimal可以实现对浮点数的运算,不会造成精度丢失。通常情况下,大部分需要浮点数精确运算结果的业务场景(比如涉及到钱的场景)都是通过BigDecimal来做的。想要解决浮点数运算精度丢失这个问题,可以直接使用BigDecimal来定义浮点数的值,然后再进行浮点数的运算操作即可。// 0浮点数没有办法用二进制精确表示,因此存在精度丢失的风险。不过,Java 提供了BigDecimal来操作浮点数。BigDecimal的实现利用到了BigInteger(用来操作大整数), 所不同的是。原创 2024-08-19 22:57:44 · 1037 阅读 · 0 评论 -
浅谈integer缓存机制原理
当赋值100给Integer时,刚好在这个范围内,所以从cache中取对应的Integer并返回,所以a和b返回的是同一个对象,所以 比较是相等的,当赋值200给Integer时,不在cache 的范围内,所以会new Integer并返回,当然 比较的结果是不相等的。1、2、3都好理解,缓存范围是 [-128,127],1、2都在范围内,返回的是缓存中的对象,因此输出true,3不在范围内,返回的是新 new 的Integer,因此输出false。公众号:seven97,欢迎关注~原创 2024-08-18 23:50:03 · 1076 阅读 · 0 评论