每日一题 - 202402
2-29
Mybatis 如何将查询结果封装为对象?
Mybatis 有两种映射形式,第一种是使用``标签,逐一定义数据库列名和对象属性名之间的映射关系。 第二种是使用sql列的别名功能,将列的别名书写为对象属性名。
有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
2-28
Dao 接口的工作原理是什么
Dao 接口即 Mapper 接口,接口的全限名,就是映射文件中的namespace的值;接口的方法名,就是映射文件中 Mapper 的 Statement 的 id 值; 接口方法内的参数,就是传递给 sql 的参数。
Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个 MapperStatement。 在 Mybatis 中每、、、标签,都会被解析为一个 MapperStatement 对象。
2-27
Mybatis 查询时当实体类中的属性名和表中的字段名不一样,怎么办?
- 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
- 通过 `` 来映射字段名和实体类属性名的一一对应的关系。
2-26
Mybatis 中 #{}
和 ${}
的区别是什么?
#{}
是预编译处理,可以防止 SQL 注入。${}
是字符串替换,不会进行预编译处理,可能会导致 SQL 注入。
<select id="selectBlog" resultType="Blog">
<!-- Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值; -->
select * from blog where id = #{id}
</select>
<select id="selectBlog" resultType="Blog">
<!-- Mybatis在处理${}时,就是把${}替换成变量的值。-->
select * from blog where id = ${id}
</select>
2-25
什么是 ORM?
ORM(Object-Relational Mapping)对象关系映射,是一种数据持久化技术。它在对象模型和关系型数据库直接建立起对应关系,并且提供一种机制, 通过JavaBean对象去操作数据库表的数据。 MyBatis通过简单的XML或者注解的方式进行配置和原始映射,将实体类和SQL语句之间建立映射关系, 是一种半自动(之所以说是半自动,因为我们要自己写SQL)的ORM实现。
2-24
什么是数据持久化?
数据持久化是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称。 例如,文件的存储、数据的读取等都是数据持久化操作。数据模型可以是任何数据结构或对象的模型、XML、二进制流等。 当我们编写应用程序操作数据库,对表数据进行增删改查的操作的时候就是数据持久化的操作。
2-23
怎么确保一个集合不能被修改?
可以使用 Collections.unmodifiableList()
方法来确保一个集合不能被修改。
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
List<String> unmodifiableList = Collections.unmodifiableList(list);
unmodifiableList.add("d"); // 运行时抛出 Java. lang. UnsupportedOperationException 异常。
2-22
Iterator 是什么?
Iterator 是 JAVA 集合框架中的迭代器接口,它是一个对象,它可以遍历并选择集合中的元素。迭代器取代了 JAVA 集合框架中的 Enumeration,迭代器允许调用者在迭代过程中移除元素。
2-21
什么是散列表?
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。
2-20
HashMap 是怎么解决 hash 冲突的?
HashMap 是基于哈希表实现的,哈希表是数组和链表的结合体,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的。 HashMap 的做法是用链表和红黑树存储相同 hash 值的 value。当 hash 冲突的个数比较少时,使用链表否则使用红黑树。
2-19
简述快速排序的过程。
- 选择一个基准元素(第一个或最后一个)。
- 通过一趟排序将待排序的记录分割成独立的两个部分,其中一部分记录的元素值均比基准元素值小,另一部分记录的元素值比基准值大。
- 此时基准元素在其排好序后的正确位置。
- 然后分别对这两部分记录使用相同方法进行排序,直到整个序列有序。
2-18
ArrayList 和 LinkedList 的区别是什么?
- ArrayList 是基于动态数组实现的,LinkedList 是基于双向链表实现的。
- ArrayList 支持随机访问,LinkedList 只能顺序访问。
- LinkedList 在插入和删除时效率较高,因为 ArrayList 增删操作可能要影响其他数据的下标。
2-17
HashMap 的实现原理?
HashMap 是基于哈希表实现的,哈希表是数组和链表的结合体,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的。HashMap 的做法是用链表和红黑树存储相同 hash 值的 value。当 hash 冲突的个数比较少时,使用链表否则使用红黑树。
2-16
HashSet 的实现原理?
HashSet 是基于 HashMap 实现的,HashSet 的元素存储在 HashMap 的 key 上,value 是一个固定的 Object 对象。
2-15
如何决定使用 HashMap 还是 TreeMap?
- 如果需要按自然顺序或者自定义顺序遍历键,那么使用 TreeMap。
- 如果需要快速查找键或者值,那么使用 HashMap。
2-14
HashMap 和 HashTable 的区别?
- HashMap 是非线程安全的,HashTable 是线程安全的。
- HashMap 允许
null
键和null
值,HashTable 不允许null
键和null
值。
2-13
HashMap 什么样的类适合作为键?
- 作为键的类必须重写
hashCode()
和equals()
方法。 - 作为键的类应该是不可变的,不可变的类是指创建后不可改变的类,如 String、Integer、Long 等。
- 作为键的类应该是唯一的,如果两个键的
hashCode()
相同,那么它们的equals()
方法也应该返回true
。
2-12
List 和 Map 的区别?
- List 是有序的单列数据集合,可以有重复的元素。
- Map 是无序的键值对集合,不允许重复的键,但是允许重复的值。
2-11
(力扣题库)计算数组最大连续 1 的个数。
输入: nums = [1,1,0,1,1,1]
输出: 3
输入: nums = [1,0,1,1,0,1]
输出: 2
开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3.
1 <= nums.length <= 105
nums[i] 不是 0 就是 1.
题解:
public int findMaxConsecutiveOnes(int[] nums) {
int max = 0, cur = 0;
for (int x : nums) {
cur = x == 0 ? 0 : cur + 1;
max = Math.max(max, cur);
}
return max;
}
2-10
什么是栈,什么是队列?
栈(Stack) 是一种先进后出(FILO)的数据结构,只允许在栈顶进行插入和删除操作。
队列(Queue) 是一种先进先出(FIFO)的数据结构,只允许在队列的两端进行插入和删除操作。
2-9
什么是快速失败和安全失败机制?
快速失败(Fail-Fast): 在用迭代器对集合对象进行遍历的时候,如果A线程正在对集合进行遍历,此时B线程或A线程对集合进行修改(增删改)操作, 都会导致A线程抛出 ConcurrentModificationException 异常。 这是因为迭代器在便利是直接访问集合中的内容, 并且使用一个 modCount 变量,集合在被遍历期间如果内容发生变化,modCount 也会发生变化,迭代器就会抛出异常。
安全失败(Fail-Safe): 安全失败机制的集合容器,在便利是不直接访问集合内容吗,而是先复制原有集合,并操作拷贝后的集合。
2-8
ArrayList 底层是什么?
ArrayList 采用 List 数组作为底层实现,是顺序容器,允许放入 null
元素。 ArrayList 具有自动增加底层数组容量的能力,当数组容量不足时,会自动增加容量。
2-7
JAVA 集合有哪些类?
- Set
- TreeSet 基于红黑树实现,支持有序性操作。
- HashSet 基于哈希表实现,支持快速查找。
- LinkedHashSet 具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。
- List
- ArrayList 基于动态数组实现,支持随机访问。
- Vector 和 ArrayList 类似,但是它是线程安全的。
- LinkedList 基于双向链表实现,只能顺序访问,但是可以快速插入和删除,也可以用作堆栈、队列。
- Queue
- PriorityQueue 基于堆结构实现,可以用它来实现优先队列。
- LinkedList 也可以实现双向队列。
2-6
所有的 final 修饰的字段都是编译期常量吗?
不是,final 修饰的字段,如果是基本数据类型或者是不可变对象,那么它是编译期常量,否则不是。
public class FinalTest {
public final int a = 6; // 编译期常量
public final int b = new Random().nextInt(100); // 运行期常量
public static final int c = 6; // 编译期常量
public static final int d = new Random().nextInt(100); // 运行期常量
public final String e = "hello"; // 运行期常量
public final String f = new String("hello"); // 运行期常量
}
2-5
什么是重复注解?
重复注解指允许在同一申明类型(类,属性,或方法)的多次使用同一个注解。
在 JAVA 之前,对于重复注解的解决方案如下,不是很友好:
public @interface Authority {
String role();
}
public @interface Authorities {
Authority[] value();
}
public class RepeatAnnotationUseOldVersion {
@Authorities({@Authority(role="Admin"),@Authority(role="Manager")})
public void doSomeThing(){
}
}
JAVA 8 之后:
@Repeatable(Authorities.class)
public @interface Authority {
String role();
}
public @interface Authorities {
Authority[] value();
}
public class RepeatAnnotationUseNewVersion {
@Authority(role="Admin")
@Authority(role="Manager")
public void doSomeThing(){ }
}
2-4
什么是类型注解?
注解类型被用来支持在 JAVA 程序中做强类型检查。配合插件式的 check framework
,可以在编译时检测出 runtime error,以提高代码质量。
创建类实例:new @Interned MyObject();
类型映射:myString = (@NonNull String) str;
implements 语句中:class UnmodifiableList<T> implements @Readonly List<@Readonly T> { … }
throw exception 声明:void monitorTemperature() throws @Critical TemperatureException { … }
类型注解只是语法而不是语义,并不会影响 java 的编译时间,加载时间,以及运行时间,也就是说,编译成 class 文件的时候并不包含类型注解。
2-3
Optional 要解决什么问题?
在调用一个方法得到了返回值却不能直接将返回值作为参数去调用别的方法,我们首先要判断这个返回值是否为 null, 只有在非空的前提下才能将其作为其他方法的参数。Java 8 引入了一个新的 Optional 类:这是一个可以为 null 的容器对象, 如果值存在则 isPresent()
方法会返回 true,调用 get()
方法会返回该对象。
Optional.of(new Outer())
.map(Outer::getNested)
.map(Nested::getInner)
.map(Inner::getFoo)
.ifPresent(System.out::println);
还有一种实现相同作用的方式就是通过利用一个 supplier 函数来解决嵌套路径的问题:
Outer obj = new Outer();
resolve(() -> obj.getNested().getInner().getFoo())
.ifPresent(System.out::println);
2-2
什么是 FunctionalInterface?
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface{}
FunctionalInterface 函数式接口,是 JAVA 8 中一类特殊类型接口的称呼,这种类只包含一个抽象方法(除了隐含的 Object 对象的公共方法)
- 只能有一个抽象方法。
- 可以有多个静态方法和默认方法。
- 默认包含 Object 类的方法。
2-1
类加载的生命周期?
了加载的过程包括了 加载、验证。准备。解析、初始化五个阶段, 除了解析之外,其余阶段的顺序是确定的,解析阶段可以在初始化之后进行。