江苏众安信科 Java 实习一面
江苏众安信科 Java 实习一面
1.集合的扩容机制
ArrayList 和Vector扩容机制总结: ArrayList 和Vector,底层都是Object数组,默认加载因子都是1(元素满了才扩展容量).默认容量都是10;但是ArrayList 在jdk1.8时默认为空,当添加元素时,才初始化为10个容量。ArrayList:新容量为原容量的1.5倍,Vector:新容量为原容量的2倍.
ArrayList 默认初始容量为10,(jdk8的时候底层Object[] elementData数组初始化为{},并没有创建长度为10的数组。在add元素时才创建了10个容量。) 线程不安全,查询速度快 底层数据结构是数组结构 扩容增量:原容量的 0.5倍,新容量为原容量的1.5倍。 如 ArrayList的容量为10,一次扩容后是容量为15
同样可以通过分析源码知道: Vector: 默认初始容量为10,(jdk7和jdk8一样都初始容量为10)。 线程安全,但速度慢 底层数据结构是数组结构 加载因子为1:即当 元素个数 超过 容量长度 时,进行扩容 扩容增量:原容量的 1倍,新容量为原容量的2倍。 如 Vector的容量为10,一次扩容后是容量为20
LinkedList没有扩容机制:
LinkedList:没有扩容机制,因为其底层是双向链表结构。不存在数组的扩容一说,没有初始化大小,也没有扩容的机制,就是一直在前面或者后面新增就好。
Set下的三个实现类集合HashSet和LinkedHashSet,TreeSet,扩容总结:LinkedHashSet,TreeSet没有数组的扩容机制
HashSet和HashMap扩容机制总结: HashSet和HashMap都是默认初始容量是16(jdk1.7的),但是jdk1.8做了优化,初始容量为0,第一次存元素的时候才扩容为16,加载因子是0.75,扩容为原来的2倍。而带LinkedHashSet和LinkedHashMap是链表不存在扩容的,HashSet:底层是数组+链表的结构。
Set(集) 元素无序的、不可重复。 HashSet:线程不安全,存取速度快 底层实现是一个HashMap(保存数据),HashSet:底层是数组+链表的结构,实现Set接口 默认初始容量为16(jdk1.8及以后)(为何是16,见下方对HashMap的描述) 加载因子为0.75:即当 元素个数 超过 容量长度的0.75倍 时,进行扩容 扩容增量:原容量的 1 倍,新容量为原容量的2倍。 如 HashSet的容量为16,一次扩容后是容量为32。 因为构造一个HashSet,其实相当于新建一个HashMap,然后取HashMap的Key。 扩容机制和HashMap一样。
Map是一个双列集合: HashMap:jdk1.8默认初始容量0,当第一次put元素的时候才扩容为16,jdk1.7是初始化容量为16 (为何是16:16是2^4,可以提高查询效率,另外,32=16<<1 –>至于详细的原因可另行分析,或分析源代码) 加载因子为0.75:即当 元素个数 超过 容量长度的0.75倍 时,进行扩容 扩容增量:原容量的 1 倍,新容量为原容量的2倍。 如 HashSet的容量为16,一次扩容后是容量为32 Hashtable默认初始容量11。 二、扩容加载因子(0.75),当超出默认长度(int)(11*0.75)=8时,扩容为oldx2+1。新容量为原容量的2倍+1. int newCapacity = (oldCapacity << 1) + 1;
2.java的基本类型
3.包装类和基本类型的区别
1.int是基本数据类型,Integer是int的封装类,是引用类型。int默认值是0,而Integer默认值 是null,所以Integer能区分出0和null的情况。一旦java看到null,就知道这个引用还没有指向某个 对象,再任何引用使用前,必须为其指定一个对象,否则会报错。
2.基本数据类型在声明时系统会自动给它分配空间,而引用类型声明时只是分配了引用空间, 必须通过实例化开辟数据空间之后才可以赋值。数组对象也是一个引用对象,将一个数组赋值给另 一个数组时只是复制了一个引用,所以通过某一个数组所做的修改在另一个数组中也看的见。
4.swap函数能不能交换 int 类型的数据
public class Swap
{
public static void main(String[] args)
{
int c = 3;
int d = 5;
swap(c, d);
System.out.println("c: " + c + " d: " + d);
}
public static void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
}
运行结果: java Swap c: 3 d: 5
为什么调用swap()方法后并没有交换c、d的值呢,因为java只有值传递(没有引用传递),所以其实调用swap()时是把值赋给a、b,赋完后与c、d就没什么关系,c、d还是原来的值。其实就是值传递。不理解的话回去看看值传递。
解决方案:
1.通过数组对象交换
public class TestSwap {
public static void main(String[] args){
int a = 3;
int b = 5;
System.out.println("交换前:"+"a="+a+" b="+b);
//以数组接收后赋值,注意赋值顺序,注意对应关系
int[] arr = swap(a,b);
a = arr[0];
b = arr[1];
System.out.println("交换后:"+"a="+a+" b="+b);
}
//交换
private static int[] swap(int x, int y){
//以数组形式返回
return new int[]{y,x};
}
}
2.通过反射与非类成员包装对象
public classTest{
public static void main(String[] args) throws Exception{
Integer a = 1;
Integer b = 2;
System.out.println("before : a=="+a+";b=="+b);
swap(a,b);
System.out.println("after : a=="+a+";b=="+b);
}
public static void swap(Integer num1,Integer num2) throws IllegalAccessException,NoSuchFieldException{
Field field = num1.getClass().getDeclaredField("value");
field.setAccessible(true);
int temp = num1;
field.set(num1,num2);
field.set(num2,new Integer(temp));
}
}
5.mysql数据库的基本类型
MySQL的数据类型包括整型类型,浮点数类型,定点数类型,位(BIT)类型等。
6.TIMESTAMP时间戳有了解过吗
-
定义: TIMESTAMP用来存储日期和时间的组合,精确到秒或者毫秒,具体取决于数据库系统的实现。它可以自动记录数据行的创建或最后一次修改的时间。
-
MySQL中的TIMESTAMP:
在MySQL中,TIMESTAMP类型的列可以自动管理时间。例如,可以设置默认值为CURRENT_TIMESTAMP,这样在插入新记录时会自动填充当前时间。
可以使用ON UPDATE CURRENT_TIMESTAMP使得每次更新记录时自动更新该TIMESTAMP列,反映最新的修改时间。
MySQL的TIMESTAMP支持从'1970-01-01 00:00:01' UTC到'2038-01-19 03:14:07' UTC的时间范围,这被称为"2038问题"或"Y2K38"问题。
-
数据库中的行为:
不同于某些误解,数据库中的TIMESTAMP列并不是所有表共享的计数器,而是每行独立的,并且不一定是递增的数字。递增的行为可能是因为某些特定的设置,如上述MySQL中的自动更新配置。
-
应用场景:
记录数据的创建时间和最后修改时间,常用于审计追踪、版本控制、数据分析等场景。
在多用户系统中,帮助解决并发冲突,通过比较时间戳判断哪个操作更“新”。
-
区块链中的时间戳:
在区块链技术中,时间戳用于证明某个事件或交易发生的具体时间,通过加密签名确保时间信息不可篡改。每个区块包含前一块的哈希值和自己的时间戳,形成不可逆的时间链,增强数据的可信度和安全性。
总的来说,TIMESTAMP时间戳是一种强大的工具,广泛应用于记录和验证时间相关的数据,无论是在传统数据库管理系统还是新兴的分布式账本技术中。
7.DATE和TIMESTAMP如何取舍,或者说是在项目中有没有出现时区相关的问题
在项目开发中选择DATE和TIMESTAMP主要取决于项目的具体需求,特别是对时间精度和时区处理的需求。以下是两者之间的一些关键差异和取舍考虑: DATE vs TIMESTAMP 精度与范围: DATE: 只存储日期信息(年、月、日),不包含时间部分,精度为天。 TIMESTAMP: 存储日期和时间信息(年、月、日、时、分、秒,甚至毫秒,依据数据库系统),精度更高。 时区处理: DATE: 不涉及时区问题,因为只存储日期,通常假设基于无时区的日期。 TIMESTAMP: 在MySQL中,默认情况下TIMESTAMP会根据系统时区进行存储和检索,可以自动调整为本地时区显示,这在处理跨越时区的应用时非常有用。 其他数据库系统(如PostgreSQL)可能有不同的处理方式,但TIMESTAMP通常提供了更好的时区支持。 时区问题解决策略:
-
统一时区存储:
在存储数据时,可以选择将所有时间统一转换为UTC(协调世界时)存储,这样可以避免因用户所在时区不同而产生的混乱。
-
明确时区信息:
数据库设计时,可以额外存储时区信息,以便在检索时根据用户所在的时区进行转换。
-
使用数据库特性:
利用数据库提供的时区功能,比如MySQL的CONVERT_TZ()函数,可以在查询时动态转换时区。
-
应用层处理:
在应用程序层面处理时区转换,即在获取或展示数据时,根据用户的时区偏好进行转换。
-
配置服务器时区:
确保数据库服务器和应用服务器的时区配置正确,与项目需求一致。
-
国际化设置:
对于Web应用,使用国际化(i18n)框架处理时间显示,这些框架通常内置了对时区的支持。
综上所述,选择DATE还是TIMESTAMP,以及如何处理时区问题,应基于项目的具体需求、用户分布、以及是否需要跨时区操作等因素综合考虑。在处理时区问题时,推荐采用统一存储时区(如UTC)和在应用层或查询时进行转换的方法,以保持数据的一致性和易维护性。
8.情景题-有一个person类,其中有姓名、年龄、地址三个字段,现在有100个数据,如何快速查到“30岁的张三”,不是数据库的操作
用ArrayList查询
import java.util.ArrayList;
import java.util.List;
class Person {
String name;
int age;
String address;
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
// Getter methods (omitted for brevity)
}
public class Main {
public static void main(String[] args) {
// 初始化100个Person对象的列表,这里仅示例化两个作为演示
List<Person> persons = new ArrayList<>();
persons.add(new Person("张三", 30, "地址1"));
persons.add(new Person("李四", 25, "地址2"));
// ... 其他98个Person对象
// 查找年龄为30岁的张三
Person targetPerson = null;
for (Person person : persons) {
if ("张三".equals(person.getName()) && person.getAge() == 30) {
targetPerson = person;
break;
}
}
if (targetPerson != null) {
System.out.printf("找到了:姓名=%s, 年龄=%d, 地址=%s%n",
targetPerson.getName(), targetPerson.getAge(), targetPerson.getAddress());
} else {
System.out.println("没有找到30岁的张三");
}
}
}
9.Spring IOC和AOP
10.@Controller和@RestController的区别
11.使用过哪些注解呢
12.项目中,你在什么情况中使用@Transactional呢
13.假如A有个事务,B有个事务,A里调用B,如果B发生异常,A、B回不回滚呢
在Spring中,默认的事务传播级别是PROPAGATION_REQUIRED。如果方法A和方法B都在同一个事务管理器下,并且都配置了默认的事务传播行为,那么当方法A调用方法B时,会遵循以下规则: 方法A开始一个事务(如果还没有事务的话)。 方法B被调用,由于它的传播级别也是PROPAGATION_REQUIRED,它会加入到方法A的同一事务中。 因此,如果在方法B中发生了异常,这个异常会被传播到调用者,即方法A。由于它们都在同一个事务中,B中的异常会导致整个事务失败,进而导致A和B中的所有数据库操作都会回滚。这是Spring事务管理的自动回滚行为,只要事务配置正确并且抛出的异常是未检查异常(继承自RuntimeException的异常)或者是显式声明需要回滚的检查异常,事务就会回滚。 总结来说,在这种情况下,如果B发生异常,A和B都将回滚。
14.mysql事务隔离级别
READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可 能会导致脏读、幻读或不可重复读。
READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是 幻读或不可重复读仍有可能发生。
REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身 事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐 个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读 以及幻读
15.A查询到一个数据10,B提交把数据变为11,那么A查询到的是10还是11呢
默认REPEATABLE-READ(可重复读)事务隔离级别,所以,A还是10
16.有了解过线程吗
17.讲一下你项目的亮点
18.你在项目中是如何使用dubbo的呢
19.nacos里的xxx也能远程调用,为什么要用dubbo呢
两者侧重点不一样。
Nacos 主要功能集中在 动态服务发现、服务配置、服务元数据及流量管理。你可以把他简单的理解为是一个注册中心和配置中心。
Dubbo 是一款高性能、轻量级的开源 Java 服务框架。 主要功能点在于 RPC 框架。
你疑惑的点是在于 两者都有 服务自动注册和发现,流量管理的功能。
Dubbo的确有这些功能,但是只限于在自身RPC框架上使用。
Nacos更加通用一些。