江苏众安信科 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更加通用一些。

20.算法题-如何用两个栈实现一个队列

#软件开发笔面经#
全部评论
看到白条哥整理的面经,狠狠的赚一笔
点赞 回复 分享
发布于 10-03 19:27 江苏

相关推荐

3 7 评论
分享
牛客网
牛客企业服务