1.oj判题系统1-11 2.leetCode题4道 3.面试题十几道

day4 1.学习了用户中心项目优化,部署阶段 2.刷了三道回溯LeetCode题 3.看了二十道面试题

day3 1.学习了用户中心项目19-30 2.刷了3 道回溯算法的leetcode题 3.看 了12道经典面试题

day3 2024-3-10 1.学习了用户中心项目19-30 2.刷了3道leetCode题 3.看了12道经典面试题

day2 2024.3.10 1.学习了用户中心项目1-19 2.刷了leetCode 78 和 90题关于回溯的 3.经典面试题 (一)为什么重写 equals 还要重写 hashcode? 当你重写 equals() 方法时,通常也需要重写 hashCode() 方法,以确保两个相等的对象(即 equals() 返回 true)具有相同的哈希码(即 hashCode() 返回相同的值)。这是 Java 编程语言中的一个约定,也是 Object 类中 equals() 和 hashCode() 方法的通用契约。 这个契约的重要性主要体现在以下几个方面: 散列数据结构:当你使用散列数据结构(如 HashMap、HashSet 等)来存储对象时,对象的哈希码用于确定对象在散列表中的位置。如果两个相等的对象(通过 equals() 方法判断)具有不同的哈希码,那么这些数据结构可能无法正确地工作。例如,当你尝试从一个 HashSet 中检索一个对象时,HashSet 会使用对象的哈希码来快速定位对象在集合中的位置。如果对象的哈希码不正确,HashSet 可能无法找到该对象,导致 contains() 方法返回 false,即使 equals() 方法会返回 true。 集合框架的一致性:Java 集合框架(如 List、Set、Map 等)在内部依赖于 equals() 和 hashCode() 方法的正确实现。例如,List 接口中的 contains() 方法依赖于 equals() 方法来判断列表中是否包含某个元素。如果 equals() 方法被重写但没有重写 hashCode() 方法,那么这些集合方法可能无法正常工作。 性能:合理的 hashCode() 实现可以提高散列数据结构的性能。当两个相等的对象具有相同的哈希码时,散列数据结构可以更快地找到这些对象。如果哈希码分布均匀,那么散列数据结构在查找、插入和删除操作上的性能会更加优秀。 因此,当你在 Java 中重写 equals() 方法时,通常也应该重写 hashCode() 方法,以确保这两个方法之间的契约得到遵守。一种常见的做法是在 equals() 方法中使用的所有字段上计算哈希码,以确保相等的对象具有相同的哈希码。这可以通过调用每个字段的 hashCode() 方法并将结果组合起来实现。 (二) == 和 equals 比较的区别 在Java中,== 和 equals() 方法用于比较对象,但它们之间存在一些重要的区别: 比较的对象类型: == 操作符用于比较两个对象的引用是否相等,即它们是否指向内存中的同一个对象实例。 equals() 方法用于比较两个对象的内容是否相等,即它们的内容是否相同。 默认行为: == 操作符的默认行为是比较对象的引用地址。 equals() 方法的默认行为也是比较对象的引用地址,但这个方法可以被重写以提供自定义的比较逻辑。 用途: == 通常用于比较基本数据类型(如 int, float, char 等)和对象的引用。 equals() 主要用于比较对象的内容,特别是在重写了该方法的情况下。 自定义对象: 对于自定义对象,如果两个对象的内容相同但它们在内存中位于不同的位置(即不是同一个对象实例),那么使用 == 会返回 false,而使用 equals()(如果已重写)可能会返回 true,这取决于 equals() 方法的实现。 String类: String 类是一个特殊的例子,其中 equals() 方法已被重写以比较字符串的内容而不是引用。因此,对于字符串, equals() 和 == 可能会产生不同的结果。使用 equals() 来比较字符串的内容通常是更好的做法。 自动装箱: 对于基本数据类型的包装类(如 Integer, Double 等),== 比较的是两个对象是否完全相同(即引用相同),而 equals() 比较的是它们包装的基本值是否相等。 空值处理: 使用 == 比较一个对象和一个 null 引用会引发 NullPointerException。 使用 equals() 方法比较一个对象和 null 通常是安全的,因为大多数 equals() 方法的实现都会首先检查参数是否为 null。 总的来说,== 和 equals() 在Java中用于不同的目的,并且在使用时需要根据具体的情况选择使用哪一个。对于自定义对象,通常建议重写 equals() 方法以提供自定义的比较逻辑,并在需要比较对象内容时使用该方法。 (三)为啥有时会出现 4.0 - 3.6 = 0.40000001 这种现象? 在Java中,当您执行4.0 - 3.6这样的浮点数运算时,之所以有时会得到0.40000001这样的结果,主要是因为以下原因: 二进制浮点数表示的不精确性:计算机内部使用IEEE 754标准来表示浮点数。这种表示法对于某些十进制小数来说并不是完全精确的。例如,0.4在二进制中是一个无限循环小数,因此无法用有限的位数来精确表示。 舍入误差:在进行浮点数运算时,由于精度限制,可能会出现舍入误差。这些误差可能会累积,导致最终结果与预期有所不同。 运算顺序和精度:不同的编译器和平台可能会以稍微不同的方式处理浮点数运算,这也会影响结果的精确性。此外,Java的double类型有固定的精度(大约15-17位十进制数字),超出这个范围的精度可能会丢失。 打印输出的格式:当您打印浮点数时,默认的格式化输出可能会显示更多的小数位,这可能会让您误以为结果是不精确的。实际上,这些额外的位数可能只是由于打印输出时的格式化设置而显示的。 为了减少这种不精确性,您可以采取以下措施: 使用BigDecimal类:Java中的BigDecimal类提供了高精度的十进制数运算,适用于需要精确计算的情况,如金融计算。 控制打印输出的格式:使用String.format()或DecimalFormat类来控制打印输出时的浮点数格式,只显示您想要的小数位数。 避免不必要的浮点数运算:尽可能在需要精确计算的地方使用整数运算,或者将浮点数转换为整数进行计算。 总之,Java中出现4.0 - 3.6 = 0.40000001这种现象是由于浮点数在二进制中的不精确表示和计算过程中的舍入误差所导致的。在需要高精度的计算中,应该采取适当的措施来避免这种误差。 final 关键字的作用 在Java中,final 是一个关键字,它可以用来修饰类、方法、变量以及参数。final 的作用主要是用来表示一个实体(类、方法、变量等)是不可变的,即它的值或状态在初始化后就不能被改变。以下是 final 在Java中的具体作用: 修饰类:当一个类被声明为 final 时,这意味着这个类不能被继承。也就是说,没有其他类可以继承自这个 final 类。例如,String 类就是一个 final 类,因此你不能创建一个继承自 String 的新类。 java 复制 final class FinalClass { // ... } 修饰方法:如果一个方法被声明为 final,那么这个方法就不能被子类重写(Override)。这保证了子类不会改变父类中该方法的行为。 java 复制 class ParentClass { final void finalMethod() { // ... } } 修饰变量:final 变量也被称为常量。对于基本数据类型(如 int, double, char 等)的变量,final 意味着变量的值在初始化后不能被改变。对于引用类型的变量,final 意味着变量引用的对象地址不能改变,但是对象本身的内容(如果是可变对象)是可以改变的。 java 复制 final int constantInt = 10; // 基本数据类型常量 final String constantString = "Hello"; // 引用类型常量,引用不可变,但字符串内容可变 修饰参数:在方法参数上使用 final 可以确保在方法内部不会改变这个参数的值。这对于保证方法的纯洁性(不修改输入参数)是很有用的。 java 复制 public void myMethod(final String param) { // 不能改变param引用的对象 } 使用 final 关键字可以提高代码的可读性和可维护性,因为它明确地告诉读者这个实体是不可变的。此外,编译器也可以利用 final 的这个特性进行某些优化,例如,如果一个局部变量被声明为 final,并且它的值在初始化后没有被改变,那么编译器可能会将它当作常量来处理。 介绍 Java 的集合类 Java的集合类是Java编程语言中用于存储和操作对象集合的核心部分。这些集合类为数据提供了有组织的方式来存储和检索。下面我将介绍一些常用的Java集合类及其常用子类和常用方法: 1. List(列表) 常用子类: ArrayList:基于数组实现的列表,适合随机访问元素。 LinkedList:基于链表实现的列表,适合频繁插入和删除操作。 Vector:线程安全的列表,内部是数组数据结构,但性能较低。 常用方法: add(E e): 在列表末尾添加一个元素。 remove(E e): 移除列表中第一个出现的指定元素。 get(int index): 返回列表中指定位置的元素。 size(): 返回列表中的元素数量。 isEmpty(): 检查列表是否为空。 2. Set(集合) 常用子类: HashSet:基于哈希表实现的集合,元素无序且唯一。 TreeSet:基于红黑树实现的集合,元素有序且唯一。 LinkedHashSet:与HashSet类似,但元素顺序与添加顺序一致。 常用方法: add(E e): 添加一个元素到集合中。 remove(E e): 从集合中移除一个元素。 contains(E e): 检查集合中是否包含指定元素。 size(): 返回集合中的元素数量。 isEmpty(): 检查集合是否为空。 3. Map(映射) 常用子类: HashMap:基于哈希表实现的映射,键和值都可以为null。 TreeMap:基于红黑树实现的映射,键和值有序。 LinkedHashMap:保持插入顺序的HashMap。 常用方法: put(K key, V value): 添加一个键值对到映射中。 get(K key): 根据键获取对应的值。 remove(K key): 从映射中移除一个键值对。 containsKey(K key): 检查映射中是否包含指定键。 containsValue(V value): 检查映射中是否存在指定值。 size(): 返回映射中的键值对数量。 isEmpty(): 检查映射是否为空。 4. Queue(队列) 常用子类: LinkedList:可以作为队列使用,支持add、remove、element、peek等方法。 PriorityQueue:基于优先级堆的队列,元素根据自然排序或比较器排序。 常用方法: add(E e): 在队列末尾添加一个元素。 remove(): 移除队列头部的元素。 element(): 返回队列头部的元素,但不移除。 peek(): 同element(),返回队列头部的元素,但不移除。 5. Deque(双端队列) 常用子类: ArrayDeque:基于数组的双端队列,支持在队列两端添加和移除元素。 LinkedList:也可以作为双端队列使用。 常用方法: addFirst(E e): 在队列头部添加一个元素。 addLast(E e): 在队列尾部添加一个元素。 removeFirst(): 移除队列头部的元素。 removeLast(): 移除队列尾部的元素。 getFirst(): 返回队列头部的元素,但不移除。 getLast(): 返回队列尾部的元素,但不移除。 6.Stack(栈): Stack是一种后进先出(LIFO)的数据结构。 虽然Java没有专门的Stack类,但Deque接口的实现类(如ArrayDeque和LinkedList)可以用作栈。 这些集合类和它们的常用子类提供了丰富的数据结构和操作方式,使得Java开发者能够灵活地处理各种数据需求。在选择使用哪种集合类时,需要根据数据的特性、操作的频率以及性能要求来做出决策。 (四)ArrayList 和 LinkedList 的区别 Java中的ArrayList和LinkedList是两种常用的列表(List)实现,它们各有特点和适用场景。以下是它们之间的主要区别: 内部数据结构: ArrayList:内部基于动态数组实现,元素在内存中是连续的。 LinkedList:基于双向链表实现,元素在内存中不是连续的,每个元素存储了前一个和后一个元素的引用。 访问元素: ArrayList:由于元素在内存中连续,所以通过索引访问元素(get(int index))非常快,时间复杂度为O(1)。 LinkedList:链表结构导致通过索引访问元素需要遍历链表,时间复杂度为O(n)。但访问首尾元素(getFirst(), getLast())是很快的,因为可以直接通过引用到达。 插入和删除元素: ArrayList:在列表末尾添加或删除元素是快速的,时间复杂度为O(1)。但在列表中间插入或删除元素需要移动元素以保持连续性,时间复杂度为O(n)。 LinkedList:在列表的开头或结尾插入或删除元素是非常快的,时间复杂度为O(1)。在列表中间插入或删除元素需要遍历到指定位置,时间复杂度为O(n),但由于链表特性,这种操作通常比ArrayList在列表中间的操作要快。 内存使用: ArrayList:由于元素在内存中连续存储,所以内存使用更加紧凑,并且支持快速的随机访问。 LinkedList:由于元素存储了额外的引用信息,所以内存使用相对较多。 线程安全: ArrayList和LinkedList都不是线程安全的。如果需要在多线程环境下使用,需要外部同步或使用线程安全的集合类,如Collections.synchronizedList或CopyOnWriteArrayList。 失败快速性: ArrayList:在迭代过程中如果结构发生变化(除了通过迭代器自身的remove方法),将会抛出ConcurrentModificationException。 LinkedList:同样会在迭代过程中如果结构发生变化时抛出ConcurrentModificationException。 在选择ArrayList和LinkedList时,应考虑你的具体需求: 如果你需要频繁地访问元素,尤其是通过索引访问,那么ArrayList是更好的选择。 如果你需要在列表的开头和结尾频繁地插入和删除元素,或者需要频繁地在列表中间进行插入和删除操作,那么LinkedList可能更适合你。 总之,选择哪种列表实现取决于你的具体使用场景和需求。 继续加油[奋斗][奋斗][奋斗]

Day1 1.今天学习了TypeScript的类型:标注位置,复杂类型,函数类型,字面量与nullish类型,泛型。以及ts的意义; 2.学习了Vue3的基础:环境配置,main.ts,ref,reactive,属性绑定与事件绑定,表单绑定,计算属性,xhr的基本使用和xhr-promise改造,axios的获取发送数据以及baseURL和拦截器,条件与列表,监听器,Vueuse,useRequest,usePagination,子组件等; 3.阅读了Java核心技术卷Ⅰ的并发相关知识; [奋斗][奋斗][奋斗] Java 后端

下载 APP