1、 讲解一下在项目中你完成的模块和实现什么样的功能?
2、 用户管理模块涉及到哪些表单?权限是跟角色走还是跟用户走?
3、 怎么控制模块权限的校验?是怎样的实现原理?是通过什么方式去拦截?
4、 AOP切面编程是怎样实现的?
AOP切面编程是怎样实现的:方法一:使用自定义注解 1.首先
5、 Dubbo框架的组成部分有哪些?为什么采用Dubbo框架?这种微服务架构与普通的单体架构有什么区别?Dubbo里面有哪些部分?讲一下Dubbo里面的注册中心
zookeeper
6、 用到了redis集群的几种架构?集群方案是怎样做的?缓存里面存了什么东西?缓存如何跟数据库保持同步?
用到了dubbo架构,注册中心zookeeper
7、 JAVA有哪些集合类?都有什么区别?
list:arraylist的数据结构是数组,查询快
LinkedList:数据结构是红黑数,增删快
当数据量较大时,大约在容量的1/10处开始,LinkedList的效率就开始没有ArrayList效率高了,特别到一半以及后半的位置插入时,LinkedList效率明显要低于ArrayList,而且数据量越大,越明显
从源码可以看出,ArrayList想要get(int index)元素时,直接返回index位置上的元素,而LinkedList需要通过for循环进行查找,虽然LinkedList已经在查找方法上做了优化,比如index < size / 2,则从左边开始查找,反之从右边开始查找,但是还是比ArrayList要慢。这点是毋庸置疑的。
ArrayList想要在指定位置插入或删除元素时,主要耗时的是System.arraycopy动作,会移动index后面所有的元素;LinkedList主耗时的是要先通过for循环找到index,然后直接插入或删除。这就导致了两者并非一定谁快谁慢,下面通过一个测试程序来测试一下两者插入的速度:
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/*
* @description 测试ArrayList和LinkedList插入的效率
* @eson_15
*/
public class ArrayOrLinked {
static List<Integer> array=new ArrayList<Integer>();
static List<Integer> linked=new LinkedList<Integer>();
public static void main(String[] args) {
//首先分别给两者插入10000条数据
for(int i=0;i<10000;i++){
array.add(i);
linked.add(i);
}
//获得两者随机访问的时间
System.out.println("array time:"+getTime(array));
System.out.println("linked time:"+getTime(linked));
//获得两者插入数据的时间
System.out.println("array insert time:"+insertTime(array));
System.out.println("linked insert time:"+insertTime(linked));
}
public static long getTime(List<Integer> list){
long time=System.currentTimeMillis();
for(int i = 0; i < 10000; i++){
int index = Collections.binarySearch(list, list.get(i));
if(index != i){
System.out.println("ERROR!");
}
}
return System.currentTimeMillis()-time;
}
//插入数据
public static long insertTime(List<Integer> list){
/*
* 插入的数据量和插入的位置是决定两者性能的主要方面,
* 我们可以通过修改这两个数据,来测试两者的性能
*/
long num = 10000; //表示要插入的数据量
int index = 1000; //表示从哪个位置插入
long time=System.currentTimeMillis();
for(int i = 1; i < num; i++){
list.add(index, i);
}
return System.currentTimeMillis()-time;
}
}
set去重:hashset哈希表
TreeSet:底层实现为二叉树,元素排好序
map:hashMap:1.7数组+链表
1.8版本底层是数据+链表+红黑树(当链表大于8的时候,链表会转换为红黑树),线程不安全,
1.左子树上所有结点的值均小于或等于它的根结点的值。
2.右子树上所有结点的值均大于或等于它的根结点的值。
3.左、右子树也分别为二叉排序树。
TreeMap:红黑树对所有的key进行排序
8、 项目里用到了哪些开源的jar包?
9、 讲解几种设计模式?
单例模式:一个类中只能有一个实例,提供全局访问点
工厂方法模式:定义一个创建对象接口,让子类决定实例化
代理模式:创建一个对象的代理,由代理对象控制对原对象的引用
迭代器模式:提供了很多的遍历方式
原型模式:通过复制现有的实例进行创建新的实例
10、 数据库层面有哪些优化的方式?如果业务数据量比较大,每天要传几百万条数据,怎么处理?
1.数据库创建时的优化
1.表与表之间的业务联系要明确
2.表字段尽量使用数据型
3.属性尽量使用定长
4.建立合理的索引
2.数据库查询时的优化
1.尽量将要输出的字段写出来,不要使用*
2.合理的连表查询
3.查询的时候要注意是否走索引
3.数据库进行读写分离
11、了解哪些前端的技术?
vue,ajax
12 、 springmvc执行流程
第一步:发起请求到前端控制器(DispatcherServlet)
第二步:前端控制器请求HandlerMapping查找 Handler
第三步:处理器映射器HandlerMapping向前端控制器返回Handler
第四步:前端控制器调用处理器适配器去执行Handler
第五步:处理器适配器去执行Handler
第六步:Handler执行完成给适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回ModelAndView
第八步:前端控制器请求视图解析器去进行视图解析,
第九步:视图解析器向前端控制器返回View
第十步:前端控制器进行视图渲染,并向用户响应结果
13、SpringAOP通知方法和切入点
通知方法:
Before:在目标方法执行之前执行
After:在目标方法执行之后执行,不管是否报错
afterReturning:在执行目标方法值后执行
afterThowing:在执行到目标方法异常后执行
Round:环绕通知,在目标方法前后执行
切入点:
Bean:粗粒度 按bean匹配当前bean种的方法都会执行通知
within:粗粒度 可以匹配多个类
execution:细粒度 方法参数级别
annotation:细粒度按注解匹配
14 、Mybatis处理结果集
1.单行结果集映射:接口中方法返回值定义为Map类型,sql语句的resultType属性设置为map即可。这种情况默认把列名作为key,列中的值作为value。
也就是说用map<Strirng,Object>接收,一个map集合对应查询结果所封装的一个对象(一行数据对应一个对象)
2.多行结果集映射:List<Map<String,Object>>接收,存放查询出来的多个对象
如果有一些特殊的情况,比如需要使用id值作为key,把一行数据封装成的对象
15、redis
15.1、redis五个基本类型
:set,string,hash,list,sorted set
15.2、持久化:
RDB:在一段时间间隔进行快照
AOF:记录每次写的操作,服务器重启时会重新执行这段写得操作来恢复数据
15.4、哨兵机制:
Redis sentinel 是一个分布式系统中监控 redis 主从服务器,并在主服务器下线时自动进行故障转移。其中三个特性:
监控(Monitoring):Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作。
特点:
1、保证高可用
2、监控各个节点
3、自动故障迁移
缺陷:写操作无法负载均衡;存储能力受到单机的限制。
15.5、使用过Redis分布式锁么,它是怎么实现的?
先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
15.6、如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?
set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的!
15.7、使用过Redis做异步队列么,你是怎么用的?有什么缺点?
一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。
缺点:
在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。
15.8、能不能生产一次消费多次呢?
使用pub/sub主题订阅者模式,可以实现1:N的消息队列。
15.9、什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?缓存穿透
缓存穿透
一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。
如何避免?
1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。
2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。
缓存击穿
缓存击穿,就是某个热点数据失效时,大量针对这个数据的请求会穿透到数据源。
如何避免?
可以使用互斥锁更新,保证同一个进程中针对同一个数据不会并发请求到 DB,减小 DB 压力。
使用随机退避方式,失效时随机 sleep 一个很短的时间,再次查询,如果失败再执行更新。
针对多个热点 key 同时失效的问题,可以在缓存时使用固定时间加上一个小的随机数,避免大量热点 key 同一时刻失效。
缓存雪崩
当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统崩溃。
如何避免?
使用快速失败的熔断策略,减少 DB 瞬间压力;
使用主从模式和集群模式来尽量保证缓存服务的高可用。
16、Java中的HashMap的工作原理是什么?
Java中的HashMap是以键值对(key-value)的形式存储元素的。HashMap需要一个hash函数,它使用hashCode() 和equals()方法来向集合/从集合添加和检索元素。当调用put()方法的时候,HashMap会计算key的hash值,然后把键值对存储在集合 中合适的索引上。如果key已经存在了,value会被更新成新值。HashMap的一些重要的特性是它的容量(capacity),负载因子(load factor)和扩容极限(threshold resizing)。
17、HashMap和HashTable:
HashMap:1.7版本 底层是数组+链表
1.8版本底层是数据+链表+红黑树(当链表大于8的时候,链表会转换为红黑树),线程不安全,
1.左子树上所有结点的值均小于或等于它的根结点的值。
2.右子树上所有结点的值均大于或等于它的根结点的值。
3.左、右子树也分别为二叉排序树。
2.区别:
* 1.HashMap是线程不安全的,效率高,JDK1.2版本
* Hashtable是线程安全的,效率低,JDK1.0版本
* 2.HashMap可以存储null键和null值
* Hashtable不可以存储null键和null值
3.共同点:都是双列集合,底层都是哈希算法
18、创建线程的三种方法
继承Thread类:定义Thread类的子类,重写run方法
接口Runnable:定义接口实现类,并重写给接口的run方法
callable和Future创建线程
19、元注解
@Target(ElementType.TYPE) 该注解对类有效
@Retention(RetentionPolicy.RUNTIME) 表示运行期有效 整个周期
@Documented 动态生成文档信息
@Inherited 该注解是否允许被继承 允许
20、spring boot(application)的运行机制
SpringBoot就是通过根据配置文件,自动装配所属依赖的类,在用动态代理的方式,注入的spring容器中
21、arrayList和linkedList
ArrayList本质是数组的操作
增删慢:
1.每当插入或删除操作时 对应的需要向前或向后的移动元素
2.当插入元素时 需要判定是否需要扩容操作
扩容操作:创建一个新数组 增加length 再将元素放入进去
较为繁琐
查询快:
数组的访问 实际上是对地址的访问 效率是挺高的
列如 new int arr[5];
arr数组的地址假设为0x1000
arr[0] ~ arr[5] 地址可看作为 0x1000 + i * 4
首地址 + 下标 + 引用数据类型的字节大小
**LinkedList:**通过代价较低的在List中间进行插入和删除操作,**只需要链接新的元素,而不必修改列表中剩余的元素,无论列表尺寸如何变化,其代价大致相同,**提供了优化的顺序访问,随机访问相对较慢,特性较ArrayList更大,而且还添加了可以使其作为栈、队列或双端队列的方法,底层由双向链表实现。
22、SpringMVC
SpringMVC,它是属于Spring基本架构里面的一个组成部分,属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面,所以我们在后期和 Spring 进行整合的时候,几乎不需要别的什么配置。
模型(Model )封装了应用程序的数据和一般他们会组成的POJO。
视图(View)是负责呈现模型数据和一般它生成的HTML输出,客户端的浏览器能够解释。
控制器(Controller )负责处理用户的请求,并建立适当的模型,并把它传递给视图渲染。
23、线程的三种创建方式
23.1、Thread
(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
(2)创建Thread子类的实例,即创建了线程对象。
(3)调用线程对象的start()方法来启动该线程。
23.2、Runnable
(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
(3)调用线程对象的start()方法来启动该线程。
23.3、通过Callable和Future创建线程
(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
23.3、三个方式的对比
23.3.1、采用实现Runnable、Callable接口的方式创见多线程时,优势是:
线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
劣势是:
编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。
23.3.2、使用继承Thread类的方式创建多线程时优势是:
编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。
劣势是:
线程类已经继承了Thread类,所以不能再继承其他父类。
24、spring在ssm中起什么作用:
spring:轻量级框架
bean:Bean工厂,用来管理Bean的生命周期和框架集成;
1、IOC/DI(控制反转/依赖注入) :把dao依赖注入到service层,service层反转给action层,Spring顶层容器为BeanFactory。
2、AOP:面向切面编程
24、spring的事务
25、IOC在项目中的作用?
Ioc解决对象之间的依赖问题,把所有Bean的依赖关系通过配置文件或注解关联起来,降低了耦合度。
26、Spring DI的三个方式?
1.接口注入
2.setter方法注入
3.构造方法注入
27、什么是MyBatis的接口绑定,有什么好处?
接口绑定,就是在 MyBatis 中任意定义接口,然后把接口里面的方法和 SQL 语句绑
定, 我们直接调用接口方法就可以,这样比起原来了 SqlSession 提供的方法我们可
以有更加灵活的选择和设置。
接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加上
@Select、@Update 等注解,里面包含 Sql 语句来绑定;另外一种就是通过 xml
里面写 SQL 来绑定, 在这种情况下,要指定 xml 映射文件里面的 namespace 必须
为接口的全路径名。当 Sql 语句比较简单时候,用注解绑定, 当 SQL 语句比较复杂
时候,用 xml 绑定,一般用 xml 绑定的比较多。
28、Mybatis在核心处理类叫?
SqlSession
29、Mybatis查询表名和返回实体Bean对象不一致,如何处理?
首先:最好把实体类里面的du变量名称和表里面字段写zhi成一致。dao
然后:在SqlMapConfig.xml中 这就是把你shu的实体类写了个别名
最后:在写查询添加的时候:返回实体类对象 select * from tb_game这样查出的结果就对应上数据了。
30、什么是Dubbo框架
Dubbo 是一款高性能、轻量级的开源 Java 服务框架
提供了六大核心能力:面向接口代理的高性能RPC调用,智能容错和负载均衡,服务自动注册和发现,高度可扩展能力,运行期流量调度,可视化的服务治理与运维。
31、zookeeper的执行流程
ZooKeeper的基本运转流程:
1、选举Leader。
2、同步数据。
3、选举Leader过程中算法有很多,但要达到的选举标准是一致的。
4、Leader要具有最高的执行ID,类似root权限。
5、集群中大多数的机器得到响应并接受选出的Leader。
32、Dubbo和springCloud分别的什么协议
Dobbo协议:底层就是http的包装(tcp/ip)
SpringCloud协议:
RestTemplate 方式
Feign 的方式
33、Dubbo框架和springCloud的区别
dubbo支持多种协议,默认使用dubbo协议。
Springcloud只能支持http协议。
dubbo的注册中心zookeeper
SpringCloud的注册中心Eureka
35、面向对象
继承:当多个类具有相同的属性(特征)和方法(方法)时,将相同的部分抽取出来放到一个类中,作为父类,其他类继承这个类,继承后自动拥有父类的属性和方法,父类的私有方法和构造方法不能被继承。子类也可以复写父类的方法,即是重写;子类不能继承父类中private的成员变量和方法;
封装:就是把属性私有化,提供公共方法访问私有对象。
多态:一种定义,多种实现,同一类事务表现出多种形态。在一个类中,允许多个类用同一个方法,参数不同,完成的功能也不同。对象多态:子类对象可以与父类对象进行互相转换,而且根据其使用的子类的不同,完成的功能也不同。
36、servlet的生命周期
调用 init() 方法初始化
调用 service() 方法来处理客户端的请求
调用 destroy() 方法释放资源,标记自身为可回收
被垃圾回收器回收
37、forward和redirect的区别
是servlet种的两种主要的跳转方式。forward又叫转发,redirect叫做重定向。
.1、从地址栏显示来说:forward是服务器内部重定向,
客户端浏览器的网址不会发生变化;redirect发生一个状态码,告诉服务器去重新请求那个网址,显示的的新的网址
2、数据共享:在定向过程中forward使用的是同一个request,可以共享;redirect不可以。
3、应用场景:forward一般用于用户登录:redirect用于用户注销登录返回主页面或者跳转其他页面
4、forward效率更高
5、本质上说:forward转发是服务器上的行为,而redirect是客户端行为
6、次数:forward只有一次,redirect两次
38、数据库主键与外键的区别
关系型数据库中的一条记录中有若干个属性,若其中某一个属性组(注意是组)能唯一标识一条记录,该属性组就可以成为一个主键
.比如
学生表(学号,姓名,性别,班级)
其中每个学生的学号是唯一的,学号就是一个主键
课程表(课程编号,课程名,学分)
其中课程编号是唯一的,课程编号就是一个主键
成绩表(学号,课程号,成绩)
成绩表中单一一个属性无法唯一标识一条记录,学号和课程号的组合才可以唯一标识一条记录,所以 学号和课程号的属性组是一个主键
成绩表中的学号不是成绩表的主键,但它和学生表中的学号相对应,并且学生表中的学号是学生表的主键,则称成绩表中的学号是学生表的外键
同理 成绩表中的课程号是课程表的外键
定义主键和外键主要是为了维护关系数据库的完整性,总结一下:
1.主键是能确定一条记录的唯一标识,比如,一条记录包括身份正号,姓名,年龄。
身份证号是唯一能确定你这个人的,其他都可能有重复,所以,身份证号是主键。
2.外键用于与另一张表的关联。是能确定另一张表记录的字段,用于保持数据的一致性。
比如,A表中的一个字段,是B表的主键,那他就可以是A表的外键。
39、RPC调用
两个服务器,客户端服务器为消费者,服务端服务器为服务者,消费者想要调用他的方法,消费者只需要给他发送一个请求,然后服务器把结果返回给消费者
40、用的数据库
Oracle一般指甲骨文公司
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品
SQLyog 是一个快速而简洁的图形化管理MYSQL数据库的工具
41、数据库的函数
聚合函数:(常用于group by从句的select查询中)
count():统计数目
max():求最大值
min():求最小值
sum():求和
avg():求平均值
select count(*) from emp;#统计记录数
select count(1) from emp;#统计记录数
select count(comm) from emp;#统计非空字段的数目
select sum(sal) from emp;#求和
select max(sal) from emp;#求最大值
select min(sal) from emp;#求最小值
select avg(sal) from emp;#求平均值
分组函数:
经常和聚合函数一起使用
having 表示在分组之后实现检索
在使用分组时,select 后面可以跟聚合函数,分组字段,但其他字段不能写。
注意:有多少个分组就返回多少条记录。
#每个部门平均工资,每个部门返回一个平局值
#select deptno,avg(sal),ename from emp group by deptno;#select后面不能跟ename字段
select deptno,avg(sal) from emp group by deptno;
#注意:条件的执行顺序是从左往后执行
#where必须放在group by之前使用
#where中不能使用聚合函数
#求平均工资大于2000的部门编号和平均工资
select deptno, avg(sal) nsal from emp group by deptno having nsal > 2000;
42、反向代理
反向代理位于用户和应用服务器之间,是连接用户和服务器的中介。于是我们可以
1.缓存,将服务器的响应缓存在自己的内存中,减少服务器的压力。
2.负载均衡,将用户请求分配给多个服务器。
3.访问控制
4.加上一些特殊的东西做特殊的事情(如IPS—入侵防御系统、web应用防火墙等)
43、mybatis与jdbc的区别
mybatis包装了jdbc
44、juqery常用的选择器
类选择器 #
id选择器 .
45、数据库中#与$区别
**#在mybatis是占位符号,可以防止sql注入;KaTeX parse error: Expected 'EOF', got '#' at position 25: …*.下面我们详细说下这个东西:#̲是JDBC预编译一个语句,动态…会直接将参数进行string替换,动态解析的时候直接进行变量替换.一般情况下$来表示数据库对象,例如表明.例如:select * from KaTeX parse error: Expected 'EOF', got '#' at position 25: …me} where name=#̲{};如果表明改成#,编译过后…就会在预编译之前将name的值传给sql,显然这样子做不能防止sql注入.因此,我们在使用# $要根据实际的应用场景来实现.
46、数据库中左连接,右连接,内连接
left join:就是左表中的所有记录与右表中所连接字段相同的字段
right join:就是右边的所有记录与左表中所连接字段相同的字段
inner join:两个表中连接字段相等的行。取交集
47、== 和 equals 的区别是什么
== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。
(基本数据类型包括String == 比较的是值,
引用对象之间 == 比较的是内存地址)
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
String str1 = "Hello";
String str5 = "Hello";
String str2 = new String("Hello");
String str4 = new String("Hello");
String str3 = str2; // 引用传递,同一对象
System.out.println(str1 == str2); // false(str2是new的一个新地址)
System.out.println(str1 == str3); // false(str3和str2内存地址一样,和str1地址不同)
System.out.println(str2 == str3); // true(引用str2,地址相同)
System.out.println(str1 == str5); // true(String作为基本类型,没创建新地址)
System.out.println(str4 == str2); // false(内存地址不同)
System.out.println(str1.equals(str2)); // true(内容一致,都是“hello”)
System.out.println(str1.equals(str3)); // true(内容一致,都是“hello”)
System.out.println(str2.equals(str3)); // true(内容一致,都是“hello”)
System.out.println(str2.equals(str4)); // true(内容一致,都是“hello”)
System.out.println(str1.equals(str5)); // true(内容一致,都是“hello”)
说明:
String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。
当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象。
48、String 是最基本的数据类型吗
不是。Java 中的基本数据类型只有 8 个 :byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type),剩下的都是引用类型(referencetype),Java 5 以后引入的枚举类型也算是一种比较特殊的引用类型。
这是很基础的东西,但是很多初学者却容易忽视,Java 的 8 种基本数据类型中不包括 String,基本数据类型中用来描述文本数据的是 char,但是它只能表示单个字符,比如 ‘a’,‘好’ 之类的,如果要描述一段文本,就需要用多个 char 类型的变量,也就是一个 char 类型数组,比如“你好” 就是长度为2的数组 char[] chars = {‘你’,‘好’};
但是使用数组过于麻烦,所以就有了 String,String 底层就是一个 char 类型的数组,只是使用的时候开发者不需要直接操作底层数组,用更加简便的方式即可完成对字符串的使用。
49、String有哪些特性
不变性:String 是只读字符串,是一个典型的 immutable 对象,对它进行任何操作,其实都是创建一个新的对象,再把引用指向该对象。不变模式的主要作用在于当一个对象需要被多线程共享并频繁访问时,可以保证数据的一致性。
常量池优化:String 对象创建之后,会在字符串常量池中进行缓存,如果下次创建同样的对象时,会直接返回缓存的引用。
final:使用 final 来定义 String 类,表示 String 类不能被继承,提高了系统的安全性。
堆和栈
栈内存:栈内存首先是一个内存区域,存储的都是局部变量,凡是定义在方法中的都是局部变量(方法外部都是全局变量),for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期都很短。
堆内存:存储的是数组和对象(其实数组就是对象),凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的,但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了。堆里的实体虽然不会被释放,但是会被当成垃圾,Java有垃圾回收机制不定时的收取。
nginx的配置
nginx中的nginx.conf
三种负载均衡:轮询
权重 weight
ip-hash
配置后台服务器
server {
listen 80;
server_name manage.jt.com;
location / {
#proxy_pass http://localhost:8091;
proxy_pass http://jtWindows;
}
}
# 配置tomcat服务器集群 1.轮询策略
upstream jtWindows {
server localhost:8080;
server localhost:8081;
server localhost:8082;
}
八大类型的转换
数据类型 | 所占字节 | 数据范围 | 包装类型 |
---|---|---|---|
byte | 1字节 | -128~127 | Byte |
short | 2字节 | -215~215-1 | Short |
int | 4字节 | -231~231-1 | Integer |
long | 8字节 | -263~263-1 | Long |
char | 2字节 | Character | |
float | 4字节 | Float | |
double | 8字节 | Double | |
boolean | Boolean |
- char类型的数据本身是unsigned其数值范围是:0~2^16-1,因此byte和short不能自动类型转换成char(signed:有符号的,unsigned:无符号的)
- 隐式转换也叫自动类型转换(由系统自动完成):
byte -> short (char) -> int -> long -> float -> double 从左到右的数据类型能发生隐式转换
排序方式
冒泡排序
array.sort();
Collections是一个工具类,sort是其中的静态方法,是用来对List类型进行排序的,它有两种参数形式:
参数中 $和#
#{}:
- 预编译
- 编译成占位符
- 可以防止sql注入
- 自动判断数据类型
- 一个参数时,可以使用任意参数名称进行接收
${}:
1 . 非预编译
2、 sql的直接拼接
3、 不能防止sql注入
4、 需要判断数据类型,如果是字符串,需要手动添加引号。
5、 一个参数时,参数名称必须是value,才能接收参数。
常见的前端的技术
SpringCloud常用的组件
1.Eureka注册中心
2.Ribbon负载均衡
3.zuul网关
4.Hystrix 熔断器
5.config配置中心
SpringBoot常用的注解
@SpringBootApplication
自动装配
SpringApplication.run
SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfiguration
数据库中的索引作用
1.通过唯一的索引,可以保证每一行的数据的唯一性
2.大大加快数据的检索速度
取出list,set,map中的数据
创建对象的四种方式
1.new
2.反射
3.反序列化
4.clone
数据库中间件
mycat