中科联芯面试-Java

1、i++和++i的区别

在Java中,i++ 和 ++i 都是用来对变量 i 进行自增操作的,但是它们在表达式中使用时的行为有所不同。

i++(后缀增量):返回变量的原始值(自增前的值),在表达式执行完毕后,变量的值会增加1。

++i(前缀增量):先将变量的值增加1,返回变量的新值(自增后的值)。

int i = 0;
// 使用 i++ 在复合赋值中的行为
int c = 10 + i++; // c 被赋值为 10 + 0 = 10, 然后 i 变为 1
// 使用 ++i 在复合赋值中的行为
int d = 10 + ++i; // i 先变为 2, 然后 d 被赋值为 10 + 2 = 12

2、简单介绍一下SpringIOC

·IOC(inversion of control)控制反转,在IOC之前对象的控制权在我们的代码中,我们自己new的对象,在Spring中,应用程序不再控制对象的创建,而是被动地接受由容器注入的对象。

Spring的IOC对象由IOC容器创建并管理,我们只需要在想要使用的时候从容器中获取就行了;@Resource 、@Autowired

*【拓展:Autowired和Resource的关系:

·Autowired在获取bean的时候,先是byType的方式,再是byName的方式;

·Resource在获取bean的时候,和Autowired恰好相反,先是byName方式,然后再是byType方式】

3、判断对象的判断是否相同

·在Java中,可以使用==运算符来比较两个对象的引用是否相同,也就是它们是否指向同一个对象实例。(比对内存地址);

·默认情况下,equals()方法比较的是对象的引用。但你可以根据需求重写这个方法,让它比较对象的实际内容。同时重写equals方法时,也必须重写hashCode方法,以确保两个相等的对象拥有相同的哈希码。

·使用java.util.Objects类的deepEquals()方法

如果想比较两个对象数组是否深度相等(即数组中的所有元素都相等),可以使用java.util.Objects类的deepEquals()方法。

4、Spring bean中如何实现懒加载

在Spring框架中,可以通过【使用XML配置】【使用注解配置】【全局懒加载】的方式实现懒加载。

使用XML配置

<bean id="myBean" class="com.example.MyBean" lazy-init="true"/>

使用注解配置

@Component
@Lazy
public class MyBean {
    // ...
}

全局懒加载

<beans default-lazy-init="true">
    <!-- 其他Bean定义 -->
</beans>

5、类的加载过程是怎么样的

Java中类的加载阶段分为加载(Loading)、链接(Linking)和初始化(Initialization)。其中连接过程又包含了验证、准备和解析。

·加载阶段的目的是将类的.class文件加载到JVM中。

·在链接阶段,Java类加载器对类进行验证、准备和解析操作。

·初始化是类加载的最后一步,也是真正执行类中定义的 Java 程序代码(字节码),初始化阶段是执行类构造器 <clinit> ()方法的过程。这里利用了一种懒加载的思想,所有Java虚拟机实现(如HotSpot等)必须在每个类或接口被Java程序首次主动使用时才初始化,但类加载不一定,静态代码块在类初始化时执行。

6、一个类中有静态代码块、静态方法、构造函数,他们的执行顺序是怎么样的,构造函数中是否可以使用静态代码块和静态方法

在Java中,类加载和初始化的过程遵循以下顺序:

静态代码块:当类被加载到JVM时,静态代码块(static initializer)会被执行,并且只执行一次。静态代码块通常用于初始化静态变量。

静态方法:静态方法(static method)可以在类加载之后的任何时间被调用,且不需要类的实例。

构造函数:当创建类的实例时,构造函数(constructor)会被调用。

以下是他们的执行顺序:

当类第一次被使用时(例如,创建类的实例或访问类的静态成员),JVM会加载这个类。

在类加载过程中,静态代码块会被执行(如果有的话)。

随后,如果创建了类的实例,构造函数会被执行。

构造函数不能直接调用静态代码块,因为静态代码块是类初始化的一部分,它不由构造函数控制。

构造函数可以调用静态方法,因为静态方法是类的成员,可以在类的任何地方被调用,包括构造函数。

7、java的byte基本数据类型范围

byte 8bit位 2^7 -> -128 ~ 127

拓展:

short 16位: -2^15 ~2^15-1

int 32位: -2^31 ~ 2^31 -1

long 64位 : -2^63 ~ 2^63 -1

float 32位,单精度 32 位 IEEE 754 浮点数。

double 64位,双精度 64 位 IEEE 754 浮点数。

char - 16位,表示 Unicode 字符,取值范围从 ‘\u0000’(即为 0)到 ‘\uffff’(即为 65,535)

boolean 表示逻辑值 true 和 false。

8、单例模式的线程安全写法

饿汉式(线程安全)在类加载时就立即初始化并创建单例对象。

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();


    private Singleton() {}


    public static Singleton getInstance() {
        return INSTANCE;
    }
}

懒汉式(线程安全)

在类加载时不初始化,在第一次使用时初始化,使用同步方法保证线程安全。

public class Singleton {
    private static Singleton instance;


    private Singleton() {}


    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

双重校验锁(线程安全)

结合了懒汉式和饿汉式的优点,既实现了延迟加载,又保证了线程安全(注意volatile)

public class Singleton {
    private volatile static Singleton singleton;


    private Singleton() {}


    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

静态内部类(线程安全)

利用静态内部类来实现延迟加载,并且保证了线程安全。

public class Singleton {
    private Singleton() {}


    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }


    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}



枚举(线程安全)

使用枚举来实现单例是最简单、最安全的方式。

public enum Singleton {
    INSTANCE;


    public void someMethod() {
        // 方法实现
    }
}

*9、JDBC的参数

JDBC操作数据库的流程:

加载JDBC驱动:

早期版本需要显式加载驱动类:Class.forName("com.mysql.jdbc.Driver");

从JDBC 4.0(Java 6)开始,驱动加载是自动的,无需显式加载。

建立连接:

使用DriverManager.getConnection()方法建立到数据库的连接。

需要提供数据库的URL、用户名和密码。

示例:Connection conn = DriverManager.getConnection(url, username, password);

创建Statement或PreparedStatement:

Statement用于执行不带参数的简单SQL语句。

PreparedStatement用于执行带参数的SQL语句,可以防止SQL注入攻击,并且可以高效地执行多次。

执行SQL语句:

使用executeQuery()方法执行查询语句,返回ResultSet对象。

使用executeUpdate()方法执行更新(INSERT、UPDATE、DELETE)语句,返回影响的行数。

对于PreparedStatement,需要先设置参数。

处理结果:

对于查询操作,通过ResultSet对象遍历查询结果。

对于更新操作,处理executeUpdate()方法返回的影响行数。

关闭资源:

依次关闭ResultSet、Statement/PreparedStatement和Connection对象。

通常在finally块中关闭资源以确保即使在发生异常时也能关闭。

执行SQL需要的参数:

数据库URL:用于指定数据库的位置,格式通常是jdbc:subprotocol:subname。

例如:jdbc:mysql://localhost:3306/mydatabase

用户名:用于登录数据库的用户名。

密码:用于登录数据库的密码。

SQL语句:要执行的SQL命令。

参数(仅对于PreparedStatement):

如果SQL语句包含参数(如?),则需要为每个参数提供值。

使用setXXX()方法(如setInt(), setString()等)设置参数值。

*10、数据库的优化策略

1. 设计优化

规范化:确保数据库设计遵循规范化规则,减少数据冗余。

反规范化:在某些情况下,为了提高性能,可以适当反规范化,例如存储预先计算好的数据。

索引:合理创建索引,以加速查询速度,但要避免过度索引。

数据分区:将大表分割成更小、更易于管理的部分。

数据分片:将数据分布到不同的数据库实例中,提高并发处理能力。

2. 查询优化

选择合适的索引:根据查询条件创建索引,避免全表扫描。

优化SQL语句:重写SQL查询,避免使用子查询、联合查询等复杂结构。

减少数据量:使用LIMIT语句限制返回的数据量。

使用存储过程:将常用的查询逻辑封装为存储过程,减少网络传输。

**避免使用SELECT ***:只查询需要的列,减少数据传输量。

3. 硬件优化

增加内存:提高数据库缓存,减少磁盘I/O。

使用SSD:使用固态硬盘替换机械硬盘,提高I/O性能。

网络优化:优化网络配置,减少数据传输延迟。

4. 配置优化

调整缓冲池大小:根据系统内存调整数据库缓冲池大小。

调整日志文件大小:适当调整事务日志大小,避免频繁写入。

配置合理的连接池:使用连接池来管理数据库连接,避免频繁建立和关闭连接。

5. 性能监控

使用监控工具:使用数据库自带的监控工具或第三方工具监控数据库性能。

分析慢查询日志:定期分析慢查询日志,找出性能瓶颈。

系统性能分析:使用操作系统工具监控CPU、内存、磁盘I/O等指标。

6. 数据库维护

定期更新统计信息:确保数据库优化器有准确的统计信息来生成执行计划。

定期重建索引:重建碎片化的索引,提高查询效率。

数据归档:定期将不活跃的数据归档,减少数据库大小。

7. 应用层优化

缓存:在应用层使用缓存减少数据库访问。

批处理:使用批处理减少数据库交互次数。

读写分离:在高并发场景下,使用读写分离减轻数据库压力。

11、介绍一下Spring的事务,有哪些类型

编程式事务管理

TransactionTemplate:通过使用TransactionTemplate,可以将事务管理代码与业务逻辑代码分离,通过调用TransactionTemplate的execute方法来执行业务逻辑。

PlatformTransactionManager:直接使用PlatformTransactionManager实现类进行编程式事务管理,需要手动编写事务开始、提交和回滚的代码。

声明式事务管理

声明式事务管理是通过AOP(面向切面编程)实现的,它允许开发者通过声明的方式管理事务,而不需要编写事务管理代码。

基于XML配置:在Spring的配置文件中使用<tx>命名空间定义事务规则。

基于注解:使用@Transactional注解来声明事务边界。

事务传播行为

Spring事务的传播行为定义了事务方法之间的调用关系,以下是Spring支持的七种事务传播行为:

REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入这个事务中。这是最常见的选择。

SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。

MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。

REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。

NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作。

事务隔离级别

Spring支持以下几种事务隔离级别,以避免脏读、不可重复读和幻读等问题:

DEFAULT:使用底层数据库的默认隔离级别。

READ_UNCOMMITTED:允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。

READ_COMMITTED:允许读取并发事务已经提交的数据,可以防止脏读,但幻读或不可重复读仍有可能发生。

REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以防止脏读和不可重复读,但幻读仍有可能发生。

SERIALIZABLE:确保事务可以从数据库中读取到的数据均符合事务开始时的状态,或者事务在操作过程中可以使用的数据库内容其他事务均不能访问,可以防止脏读、不可重复读以及幻读。

【@Transactional 是Spring框架中用于声明式事务管理的关键注解。它可以应用于类或方法上,以指定事务的属性。以下是 @Transactional 注解的一些常用参数:

value (或 transactionManager):

类型:String

描述:用于指定事务管理器的名称。在存在多个事务管理器的情况下,可以用来指定具体使用哪一个事务管理器。

propagation:

类型:Propagation

描述:定义事务的传播行为。默认值为 REQUIRED。

isolation:

类型:Isolation

描述:定义事务的隔离级别。默认值为 DEFAULT。

timeout:

类型:int

描述:定义事务的超时时间,单位为秒。默认值为 -1,表示不超时。

readOnly:

类型:boolean

描述:表示当前事务是否为只读事务。默认值为 false。对于只读操作,可以设置为 true,这样可以帮助数据库引擎优化事务。

rollbackFor:

类型:Class<? extends Throwable>[]

描述:定义导致事务回滚的异常类型。默认情况下,Spring 只会回滚运行时异常(RuntimeException)和错误(Error)。

rollbackForClassName:

类型:String[]

描述:与 rollbackFor 类似,但是使用异常类的名称来指定。

noRollbackFor:

类型:Class<? extends Throwable>[]

描述:定义不会导致事务回滚的异常类型。

noRollbackForClassName:

类型:String[]

描述:与 noRollbackFor 类似,但是使用异常类的名称来指定。】

12、项目架构

不怎么问项目的业务内容,基本上就是根据你简历写的项目和技术架构来问八股

有好多答的不对,后面面试官也没耐心了,感觉悬,应该没过。

(2024/9/13更新:已经被感谢了,在意料之中,哈哈)

公司主要是给电网做人力资源系统,还有给电网做低代码的外包开发,主要是驻场开发。

上面问的问题我都整理答案出来了,想面试的同志可以参考。

#Java面试##中科联芯#
各公司面试经验 文章被收录于专栏

面试经验(八股去si,再也不想背八股了)

全部评论
感谢楼主
点赞 回复 分享
发布于 09-13 23:36 湖北

相关推荐

5 21 评论
分享
牛客网
牛客企业服务