一. JAVA基础笔试题
1、字符串1”如何转化为int型?(多选)
A、Integer.parseint(“1”):
B.Integervalueof("1").intvalue():
C、Integer.valueof(“1”)
D、(int)”1”
2.如何生成一个0-100的之间的随机整数?(多选)
A、(int)(Math.random()*100);
B.Random random = new Random();int iRandom = random.nextInt(100);
C、(int)(Math.random(100));
D、(int)Math.round(100);
3.在JAVA中,如何跳出当前的多重嵌套循环?(多选)
A、break
B.return
C、forward
D、finally
4.&和&&的区别?
&运算符有两种用法:(1)按位与;(2)逻辑与。&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者
都要求运算符左右两端的布尔值都是true整个表达式的值才是true。&&之所以称为短路运算是因为,如果&&左边的表达式
的值是false,右边的表达式会被直接短路掉,不会进行运算。很多时候我们可能都需要用&&而不是&,例如在验证用户登
录时判定用户名不是null而且不是空字符串,应当写为:username != null &&!username.equals(“”),二者的顺序不能交
换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的equals比较,否则会产生
NullPointerException异常。注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此。
5.什么是值传递和引用传递?
值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量.
引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对象本身 。
一般认为,java内的传递都是值传递. java中实例对象的传递是引用传递 。
6.是否可以在static环境中访问非static变量?
static变量在Java中是属于类的,它在所有的实例中的值是一样的。当类被Java虚拟机载入的时候,会对static变量进行初
始化。如果你的代码尝试不用实例来访问非static的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任
何实例关联上。
7.Java中的方法覆盖(Overriding)和方法重载(Overloading)是什么意思?
Java中的方法重载发生在同一个类里面两个或者是多个方法的方法名相同但是参数不同的情况。
与此相对,方法覆盖是说子类重新定义了父类的方法。方法覆盖必须有相同的方法名,
参数列表和返回类型。覆盖者可能不会限制它所覆盖的方法的访问
8.Java支持的数据类型有哪些?什么是自动拆装箱?
基本数据类型:
整数值型:byte,short,int,long,
字符型:char
浮点类型:float,double
布尔型:boolean
整数默认int型,小数默认是double型。Float和long类型的必须加后缀。
首先知道String是引用类型不是基本类型,引用类型声明的变量是指该变量在内存中实际存储的是一个引用地址,实体在
堆中。引用类型包括类、接口、数组等。String类还是final修饰的。
而包装类就属于引用类型,自动装箱和拆箱就是基本类型和引用类型之间的转换,至于为什么要转换,因为基本类型转换
为引用类型后,就可以new对象,从而调用包装类中封装好的方法进行基本类型之间的转换或者toString(当然用类名直
接调用也可以,便于一眼看出该方法是静态的),还有就是如果集合中想存放基本类型,泛型的限定类型只能是对应的包
装类型。
9.Git分支你们是怎么管理的?
feature 分支用来开发具体的功能,一般基于develop分支,最后完成功能后再合并
到develop分支。比如,目前我们针对develop分支来做功能开发,在开发的过程中会
有紧急需求需要开发,且在本次版本发布时间之前要能测试完成。我们可以基于之前稳定版本另开
一个feature分支来 做紧急需求的开发,发布并进行测试,完成之后再合并到develop分支上,
上线以后会打个release分支,用以记录版本,最后再打个tag合并到master分支。
10.接口幂等性你们是如何做的?
原文:
幂等就是一个操作,不论执行多少次,产生的效果和返回的结果都是一样的。
11.用@Transaction来控制事物,有没有出现事务不生效的场景?
首先Spring事务分类
Spring 提供了两种事务管理方式:声明式事务管理和编程式事务管理。
1.1编程式事务
在 Spring 出现以前,编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中
显式调用 beginTransaction()、commit()、rollback() 等事务管理相关的方法,这就是编程式
事务管理。简单地说,编程式事务就是在代码中显式调用开启事务、提交事务、回滚事务的
相关方法。
1.2声明式事务
Spring 的声明式事务管理是建立在 Spring AOP 机制之上的,其本质是对目标方法前后进行拦截,
并在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者
回滚事务。而Spring 声明式事务可以采用 基于 XML 配置 和 基于注解 两种方式实现
简单地说,声明式事务是编程式事务 + AOP 技术包装,使用注解进行扫包,指定范围进行
事务管理。
@Transacational失效的场景
2.1.数据库引擎是否支持事务( MySql的MyIsam引擎不支持事物)
2.2.注解所在的类是否被加载成Bean
2.3注解所在方法是否为public修饰的,不是 public则不会获取@Transactional 的属性
配置信息。注意:protected、private 修饰的方法上使用 @Transactional 注解,虽然
事务无效,但不会有任何报错,这是我们很容犯错的一点。
2.4.是否发生了自调用问题
开发中避免不了会对同一个类里面的方法调用,比如有一个类Test,它的一个方法A,A再调用本类
的方法B(不论方法B是用public还是private修饰),但方法A没有声明注解事务,而B方法有。
则外部调用方法A之后,方法B的事务是不会起作用的。这也是经常犯错误的一个地方。
那为啥会出现这种情况?其实这还是由于使用Spring AOP代理造成的,因为只有当事务方法被
当前类 以外的代码调用时,才会由Spring生成的代理对象来管理。
12.数据库三大范式怎么理解的?
三大范式的定义:
第一范式:每个属性值都必须是原子值,即仅仅是一个简单值而不含内部结构。
第二范式:满足第一范式条件,而且每个非关键字属性都由整个关键字决定(而不是由关键字的一部
分来决定)。
第三范式:符合第二范式的条件,每个非关键字属性都仅由关键字决定,而且一个非关键字属性
不能仅仅是对另一个非关键字属性的进一步描述(即一个非关键字属性值不依赖于另一个非关键字
属性值)。
13.银行家算法的含义?
银行家算法(Banker's Algorithm)是一个避免死锁(Deadlock)的著名算法
它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。银行家就好比操作系统,
资金就是资源,客户就相当于要申请资源的进程。在避免死锁方法中允许进程动态地申请资源,
但系统在进行资源分配之前,应先计算此次分配资源的安全性,若分配不会导致系统进入不安全
状态,则分配,否则等待。
死锁是指多个进程争夺共享资源而造成的僵局的状况。其实死锁的原因归根结底就是两个:资源不足
和排序不当。
14.MySQL主从机制
主从就是读写分离,主数据库负责写服务器
1.主数据库进行增删改操作后,相应操作记录的语句(比如 create database test)会记录
到binlog日志文件中(binlog日志文件一般和数据库data文件夹在一起
2.从数据库会请求主数据库的binlog日志文件,获取到新的操作语句,然后在自己的从数据库
上自动执行相同的操作语句,进而实现主从的同步。
15.数据库设计的思路
1.设计数据库之前,考察现有环境:定义数据库对象的命名规范;检查表名、报表名和查询名
之间的命名规范;以及明确业务需求等
2.设计表和字段
标准化和数据驱动:数据的标准化不仅方便了自己而且也方便了其他人。标准化有好几种形式,
但 Third Normal Form(3NF)通常被认为在性能、扩展性和数据完整性方面达到了最好平衡。
简单来说,3NF 规定:
* 表内的每一个值都只能被表达一次。
* 表内的每一行都应该被唯一的标识(有唯一键)。
* 表内不应该存储依赖于其他键的非键信息。
当然,标准化不能过头,为了效率的缘故,对表不进行标准化有时也是必要的,这样的例子很多。
曾经有个开发餐饮分析软件的活就是用非标准化表把查询时间从平均 40 秒降低到了两秒左右。
虽然我不得不这么做,但我绝不把数据表的非标准化当作当然的设计理念。而具体的操作不过是
一种派生。所以如果表出了问题重新产生非标准化的表是完全可能的。
3. 选择键和索引
键设计 4 原则
* 为关联字段创建外键。
* 所有的键都必须唯一。
* 避免使用复合键。
* 外键总是关联唯一的键字段。
索引是从数据库中获取数据的最高效方式之一。95% 的数据库性能问题都可以采用索引技术
得到解决。作为一条规则,我通常对逻辑主键使用唯一的成组索引,对系统键(作为存储过程)
采用唯一的非成组索引,对任何外键列[字段]采用非成组索引。不过,索引就象是盐,太多了
菜就咸了。你得考虑数据库的空间有多大,表如何进行访问,还有这些访问是否主要用作读写。
16.可重入锁是什么
可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。
可重入锁有 synchronized ReentrantLock
使用ReentrantLock的注意点
ReentrantLock 和 synchronized 不一样,需要手动释放锁,所以使用 ReentrantLock的时
候一定要手动释放锁,并且加锁次数和释放次数要一样
16.1不可重入锁
若当前线程执行中已经获取了锁,如果再次获取该锁时,就会获取不到被阻塞。叫做不可重入锁。
17.公平锁和非公平锁的区别
公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列
的第一位才能得到锁。
优点:所有的线程都能得到资源,不会饿死在队列中。
缺点:吞吐量会下降很多,队列里面除了第一个线程,其他的线程都会阻塞,cpu唤醒阻塞
线程的开销会很大。
非公平锁:多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,
如果能获取到,就直接获取到锁。
优点:可以减少CPU唤醒线程的开销,整体的吞吐效率会高点,CPU也不必取唤醒所有线程,
会减少唤起线程的数量。
缺点:你们可能也发现了,这样可能导致队列中间的线程一直获取不到锁或者长时间获取不到
锁,导致饿死。
18.聚簇索引和非聚簇索引的区别
聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据
非聚簇索引:将数据存储于索引分开结构,索引结构的叶子节点指向了数据的对应行,
myisam通过key_buffer把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),
在内存中直接搜索索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在
key buffer命中时,速度慢的原因
澄清一个概念:innodb中,在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是
需要二次查找,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引,辅助索引叶子节点
存储的不再是行的物理位置,而是主键值
19.SpringIOC的启动流程
IOC的启动流程分为两个阶段,第一阶段是容器的启动阶段,第二阶段是Bean实例化阶段。
容器的启动阶段:加载配置信息,分析配置信息,其他
Bean实例化阶段:实例化对象,装配依赖,生命周期回调,其他
20.jdk1.7跟jdk1.8中hashMap的区别
Hashmap解决冲突是采用链表,性能上就抱有一定疑问,如果说成百上千个节点在Hash时
发生碰撞。存储在一个链表中,那么如果要查找其中的一个节点,就不可避免的花费 O(n)
的查找时间,这是很大的性能损失。这个问题在接JDK8得到了解决。即在最坏的情况下,
链表查找的时间复杂度也是O(logn),而红黑树一直是O(logn)。这样会提高HashMao的
效率。而JDK8中采用的是位桶+链表 / 红黑树的方式,也是非线程安全的。当某个位桶的链
表的长度达到某个阀值的时候,这个链表就将转化成红黑树。
21.threadLocal的作用
hreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本
解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步
机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。
22.Redis和zookeeper分别怎么实现分布式锁
1.基于Redis实现分布式锁(setnx)setnx也可以存入key,如果存入key成功返回1,
如果存入的key已经存在了,返回0.
2.基于Zookeeper实现分布式锁 Zookeeper是一个分布式协调工具,在分布式解决方案中。
多个客户端(jvm),同时在zk上创建相同的一个临时节点,因为临时节点路径是保证
唯一,只要谁能够创建节点成功,谁就能够获取到锁,没有创建成功节点,就会进行等待,
当释放锁的时候,采用事件通知给客户端重新获取锁的资源。
23.Redis存储string数据是使用的二进制方式还是数据流的方式
字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这便意味着该类型
可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等。在Redis中字符串类型的
Value最多可以容纳的数据长度是512M。
24.数据库隔离级别是哪四种
事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted) 是 是 是
不可重复读(read-committed) 否 是 是
可重复读(repeatable-read) 否 否 是
串行化(serializable) 否 否 否
mysql默认的事务隔离级别为repeatable-read
25.类加载器分为哪四种?是什么关系
类加载器:通过一个类的全限定名去获取此类的二进制字节流,这个动作放在java虚拟机外部
实现,以便程序可以自己选择执行那个类。类加载器符合双亲委派机制,即从上往下
依次是:
1.启动类加载器(bootstrap class loader):在Java_home/lib下,启动类加载器无法
被虚拟机直接引用。
2.拓展类加载器:在Java_home/lib/ext下,使用extclassloader,用户可以直接使用。
3.应用程序加载器:又称系统类加载器,使用appclassloader,如果没有自定义加载器,
则使用它。
4.自定义类加载器 java.lang.classloder
自定义类加载器需要继承java.lang.ClassLoader。用户在编写自定义类加载器时,
如果需要把请求委派给引导类加载器,直接填null即可
26.string类可以自定义吗?
总的来说就是不能。 因为String类是JDK自带的基础类且为final,不能修改。
当然,如果够牛,你可以去下一个JDK的源代码,然后修改String类,并替换现有的
JDK中相应文件。但这绝对不推荐,而且也没有人会这么做,因为,基于它开发出来
的应用程序就丧失了可移植性
27.创建新线程的方式
一,通过继承Thread类创建线程类
通过继承Thread类来创建并启动多线程的步骤如下:
1、定义一个类继承Thread类,并重写Thread类的run()方法,run()方法的方法体就是线程
要完成的任务,因此把run()称为线程的执行体;
2、创建该类的实例对象,即创建了线程对象;
3、调用线程对象的start()方法来启动线程;
二,通过实现Runnable接口创建线程类
这种方式创建并启动多线程的步骤如下:
1、定义一个类实现Runnable接口;
2、创建该类的实例对象obj;
3、将obj作为构造器参数传入Thread类实例对象,这个对象才是真正的线程对象;
4、调用线程对象的start()方法启动该线程;
实现Runnable接口创建多线程程序的好处:
1.避免了单继承的局限性
一个类只能继承一个类,类继承了Thread类就不能进继承其他类,实现了Runnable接口,
还可以继承其他类,实现其他接口。
2.增强了程序的扩展性,降低了程序的耦合性
把设置线程任务和开启新线程进行了分离,可以通过传入不同的Runnable接口实现类,
实现不同的功能。
三,通过Callable和Future接口创建线程,基本没用过
28.四大线程池的作用
1.newCachedThreadPool
创建一个线程池,如果线程池中的线程数量过大,它可以有效的回收多余的线程,如果线程数
不足,那么它可以创建新的线程。
2.newFixedThreadPool
这种方式可以指定线程池中的线程数。举个栗子,如果一间澡堂子最大只能容纳20个人
同时洗澡,那么后面来的人只能在外面排队等待。如果硬往里冲,那么只会出现一种情景,
摩擦摩擦...
3.newScheduledThreadPool
该线程池支持定时,以及周期性的任务执行,我们可以延迟任务的执行时间,也可以设置
一个周期性的时间让任务重复执行。
4.newSingleThreadExecutor
这是一个单线程池,至始至终都由一个线程来执行。
线程池的作用主要是为了提升系统的性能以及使用率
29.事务的四大特性
原子性(Atomicity):操作这些指令时,要么全部执行成功,要么全部不执行。只要其中一个指令执行失败,
所有的指令都执行失败,数据进行回滚,回到执行指令前的数据状态。
eg:拿转账来说,假设用户A和用户B两者的钱加起来一共是20000,那么不管A和B之间如何转账,转几次账,
事务结束后两个用户的钱相加起来应该还得是20000,这就是事务的一致性。
● 一致性(Consistency):事务的执行使数据从一个状态转换为另一个状态,但是对于整个数据的完整性
保持稳定。
● 隔离性(Isolation):隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户
开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前
就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
● 持久性(Durability):当事务正确完成后,它对于数据的改变是永久性的。
eg: 例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成
直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全
执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。
30.数据表分表:垂直拆分和水平拆分的实现
一.垂直拆分
专库专用
一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,分布到不同的
数据库上面,这样也就将数据或者说压力分担到不同的库上面,
二.水平拆分
垂直拆分后遇到单机瓶颈,可以使用水平拆分。相对于垂直拆分的区别是:垂直拆分是把不同的表拆到不同的
数据库中,而水平拆分是把同一个表拆到不同的数据库中。
相对于垂直拆分,水平拆分不是将表的数据做分类,而是按照某个字段的某种规则来分散到多个库之中,每个
表中包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中 的某些
行切分到一个数据库,而另外的某些行又切分到其他的数据库中,主要有分表,分库两种模式
31.dubbo服务注册和消费实现
待完善。。。。