Java基础题
1. Java面向对象有哪些特征
继承、封装、多态三大特征相互相乘
封装:封装内部的一些实现机制,就跟方法封装一些实现的机制一样
继承:就是从已有的类派生出新的类,新的类继承已有类的行为和属性,并扩展新的能力。
多态:多态有多种形式,封装和继承最终归于多态。多态指的是类与类的关系,多态必要的三要素,继承、重写,父类引用指向子类对象。
为什么这些面向特征能帮助我们写很好的代码:
封装:封装好的东西可以重复利用,增加了代码的复用性
继承:也是增加代码的复用性
多态:增加了代码的可移植性,健壮性、灵活性,实现可以随便
2. ArrayList和LinkedList有什么区别
相同点:
首先ArrayList和LinkedList都实现了list接口
不同点:
ArrayList是基于索引数据接口,它的底层是数组。
LinkedList:是以元素列表的形式存储他的数据。
linkedlist比ArrayList更占空间,因为linkedlist一个字节存储两个引用,一个指向前一个元素,一个指向下一个元素。一般Linkedlist用于要求顺序较高的增和删较频繁的场景,因为Linkedlist的一些方法可以快速进行指定,LinkedList删除字节的后,不会重新排序,而是指向下一个元素。所以对于删除、修改要比ArrayList效果要高。
查询速度方面ArrayList要大于linkedlist,因为ArrayList是基于索引数据结构,使用索引在数组里面搜索和查询数据是很快的。但是删除数据开销比较大,删除数据之后需要重写排列数组中所有的数据。所以删除修改ArrayList没有LinkedList性能高。
3. java中==equals有哪些区别
- ==:比较他们的数值是否相等,列如:int、long、double、short、byte、float这些都是数值类型,是不能直接new的,比较他们的地址是否相等,如果地址相等则返回true,否则false。如果两个String变量字符串比较,如果是没有new,地址相同,则也是返回true
- equals():两个方法之间的比较,如果两个对象内容相等则返回true,否则false。
- 注意点:Integer比较也需要使用equals(),就算是地址相等。因为Integer数值超过[-128,127]的时候会new一个对象,==是地址比较,一旦new了,就是就扩容了一块地址,那么最终的结果肯定就有问题了。
4 .Java中异常处理机制
try、catch、finally:捕获异常
throw:抛出异常
throws:声明异常
5. 重载和重写的区别(区别无参构造和有参)
重载:写在一个类里面的,一个方法可以有多个实现,参数和返回值不同即可
重写:是子类父类中,子类重写父类的方法。
重写和重载方法名必须相同
6. String、StringBuffer、StringBuilder区别以及使用场景
都可以存储和操作字符串
String:声明的变量是引用类型,每次改变量值都会新建一个String对象,所以频繁更改变量的时候,避免使用String。
StringBuffer/Stringbuilder:都是可以直接修改,而不会在新建一个对象。变量值是进行追加,然后StringBuffer是jdk0版本的,Stringbuilder是jdk5版本时候的,stringbuilder效率要比stringbuffer效率高,因为stringbuffer方法有加上安全锁,线程安全了,对应的效率就低了
7. 怎样声明一个类不会被继承,什么场景下会用
被fianl修饰
当前类不在被继承,不需要重写。
8. Spring的核心
Spring是一个开源框架,为了简化企业开发而诞
生的,我们现在用到的springboot、springcloud都是基于spring基础之上研发的。我现在做的MES系统不是原生的springcloud,是通过springboot集成的。
开发中用到服务端采用三层架构,每一层都提供了技术支持:
表示层(web):提供了springmvc等框架的整合
业务层(service):管理事务、记录日志等
持久层(dao):提供了与mybatis、hibernate等框架整合
spring的核心是ioc控制反转、aop面向切面。
ioc控制反转:
1、控制什么:控制对象的创建和销毁、就是对象的声明周期
2、反转什么:之前创建一个对象都是new,现在有了IOC,就可以把对象控制权交给了IOC容器。
这样说可能有点模糊:
举列有一个用户,有一辆车,每天就是干两件事,上学、回家。
阶段一(用户自己创建一辆车完成功能)
创建
一个汽车类
一个用户类
当用户需要用到车,就new一个汽车类,调用方法,实现我们要去的地方
(问题:如果每次用车时,就要new一个汽车类,非常麻烦)
阶段二(用户自己传递奔驰车完成功能)
用户类添加构造方法汽车类作为参数,用户需要用车,只需要传递一辆车就可以实现。
(问题:现在汽车类是一辆具体的(宝马),那换一辆车开,就需要修改汽车里面的方法,就比较麻烦)
阶段三 (用传递车完成功能(不是具体的车)
这里可以定义车的接口
- 宝马车类
- 奔驰车类
- 奥迪车类
实现车(car类)接口
用户类构造方法参数是car接口,没有具体的实现方法,所以现在可以用到容器进行管理,当我们需要用到车,直接到容器里面拿。这里也是一个控制反转的思想,我们把车创建销毁交给容器,而且控制权也交给容器,我们只是使用功能。
项目中有SpringUtils的工具类,方便我们在开发中获取bean。
这里面大概就是我理解ioc的控制反转和注入。
案例代码地址:https://baijiahao.baidu.com/s?id=1654948911688026610&wfr=spider&for=pc
aop:是面向切面编程,简单的说在程序运行时候,动态的将代码切入到类的指定方法,指定位置上的编程思想就是面向切面编程。也可也说动态代理。
列举:做了一个sn调拨功能:
流程概述:pad扫入调拨单,调拨单有分为主表子表(子表为明细表)扫主表的单据号,pad带出信息,然后点击一条明细进去,通过明细的物料编码到条码存库,关联出条码信息出来,进行调拨。这里会条码库存、库存数量、条码关联档案、还有就是调拨sn这几个功能进行数据库操作。如果出现了异常、这里肯定就要进行回滚。那这些业务逻辑只要有进行数据库操作的地方都要加上事务,列如开启事务、提交事务、回滚操作。那都加上才能达到原子性。但是这样代码看起来就很臃肿,不美观、易读性差。
解决:
这里直接引用spring事务@Transactional(rollbackFor=Exception.class)和动态代理JDK代理实现。
只需要在Service业务上面加上注解,这样就保证了事务的原子性,也解决了代码的臃肿冗余性。
这里大概就是我对aop面向切面的大概理解。
9. java常用设计模式
简介:为什么使用设计模式:首先设计模式是可以被我们反复使用、优化经验设计的一个总结,使我们的代码更容易被人理解、代码重用性,代码的可靠性、程序的重用性
单列模式
- 单列模式只有一个类
- 单列对象必须由单列类自行创建
- 单列类对外提供一个访问单列的全局访问点
(注:私有静态变量、构造方法,公有的静态访问方法) - 懒汉模式和饿汉模式
懒汉模式特点:类加载时没有生成单列,当我们调用getinstance方法时才会创建这个单列
饿汉模式特点:类加载的时候就创建一个静态对象出来,以后不再改变,线程相对来说就是安全的。 - 应用场景:频繁创建和销毁对象,频繁访问数据库或文件对象。就可以使用单列模式。单列模式只允许创建一个对象,因此比较节省内存。速度快。
工厂模式
-
简单工厂模式:
-
工厂方法:
-
抽象工厂模式:
属于创建型模式,它提供了一种创建对象最佳方式,为什么了,在工厂模式中,我们创建对象时不会暴露客户端创建逻辑,通过共同的接口指向新创建的对象。 -
举列:当我们需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆车是怎么做出来的,以及这辆车是怎么实现的。
如:创建一个车的接口,创建一个宝马奔驰类实现车的接口,在创建一个工厂,用户调用的时候(只需要告诉工厂是需要宝马还是奔驰就行了)。
优点:扩展性高、如果想增加一个产品只需要在扩展一个工厂类,我们只需要关心产品接口就可以。
缺点:每次增加一个产品,就要对应增加实现类和工厂,在我们开发中,类的个数就会成倍增加,也增加了类之间的依赖。
应用场景:我们计划是不同的条件创建不同的实列,解决了我们接口选择的问题。
代码案例:https://www.runoob.com/design-pattern/factory-pattern.html代理模式
什么是代理模式:
- 通过代理控制对象的访问,可以在对象调用方法之前,调用方法之后去处理新的功能。
- 代理在原有的代码乃至业务流程都不修改的情况下,直接在业务流程中切入新代码,增加新功能,和spring aop面向切面编程很相似。
代理模式运行的场景:
- spring aop、日志打印、异常处理、事务控制、权限控制等
代理分类:
- 静态代理(静态定义代理类),也是动态代理的理论基础
- 动态代理(动态生产代理类,也称为JDK自带动态代理),使用反射完成代理,需要有顶层接口才能使用,常见是mybatis的mapper文件是代理
举列:
静态代理案例:https://blog.csdn.net/weixin_43122090/article/details/105462226
10. servlet声明周期
加载并实列化,初始化,服务,销毁
程序启动的时候,就会进行加载实列化,初始化,然后当用户进行操作的时候,就会进入控制层,服务层,由方法调用doget或dopost方法来响应用户,然后当容器资源紧张,或者长时间没有接受到请求就会销毁。
12. JVM、JRE、JDK的关系
JDK是java中开发的工具包,开发中API的一些包都是来自于JDK中
JER是java中的一个运行环境
JVN是java中的虚拟机,是java实现跨平台最重要的部分,可以运行java编写的软件程序。
13. Mybatis
mybatis是一个持久层框架,是实现了一个使用JPA对数据库进行增删改查的一个开源框架,他对jdbc数据库的过程进行了封装,是开发者更专注与SQL的本身,不用去关注实现的过程,他是一个半自动华的orm的组件。Hibernate是一个完完全全的orm的组件
bean的声明周期
1、 实例化(Instantiation)
2、 属性设置(populate)
3、 初始化(Initialization)
4、 销毁(Destruction)
14. 数据库事务
原子性:事务都是一个整体的,不可分离的,要么全部成功,要么全部失败
一致性:数据库执行前后,数据要和真实状态保持一致。这种一致性,在我们开发定义,自己给定的规格
列如:a仓库:5000 b仓库:5000 他们互转的数量不能大于5000,数量不能是负数
隔离性:多个用户并发操作数据库的时候,一个用户操作事务不能被其他用户事务干扰,也就是多个事务操作的隔离
持久性:一个事务提交成功了,那么他对数据库的数据操作就是永久性的,就算数据库出现故障,数据也是永久保存下来的。
15. java集合
List、Set、Map
List添加元素是有序的、可重复、有索引的
- LinkedList和Arraylist都实现了List接口
- ArrayList:实现了List接口,基于索引的接口,底层是数组,查询快。所有查询量大的时候会使用List作为集合来查。在修改和删除方便会比较慢,删除一个元素后,会进行重新排序
- LinkedList:以链表的形式进行存储数据,一个指向前一个,一个指向下一个,一般对顺序要求较高的增删操作频繁的场景,因为Linkedlist有指定的方法,可以快速进行操作。删除元素的时候,因为是已链表的形式进行存储的,上一个元素自动指向下一个,所以在修改和删除要比ArrayList性能要高。
- public void add(int index, E element): 将指定的元素,添加到该集合中的指定位置上。
- public E get(int index):返回集合中指定位置的元素。
- public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。
- public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回更新前的元素值。
小结:
List系列集合有序,可重复,有索引的。
ArrayList实现类集合底层基于数组存储数据的,查询快,增删慢!!
开发中ArrayList集合用的最多!!
List遍历方式:
(1)for循环。(独有)
(2)迭代器。
(3)foreach。
(4)JDK 1.8新技术。
Set:添加元素是无序的、无索引,并且元素不可以重复,允许一个空元素。可以高效添加删除、用于判断,可以过于重复元素
Map:
HashMap:以键值对的方法存储(key,value),并且键不可以重复,允许一个键为空。
用于我们需要指定key取出或者存储的时候
16. 多线程
1. 进程和线程的区别
举个列子:有一辆火车,火车有很多节,这个火车可以比作为进程,每一节可以比作为线程,进程必须最少要包含一个线程,线程也不能独立存在。
2. 并行、并发、串行的区别
串行:串行在时间上不可能发生重叠,前一个没有执行完,下一个不能执行,只能等待,前一个执行完,下一个才能执行。
并行:并行在时间上是重叠的,两个任务同时执行,互不干扰。
并发:并发是允许两个任务相互干扰,同一时间,只有一个任务执行,交替执行。
3. 什么是线程安全
当多个线程访问一个对象的时候,如果没有进行额为的同步或其他协调操作的时候,调用这个对象的访问结果都是正确的,那么可以说这个对象线程就是安全的。
4. Thread和Runnable
首先Thread和Runnable是一个继承关系,无论是使用Thread或者Runnable,都会new Thread,在执行一个run方法,如果是比较复杂的任务,那就可以用继承 thread,如果只是简单的执行一些方法,那就可以实现Runnable
5. 线程的生命周期和状态
- 新建:新创建一个线程
- 就绪:线程创建后,其它线程调用该对象的start方法,该状态的线程位于可运行的线程池中,变的可运行,等待获取CPU的使用权限。
- 运行:运行状态线程获取CPU权限,执行程序代码。
- 阻塞:阻塞状态是因为线程某种原因放弃了CUP的使用权,暂时停止运行,直到进入线程就绪状态,才有机会进入运行状态,
列如sleep方法让线程进入休眠状态,resume(v曾)方法可以让线程立即运行 - 死亡:死亡状态就是说该线程执行完了或者遇到了异常退出了run方法,该线程生命周期结束
6. 并发数据不一致的问题
采用乐观锁,乐观锁顾名思义乐观,两个人都可以访问,访问到数据,但是某个人修改的时候,数据库的版本号也会进行修改进行加一,如果下一个在修改的时候,版本号就会不匹配就修改不了
17. mybatis的优化
一级缓存:mybatis会自动开启,数据缓存到SqlSession中,如果下次请求发现SqlSession中存在相当数据,则不在请求访问数据库,直接从缓存中读取。也可以使用Redis进行一个性能优化,列如把查询的数据存入Redis缓存当中。
二级缓存:整合ehcache框架
18. Java反射
在程序运行的时候,需要动态的加载一些类,而这些类一开始用不到,就不需要加载,在运行的时候根据需要才加载,原来使用new指定的类,属于硬编码形式,现在反射可以用类名参数就可以生成对象,降低了代码的耦合性,提高了程序的灵活性。列如spring的ioc和aop以及动态代理也是反射的编程思想,以及mybati-puls生成的方法也是反射编程思想
19. MySQL的死锁
MySQL的死锁会在innoDB引擎出现的问题
死锁是指两个或者两个以上的进程在执行的过程中,因争夺资源而造成的一种相互等待现象,若没有外力作用,就造成了死锁
多线程的并行。并发会造成死锁,串行不会造成死锁
解决死锁:
可以设置锁或者事务的超时时间
使用悲观锁或者乐观锁
通过事务的日志进行排产
还有一种最暴力的解决方案,就是把你存储死锁的那些表数据清空或者删除,重新执行脚本。这种在本地库还可以,在开发库就不推荐使用了。
20. 消息队列(MQ)(卡布卡)
消息队列简称MQ,我们可以理解为一个存放消息的容器,当我们需要使用消息的时候可以取出消息供自己使用。消息队列是分布式系统中的一个组件
消息队列的应用场景:
异步处理:在网站新用户注册时,需要将用户的信息保存到数据库中,同时还需要额外发送注册的邮件通知、以及短信注册码给用户。但因为发送邮件、发送注册短信需要连接外部的服务器,需要额外等待一段时间,此时,就可以使用消息队列来进行异步处理,从而实现快速响应。
系统解耦:使用消息队列可以实现系统与系统之间的解耦,比如 买票系统中买票,用户是不直接调用数据库系统的接口,而是把订单信息放到消息队列当中,然后数据库系统从消息队列当中拿去信息,然后再去减库存信息。
流行削峰:在像双11 的时候秒杀等系统的时候,用户直接访问数据库,数据库一时接受到大量的数据请求,就会压垮数据库,所以在这个时候加入消息队列,用消息队列的大吞吐量,快速处理用户的请求(哪怕是Redis还不足够应对这种大数据访问)。
因为消息队列是低延迟、高可靠、高吞吐的,可以应对大量并发
21. 说一下你对分布式理解是什么样的?
就是一种微服务的架构,就可以理解在同一个系统中,把不同的业务拆分成单个服务,对于这个服务,可以交给一个团队去独立的技术选型,独立的部署独立的运维,它这样是非常有好处的,这就是我对微服务的理解
Springcloud是一系列框架的集合,他利用SpringCloud的开发便利性简化了分布式系统基础设施的开发,如服务发现、服务注册、配置中心、消息总线、负载均衡、熔断器、数据监控等,都可以用SpringBoot的开发分隔做到一键启动和部署。
22. Springcloud里面的组件
1. 注册中心
第一个涉及到的就是注册中心,他主要承担的就是把我们的各种服务,把它注册到里面去,然后注册到这个里面去之后,
以后要调他的要先从这个里面来拿服务,这就是注册中心第一个
2. 服务发现
第二个既然有服务,那我们这个服务可能注册多个所以第二个组件feing,他是做负载均衡调用的,他主要的作用就是,他从注册中心拿到一堆服务列表,比如说我要那一个用户服务,那他可能有3个或者5个,这个时候我就要按照一定的负载均衡策略。然后完成调用,而这个操作就是交给ribbon或者feing,去做一个载均衡的调用,这个是第二个,
3. 熔断器
第三个的话除了做这个正常调用以外我们还有可能要做一下的事情,比如说我在调用这个服务的时候,这个服务突然挂了,这个时候为了保证服务的一个健壮性,要用到springcloud的hystrix(熔断器)然后他主要就是做熔断和降级以及限流的这个是第三个
4. 分布式配置
第四个的话我们众多的服务当中它有一些配置,而这些配置我把他分散到不同的模块当中,不同的微服务当中,这样管理起来是不好管理的,所以他要有一个统一的配置中心,springcloud configure这是配置中心
5. 网关
然后第五个就是最后一个网关,就像我们有n多个微服务,而这些服务,他最终是要暴露给前端调用的,而前端如果是一个服务
就有一个地址,他是非常不好管理的,这个时候我们处于让他统一管理统一地址,这个是第一个作用
二个作用是我还可以对我要访问的微服务做统一鉴权等等操作,而这些操作统统交给微服务的网关去处理,然后这就是springcloud的五大组
JVM虚拟机
jvm是整个java实现跨平台最核心的部分,所有的java程序首先编译成.class的类文件,编译后就可以到虚拟机上面执行,class文件是不可以直接与机器的操作系统相关联的,而是通过虚拟机间接与操作系统交互,由虚拟机将程序编译给到本地系统执行。还有就是jvm是不能直接运行class文件,因为class文件需要类库,这个时候需要用到jre,首先jre是java中的运行环境,jre里面会生成类库的,也是jvm所需要的库。
jre里面也包含了jvm
23. Java中函数式编程-Stream流-Lambda表达式
jdk1.8中新增了流Stream,和Lambda表达式
Stream流、Lambda表达式是函数式编程思想,可以让我们不用关注什么对象,而是关注对数据进行了什么操作,Stream可以很方便对我们的集合数组进行操作。并且在大数据下处理效果高,列如有大数据量集合可以使用我们的并行流进行操作。可以消灭嵌套地狱的if。让代码简洁、易理解,并且、快速开发。
24. Java泛型(约束类型)
- 泛型就是一个标签:尖括号里面加入:<数据类型>
- 泛型可以在编译阶段约束只能操作某种数据类型
- JDK1.7后,泛型后面的申明可以省略不写!列如:List
arrayList = new ArrayList(); - 泛型和集合都只能支持引用数据类型,不支持基本数据类型
基本数据类型:
八种基本类型
1.布尔类型 boolean(未指明多少字节)
2.字符类型 chart(2个字节)
3.浮点类型 float(4个字节),double(8个字节)
4.整数类型 byte(1字节),short(2个字节),int(4个字节), long(8个字节)
引用类型:
1.类,如String
2.接口
3.数组
4.对象
泛型好处:泛型在编译阶段可以确定数据类型,不需要再去强转,不会出现类型转换错误,从而体现了java的严谨性和规范性。
自定义泛型建议使用:K,E,T,V
标签:Java,一个,可以,基础,数据库,线程,java,ArrayList From: https://www.cnblogs.com/yingfa/p/16916545.html