文章目录
- Java从1.7到1.8的升级 ⭐️2
- ConcurrentHashMap的实现⭐️2
- 红黑树的结构和应用
- B+树的结构和应用
- Java中IO流的分类
- static的作用
- 类加载的过程
- Java异常的基类
- 深拷贝、浅拷贝的区别
- 重载和重写的区别
- double和float的区别
- java里如何精确表示小数
- java里的数据结构
- java里的数据类型
- jre、jdk、jvm的概念
- HashMap的Put过程
- HashMap的查找?⭐️
- HashMap和HashSet的原理区别
- HashMap中null的处理⭐️
- HashSet的遍历顺序
- Java list的实现
- Java面向对象的三大特征
- 多态的实现
- 反射的机制
- 什么是动态代理?
- Hashmap数组大小为2的幂次的原因⭐️
- 死锁产生的条件
- 死锁问题如何解决⭐️
- java反射的使用⭐️(需要例子)
- 包装类的使用场景
- 迭代器和增强for循环
- ConcurrentHashMap的线程安全
- synchronized的底层原理
- ReentrantLock
- ConcurrentHashMap的加锁机制
- sycronized和volatile的原理
- 接口和抽象类的区别
- Files的常用方法
- == 和Equals的区别⭐️
- 哪个集合接口可以实现List的并发安全⭐️
- CopyOnWriteArrayList 原理
- 栈在内存中的生长方向
Java从1.7到1.8的升级 ⭐️2
有很多,但是最重要的就是Lambda表达式以及Stream流了
ConcurrentHashMap的实现⭐️2
JDK1.7是数组+列表
JDK1.8是数组+列表+红黑树
红黑树的结构和应用
- 红黑树是一种自平衡的二叉查找树
- 节点要么是红色要么是黑色
- 红黑树的根节点一定是黑色
- 红色的叶子节点一定是黑色的
- 从根节点出发,到每一个叶子节点的末尾,都包含相同数目的黑色节点
- 红黑树的应用:HashMap
B+树的结构和应用
首先B树的结构:B树的每个叶子节点都存数据,但是相邻的叶子节点之间没有指针连接
B+树的结构:非叶子节点不存数据只存数据的索引,并且相邻的叶子节点有指针相互连接
这种底层是一个双向链表,双向链表的结构更适用于我们的范围查找
应用:在查询一条数据的时候很显然B树更加适合因为每个叶子节点都存数据,最好的情况就是O(1)
但是在范围查找的时候B树的确定就暴露出来了,因为如果使用B树作为Mysql的索引的话,在查询过程中会产生大量的I/O所以在综合考虑下下选择B+树作为Mysql的索引
Java中IO流的分类
- 从数据的流向:输入流、输出流
- 处理的字节单位:字节、字符
static的作用
- static关键字可以修饰:属性、方法、内部类、代码块;
- static修饰的资源属于类级别,是全体对象共享的资源
- 使用static修饰的属性、静态属性是在类加载过程中初始化的,使用类名.属性进行访问
类加载的过程
java文件从编码到最终运行分成俩个阶段:编码期、运行期
编码期就是执行Javac命令让java文件变成,class文件
运行期就是把.class文件交给JVM去执行
而类加载的过程就是:将.class文件的元数据加载到内存,创建class并且解析、初始化类变量的过程
Java异常的基类
Throwable是 Java 语言中所有错误和异常的基类。它有两个主要的子类:Error 和 Exception,这两个类分别代表了 Java 异常处理体系中的两个分支。
深拷贝、浅拷贝的区别
浅拷贝:拷贝基本数据类型的值、引用类型的地址值、而对于引用类型变量指向的堆中的对象不会拷贝。
深拷贝:完全拷贝一个对象,拷贝被拷贝对象的成员变量的值,堆中的对象也会拷贝一份。
重载和重写的区别
重载:一个类有多个名字,但是参数的个数不相同的方法
重写:子类和父类有一样的方法(参数相同、返回值相同、方法名字相同、但是方法体可能不同)
double和float的区别
范围:float的指数位有8位,而double的指数位有11位
精度:float是单精度 double是双精度
double和float的精度损失
float的精度为7~8位有效数字,7位肯定能保证,8位的值也存在。
double的精度为16~17位有效数字
针对浮点数丢失精度的问题,我们可以通过BigDecimal来解决
java里如何精确表示小数
通过BigDecimal来解决
java里的数据结构
数组、链表、栈、队列、二叉树、哈希表
java里的数据类型
基础数据类型:byte、short、int、long、float、double、char、布尔
引用数据类型:接口、数组、类
jre、jdk、jvm的概念
JVM:Java Virtual Machine,也就是 Java 虚拟机,是 Java 实现跨平台的关键所在,针对不同的操作系统,有不同的 JVM 实现。JVM 负责将 Java 字节码转换为特定平台的机器码,并执行。
JRE:Java Runtime Environment,也就是 Java 运行时环境,包含了运行 Java 程序所必需的库,以及 Java 虚拟机(JVM)。
JDK:Java Development Kit,是一套完整的 Java SDK(软件开发工具包),包括了 JRE 以及编译器(javac)、Java 文档生成工具(Javadoc)、Java 调试器等开发工具。为开发者提供了开发、编译、调试 Java 程序的一整套环境。
HashMap的Put过程
①.判断键值对数组table[i]是否为空或为null,否则执行resize()进行扩容;
②.根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,转向⑥,如 果table[i]不为空,转向③;
③.判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转向 ④,这里的相同指的是hashCode以及equals;
④.判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值 对,否则转向⑤;
⑤.遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操 作,否则进行链表的插入操作;遍历过程中若发现key已经存在直接覆盖value即可;
⑥.插入成功后,判断实际存在的键值对数量size是否超多了 大容量threshold,如果超过,进行扩容。
HashMap的查找?⭐️
-
将key的值hash再二次hash.
-
拿二次hash的值跟数组相模取出桶下标。
-
去对应的桶下标进行调用equals比较获得一样的key,取出值。
HashMap和HashSet的原理区别
HashMap 和 HashSet 都是 Java 中的集合类,但它们有以下几点区别: HashSet 实现了 Set 接口,只存储对象;HashMap 实现了 Map 接口,用于存储键值对。 HashSet 底层是用 HashMap 存储的,HashSet 封装了一系列 HashMap 的方法,HashSet 将(自己的)值保存到 HashMap 的 Key 里面了。
HashMap中null的处理⭐️
1.先在table[0]的链表中寻找null key,如果有null key就直接覆盖原来的value,返回原来的value;
2.如果在table[0]中没有找到,就进行头插,但是要先判断是否要扩容,需要就扩容,然后进行头插,此时table[0]就是新插入的null key Entry了。
HashSet的遍历顺序
HashSet作为集合,有多种遍历方法,如普通for循环,增强for循环,迭代器,HashSet是通过HashMap来实现的,HashMap通过hash(key)来确定存储的位置,是不具备存储顺序性的,因此HashSet遍历出的元素也并非按照插入的顺序。
HashMap底层原理
JDK8前:数组+列表
JDK8后:数组+列表+红黑树
Java list的实现
Java 的 List 是非常常用的数据类型。List 是有序的 Collection。Java List 一共三个实现类:分别是 ArrayList、Vector 和 LinkedList。
Java面向对象的三大特征
继承、封装、多态
多态的实现
多态(Polymorphism)是指在面向对象程序设计中,同一个方法调用会根据对象的不同而表现出不同的行为。简而言之,多态性是指一个接口可以有多种不同的实现方式,同一个方法名可以具有不同的行为。
在Java中,多态性通过方法的重写(Override)和方法的重载(Overload)实现。重写是指子类重新定义父类中已有的方法,而重载是指在一个类中可以定义多个同名但参数列表不同的方法。
反射的机制
反射(Reflection)机制指的是在运行时检查或操作Java程序中的字段、方法、构造方法等信息的能力。通过反射,可以在运行时动态地获取类的信息、调用类的方法、操作类的属性等。这种能力使得程序可以在运行时动态加载、探索和使用类,而不需要在编译时确定。
使用:
框架和库的设计:如Spring框架、ORM(对象关系映射)工具等,通过反射来动态地管理和操作类的实例。
调试和测试:在开发过程中,可以通过反射获取类的信息和调用方法,实现灵活的调试和测试策略。
动态代理:通过动态代理技术,可以在运行时生成代理类,实现AOP(面向切面编程)等功能。
什么是动态代理?
配置文件处理:某些情况下,可以使用反射从配置文件中读取类名、方法名等信息,并动态地加载和执行。
Hashmap数组大小为2的幂次的原因⭐️
如果为奇数的话求得的索引值会重复,加大哈希碰撞的概率
死锁产生的条件
1.互斥条件 2. 请求与保持条件 3. 不可剥夺条件 4. 循环等待条件
死锁问题如何解决⭐️
1)预防
可以通过设置某些限制条件,去破坏产生死锁的四个必要条件中的一个或者几个,来预防发生死锁。预防死锁是一种较易实现的方法,已被广泛使用。但是由于所施加的限制条件往往太严格,可能会导致系统资源利用率和系统吞吐量降低。
2)死锁避免
系统对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源;如果分配后系统可能发生死锁,则不予分配,否则予以分配。这是一种保证系统不进入死锁状态的动态策略。
3)死锁检测和解除
先检测:这种方法并不须事先采取任何限制性措施,也不必检查系统是否已经进入不安全区,此方法允许系统在运行过程中发生死锁。但可通过系统所设置的检测机构,及时地检测出死锁的发生,并精确地确定与死锁有关的进程和资源。检测方法包括定时检测、效率低时检测、进程等待时检测等。
java反射的使用⭐️(需要例子)
Java的反射机制是通过java.lang.reflect包中的类和接口来实现的,主要涉及到三个核心类:Class、Constructor和Method。通过这些类,可以在运行时动态获取和操作类的成员信息。
// 获取类的Class对象
Class<?> clazz = MyClass.class;
// 获取构造函数对象
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
// 创建实例对象
Object instance = constructor.newInstance("example", 123);
// 获取方法对象
Method method = clazz.getMethod("myMethod", String.class);
// 调用方法
method.invoke(instance, "parameter");
包装类的使用场景
泛型、Stream、装箱和拆箱
Stream流对原数组的影响
Stream的三个特性:不存储数据、不改变数据源、数据不可以重复使用
迭代器和增强for循环
在某些情况下,常规的遍历方式容易显得代码臃肿,增强for可以简化数组和集合的遍历,增强代码的可读性。但是操作难度比较大,所以一般使用Lambda表达式的情况居多。
ConcurrentHashMap的线程安全
简单理解就是,ConcurrentHashMap 是一个 Segment 数组,Segment 通过继承 ReentrantLock 来进 行加锁,所以每次需要加锁的操作锁住的是一个 segment,这样只要保证每个 Segment 是线程安全 的,也就实现了全局的线程安全。
synchronized的底层原理
synchronized的底层实现是完全依赖JVM虚拟机的,所以谈synchronized的底层实现,就不得不谈数据在JVM内存的存储:Java对象头,以及Monitor对象监视器。
ReentrantLock
重入锁,表示支持重新进入的锁,也就是说,如果当前线程 t1 通过调用 lock 方法获取了锁之后,再次调用 lock,是不会再阻塞去获取锁的,直接增加重试次数就行了。synchronized 和 ReentrantLock 都是可重入锁。
ConcurrentHashMap的加锁机制
在Java 1.7中,ConcurrentHashMap使用了分段锁(Segment Locking)的设计。它将整个Map划分为多个Segment(段),每个Segment继承自ReentrantLock,并且包含了一个散列桶数组。当进行写操作时,不是对整个Map加锁,而是仅仅对涉及操作的Segment加锁,这样就大大降低了锁的粒度,提高了并发性能。ConcurrentHashMap`在Java 1.8之后通过以下几个方面降低锁竞争并提高并发能力:
- 使用细粒度的CAS操作代替传统的锁。
- 在必要时(如修改链表头结点或扩容时)使用synchronized关键字对桶进行锁定。
- 利用红黑树去优化冲突较多时的查找和更新性能。
- 分布式锁的应用,即仅对涉及到的桶进行加锁,而不是整个数据结构。
sycronized和volatile的原理
-
volatile主要应用在多个线程对实例变量更改的场合,刷新主内存共享变量的值从而使得各个 线程可 以获得最新的值,线程读取变量的值需要从主存中读取;synchronized则是锁定当前变 量,只有当前线 程可以访问该变量,其他线程被阻塞住。另外,synchronized还会创建一个内 存屏障,内存屏障指令保 证了所有CPU操作结果都会直接刷到主存中(即释放锁前),从而保证 了操作的内存可见性,同时也使 得先获得这个锁的线程的所有操作
-
volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。 volatile不会造 成线程的阻塞;synchronized可能会造成线程的阻塞,比如多个线程争抢 synchronized锁对象时,会 出现阻塞。
-
volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的 修改可见 性和原子性,因为线程获得锁才能进入临界区,从而保证临界区中的所有语句全部得到 执行。
-
volatile标记的变量不会被编译器优化,可以禁止进行指令重排;synchronized标记的变量 可以被编 译器优化。
接口和抽象类的区别
- 接口的方法默认是 public,所有方法在接口中不能有实现(Java 8 开始 接口方法可以有默认实现),抽象类可以有非抽象的方法
- 接口中的实例变量默认是 final 类型的,而抽象类中则不一定
- 一个类可以实现多个接口,但最多只能实现一个抽象类
- 一个类实现接口的话要实现接口的所有方法,而抽象类不一定
- 接口不能用 new 实例化,但可以声明,但是必须引用一个实现该接口的对象 从设计层面来说,抽 象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
Files的常用方法
Files. exists():检测文件路径是否存在。
Files. createFile():创建文件。
Files. createDirectory():创建文件夹。
Files. delete():删除一个文件或目录。
Files. copy():复制文件。
Files. move():移动文件。
Files. size():查看文件个数。
Files. read():读取文件。
Files. write():写入文件。
== 和Equals的区别⭐️
hashcode和equals的区别.
equals() 和 hashcode() 这两个方法都是从 Object 类中继承过来的。hashCode():计算出对象实例的哈希码,并返回哈希码,又称为散列函数。equals():反映的是对象的内存地址或者对象的内容是否相等。
哪个集合接口可以实现List的并发安全⭐️
CopyOnWriteArrayList
CopyOnWriteArrayList 是线程安全的 ArrayList。CopyOnWrite 意思为写的时候会将共享变量新复制一份出来。复制的好处在于读操作是无锁的(也就是无阻塞)。
CopyOnWriteArrayList 仅适用于写操作非常少的场景,而且能够容忍读写的短暂不一致。如果读写比例均衡或者有大量写操作的话,使用 CopyOnWriteArrayList 的性能会非常糟糕。
CopyOnWriteArrayList 原理
CopyOnWriteArrayList 内部维护了一个数组,成员变量 array 就指向这个内部数组,所有的读操作都是基于 array 进行的。
栈在内存中的生长方向
栈的生长方向是由上往下的,即从高地址到低地址
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » Java基础知识
发表评论 取消回复