java知识点&面试题总结(持续更新)

最近找工作不写一遍老感觉记不住,基本纯手写,如遇到错误麻烦大家指正!

一、JavaSE

1.抽象类和接口的区别

1)语法层面
1.接口关键字为interface;抽象类关键字为abstract。
2.接口子类用implements来实现,支持可以多实现;抽象类本质也是一个类,子类用extends来继承,为单继承。
3.抽象类中可以有构造函数和main方法(构造方法用于子类的实现),接口中没有
4.抽象类的成员变量可以是变量也可以是常量,成员方法可以是抽象方法也可以非抽象方法;接口中成员变量只能是常量(默认修饰符:public static final),成员方法在jdk1.8中添加了default和static的具体方法。
2)设计层面的区别(选择的依据)
1.抽象类重点描述的是抽象的概念,比如具体生活中的概念:动物,植物,食物等
2.接口重点描述的是特征,比如 飞 这个方法,麻雀可以飞,蜻蜓可以飞。

2.面向对象的三大特征

1)封装
是指将类的细节部分包装、隐藏起来的方法。封装可以认为是一个保护屏障,防止该类的代码数据被外部定义的代码随机访问。对外界而言,它的内部细节是隐藏的,暴露给外界的只是它的访问方法。封装的优点:能够减少耦合、类内部的结构可以自由修改、隐藏信息实现细节。通俗来讲,封装就是该让你访问到的会访问到,不该访问的就隐藏起来。
2)继承
继承是从已有的类中派生出新的类,新的类能吸收已有类的属性和行为,并扩展自己新的能力,就形成了父子类关系。也提高了代码的复用性。举例来说,兔子和羊是食草动物,狮子和豹子是食肉动物,而食草动物和食肉动物又都是动物类。虽然食草动物和食肉动物都属于动物类,但两者属性和行为上又有差别,所以子类具有父类的一般特性,也会有自身的特性。
3)多态
顾名思义,多态就是同一行为具有多个不同表现形式,比如说打印机,有彩色打印机,打印彩色,黑白打印机打印黑白。多态存在的三个必要条件,继承,重写,父类引用指向子类对象。同时多态特征优点也很多,可替换性、灵活性、简化性。

3.重载和重写的区别

1)重载:发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同, 方法返回值和访问修饰符可以不同,发生在编译时期。
2)重写:发生在父子类中,方法名,参数列表必须相同,返回值范围小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类;如果父类父类方法的修饰符为private,则子类不能重写该方法。

4.java的基本数据类型有哪些

四类八中

数据类型字节数位数
整形byte18
short216
int432
long864
浮点型float432
double864
布尔型boolean18
字符型char216

5.==和equals的区别

1)== 的作用:基本类型比较值是否相同、引用类型比较的是地址值是否相同
equals的作用:默认情况下比较的是地址值,但是重写了equals方法就比较的内容。
2)一般equals比较时,常量要写前面避免空指针异常。

 
        String a = "gao";
        if ("gao".equals(a)){
            System.out.println("正常输出");
        }
        // 此时会报NullPointerException
        String b = null;
        if (b.equals(a)){
            System.out.println("空指针异常");
        }

6.java会存在内存泄漏吗


1)虽然java有垃圾回收机制,但是也还是会存在内存泄漏的问题
2)java内存泄漏指的是:对象不在被程序所使用,垃圾回收器没有将其收回,对象仍然处于被引用的状态,久而久之,不能回收的内存越来越多,最终就导致了内存溢出。
3)内存泄漏的原因:
*单例模式静态持有的引用
*各种连接(数据库连接,网络连接,IO连接等),各种流未关闭
*静态集合类引起的,如HashMap,LinkdList等,生命周期与程序一致,容器中的对象在程序结束之前不能被释放
*内部类持有外部类,非静态内比类会持有外部类,如果有地方引用了这个非静态内部类,会导致外部类也被引用,垃圾回收时无法回收这个外部类。

4)解决方法
*尽量减少使用静态变量,或者使用完及时 赋值为 null。
*明确内存对象的有效作用域,尽量缩小对象的作用域,能用局部变量处理的不用成员变量,因为局部变量弹栈会自动回收;
*减少长生命周期的对象持有短生命周期的引用;
*对于不需要使用的对象手动设置null值,不管GC何时会开始清理,我们都应及时的将无用的对象标记为可被清理的对象;
*各种连接(数据库连接,网络连接,IO连接)操作,务必显示调用close关闭。

7.String、StringBuffer、StringBuilder的区别

1)基本区别string是不可变的,stringBuffer、stringBuilder是可变的。string是字符串常量,stringBuffer和stringBuilder是字符串变量
2)性能方面,stringBuilder执行最快,其次为stringBuffer,最后是string
3)安全方面,string和stringBuffer是线程安全的,stringBuilder线程是不安全的
4)用途方面,string适用于少量字符串操作,stringBuffer适用于多线程下字符串缓冲区进行大量操作,stringbuilder适用于单线程下字符串缓冲区进行大量操作。

8.线程实现的三种方式

1)继承线程类Thread
优点:编写简单,直接使用this即可获得当前线程
缺点:继承了Thread类,就不能继承其他父类。

public class ThreadDemo01{
    public static void main(String[] args) {
        // 3.创建线程对象,调用start方法开启线程
        MyThread myThread = new MyThread();
        myThread.setName("新线程");
        // 开启线程
        myThread.start();
        // main线程中打印 1-100
        for (int i = 0; i < 100; i++) {
            System.out.println("main" + i);
        }
    }
}
// 1.创建一个类继承Thread类
class MyThread extends Thread {
    // 2.重写run方法(线程执行任务放在这里)
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName() + ":" + i);
        }
    }
}

2)实现Runnable接口
优点是:可以继承其他的类,这种方式下共享同一个target对象,适合多个相同的线程来处理同一份资源的情况
缺点就是编程相对比较复杂

public class ThreadDemo02 {
    public static void main(String[] args) {
        // 2.创建任务对象
        MyRunnable myRunnable = new MyRunnable();
        // TODO 3.创建Thread类型的对象,Thread类的构造方法需要接收一个Runnable实现类对象
        Thread thread = new Thread(myRunnable);
        // 4.开启线程
        thread.start();
    }
}
// 1.定义任务类,实现Runnable接口,并重写run方法
class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

3)实现Callable接口
重写call方法,相对于run方法,call方法是有返回值的。

public class ThreadDemo03 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建Callable的实现类对象
        MyCallable myCallable = new MyCallable();
        // 创建FutureTask<实现类返回的类型>  桥梁
        FutureTask<String> task = new FutureTask<>(myCallable);
        // 创建线程对象
        Thread th = new Thread(task, "我的线程");
        //开启线程
        th.start();
        // 获取线程执行完毕的结果 (获取call方法的返回值)
        String s = task.get(); // 此处有异常  阻塞作用
        System.out.println(s);
    }
}

// 1.创建任务类实现Callable接口
class MyCallable implements Callable<String> {
    public String getThreadName() {
        return Thread.currentThread().getName();
    }

    // 此方法返回的是线程执行完毕的结果
    @Override
    public String call() throws Exception {
        for (int i = 0; i < 100; i++) {
            System.out.println(getThreadName() + ":" + i);
        }
        return getThreadName() + "执行完毕";
    }
}

9.线程的状态 六种

new 新建状态 (创建线程对象)
runnable 就绪状态(start方法)
blocked 阻塞状态(无法获得锁对象)
waiting 等待状态(wait方法)
time_waiting 计时等待(sleep方法)
terminated 结束状态(全部代码运行完毕)

10.线程池核心参数

ThreadPoolExecutor线程池类

        public ThreadPoolExecutor(
                            int corePoolSize,                   -- 核心线程数量
                            int maximumPoolSize,                -- 最大线程数量
                            long keepAliveTime,                 -- 临时线程存活时间
                            TimeUnit unit,                      -- 临时线程存活时间单位
                            BlockingQueue<Runnable> workQueue,  -- 阻塞队列
                            ThreadFactory threadFactory,        -- 创建线程的方式
                            RejectedExecutionHandler handler    -- 取舍模式
                            )

11.递归

递归概述:以编程的角度来看,递归指的是方法定义中调用方法本身的现象

/*
        需求:用递归求5的阶乘,并把结果在控制台输出
 */
public class Demo1 {
    public static void main(String[] args) {
        int result = jc(5);
        System.out.println("5的阶乘是:" + result);
    }

    private static int jc(int n) {
        if (n == 1) {
            return 1;
        }
        return n * jc(n - 1);
    }
}

12.集合

1)ArrayList和LinkedList的区别
①首先,ArrayList底层结构是动态数组结构,地址是连续的,一旦数据存储好了,查询效率会比较高。增删较慢。LinkedList是基于链表的数据结构,其中add和remove比较占优。缺点就是LikedList要移动指针,所以查询的性能比较低。
②ArrayList和LinkedList都实现了List接口,而LinkedList还实现了Deque接口,所以LinkedList还能当双端对列来使用。
2)HashMap和Hashtable的区别
①hashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKey()
②hashTble是同步的,而hashMap是非同步的,效率上要比hashTable要高
③hashMap允许空键值,而hashTable不允许

二、JavaWeb

三、Mysql

1.where和having的区别

1.执行时机不同,where在分组之前进行筛选,不满足where条件不进行分组,having在分组之后进行过滤。
2.where不能对聚合函数进行判断

2.多表查询都有哪些

inner join… on
left join…on
right join …on
在这里插入图片描述

3.事务的四大特性

1.隔离性:一个事务不被其他事务干扰,多并发的事务之间相互隔离。
2.持久性:一个事务一旦被提交,对数据库的改变是永久性的。
3.原子性:一组sql语句是不可分隔的单位,要么都发生要么都不发生。
4.一致性:执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。

4.事务的并发访问引起的三个问题

1.脏读:一个事务读取到了另一个未提交的数据,
2.不可重复读:一个事务中两次读取的数据内容不一致,只要是update操作。
3.幻读:一个事务内读取到了别的事务插入或者删除的数据,导致前后读取记录行数不同,主要发生在delete,insert操作。

5.事务的隔离级别

1.读未提交 read uncommitted
2.读已提交 read committed 可避免脏读
3.可重复读 repeatable read 避免了脏读,和不可重复读
4.串行化 serializable 最安全,但是性能最低。
安全性:serializable > repeatable read > read committed > read uncommitted
性能 : serializable < repeatable read < read committed < read uncommitted

6.mysql的存储引擎,MyISAM和InnoDB的区别

1.MyISAM在mysql5.5之前是默认的存储引擎,虽然MyISAM性能各方面还行,但是他不支持事务和行级锁,最大的缺陷是崩溃后无法安全恢复。
2.是否支持行级锁MyISAM只有表级锁,而InnoDB支持行级锁和表级锁,默认为行级锁。也就是说MyISAM一锁就是整张表,在并发的时候性能比较低。
3.是否支持事务MyISAM不支持事务,InnoDB提供事务支持,实现了SQL标准定义的四个隔离级别,读未提交,读已提交,可重复读,串行化,InnoDB默认是可重复读,可以解决脏读和不可重复读的问题。
4.是否支持外键MyISAM是不支持外键的,而InnoDB支持。
5.是否支持数据库异常崩溃后的安全恢复MyISAM不支持,而InnoDB支持,使用InnoDB的数据库异常崩溃后,数据库重新启动的时候会保证数据库恢复到崩溃前的状态。
6.索引的实现不一样都是B+Tree作为索引结构。。。巴拉巴拉。

7.mysql的锁

请添加图片描述

8.表级锁和行级锁了解吗?有什么区别

1.表级锁:MySQL中锁定粒度最大的一种锁,是针对非索引字段加的锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定的粒度最大,触发锁冲突的概率最高,并发度最低。
2.行级锁:MySQL中锁定粒度最小的一种锁,是针对索引字段加的锁,只针对当前操作的记录进行加锁。行级锁能大大减少数据库操操作的冲突。其颗粒度最小,并发度最高,但加锁的开销也最大,加锁慢会出现死锁。

9.悲观锁和乐观锁的区别?

1.首先乐观锁和悲观锁都是用于解决并发场景的数据竞争问题,但却是两种完全不同的思想,他们使用广泛,不局限于编程语言或数据库。
2.乐观锁:指的是在操作数据库的时候非常乐观,乐观的认为别人不会同时修改数据,因此乐观锁默认是不上锁的,只有在执行更新的时候才会去判断在此期间别人是否修改了数据,如果别人修改了数据则放弃操作。----冲突较少的时候,使用乐观锁,由于乐观锁默认不上锁的特性,所以在性能方面要比悲观锁好,比较适用于读大于写的业务场景。
3.悲观锁:指的是操作数据库的时候比较悲观,悲观的认为别人一定会同时修改数据,因此悲观锁在操作数据时是直接把数据上锁,直到操作完毕后才会释放锁,在上锁期间不能操作数据。----冲突比较多的时候,使用悲观锁,对每一次的数据修改都要上锁,适合写大于读的情况。
4.读取频繁使用乐观锁,写入频繁使用悲观锁。

10.MySQL的索引

1.什么是索引:是帮助MySQL高效获取数据的有序数据结构,将数据进行排序整理的过程就称为索引。可以大大提高查询的速度。
2.创建索引
在已有的表的字段上直接创建

-- 创建普通索引
create index 索引名 on 表名(字段)
-- 创建唯一索引
creat unique index 索引名 on 表名(字段)

创建表的时候指定(掌握)

-- 创建学生表
CREATE TABLE student3(
 id INT PRIMARY KEY AUTO_INCREMENT, -- 主键索引
 name VARCHAR(32),
 telephone VARCHAR(11) UNIQUE, -- 唯一索引
 sex VARCHAR(5),
 birthday DATE,
 INDEX(name) -- 普通索引
);

3.索引创建的原则:①字段内容的可识别度不能低于70%,字段内数据唯一值得个数不能低于70%;
②经常使用where条件搜索的字段,例如user表的id name等字段
③经常使用表连接的字段,可以加快连接的速度。
④经常排序的字段,order by。因为索引已经排过序了,就会加快排序查询速度。
4.索引的缺点:索引的建立和维护都需要耗时,数据库中创建索引需要占用一定的存储空间,在表中的数据进行修改时,索引还需要动态维护。

11.索引失效的场景

1.列参与了运算(例如使用不等于查询!=,列参与了数学运算或者函数)
2.以%开头的Like模糊查询,索引失效
3.当mysql分析全表扫描比使用索引快的时候不使用索引.
4.in 走索引, not in 索引失效。
5.字符串不加单引号,造成索引失效。
6. 如果MySQL评估使用索引比全表更慢,则不使用索引。

12.MySQL的优化

TODO 太多了不写了,日后在补
https://www.cnblogs.com/huchong/p/10219318.html

四、Spring

1.Spring的特点(介绍一下Spring框架)

1.轻量

入门简单,上手较快,一个完整的spring框架大小在1M左右,占用空间小,开销也小,加载的时候不用加载全部内容。

2.IOC 控制反转,依赖注入

spring通过IOC技术促进低耦合,不主动创建对象,一个对象依赖其他对象是通过被动方式传递进来的。控制反转的意思就是,对象的控制权(创建,销毁。。)从开发者的手中转移到了工厂中。

五、SpringMVC

六、 Mybatis

1.#{} 和 ${} 的区别

1.取值的时候,${id}取值时必须使用@param,如果是单个值可以用 ${value}。#号取值时如果没有@param指定参数名称,括号里面可以随便写。
2.使用 ${ }获取参数的时候有sql注入的问题,它是直接将实参拼接到sql语句的位置。
3.#{ }是预编译方式将参数设置到sql语句中的,防止sql注入问题,参数是以 ? 显示的。

– —${ }虽然有sql注入的问题,但是也有应用场景,需要对sql语句进行拼接(不是参数)

select count(*) from user;
select count(*) from order;
select count(*) from ${tableName};

2.mybatis的核心组件

1.SqlSessionFactoryBuilder;会话工厂构造类创建会话工厂对象
2.SqlSessionFactory:会话工厂类创建会话对象
3.SqlSession:会话类

3.什么是ORM?

即对象关系映射,是一种数据持久化技术。他在对象模型和关系型数据库直接建立起对应关系,并且提供一种机制,通过javaBean对象去操作数据库表的数据。

4.实体类中属性名和表中的字段名不一样怎么办?

1.通过查询的sql语句中来给字段的名字起别名来对应。
2.通过来映射字段名和实体类属性名的一一对应的关系。

<result property = “属性名” column =”字段名”/>

3.开启驼峰映射,字段的下划线会自动转化。

5.mybatis中的模糊查询怎么查的?

使用mysql的拼接函数 concat(’ %‘,’#{ name} ‘,’ %'),既可以防止sql注入,又拼接了参数。

6.mybatis是如何进行分页的?分页的原理是什么?

1.Mybatis使用RowBounds对象进行分页,针对ResultSet结果集执行的内存分页,而不是物理分页。可以在sql内直接写带有物理分页的参数来完成物理分页的功能,也可以使用分页插件来完成物理分页。分页插件就是pageHelper分页。
2.pageHelper就是mybatis拦截器的应用,实现分页查询。

7.mybatis是否支持延迟加载(懒加载)?它的实现原理是啥?

1.mybatis支持一对一和一对多的延迟加载,在配置文件中可以配置lazyLoadingEnabled = true 开启。
2.延迟加载就是懒加载,在真正使用数据的时候才发起查询,不用的时候不查询关联的数据。
3.原理是,他使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现了a.getB()是null值,那么就会单独查询B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着a.getB().getName()就完成了调用,这就是延迟加载的基本原理。

8.mybatis的一级,二级缓存。

1.缓存就是用来提高查询和访问速度的,就是将每次的访问记录缓存在一个地方,下次查询的时首先访问的不是数据库,而是缓存,在缓存中查到了,就不访问数据库了。
2.一级缓存是本地缓存,是由PerpetualCache类的HashMap本地缓存实现的,他的作用域是SqlSession,比如说一个SqlSession执行两次sql查询,两次的位置是不同的,第一次缓存中没有去数据库,第二次就在缓存中查,等SqlSession结束后相应的缓存也就销毁了。mybatis默认一级缓存开启,不能关闭。
3.二级缓存是全局缓存,默认也是有PerpetualCache类中Hashmap存储的,他的作用域是mapper范围的,多个SqlSession可以共享二级缓存,同一个mapper的namespace,在同一个namespace中查询sql可以从缓存中命中,不同的SqlSesison可以从二级缓存中命中。先进入一级缓存,一级缓存中的SqlSession 关闭后,一级缓存的数据存入二级缓存中。一旦进行了增删改操作会将二级缓存清空。二级缓存需要手动开启 setting标签 cacheEnabled 为true开启。

七、SpringBoot

八、SpringCloud

九、mybatisPusl

十、消息中间件

1.MQ的作用

公司服务器有限,用户量暴增,此时有两个方案,1.增加服务器数量。2.将并发的请求快速存放到对列中,存放完毕后,给用户响应一个信息,操作成功
总的一句话就是,用更少的服务器接收更多的请求,缓存请求,请求在 对列中等。
RabbitMq

2.MQ的同步异步

同步请求的优点:时效性强,可以立即得到结果。
     缺点:耦合度高,性能和吞吐能力下降,有额外的资源消耗。
异步请求的优点:吞吐量提升,响应速度更快。故障隔离,服务没有直接调用,不存在级联失败的问题、调用件没有阻塞,不会造成无效资源的占用、耦合度低,每个服务可以灵活插拔,可替换、流量削峰,不管发布的流量波动多大,都由broker接收,并按照自己的速度处理。
     缺点:架构复杂,业务没有明显的流程线,不好管理、需要依赖broker
问:如果让你选择用异步还是同步,你怎么选?
大多时候用的都是同步请求,就是因为同步请求时效性很强,这是异步请求没有的。

3.RabbitMQ常见的消息模型

1)基本模式。简单对列模型
在这里插入图片描述
2)工作模式。WorkQueue也称为任务模型,多个消费者绑定到一个对列,共同消费对列的消息。
在这里插入图片描述
3)发布订阅模型
在这里插入图片描述
订阅模型中多了一个exchange角色,过程发生了变化
publisher生产者,发送消息不在直接发送给对列,而是发给交换机。
exchange交换机,exchange接收生产者的消息,处理消息又分为了三大类型
  Fanout:广播,将消息交给所有绑定到交换机的队列
  Direct:定向,把消息交给符合指定routing key 的队列
  Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列
exchange交换机只负责转发消息,不具备存储消息的能力。

4.RabbitMQ发送消息过程中出现消息丢失怎么办?

1.生产者消息确认,RabbitMQ提供了confirm机制来避免消息发送到MQ过程中丢失。这种机制必须给每个消息指定一个唯一id。消息发送到MQ以后,会返回一个结果给发送者,表示消息是否处理成功。
返回结果有两种方式:
confirm发送者确认
成功到达交换机,返回ack
位成功,返回nack
return发送者回执
消息到达交换机了,但是没有路由到对列,返回ack和路由失败原因。
2.消息持久化,生产者发送消息成功到RabbitMQ对列中,此时MQ宕机,可能就会发生消息丢失。就必须开启持久化机制。
交换机、对列、消息持久化。
3.消费者确认机制,消费者获取消息后,应该向rabbitMQ发送ack回执,表名自己已经处理消息。
消费者确认机制分为三种确认模式:
manual:手动ack,自己调用api发送ack
none:关闭ack,此模式是不可靠的,可能丢失。
auto:自动ack,由spring监测代码,没有异常返回ack。一般默认用auto模式。
当auto模式代码出现异常时,对列会不断重新发送给消费者,无限循环报错,导致消息处理飙升,出现不必要的压力。配置retry就可以解决问题,重试达到最大次数后,Spring会返回ack,消息会被丢弃。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值