Java知识笔记
文章平均质量分 78
本专栏主要记录Java基础相关的知识笔记。
川峰
10年+Android相关工作经验。专注于移动开发领域。
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
《深入理解JAVA虚拟机笔记》并发与线程安全原理
如果出现两条以上的线程争用同一个锁的情况,那轻量级锁就不再有效,必须要膨胀为重量级锁,锁标志的状态值变为“10”,此时Mark Word中存储的就是指向重量级锁(互斥量)的指针,后面等待锁的线程也必须进入阻塞状态。不过这种读取到“半个变量”的情况是非常罕见的,经过实际测试,在目前主流平台下商用的64位Java虚拟机中并不会出现非原子性访问行为,但是对于 32 位的 Java 虚拟机,譬如比较常用的32位x86平台下的HotSpot虚拟机,对long类型的数据确实存在非原子性访问的风险。原创 2023-12-30 07:15:40 · 1118 阅读 · 0 评论 -
如何理解面向对象的OO设计原则和设计模式?
高层模块不应该依赖低层模块,二者都应依赖其抽象;抽象不应依赖细节,细节应该依赖抽象。模块间的依赖关系通过接口或抽象类发生,实现类之间不发生直接的依赖关系。开发者不能干预这些生命周期,只能选择在某一个回调中处理。单一职责、开闭原则、里氏替换、接口隔离、依赖倒置。一个类应该仅有一个引起它变化的原因。一个对象应该对其他对象有最少的了解。(知道的太多,可能活不到剧终)。客户端不应该依赖它不需要的接口。面向接口编程,或面向抽象编程。面向接口编程,或面向抽象编程。永远不要过早的依赖细节。接口隔离原则 ISP。原创 2023-12-31 07:38:06 · 1310 阅读 · 0 评论 -
《深入理解JAVA虚拟机笔记》编译与优化
方法内联的优化行为理解起来是没有任何困难的,不过就是把目标方法的代码原封不动地“复制”到发起调用的方法之中,避免发生真实的方法调用而已。在一般应用中,完全不会逃逸的局部对象和不会逃逸出线程的对象所占的比例是很大的,如果能使用栈上分配,那大量的对象就会随着方法的结束而自动销毁了,垃圾收集子系统的压力将会下降很多。)〉的技术,这是整个应用程序范围内的类型分析技术,用于确定在目前已加载的类中,某个接口是否有多于一种的实现、某个类是否存在子类、某个子类是否覆盖了父类的某个虚方法等信息。根据上面的分析可知,原创 2023-12-29 14:07:49 · 1031 阅读 · 0 评论 -
《深入理解JAVA虚拟机笔记》运行时栈帧、方法分派、动态类型
Java 虚拟机以方法作为最基本的执行单元,“栈帧”(Stack Frame)则是用于支持虚拟机进行方法调用和方法执行背后的数据结构,它也是虚拟机运行时数据区中的虚拟机栈的栈元素。栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。每一个方法从调用开始至执行结束的过程,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程。每一个栈帧都包括了局部变量表、操作数栈、动态连接、方法返回地址和一些额外的附加信息。在 Java 编译程序代码时,栈帧中需要多大的局部变量表,需要多深的操作数栈就已经被分析计算原创 2023-12-29 13:19:30 · 1591 阅读 · 0 评论 -
《深入理解JAVA虚拟机笔记》Class文件格式、字节码指令
之所以要专门使用这样一个属性去记录泛型类型,是因为Java语言的泛型采用的是擦除法实现的伪泛型,字节码(Code属性)中所有的泛型信息编译(类型变量、参数化类型)在编译之后都通通被擦除掉。Code属性是Class文件中最重要的一个属性, 如果把一个Java程序中的信息分为代码(Code, 方法体里面的Java代码) 和元数据(Metadata, 包括类、 字段、 方法定义及其他信息) 两部分, 那么在整个Class文件里, Code属性用于描述代码, 所有的其他数据项目都用于描述元数据。原创 2023-12-29 08:28:06 · 1412 阅读 · 0 评论 -
《深入理解JAVA虚拟机笔记》类加载机制
这个阶段的验证是基于二进制字节流进行的,只有通过了这个阶段的验证后,这段字节流才允许进入java虚拟机内存的方法区中进行存储,所以后面的三个验证阶段全部是基于方法区的存储结构上进行的,不会再直接读取,操作字节流了。正如OSGi中的类加载器的设计不符合传统的双亲委派模型的类加载器架构,且业界对其为了实现热部署而带来的额外的高复杂度还存在不少争议,但对这方面有了解的技术人员基本还是能达成一个共识,认为OSGi中对类加载器的运用是值得学习的,完全弄懂了OSGi的实现,就算是掌握了类加载器的精粹。原创 2023-12-29 09:01:19 · 1015 阅读 · 0 评论 -
《深入理解JAVA虚拟机笔记》垃圾回收器
很多教科书判断对象是否存活的算法是这样的:客观地说,引用计数算法(Reference Counting)虽然占用了一些额外的内存空间来进行计数,但它的原理简单,判定效率也很高,在大多数情况下它都是一个不错的算法。也有一些比较著名的应用案例,例如微软COM(Component Object Model)技术、使用ActionScript 3的FlashPlayer、Python语言以及在游戏脚本领域得到许多应用的Squirrel中都使用了引用计数算法进行内存管理。但是,原创 2023-12-29 08:27:29 · 949 阅读 · 0 评论 -
《深入理解JAVA虚拟机笔记》OutOfMemoryError 异常
而使用 JDK 7 或更高版本的 JDK 来运行这段程序并不会得到相同的结果,无论是在 JDK 7 中继续使 用-XX:MaxPermSize参数或者在 JDK 8 及以上版本使用-XX:MaxMetaspaceSize参数把方法区容量同样限制在 6MB,也都不会重现 JDK 6 中的溢出异常,循环将一直进行下去。由直接内存导致的内存溢出,一个明显的特征是在 Heap Dump 文件中不会看见有什么明显的异常情况,如果发现内存溢出之后产生的 Dump 文件很小,而程序中又直接或间接使用了。原创 2023-12-28 23:32:57 · 1286 阅读 · 0 评论 -
《深入理解JAVA虚拟机笔记》对象的创建和访问、对象头
对象需要存储的运行时数据很多,其实已经超出了32、64位Bitmap结构所能记录的最大限度,但对象头里的信息是与对象自身定义的数据无关的额外存储成本,考虑到虚拟机的空间效率,Mark Word被设计成一个有着动态定义的数据结构,以便在极小的空间内存储尽量多的数据,根据对象的状态复用自己的存储空间。,无论是从父类继承下来的,还是在子类中定义的字段都必须记录起来。,因为虚拟机可以通过普通 Java对象的元数据信息确定Java对象的大小,但是如果数组的长度是不确定的,将无法通过元数据中的信息推断出数组的大小。原创 2023-12-28 22:42:53 · 961 阅读 · 0 评论 -
《深入理解JAVA虚拟机笔记》Java 运行时内存区域
Java虚拟机对Class文件的每一部分(自然也包括常量池)的格式都有严格的规定,如每一个字节用于存储哪种数据都必须符合规范上的要求才会被虚拟机认可、加载和执行,但对于运行时常量池,《Java虚拟机规范》并没有做任何细节的要求,不同的提供商实现的虚拟机可以按照自己的需要来实现这个内存区域,不过一般来说,除了保存Class文件中描述的符号引用外,还会把由符号引用翻译出来的直接引用也存储在运行时常量池中。但对于大对象(典型的如数组对象),多数虚拟机实现出于实现简单、存储高效的考虑,很可能会要求连续的内存空间。原创 2023-12-27 21:17:11 · 599 阅读 · 0 评论 -
Java 对象内存布局
在虚拟机中,Java对象在内存中的布局可以分为三块:longdoubleshortcharbyteboolean又包括:对于 64 位上的一个空对象:也就是说,原创 2023-12-27 19:56:59 · 713 阅读 · 1 评论 -
【LeetCode刷题笔记】线程同步
线程同步相关。原创 2023-12-26 10:53:24 · 799 阅读 · 0 评论 -
【面试】Java 双重检测的单例,为什么还要加 volatile 关键字?
在双重检测单例的例子中,volatile 保证的是有序性和可见性,原子性是由 synchronized 来保证的。即便发生在同一个方法/代码块内,还要看判断条件是否对该变量有依赖关系,如果没有依赖关系,那根本就无需考虑原子性问题。被 volatile 修饰的变量的修改和赋值操作,到底是不是发生在同一个方法/代码块内。还未初始化的对象实例。原创 2023-12-12 19:05:05 · 201 阅读 · 0 评论 -
【面试】Java GC 为什么会导致应用程序卡顿?
取决于两个关键因素:空间和时间。选择哪个算法要看这两个因素的对GC的重要性。没有一个算法能够兼具时间和空间都优秀的,一定是其中一个更优,而另一个会更差。也就是说鱼和熊掌不可兼得。看你更需要哪个。主要围绕两个点讨论:一些垃圾回收器的并行和并发设计算法都是为了提高GC的吞吐量原创 2023-12-12 18:38:07 · 137 阅读 · 0 评论 -
【面试】Java 所有被 new 出来的实例,都是放在堆中的吗?
对象所占用的内存空间就可以随栈帧出栈而销毁。在一般应用中,完全不会逃逸的局部对象和不会逃逸出线程的对象所占的比例是很大的,如果能使用栈上分配,那大量的对象就会随着方法的结束而自动销毁了,垃圾收集子系统的压力将会下降很多。是目前 Java 虚拟机中比较前沿的优化技术,它与类型继承关系分析一样,将其用到的成员变量恢复为原始类型来访问,这个过程就称为“标量替换”直接创建它的若干个被这个方法使用的成员变量来代替。标量替换可以视作栈上分配的一种特例。),则可能为这个对象实例。对象的成员变量在栈上。原创 2023-12-12 17:44:10 · 315 阅读 · 0 评论 -
【面试】Java 能否自己写一个叫做 java.lang.Object 的类?
【代码】【面试】Java 能否自己写一个叫做 java.lang.Object 的类?原创 2023-12-12 17:27:13 · 217 阅读 · 0 评论 -
【面试】Android 平台的虚拟机是基于栈的吗?(No)
基于栈的虚拟机:基于寄存器的虚拟机:这里的寄存器是指虚拟机里的,是一个虚拟的概念,并不是 CPU 硬件里的寄存器。JAVA 虚拟机与 Android 虚拟机的区别:栈和寄存器的区别Java 虚拟机都是基于栈的结构,而 Dalvik 虚拟机则是基于寄存器。基于栈的指令很紧凑,Java 虚拟机使用的指令只占一个字节,因而称为字节码。基于寄存器的指令由于需要指定源地址和目标地址,因此需要占用更多的指令空间。Dalvik 虚拟机的某些指令需要占用两个字节基于栈和基于寄存器的指令集各有优劣,一般而言,执行同样的功能,原创 2023-12-12 16:38:19 · 1008 阅读 · 0 评论 -
【面试】Java HashMap 的容量为什么一定是 2 的 n 次幂?
原创 2023-12-11 03:23:46 · 134 阅读 · 0 评论 -
【面试】Java String 的 hashCode 为什么乘数是 31?
原创 2023-12-11 03:12:31 · 131 阅读 · 0 评论 -
【面试】Java 线程安全&线程池
CPU 密集型任务线程数:建议CPU数 + 1IO 密集型任务线程数:建议CPU数 x 2实现线程池中任务按优先级执行:实现 Runnable, Comparable 接口,在 compareTo 中比较任务优先级进行排序实现线程池的暂停/恢复:利用 ReentrantLock.newCondition() 通过 Condition 的 await()/signal() 实现。原创 2023-12-11 03:05:42 · 658 阅读 · 0 评论 -
【面试】Java GC 垃圾回收算法
引用计数法可达性分析算法虚拟机栈(栈帧中的局部变量表)方法区中类静态属性方法区中常量本地方法栈中 Native 方法Class标记-清除算法标记-整理算法复制算法分代收集算法新生代复制算法老年代标记整理算法新生代老年代其中也就是说,。。。一般在空间不足的情况下发生。持久代nullnull。java提供了一个finalize方法,可以帮助我们进行资源释放,类似于C++中的析构函数。但是目前普遍的认识是不要使用,为什么呢?就是因为对java虚拟机的垃圾回收有影响。我们都知道一个对象。原创 2023-12-11 00:03:08 · 904 阅读 · 0 评论 -
Java 何时会触发一个类的初始化
Java 何时会触发一个类的初始化?使用new关键字创建对象访问类的静态成员变量 或 对类的静态成员变量进行赋值调用类的静态方法反射调用类时,如 Class.forName()初始化子类时,会先初始化其父类(如果父类还没有进行过初始化的话)遇到启动类时,如果一个类被标记为启动类(即包含main方法),虚拟机会先初始化这个主类。实现带有默认方法的接口的类被初始化时(拥有被default关键字修饰的接口方法的类)使用 JDK7 新加入的动态语言支持时 MethodHandle虚拟机在何时加载类原创 2023-12-10 23:10:26 · 1321 阅读 · 0 评论 -
Java 匿名内部类使用的外部变量,为什么一定要加 final?
这一切都是编译器为我们自动实现的,但对于开发者而言,体验上就会跟 Java 有明显的不同:“Java 需要。保证匿名内部类捕获的副本引用和外部的局部变量始终都指向同一个对象,也就是没有人可以修改它们的指向。捕获”,但这是一个错觉,实际上 Kotlin 也需要,只不过你看不到而已。内存泄漏的根本原因就是一个长生命周期的对象被一个短生命周期的对象所引用。所以虽然与 Java 的解决方式不同,但本质上看思想是一致的,,可以认为是 Kotlin 为了解决。注意:匿名内部类捕获的局部变量加。,Kotlin 中还有。原创 2023-12-10 16:14:08 · 1240 阅读 · 0 评论 -
Java 泛型相关知识
所以对于这两种通配符,需要结合所调用函数的传参的意图来理解,否则你单独定义一个变量类型是上界或下界,你就会非常莫名奇妙根本不能理解为什么要这么做,这里的上界或下界其实是针对传入的实参而言的。其实说白了,就是为了入参和出参使用需求,一个只读一个只写。至于读取或写入的类型,很容易能推断出来。上界通配符和下界通配符是 Java 中一种很奇怪的设计,或许它的意图非常巧妙,但是很难让人理解。关于上界通配符和下界通配符的使用,例如 Java 中。即用最顶层的类接受下面的子类型都可以。为什么使用泛型,使用泛型的好处?原创 2023-12-09 20:14:27 · 1515 阅读 · 0 评论 -
【面试】Java HashMap 面试题总结
更要命的是如果散列本身做得不好,分布上成等差数列的漏洞,如果正好让最后几个低位呈现规律性重复,就无比蛋疼。这时候。原创 2023-12-09 03:55:43 · 541 阅读 · 0 评论 -
【面试】Java 如何正确的停止一个线程?
并且是在很早的版本。因为该方法会导致一系列内存相关的问题。几乎所有语言里面的停止的方法都是一样的问题,都废弃了该方法。方法一直读取的当前状态,不会改变它。方法,底层C代码里会清空状态为。原创 2023-12-08 17:19:32 · 249 阅读 · 0 评论 -
【面试】Java基础面试问题总结
Java之所以可以“一次编译,到处运行”,一是因为 JVM 针对各种操作系统、平台都进行了定制,二是因为无论在什么平台,都可以编译生成固定格式的字节码(.class文件)供JVM使用。因此,也可以看出字节码对于Java生态的重要性。之所以被称之为字节码,是因为字节码文件由十六进制值组成而 JVM 以两个十六进制值为一组,即以字节为单位进行读取。在Java中一般是用javac命令编译源代码为字节码文件,一个.java文件从编译到运行的示例如图所示。原创 2023-12-08 17:01:59 · 867 阅读 · 0 评论 -
Java String相关问题
局部变量在stack中,包括基本类型变量和引用变量。成员变量在heap中,包括基本类型变量和引用变量。例如,这句如果是定义在方法中,左边的str是分配在栈中的,如果是定义在类的成员变量,则str是存放在堆中的。所有显示的字面量会放入常量池中,如果常量池中已经有对应的字符串就无需创建,否则就会新创建一个。所有的字面量 + 字面量、final变量 + final变量拼接都合并会生成一个新的字面常量放入常量池中。所有方式都会创建一个String对象,存放在堆中。原创 2023-12-07 15:45:06 · 1236 阅读 · 0 评论 -
Java 中 char 和 Unicode、UTF-8、UTF-16、ASCII、GBK 的关系
关于这几种字符编码的关系,经过各种资料研究,总结如下图(请右键在新标签页打开查看或者下载后使用看图工具放大查看):1[0-127]A1-F7A1-A9XX7F4~6HEX由于只规定了表示符号的二进制代码,却没有规定如何存储这个二进制代码。所以如何存储有不同的实现。而就是针对的不同存储方式的具体实现。0-1271282340000~FFFF注意:很多资料和文章中将 UTF-8 和 UTF-16 都称为定长编码,但实际上它们是可变长编码的,例如一个中文汉字用 UTF-8 表示的话,就需要 3 个字节。原创 2023-12-07 06:47:25 · 2510 阅读 · 0 评论 -
《Java 并发编程艺术》笔记(下)
子类推荐被定义为自定义同步组件的静态内部类,同步器自身没有实现任何同步接口,它仅仅是定义了若干同步状态获取和释放的方法来供自定义同步组件使用,同步器既可以支持独占式地获取同步状态,也可以支持共享式地获取同步状态,这样就可以方便实现不同类型的同步组件(在图5-4中,由于非首节点线程前驱节点出队或被中断而从等待状态返回,随后检查自己的前驱是否是头节点,如果是则尝试获取同步状态,可以看到节点与及节点之间在循环检查的过程中基本上不相互通信,而是简单地判断自己的前驱是否为头节点,这样就使得节点的释放符合。原创 2023-12-07 06:43:27 · 260 阅读 · 0 评论 -
Java 之注解相关知识
Java注解按照运行机制来分有以下几类classOverrideDeprected除了JDK自带的常见注解外,java中提供了四种元注解:@Retention@Target@Document@Inherited;元注解负责注解其他注解,可以用来自定义注解。原创 2023-12-07 01:15:08 · 118 阅读 · 0 评论 -
《Java 并发编程艺术》笔记(上)
从 JDK 5 开始,Java使用新的 JSR-133 内存模型,JSR-133使用happens-before的概念来阐述操作之间的内存可见性。在JMM中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。这里提到的两个操作既可以是在一个线程之内,也可以是在不同线程之间。JSR-133 对happens-before关系的定义如下1)原创 2023-12-06 21:42:05 · 220 阅读 · 0 评论 -
Java 线程池到底是如何复用线程的
其实 Java 线程池的实现原理很简单,说白了就是和。当用户向线程池提交一个任务时,线程池会先将任务放入中。中的线程会不断的从中获取线程然后执行。当中没有任务的时候,就会。上图是一张线程池工作的精简图,实际的过程比这个要复杂的多,不过这些应该能够完全覆盖到线程池的整个工作流程了。原创 2023-12-06 16:01:13 · 1694 阅读 · 0 评论 -
【面试】Java 多线程总结版
死锁:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。死锁必须具备以下四个条件:互斥条件:该资源任意一个时刻只由一个线程占用。请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。不剥夺条件:线程已获得的资源在末使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。如何避免线程死锁?只要破坏产生死锁的四个条件中的其中一个就可以了破坏互斥条件。原创 2023-12-06 14:14:28 · 884 阅读 · 0 评论 -
Java 深入理解反射(反射的性能开销以及优化)
影响反射调用耗时有以下原因:方法表查找构建Object数组以及可能存在的自动装拆箱操作运行时权限检查方法内联/逃逸分析如何优化反射性能开销?尽量避免反射调用虚方法关闭运行时权限检查可能需要增大基本数据类型对应的包装类缓存关闭 Inflation 机制提高 JVM 关于每个调用能够记录的类型数目JVM 是如何实现反射的?Java反射原理简析关于反射调用方法的一个log。原创 2023-12-04 09:35:11 · 1380 阅读 · 0 评论 -
Java 利用反射修改 static + final修饰的成员变量的值
Java 利用反射修改 static + final修饰的成员变量的值原创 2023-12-04 08:54:55 · 1354 阅读 · 0 评论 -
Java 反射使用总结
invoke方法有两个参数,第一个参数是要调用方法的对象,上面的代码中就是Bird的对象,第二个参数是调用方法要传入的参数。Class类对象就相当于B超的探头,将一个类的方法、变量、接口、类名、类修饰符等信息告诉运行的程序。和私有变量一样,私有方法也是不允许其他的类随意调用的,但是通过反射可以饶过这一限制。通过反射可以在运行时获取到类的所有成员变量,还可以给成员变量赋值和获取成员变量的值。方法,必须提供要获取的方法名以及方法名的参数。都只能获取到类声明的成员方法,不能获取到从父类继承来的方法。原创 2023-12-04 08:43:10 · 99 阅读 · 0 评论 -
Java 反射机制知识点
我们知道,类和类的成员变量及方法都是要求有权限控制的(public、protected、private);而当类中的信息封装为私有时,外部对该类中私有的信息是没有访问权限的,也就是说当该类里的内容信息均受private权限控制时,外部想要获取和处理该类里的私有信息是几乎不可能的;但是,有时候这种需求是有的,而当我们非得需要去动用别的类里封装的私有信息时,java的反射机制就起到了非常关键的作用了;原创 2023-12-04 08:06:37 · 154 阅读 · 0 评论 -
Java 不要在父类的构造方法里面调用可以被子类重写的方法
换言之,如果设置了默认值,即使之前已经被赋值,也会被默认值覆盖。相比于第一个坑,第二个坑显得更加隐式和不容易理解。原创 2023-12-04 07:28:43 · 1015 阅读 · 0 评论 -
Java 学习之多态
静态方法只能继承,不能重写Override,如果子类中定义了同名同形式的静态方法,它对父类方法只起到隐藏的作用。因为父类引用指向的是 Cat 类的对象,而要强制转换成 Dog 类,这是不可能的。,如上面的例子中,将 p 转换为子类 Child 类型的引用。如果想要调用子类中有而父类中没有的方法,需要进行强制类型转换。因为多态是一种运行期的行为,不是编译期的行为。,即不需要加上前面的小括号和父类类型名。,即指向谁才能转换成谁。父类型的引用必须指向子类的对象。对于向上的类型转换,对于向下的类型转换,原创 2023-12-04 06:37:27 · 148 阅读 · 0 评论
分享