知识学习

以下知识点来自网站上各个地方,我对此进行整合,方便学习。谢谢。

1、spring注解

  1. @Controller 标识一个该类是Spring MVC controller处理器,用来创建处理http请求的对象。
  2. @RestController Spring4之后加入的注解,不需要再配置@ResponseBody,默认返回json格式。
  3. @Service 用于标注业务层组件,有一个用注解的方式把这个类注入到spring配置中。
  4. @Autowired 用来装配bean,都可以写在字段上,或者方法上。默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false。
  5. @RequestMapping 类定义处: 提供初步的请求映射信息,相对于 WEB 应用的根目录。方法处: 提供进一步的细分映射信息,相对于类定义处的 URL。
  6. @RequestParam 用于将请求参数区数据映射到功能处理方法的参数上。
  7. @ModelAttribute (1)标记在方法上。标记在方法上,会在每一个@RequestMapping标注的方法前执行,如果有返回值,则自动将该 返回值加入到ModelMap中。
    (2)标记在方法的参数上。标记在方法的参数上,会将客户端传递过来的参数按名称注入到指定对象中,并且会将这个对象自动加入ModelMap中,便于View层使用。
  8. @Resource 作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入。
  9. @PostConstruct 用来标记是在项目启动的时候执行这个方法。用来修饰一个非静态的void()方法,也就是spring容器启动时就执行,多用于一些全局配置、数据字典之类的加载。
  10. @PreDestroy 被@PreDestroy修饰的方法会在服务器卸载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的destroy()方法。
  11. @Repository 用于标注数据访问组件,即DAO组件。
  12. @Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
  13. @Scope 用来配置 spring bean 的作用域,它标识 bean 的作用域。
  14. @SessionAttributes 可以使得模型中的数据存储一份到session域中。
  15. @Qualifier @Qualifier 注释和 @Autowired 注释通过指定哪一个真正的 bean 将会被装配来消除混乱。
  16. @Required 适用于bean属性setter方法,并表示受影响的bean属性必须在XML配置文件在配置时进行填充。否则,容器会抛出一个BeanInitializationException异常。

2、线程和进程的区别

  1. 调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。
  2. 并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行。
  3. 拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。

3、mybatis中#{}和${}的区别

  1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。$将传入的数据直接显示生成在sql中。
  2. #方式能够很大程度防止sql注入。$方式无法防止Sql注入
  3. $方式一般用于传入数据库对象,例如传入表名
  4. MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
  5. 一般能用#就不用$

5、公共锁与分离锁

  1. 公共锁:这种方法确实可以确保同时只能由一个线程来对容器中的同步方法进行操作,但是却不可避免的导致了吞吐量的下降。
  2. 分离锁:分离锁是首先把容器中的数据进行分段,每一段有一把锁,这样整个容器就有多把锁。当多个线程并发访问容器时,每个线程只占有其中一段数据的锁,其它线程可以对其它数据段进行操作,这样就能够提高容器的并发访问效率。

6、concurrentHashMap

  1. ConcurrentHashMap 实例中包含由若干个 Segment 对象组成的数组,一个Sement由若干个HashEntry对象组成的数组。Segment 用来充当锁的角色,每个 Segment 对象守护整个散列映射表的若干个桶,每个桶是由若干个 HashEntry 对象链接起来的链表;HashEntry 用来封装映射表的键 / 值对。
  2. Concurrenthashmap线程安全的,1.7是在jdk1.7中采用Segment + HashEntry的方式进行实现的,lock加在Segment上面。1.7size计算是先采用不加锁的方式,连续计算元素的个数,最多计算3次:1、如果前后两次计算结果相同,则说明计算出来的元素个数是准确的;2、如果前后两次计算结果都不同,则给每个Segment进行加锁,再计算一次元素的个数;
    1.8中放弃了Segment臃肿的设计,取而代之的是采用Node + CAS + Synchronized来保证并发安全进行实现,1.8中使用一个volatile类型的变量baseCount记录元素的个数,当插入新数据或则删除数据时,会通过addCount()方法更新baseCount,通过累加baseCount和CounterCell数组中的数量,即可得到元素的总个数;

7、红黑

http://www.sohu.com/a/201923614_466939

8、线程池

在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁,这就是”池化资源”技术产生的原因。线程池顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。
Java 5+中的Executor接口定义一个执行线程的工具。它的子类型即线程池接口是ExecutorService。要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,因此在工具类Executors面提供了一些静态工厂方法,
生成一些常用的线程池,如下所示:

  • newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
  • newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
  • newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
  • newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

9、Java的堆栈

Java的堆栈:https://jingyan.baidu.com/article/9c69d48f55d75f13c8024e41.html

10、为什么HashMap线程不安全

1、put的时候导致的多线程数据不一致。
这个问题比较好想象,比如有两个线程A和B,首先A希望插入一个key-value对到HashMap中,首先计算记录所要落到的桶的索引坐标,然后获取到该桶里面的链表头结点,此时线程A的时间片用完了,而此时线程B被调度得以执行,和线程A一样执行,只不过线程B成功将记录插到了桶里面,假设线程A插入的记录计算出来的桶索引和线程B要插入的记录计算出来的桶索引是一样的,那么当线程B成功插入之后,线程A再次被调度运行时,它依然持有过期的链表头但是它对此一无所知,以至于它认为它应该这样做,如此一来就覆盖了线程B插入的记录,这样线程B插入的记录就凭空消失了,造成了数据不一致的行为。
2、另外一个比较明显的线程不安全的问题是HashMap的get操作可能因为resize而引起死循环(cpu100%)。
具体分析:https://www.jianshu.com/p/e2f75c8cce01

11、java单例模式-懒汉式与饿汉式(保证线程安全性)

懒汉式:

public static class SingletonOptimizeLazy {
    static SingletonOptimizeLazy instance = null;
    public static SingletonOptimizeLazy getInstance() {
      if (instance == null) {
        createInstance();
      }
      return instance;
    }
    private synchronized static SingletonOptimizeLazy createInstance() {
      if (instance == null) {
        instance = new SingletonOptimizeLazy();
      }
      return instance;
    }
}

饿汉式:

public class SingletonOptimizeHun {

	private static SingletonOptimizeHun instance = new SingletonOptimizeHun();
	
	public static SingletonOptimizeHun getInstance() {
		return instance;
	}
}

12、过滤器filter和拦截器Interceptor的区别

spring的拦截器和servlet的过滤器有相似之处,都是AOP思想的体现,都可以实现权限检查,日志记录,不同的是

  1. 适用范围不同:Filter是Servlet容器规定的,只能使用在servlet容器中,而拦截器的使用范围就大得多
  2. 使用的资源不同:拦截器是属于spring的一个组件,因此可以使用spring的所有资源,对象,如service对象,数据源,事务控制等,而过滤器就不行
  3. 深度不同:Filter还在servlet前后起作用。而拦截器能够深入到方法前后,异常抛出前后,因此拦截器具有更大的弹性,所有在spring框架中应该优先使用拦截器。
    通过调试可以发现,拦截器的执行过程是在过滤器的doFilter中执行的,过滤器的初始化会在项目启动时执行。

13、Java类加载机制

Java类加载分为5个过程,分别为:加载,连接(验证,准备,解析),初始化,使用,卸载。

  1. 加载
    加载主要是将.class文件(也可以是zip包)通过二进制字节流读入到JVM中。 在加载阶段,JVM需要完成3件事:
    1)通过classloader在classpath中获取XXX.class文件,将其以二进制流的形式读入内存。
    2)将字节流所代表的静态存储结构转化为方法区的运行时数据结构;
    3)在内存中生成一个该类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
  2. 连接
    主要确保加载进来的字节流符合JVM规范。验证阶段会完成以下4个阶段的检验动作:
    1)文件格式验证
    2)元数据验证(是否符合Java语言规范)
    3)字节码验证(确定程序语义合法,符合逻辑)
    4)符号引用验证(确保下一步的解析能正常执行)
    2.2. 准备
    准备是连接阶段的第二步,主要为静态变量在方法区分配内存,并设置默认初始值。
    2.3. 解析
    解析是连接阶段的第三步,是虚拟机将常量池内的符号引用替换为直接引用的过程。
  3. 初始化
    初始化阶段是类加载过程的最后一步,主要是根据程序中的赋值语句主动为类变量赋值。
    当有继承关系时,先初始化父类再初始化子类,所以创建一个子类时其实内存中存在两个对象实例。
    注:如果类的继承关系过长,单从类初始化角度考虑,这种设计不太可取。原因我想你已经猜到了。
    通常建议的类继承关系最多不超过三层,即父-子-孙。某些特殊的应用场景中可能会加到4层,但就此打住,第4层已经有代码设计上的弊 端了。
  4. 使用
    程序之间相互调用。
  5. 卸载
    即销毁一个对象,一般情况下中有JVM垃圾回收器完成。代码层面的销毁只是将引用置为null。
    结论:
    (1)父类的静态代码块->子类的静态代码块->初始化父类的属性值/父类的普通代码块(自上而下的顺序排列)->父类的构造方法->初始化子类的属性值/子类的普通代码块(自上而下的顺序排列)->子类的构造方法。
    (2)静态资源在类的初始化中只会执行一次。
    (3)非静态资源会随对象的创建而执行初始化。每创建一个对象,执行一次初始化。
    类加载器:
    (1)启动类加载器(Bootstrap ClassLoader):最顶层的类加载器,负责加载 JAVA_HOME\lib 目录中的,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可(按文件名识别,如rt.jar)的类。
    (2)扩展类加载器(Extension ClassLoader):负责加载 JAVA_HOME\lib\ext 目录中的,或通过java.ext.dirs系统变量指定路径中的类库。
    (3)应用程序类加载器(Application ClassLoader):也叫做系统类加载器,可以通过getSystemClassLoader()获取,负责加载用户路径(classpath)上的类库。如果没有自定义类加载器,一般这个就是默认的类加载器。
    原文:https://www.jianshu.com/p/202f6abb229c

14、IPv4与IPv6的区别

(1)IPv6的地址空间更大。IPv4中规定IP地址长度为32,即有232-1个地址;而IPv6中IP地址的长度为128,即有2128-1个地址。夸张点说就是,如果IPV6被广泛应用以后,全世界的每一粒沙子都会有相对应的一个IP地址。
(2)IPv6的路由表更小。IPv6的地址分配一开始就遵循聚类(Aggregation)的原则,这使得路由器能在路由表中用一条记录(Entry)表示一片子网,大大减小了路由器中路由表的长度,提高了路由器转发数据包的速度。
(3)IPv6的组播支持以及对流的支持增强。这使得网络上的多媒体应用有了长足发展的机会,为服务质量控制提供了良好的网络平台。
(4)IPv6加入了对自动配置的支持。这是对DHCP协议的改进和扩展,使得网络(尤其是局域网)的管理更加方便和快捷。
(5)IPv6具有更高的安全性。在使用IPv6网络中,用户可以对网络层的数据进行加密并对IP报文进行校验,这极大地增强了网络安全。

16、意向锁

解决的问题:如果另一个任务试图在该表级别上应用共享或排它锁,则受到由第一个任务控制的表级别意向锁的阻塞。第二个任务在锁定该表前不必检查各个页或行锁,而只需检查表上的意向锁。

17、Java的程序类型

Java程序的种类有:
(一)内嵌于Web文件中,由浏览器来观看的_Applet
(二)可独立运行的 Application
(三)服务器端的 Servlets

18、hashmap的put和get的过程,以及resize

(一)put函数的思路大致分以下几步
1、对key的hashCode()进行hash后计算数组下标index;
2、如果当前数组table为null,进行resize()初始化;
3、如果没碰撞直接放到对应下标的bucket里;
4、如果碰撞了,且节点已经存在,就替换掉 value;如果碰撞后发现为树结构,挂载到树上。
5、如果碰撞后为链表,添加到链表尾,并判断链表如果过长(大于等于TREEIFY_THRESHOLD,默认8),就把链表转换成树结构;
6、数据 put 后,如果数据量超过容量,就要resize。
(二)resize的过程
数组下标计算: index = (table.length - 1) & hash ,由于 table.length 也就是capacity 肯定是2的N次方,使用 & 位运算意味着只是多了最高位,这样就不用重新计算 index,元素要么在原位置,要么在原位置+ 原来的hash。
(三)get
1、先计算key的hash值,根据这个hash值去数组中找数据
2、如果位置只有一个值,那直接返回。如果多个数,链表:通过.next() 循环获取,知道找到满足条件的key为止。如果大于等于8个,红黑树:直接调用getTreeNode()。

20、Java的动态代理

https://www.jianshu.com/p/95970b089360

21、Bean的生命周期

https://www.jianshu.com/p/ebbb129612ec

22、@RequestBody,@RequestParam的区别

RequestBody:1.@requestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容
2.通过@requestBody可以将请求体中的JSON字符串绑定到相应的bean上,当然,也可以将其分别绑定到对应的字符串上。
3.处理HttpEntity传递过来的数据,一般用来处理非Content-Type: application/x-www-form-urlencoded编码格式的数据。 GET请求中,因为没有HttpEntity,所以@RequestBody并不适用。POST请求中,通过HttpEntity传递的参数,必须要在请求头中声明数据的类型Content-Type,SpringMVC通过使用HandlerAdapter 配置的HttpMessageConverters来解析HttpEntity中的数据,然后绑定到相应的bean上。
RequestParam:1.RequestParam可以接受简单类型的属性,也可以接受对象类型。实质是将Request.getParameter() 中的Key-Value参数Map利用Spring的转化机制ConversionService配置,转化成参数接收对象或字段。
2.在Content-Type: application/x-www-form-urlencoded的请求中,get 方式中queryString的值,和post方式中 body data的值都会被Servlet接受到并转化到Request.getParameter()参数集中,所以@RequestParam可以获取的到。

23、resultMap与resultType的区别

MyBatis的每一个查询映射的返回类型都是ResultMap,只是当我们提供的返回类型属性是resultType的时候,MyBatis对自动的给我们把对应的值赋给resultType所指定对象的属性,而当我们提供的返回类型是resultMap的时候,将数据库中列数据复制到对象的相应属性上,可以用于,column:数据库中列名称,property:类中属性名称。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值