每日面经03

1.String一些方法?

答:length()方法是获取字符串长度,charAt(int index)是返回指定索引的字符,equals(Object anther)比较两个字符串的内容是否完全相同,compareTo(String s)按照字典顺序比较两个字符串,相等是0,小于为负数,否者是正数。contains(CharSequence s)检查字符串中是否包含某个字符,replace(CharSequence s,CharSequence sb)用新的字符替换旧的字符,substring(int begin,int end)截取字符,获取新的字符。

2.抽象类和接口有什么区别?

答:抽象类主要是规定了所继承的它的子类必须要实现具体的方法,但是不涉及该方法的具体实现。而接口通常是涉及了到了方法的具体实现。一个类可以实现多个接口,但是只能继承一个抽象类,抽象类可以包含各种类型的成员变量,但是接口只能包含常量,不能有变量,在抽象类中可以有多种访问修饰符,比如说private、protected或public,而接口中的方法和变量默认都是public。直到jdk8引入了private方法,但是场景有限。

3.Java容器有哪些?

答:Java容器主要是指Java集合框架中的类和接口,它们主要用于存储对象的集合。主要是分成四个部分,列表(List),集合(Set),队列(Queue),映射(Map)。每个部分都有他们的具体实现。首先是列表List:特点是有序(存取顺序),有索引,可以包含重复元素。主要的实现类是ArrayList:基于动态数组的实现,因为有索引所以可以快速的进行随机访问和高效的遍历。LinkedList是基于双向链表实现的,因为每个元素节点包含三部分,数据部分和两个指针,所以在执行新增或者是删除的时候只需要修改元素的前后两个指针即可时间复杂度是O(1)。Vector(迭代器):和ArrayList相似,但是他是同步的,用于多线程环境,其内部通过在关键的方法上使用synchronized关键字来实现线程安全。然后,是集合Set:其特点是无序的,元素不可重复的,无索引,其实现类有HashSet:基于哈希表实现的,提供高效的遍历,但是不保证存取元素的顺序,LinkedHashSet基于哈希表和链表的实现,维护了元素的插入顺序。底层的数据结构依然是哈希表,只是每个元素又额外的多了一个链表的机制记录存储的顺序。最后的话是TreeSet:基于红黑树实现,元素按照自然排序或者自定义比较器去排序。自然排序的话基本数据类型是从小到大的顺序,字符串是按照字符在ASCLL码表中的数字升序进行排序,自定义规则的话是实现重写compareTo接口进行自定义。

然后就是队列(Queue),按照指定顺序处理元素的集合,主要的实现类包括LinkedList、PriorityQueue等,LinkedList:基于优先级堆实现,元素按照自然顺序或者自定义的比较器进行排序。最后是映射(Map)存储键值对的对象,主要实现类包括HashMap、LinkedHashMap,TreeMap和Hashtable。HashMap:基于哈希表的Map接口实现,不保证顺序。LinkedHashMap:基于哈希表和链表实现,保持了键值对的插入顺序,TreeMap:基于红黑数实现,按照键的自然排序或自定义排序。HashTable和HashMao类似但是他是同步的。

4.创建线程的方式?

在Java中一共有四种常见的创建线程的方式,第一种是继承Thread类,需要创建一个继承Thread类的子类,并且在子类中重写run()方法定义线程执行的操作,然后创建该子类的实例并且调用其start()方法来启动线程。

class MyThread extends Thread {
    public void run() {
        System.out.println("Thread running by extending Thread class.");
    }
}

// 使用示例
public class ThreadExample {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
    }
}

第二种是实现runnable接口的run方法,然后将Runnanle实例传递给Thread类的构造器,并且通过Thread对象的start()方法启动线程。

class MyRunnable implements Runnable {
    public void run() {
        // 线程执行的代码
    }
}

Thread t = new Thread(new MyRunnable());
t.start();

第三种就是使用Callable和FutrueTask,对于需要返回结果的情况,可以使用Callable接口,与Runable相似,但是它可以返回一个结果或抛出异常,Callable任务可以提交给ExecutorService执行,并且返回一个Futrue对象,通过FutrueTack包装Callable对象,也可以创建一个线程执行FutureTask,并且通过它来获取执行的结果。

class MyCallable implements Callable<Integer> {
    public Integer call() throws Exception {
        // 线程执行的代码,返回结果
        return 123;
    }
}

FutureTask<Integer> task = new FutureTask<>(new MyCallable());
Thread t = new Thread(task);
t.start();
// 获取执行结果
Integer result = task.get();

然后最后的一种就是创建线程池,推荐是使用ExecutorService来创建和管理线程池,通过调用Executors类的静态方法可以创建不同类型的线程池,然后通过submit()提交Runnable或者是Callable任务。

ExecutorService executor = Executors.newFixedThreadPool(4);
executor.submit(new MyRunnable());
Future<Integer> future = executor.submit(new MyCallable());
executor.shutdown();

如果任务简单且不需要返回值,可以选择Runnable接口;如果需要返回执行结果,可以使用Callable接口;如果需要管理大量线程,推荐使用ExecutorService

5.把外部的引用传递到匿名内部类中,在内部类里面修改这个引用,会不会对原引用造成影响,修改引用的值呢?

如果是修改引用指向的对象的状态(即,修改对象的字段或属性),那么这种修改确实会影响到原始对象,因为匿名内部类和外部代码实际上是指向同一个对象实例。例如,如果你传递了一个列表对象到匿名内部类中,并在内部类里向这个列表添加了一个元素,那么外部的列表也会显示这个新添加的元素。

但是,如果尝试改变引用本身,即让它指向另一个对象,这种改变仅在匿名内部类内部有效,并不会影响到传递进来的原始引用。这是因为Java是按值传递参数的(对于对象引用,传递的是引用的副本)。因此,尽管你在内部类中改变了引用副本的指向,但这不会改变外部原始引用的指向。

final List<String> list = new ArrayList<>();
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        list.add("some string"); // 这会改变原始list对象的状态,外部的list也会受到影响。
        // list = new ArrayList<>(); // 假如这样写,仅是尝试改变引用,实际不会影响到外部的list引用。
    }
});

6.ssm和boot的常见注解?

对于Spring:

第一类是:声明bean,有@Component、@Service、@Repository、@Controller
第二类是:依赖注入相关的,有@Autowired、@Qualifier、@Resourse
第三类是:设置作用域 @Scope
第四类是:spring配置相关的,比如@Configuration,@ComponentScan 和@Bean
第五类是:跟aop相关做增强的注解 @Aspect,@Before,@After,@Around,@Pointcut

对于SpringMVC:

@RequestMapping,
@RequestBody(将json转java)
@RequestParam:指定请求参数的名称;
@PathViriable
@ResponseBody(java转成json)
@RequestHeader:获取指定的请求头数据,还有像@PostMapping、@GetMapping这些。

对于SpringBoot:

Spring Boot的核心注解是@SpringBootApplication , 他由几个注解组成 @SpringBootConfiguration: 组合了- @Configuration注解,实现配置文件的功能;@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项@ComponentScan:Spring组件扫描

7.sleep()和wait()的区别?

1.所属的类别:s是Thread类的静态方法,w是Object类的方法,因此所有的java对象都继承w方法

2.锁的处理:当线程执行时,s不会释放锁对象,w就会,允许其他线程对该对象执行同步代码块方法。

3.唤醒条件:s在指定的时间后,线程会自动醒来,继续执行。w需要等待其他线程调用同一个对象上的notify()或notifyAll()方法才会被唤醒。

8.mybatis #{}和${}的区别?

#表示预处理语句的参数占位符,Mybatis会先编译SQL语句,然后再设置参数值替换占位符。这种方式可以有效的防止SQL注入的攻击。这个通常用于表的字段值的动态替换。以?作为占位符根据数据类型进行适当的转换。

$表示直接替换,直接把里面的内容替换成变量值,直接发送到数据库执行,没有进行预处理和类型转换,可能会引起SQL注入的风险。这个通常用于表名列名这些静态的替换。

// 使用#{}
SELECT * FROM users WHERE id = #{id};

// 使用${}
SELECT * FROM ${tableName} WHERE id = #{id};

9.启动一个线程是run()还是start()?

启动一个新的线程应该通过调用线程对象的start()方法,而不是直接调用run()方法,run方法只是一个普通大方法,可以实现当前线程所需要执行的代码逻辑。

10.介绍Spring IOC和Spring Aop?

IOC:传统的对象创建方式中,对象的依赖关系通常由对象本身在内部创建和管理,而使用了IOC后,这些依赖关系的创建和绑定转移到了容器的外部,由容器进行控制和管理,这种方式也称为依赖注入,好处就是通过减少对象之间的耦合,使得代码易于测试维护和扩展。

AOP:是一种编程范式,用于将应用程序的公共行为(切面)与核心业务逻辑分开,通过切点将这些行为动态的应用到逻辑代码上(连接点),可以实现在方法调用前后执行特点的代码,而无需修改原有方法的实现。提高了代码的重用性,让逻辑业务维护起来更加的简单。

使用的步骤:

//依赖的注入
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.3.8</version> <!-- 请使用适合你项目的版本 -->
</dependency>

//定义切面-通知-切点
@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.yourpackage..*.*(..))") // 指定切点表达式
    public void logBeforeMethod(JoinPoint joinPoint) {
        System.out.println("Before executing method: " + joinPoint.getSignature().getName());
    }
    
    @After("execution(* com.yourpackage..*.*(..))") // 指定切点表达式
    public void logAfterMethod(JoinPoint joinPoint) {
        System.out.println("After executing method: " + joinPoint.getSignature().getName());
    }
}

//配置生效
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("com.yourpackage") // 替换为你的包路径
@EnableAspectJAutoProxy
public class AppConfig {
}

11.Spring框架使用到的设计模式?

12.MySQL的四个隔离级别以及默认隔离级别?

MySQL的四个隔离级别分别是未提交读,读已提交,不可重复度和串行化,默认的隔离级别是可重复度。未提交读什么问题也解决不了,读已提交解决了脏读,不可重复度解决了脏读和可重复读,串行化解决了所有的问题。但是性能较差.

脏读:当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
可重复读:比如在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
第三是幻读(Phantom read):幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

13.A事务未提交,B事务上查询到的是旧值还是新值?

查询到的是旧值,在默认情况下,如果事务A未提交,那么事务B查询到的是旧值,因为数据库系统保证了未提交事务的修改对其他事务不可见,以此来保证数据的一致性和隔离性。

14.编写sql语句哪些情况导致索引失效?

不遵循最左前缀法则,以%开头的like模糊查询,使用索引时进行运算操作或者是类型转换(如字符串没加单引号),使用复合索引时中间使用了范围查询如<,>。

15.sql语句隐式类型转换?

隐式类型转换也称作自动类型转换,SQL在查询执行过程中使用了不同类型的护具进行比较或者计算时会自动转换类型。查询性能会下降,因为需要额外处理进行了类型转换。转换时可能会发生精度丢失的问题,可能会导致索引失效。尽量使用显式类型转换,比如调用转换函数。


** 如果一个整数类型的列与一个字符串类型的常量进行比较,数据库可能会自动将字符串转换为整数类型,以便进行比较。
SELECT * FROM table WHERE int_column = '123';

16.Redisson的底层原理?以及与SETNX的区别?

17.了解的MVCC模式?

MVCC称为多版本并发控制,指维护一个数据的多个版本,使得读写操作没有冲突,具体实现主要依赖于数据库记录中的三个隐藏字段,undo log日志,以及readView(读视图)。主要保证事务的隔离性。

三个隐藏字段:

undo log日志(主要是保证事务的原子性):回滚日志,在insert,update和delete的时候产生的便于数据回滚的日志,当使用insert的时候,只在回滚的时候需要,在事务提交之后可以被立即删除。而update和delete的时候产生的undo log日志不仅在回滚的时候需要,在快照读的时候也需要,不会被立即删除。当不同的事物或者是相同的事务对同一条记录进行修改的时候,会导致该记录的undolog日志生成一条记录版本链表,链表的头部记录的时候旧记录,尾部记录的是最早的记录。

然后就是读视图了readView,是快照读(不加锁的查询数据)SQL执行的时候MVCC提取数据的依据。在不同的隔离级别下,按照版本链表所提取的信息进行规则比较,从而获取到我们所需要读取到的数据。

18.Redis的持久化方式?两者有什么区别?Redis宕机哪个恢复比较快?

主要是有两种方式RDB(redis数据备份文件)和AOF,RDB是一个快照文件,它是把redis中存储的数据写到磁盘上,当redis实例宕机时会从RDB快照文件中读取数据并使其恢复。AOF是追加文件,每当执行redis的写命令(数据库的写操作)时会把命令存储在AOF文件中,当redis实例宕机的时候会从这个文件中再执行一遍命令来恢复数据。这两种方式RDB恢复数据比较快。因为它是二进制文件,保存的时候体积也比较小所以恢复很快,但是他可能会丢失数据。所以我们通常使用AOP来恢复,它丢失数据的风险要小很多,在AOF中可以设置刷盘策略,当时设置的是每秒批量插入一次命令。

19.Redis有用过么?数据类型知道么

是的,我之前的项目中有用到过Redis,主要作用缓存系统,以提高响应速度和处理的效率,它是一个开源的基于内存的键值数据库,支持多种类型的数据结构,它的主要特点包括高性能,支持持久化,原子操作等非常适合需要快速访问大量数据的场景,Redis支持的数据类型主要是有五种。首先是字符串(String)类型,一个键对应一个字符串值,常用于缓存、计数等。然后是Hash类型键值对集合,适用于存储对象和实现更加复杂的数据结构。然后是列表存储简单的字符串列表,按照插入顺序排序,可以在列表的头部或尾部添加元素,常用于消息队列,最新消息列表等等。然后是集合Sets,这是不允许重复无序的集合,可以实现并集,交集、差集等操作,适用于标签,好友关系等功能,最后是Sorted Set:不预序重复的元素集合,每个元素关联一个浮点数分数,可以按照分数进行排序,适用于排行榜,带权重的队列等场景。我的项目中用到的是String类型的bitMap位图去记录用户的每日签到情况,使用ZSet结构存储累计积分记录实现实时积分排行榜功能。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值