ThreadLocal(线程变量副本) --整理 javascript
Synchronized实现内存共享,ThreadLocal为每一个线程维护一个本地变量。 php
采用空间换时间,它用于线程间的数据隔离,为每个使用该变量的线程提供一个副本,每一个线程均可以独立地改变本身的副本,副本之间不共享数据.而不会和其余线程的副本冲突。 css
ThreadLocal类中维护一个Map,用于存储每个线程的变量副本,Map中元素的键为线程对 象,而值为对应线程的变量副本。 html
ThreadLocal在Spring中发挥着巨大的做用,在管理Request做用域中的Bean、事务管理、任务调度、AOP等模块都出现了它的身影。 java
Spring中绝大部分Bean均可以声明成Singleton做用域,采用ThreadLocal进行封装,所以有状态的Bean就可以以singleton的方式在多线程中正常工做了。web
友情连接:深刻研究java.lang.ThreadLocal类 面试
Java内存模型:算法
Java虚拟机规范中将Java运行时数据分为六种。spring
1.程序计数器:是一个数据结构,用于保存当前正常执行的程序的内存地址 。Java虚拟机的多线程就是经过线程轮流切换并分配处理器时间来实现的,为了线程切换后能恢复到正确的位置,每条线程都须要一个独立的程序计数器 ,互不影响,该区域为“线程私有”。sql
2.Java虚拟机栈:线程私有的,与线程生命周期相同,用于存储局部变量表 ,操做栈,方法返回值 。局部变量表放着基本数据类型 ,还有对象的引用 。
3.本地方法栈:跟虚拟机栈很像,不过它是为虚拟机使用到的Native方法服务 。
4.Java堆:全部线程共享的一块内存区域 ,对象实例几乎都在这分配内存 。
5.方法区:各个线程共享的区域 ,储存虚拟机加载的类信息,常量,静态变量,编译后的代码 。
6.运行时常量池:表明运行时每一个class文件中的常量表。包括几种常量:编译时的数字常量、方法或者域的引用 。
友情连接: Java中JVM虚拟机详解
“你能不能谈谈,java GC是在何时,对什么东西,作了什么事情?”
在何时:
1.新生代有一个Eden区和两个survivor区,首先将对象放入Eden区,若是空间不足就向其中的一个survivor区上放,若是仍然放不下就会引起一次发生在新生代的minor GC ,将存活的对象放入另外一个survivor区中,而后清空Eden和以前的那个survivor区的内存。在某次GC过程当中,若是发现仍然又放不下的对象,就将这些对象放入老年代内存 里去。
2.大对象以及长期存活 的对象直接进入老年区 。
3.当每次执行minor GC的时候应该对要晋升到老年代的对象进行分析,若是这些立刻要到老年区的老年对象的大小超过了老年区的剩余大小 ,那么执行一次Full GC以尽量地得到老年区的空间。
对什么东西:从GC Roots搜索不到,并且通过一次标记清理以后仍没有复活的对象。
作什么: 新生代:复制清理 ; 老年代:标记-清除和标记-压缩算法 ; 永久代:存放Java中的类和加载类的类加载器自己。
GC Roots都有哪些: 1. 虚拟机栈中的引用的对象 2. 方法区中静态属性引用的对象,常量引用的对象 3. 本地方法栈中JNI(即通常说的Native方法)引用的对象 。
友情连接:Java GC的那些事(上)
友情连接:Java GC的那些事(下)
友情连接:CMS垃圾收集器介绍
Synchronized 与Lock都是可重入锁 ,同一个线程再次进入同步代码的时候.可使用本身已经获取到的锁。
Synchronized是悲观锁机制,独占锁。而Locks.ReentrantLock是乐观锁,每次不加锁而是假设没有冲突而去完成某项操做,若是由于冲突失败就重试,直到成功为止。
b) tryLock(), 若是获取了锁当即返回true,若是别的线程正持有锁,当即返回false; c)tryLock(long timeout,TimeUnit unit), 若是获取了锁定当即返回true,若是别的线程正持有锁,会等待参数给定的时间,在等待的过程当中,若是获取了锁定,就返回true,若是等待超时,返回false; ReentrantLock适用场景
某个线程在等待一个锁的控制权的这段时间须要中断
须要分开处理一些wait-notify,ReentrantLock里面的Condition应用,可以控制notify哪一个线程,锁能够绑定多个条件。
具备公平锁功能,每一个到来的线程都将排队等候。
友情连接: Synchronized关键字、Lock,并解释它们之间的区别
StringBuffer是线程安全的,每次操做字符串,String会生成一个新的对象,而StringBuffer不会;StringBuilder是非线程安全的
友情连接:String、StringBuffer与StringBuilder之间区别
fail-fast:机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操做时,就可能会产生fail-fast事件 。 例如:当某一个线程A经过iterator去遍历某集合的过程当中,若该集合的内容被其余线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件
happens-before:若是两个操做之间具备happens-before 关系,那么前一个操做的结果就会对后面一个操做可见。 1.程序顺序规则:一个线程中的每一个操做,happens- before 于该线程中的任意后续操做。 2.监视器锁规则:对一个监视器锁的解锁,happens- before 于随后对这个监视器锁的加锁。 3.volatile变量规则:对一个volatile域的写,happens- before于任意后续对这个volatile域的读。 4.传递性:若是A happens- before B,且B happens- before C,那么A happens- before C。 5.线程启动规则:Thread对象的start()方法happens- before于此线程的每个动做。
Volatile和Synchronized四个不一样点: 1 粒度不一样,前者针对变量 ,后者锁对象和类 2 syn阻塞,volatile线程不阻塞 3 syn保证三大特性,volatile不保证原子性 4 syn编译器优化,volatile不优化 volatile具有两种特性: 1. 保证此变量对全部线程的可见性,指一条线程修改了这个变量的值,新值对于其余线程来讲是可见的,但并非多线程安全的。 2. 禁止指令重排序优化。 Volatile如何保证内存可见性: 1.当写一个volatile变量时 ,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。 2.当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。
同步:就是一个任务的完成须要依赖另一个任务,只有等待被依赖的任务完成后,依赖任务才能完成。 异步:不须要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工做,只要本身任务完成了就算完成了,被依赖的任务是否完成会通知回来。(异步的特色就是通知)。 打电话和发短信来比喻同步和异步操做。 阻塞:CPU停下来等一个慢的操做完成之后,才会接着完成其余的工做。 非阻塞:非阻塞就是在这个慢的执行时,CPU去作其余工做,等这个慢的完成后,CPU才会接着完成后续的操做。 非阻塞会形成线程切换增长,增长CPU的使用时间能不能补偿系统的切换成本须要考虑。
友情连接:Java并发编程之volatile关键字解析
CAS(Compare And Swap) 无锁算法: CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知此次竞争中失败,并能够再次尝试 。 CAS有3个操做数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改成B ,不然什么都不作。
友情连接:非阻塞同步算法与CAS(Compare and Swap)无锁算法
线程池的做用: 在程序启动的时候就建立若干线程来响应处理 ,它们被称为线程池,里面的线程叫工做线程 第一:下降资源消耗。经过重复利用已建立的线程下降线程建立和销毁形成的消耗。 第二:提升响应速度。当任务到达时,任务能够不须要等到e线程建立就能当即执行。 第三:提升线程的可管理性。 经常使用线程池:ExecutorService 是主要的实现类,其中经常使用的有 Executors.newSingleThreadPool(),newFixedThreadPool(),newcachedTheadPool(),newScheduledThreadPool()。
友情连接:线程池原理
友情连接:线程池原理解析
类加载器工做机制: 1.加载:将Java二进制代码导入jvm中,生成Class文件。 2.链接:a)校验:检查载入Class文件数据的正确性 (检查数据结构)b)准备:给类的静态变量分配存储空间 c)解析:将符号引用转成直接引用 (java类并不知道所引用的类的实际地址,所以只能使用符号引用来代替 )3:初始化:对类的静态变量,静态方法和静态代码块执行初始化工做。
双亲委派模型 :类加载器收到类加载请求,首先将请求委派给父类加载器完成 确保类的惟一性 用户自定义加载器->应用程序加载器-appClassLoad用于加载自定义类的加载器 >扩展类加载器-extClassLoad用于加载:%JDK%/jre/lib/ext目录下的第三方jar包中的类 >启动类加载器bootstrapclassload 根类加载器:打印:null。用于加载Java类库中的类 。
友情连接:深刻理解Java虚拟机笔记—双亲委派模型
友情连接:JVM类加载的那些事
友情连接:JVM(1):Java 类的加载机制
一致性哈希:
Memcahed缓存: 数据结构:key,value对 使用方法:get,put等方法
友情连接:hashcode(),equal()方法深刻解析
Redis数据结构: String—字符串(key-value 类型) Hash—字典(hashmap) Redis的哈希结构能够使你像在数据库中更新一个属性同样只修改某一项属性值 List—列表 实现消息队列 Set—集合 利用惟一性 Zset Sorted Set—有序集合 能够进行排序 能够实现数据持久化
友情连接: Spring + Redis 实现数据的缓存
java自动装箱拆箱深刻剖析
谈谈Java反射机制
如何写一个不可变类?
要建立不可变类,要实现下面几个步骤:
将类声明为final,因此它不能被继承
将全部的成员声明为私有的 ,这样就不容许直接访问这些成员
对变量不要提供setter方法
将全部可变的成员声明为final,这样只能对它们赋值一次
经过构造器初始化全部成员,进行深拷贝(deep copy)
在getter方法中,不要直接返回对象自己,而是克隆对象,并返回对象的拷贝
索引:B+,B-,全文索引 Mysql的索引是一个数据结构,旨在使数据库高效的查找数据。 经常使用的数据结构是B+Tree ,每一个叶子节点不但存放了索引键的相关信息还增长了指向相邻叶子节点的指针,这样就造成了带有顺序访问指针的B+Tree ,作这个优化的目的是提升不一样区间访问的性能。 何时使用索引: 1. 常常出如今group by,order by和distinc关键字后面的字段 2. 常常与其余表进行链接的表,在链接字段上应该创建索引 3. 常常出如今Where子句中的字段 4. 常常出现用做查询选择的字段
友情连接:MySQL:InnoDB存储引擎的B+树索引算法
友情连接:MySQL索引背后的数据结构及算法原理
Spring IOC (控制反转,依赖注入)
Spring支持三种依赖注入方式,分别是属性(Setter方法)注入,构造注入和对象注入。
在Spring中,那些组成应用的主体及由Spring IOC容器所管理的对象被称之为Bean 。
Spring的IOC容器经过反射的机制实例化Bean并创建Bean之间的依赖关系 。 简单地讲,Bean就是由Spring IOC容器初始化、装配及被管理的对象 。 获取Bean对象的过程,首先经过Resource加载配置文件并启动IOC容器,而后经过getBean方法获取bean对象,就能够调用他的方法。 Spring Bean的做用域: Singleton:Spring IOC容器中只有一个共享的Bean实例,通常都是Singleton做用域。 Prototype:每个请求,会产生一个新的Bean实例。 Request:每一次http请求会产生一个新的Bean实例。
友情连接: Spring框架IOC容器和AOP解析
友情连接:浅谈Spring框架注解的用法分析
友情连接:关于Spring的69个面试问答——终极列表
- 导航条 - 首页 全部文章 资讯 Web 架构 基础技术 书籍 教程 Java小组 工具资源
这篇文章总结了一些关于Spring框架的重要问题,这些问题都是你在面试或笔试过程当中可能会被问到的。下次你不再用担忧你的面试了,Java Code Geeks这就帮你解答。
大多数你可能被问到的问题都列举在下面的列表中了。全部的核心模块,从基础的Spring功能(如Spring Beans)到上层的Spring MVC框架,文章中都会进行简短的讲解。看完这些面试问题,你应该看看咱们的Spring教程 。
咱们开始吧!
目录
Spring概述
依赖注入
Spring Beans
Spring注解
Spring的对象访问
Spring面向切面编程
Spring MVC框架
Spring概述
1.什么是Spring?
Spring是一个开源的Java EE开发框架。Spring框架的核心功能能够应用在任何Java应用程序中,但对Java EE平台上的Web应用程序有更好的扩展性。Spring框架的目标是使得Java EE应用程序的开发更加简捷,经过使用POJO为基础的编程模型促进良好的编程风格。
2.Spring有哪些优势?
轻量级: Spring在大小和透明性方面绝对属于轻量级的,基础版本的Spring框架大约只有2MB。
控制反转(IOC): Spring使用控制反转技术 实现了松耦合。依赖被注入到对象,而不是建立或寻找依赖对象。
面向切面编程(AOP): Spring支持面向切面编程 ,同时把应用的业务逻辑与系统的服务分离开来。
容器:Spring包含并管理应用程序对象的配置及生命周期 。
MVC框架:Spring的web框架是一个设计优良的web MVC框架 ,很好的取代了一些web框架 。
事务管理: Spring对下至本地业务上至全局业务(JAT)提供了统一的事务管理接口 。
异常处理: Spring提供一个方便的API将特定技术的异常(由JDBC, Hibernate, 或JDO抛出)转化为一致的、Unchecked异常。
代理的共有优势:业务类只须要关注业务逻辑自己,保证了业务类的重用性 。 Java静态代理 : 代理对象和目标对象实现了相同的接口,目标对象做为代理对象的一个属性,具体接口实现中,代理对象能够在调用目标对象相应方法先后加上其余业务处理逻辑 。 缺点:一个代理类只能代理一个业务类。若是业务类增长方法时,相应的代理类也要增长方法 。 Java动态代理: Java动态代理是写一个类实现InvocationHandler接口,重写Invoke方法,在Invoke方法能够进行加强处理的逻辑的编写,这个公共代理类在运行的时候才能明确本身要代理的对象,同时能够实现该被代理类的方法的实现,而后在实现类方法的时候能够进行加强处理。 实际上:代理对象的方法 = 加强处理 + 被代理对象的方法
JDK和CGLIB生成动态代理类的区别: JDK动态代理只能针对实现了接口的类生成代理 (实例化一个类)。此时代理对象和目标对象实现了相同的接口,目标对象做为代理对象的一个属性,具体接口实现中,能够在调用目标对象相应方法先后加上其余业务处理逻辑 CGLIB是针对类实现代理 ,主要是对指定的类生成一个子类(没有实例化一个类),覆盖其中的方法 。 Spring AOP应用场景 性能检测 ,访问控制,日志管理,事务等 。 默认的策略是若是目标类实现接口,则使用JDK动态代理技术,若是目标对象没有实现接口,则默认会采用CGLIB代理
SpringMVC运行原理 1. 客户端请求提交到DispatcherServlet 2. 由DispatcherServlet控制器查询HandlerMapping,找到并分发到指定的Controller中。 4. Controller调用业务逻辑处理后,返回ModelAndView 5. DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图 6. 视图负责将结果显示到客户端
友情连接:Spring:基于注解的Spring MVC(上)
友情连接: Spring:基于注解的Spring MVC(下)
友情连接:SpringMVC与Struts2区别与比较总结
友情连接:SpringMVC与Struts2的对比
一个Http请求 DNS域名解析 –> 发起TCP的三次握手 –> 创建TCP链接后发起http请求 –> 服务器响应http请求,浏览器获得html代码 –> 浏览器解析html代码,并请求html代码中的资源(如javascript、css、图片等) –> 浏览器对页面进行渲染呈现给用户
设计存储海量数据的存储系统:设计一个叫“中间层”的一个逻辑层,在这个层,将数据库的海量数据抓出来,作成缓存,运行在服务器的内存中,同理,当有新的数据到来,也先作成缓存,再想办法,持久化到数据库中,这是一个简单的思路。主要的步骤是负载均衡,将不一样用户的请求分发到不一样的处理节点上,而后先存入缓存,定时向主数据库更新数据。读写的过程采用相似乐观锁的机制,能够一直读(在写数据的时候也能够),可是每次读的时候会有个版本的标记,若是本次读的版本低于缓存的版本,会从新读数据,这样的状况并很少,能够忍受。
友情连接: HTTP与HTTPS的区别
友情连接: HTTPS 为何更安全,先看这些
友情连接: HTTP请求报文和HTTP响应报文
友情连接: HTTP 请求方式: GET和POST的比较
什么是HTTP?
超文本传输协议(HyperText Transfer Protocol -- HTTP)是一个设计来使客户端和服务器顺利进行通信的协议。
HTTP在客户端和服务器之间以request-response protocol(请求-回复协议)工做。
GET - 从指定的服务器中获取数据
POST - 提交数据给指定的服务器处理
GET方法:
使用GET方法时,查询字符串(键值对)被附加在URL地址后面一块儿发送到服务器:
/test/demo_form.jsp?name1=value1&name2=value2
特色:
GET请求可以被缓存
GET请求会保存在浏览器的浏览记录中
以GET请求的URL可以保存为浏览器书签
GET请求有长度限制
GET请求主要用以获取数据
POST方法:
使用POST方法时,查询字符串在POST信息中单独存在,和HTTP请求一块儿发送到服务器:
POST /test/demo_form.jsp HTTP/1.1
Host: w3schools.com
name1=value1&name2=value2
特色:
POST请求不能被缓存下来
POST请求不会保存在浏览器浏览记录中
以POST请求的URL没法保存为浏览器书签
POST请求没有长度限制
GET和POST的区别:
GET
POST
点击返回/刷新按钮
没有影响
数据会从新发送(浏览器将会提示用户“数据被重新提交”)
添加书签
能够
不能够
缓存
能够
不能够
编码类型(Encoding type)
application/x-www-form-urlencoded
application/x-www-form-urlencoded or multipart/form-data. 请为二进制数据使用multipart编码
历史记录
有
没有
长度限制
有
没有
数据类型限制
只容许ASCII字符类型
没有限制。容许二进制数据
安全性
查询字符串会显示在地址栏的URL中,不安全,请不要使用GET请求提交敏感数据
由于数据不会显示在地址栏中,也不会缓存下来或保存在浏览记录中,因此看POST求情比GET请求安全,但也不是最安全的方式。如须要传送敏感数据,请使用加密方式传输
可见性
查询字符串显示在地址栏的URL中,可见
查询字符串不会显示在地址栏中,不可见
其余HTTP请求方式
方式
描述
HEAD
与GET请求相似,不一样在与服务器只返回HTTP头部信息,没有页面内容
PUT
上传指定URL的描述
DELETE
删除指定资源
OPTIONS
返回服务器支持的HTTP方法
CONNECT
转换为透明TCP/IP隧道的链接请求
Session与Cookie:Cookie可让服务端跟踪每一个客户端的访问,可是每次客户端的访问都必须传回这些Cookie,若是Cookie不少,则无形的增长了客户端与服务端的数据传输量, 而Session则很好地解决了这个问题,同一个客户端每次和服务端交互时,将数据存储经过Session到服务端,不须要每次都传回全部的Cookie值,而是传回一个ID,每一个客户端第一次访问服务器生成的惟一的ID,客户端只要传回这个ID就好了,这个ID一般为NAME为JSESSIONID的一个Cookie。这样服务端就能够经过这个ID,来将存储到服务端的KV值取出了。 Session和Cookie的超时问题,Cookie的安全问题
分布式Session框架 1. 配置服务器,Zookeeper集群管理服务器能够统一管理全部服务器的配置文件 2. 共享这些Session存储在一个分布式缓存中 ,能够随时写入和读取,并且性能要很好,如Memcache ,Tair。 3. 封装一个类继承自HttpSession,将Session存入到这个类中而后再存入分布式缓存中 4. 因为Cookie不能跨域访问,要实现Session同步,要同步SessionID写到不一样域名下。
适配器模式 :将一个接口适配到另外一个接口 ,Java I/O中InputStreamReader将Reader类适配到InputStream,从而实现了字节流到字符流的准换。 装饰者模式 :保持原来的接口,加强原来有的功能。 FileInputStream 实现了InputStream的全部接口,BufferedInputStreams继承自FileInputStream是具体的装饰器实现者,将InputStream读取的内容保存在内存中,而提升读取的性能。
Spring事务配置方法: 1. 切点信息,用于定位实施事物切面的业务类方法 2. 控制事务行为的事务属性,这些属性包括事物隔离级别,事务传播行为,超时时间,回滚规则 。 Spring经过aop/tx Schema 命名空间和@Transaction注解技术来进行声明式事物配置 。
Mybatis 每个Mybatis的应用程序都以一个SqlSessionFactory对象的实例为核心。首先用字节流经过Resource将配置文件读入,而后经过SqlSessionFactoryBuilder().build方法建立SqlSessionFactory,而后再经过SqlSessionFactory.openSession()方法建立一个SqlSession为每个数据库事务服务。 经历了Mybatis初始化 –>建立SqlSession –>运行SQL语句,返回结果三个过程
Servlet和Filter的区别: 整个流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
Filter有以下几个用处: Filter能够进行对特定的url请求和相应作预处理和后处理。 在HttpServletRequest到达Servlet以前,拦截客户的HttpServletRequest 。 根据须要检查HttpServletRequest,也能够修改HttpServletRequest头和数据。 在HttpServletResponse到达客户端以前,拦截HttpServletResponse。 根据须要检查HttpServletResponse,也能够修改HttpServletResponse头和数据。
实际上Filter和Servlet极其类似,区别只是Filter不能直接对用户生成响应。实际上Filter里doFilter()方法里的代码就是从多个Servlet的service()方法里抽取的通用代码,经过使用Filter能够实现更好的复用。
Filter和Servlet的生命周期: 1.Filter在web服务器启动时初始化 2.若是某个Servlet在web.xml配置了 1 ,(配置<load onstartup>)该Servlet也是在Tomcat(Servlet容器)启动时初始化 。 3.若是Servlet没有配置1 ,该Servlet不会在Tomcat启动时初始化,而是在 请求到来时初始化。 4.每次请求, Request都会被初始化,响应请求后,请求被销毁。 每次请求都会调用 servlet 单带service()方法 5.Servlet初始化后,将不会随着请求的结束而注销。 6.关闭Tomcat时,Servlet、Filter依次被注销。
HashMap与HashTable的区别。 一、HashMap是非线程安全的,HashTable是线程安全的。 二、HashMap的键和值都容许有null值存在,而HashTable则不行。 三、由于线程安全的问题,HashMap效率比HashTable的要高。
HashMap的实现机制: 1. 维护一个每一个元素是一个链表的数组,并且链表中的每一个节点是一个Entry[]键值对的数据结构。 2. 实现了数组+链表的特性,查找快,插入删除也快。 3. 对于每一个key,他对应的数组索引下标是 int i = hash(key.hashcode)&(len-1); 4. 每一个新加入的节点放在链表首,而后该新加入的节点指向原链表首 扩容2倍扩容 在插入元素后判断元素是否已经到达容量的,若是到达了就进行扩容,可是颇有可能扩容以后没有新元素插入,这时HashMap就进行了一次无效的扩容。
containsKey 和 containsvalue
containskey 能够用于统计文本中 某个字符串的个数.
面试题: hashMap是怎样实现key-value这样键值对的保存?
HashMap中有一个内部类Entry ,
1
2
3
4
5
6
7
static
class
Entry<k,v>
implements
Map.Entry<k,v> {
final
K key;
V value;
Entry<k,v> next;
int
hash;
}</k,v></k,v></k,v>
主要有4个属性,key ,hash,value,指向下一个节点的引用next ,看到这个实体类就明白了,在HashMap中存放的key-value实质是经过实体类Entry来保存的
面试题: hashMap的实现原理?
HashMap使用到的数据类型主要就是数组和链表,首先看原理图
在hashMap的原理图中,左边是经过数组来存放链表的第一个节点,看懂这个图这个问题就ok
面试题: hashMap的put过程?
面咱们提到过Entry类里面有一个next属性,做用是指向下一个Entry。好比说: 第一个键值对A进来,经过计算其key的hash获得的index=0,记作:Entry[0] = A。一会后又进来一个键值对B,经过计算其index也等于0,如今怎么办?HashMap会这样作:B.next = A,Entry[0] = B,若是又进来C,index也等于0,那么C.next = B,Entry[0] = C;这样咱们发现index=0的地方其实存取了A,B,C三个键值对,他们经过next这个属性连接在一块儿。 也就是说数组中存储的是最后插入的元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public
V put(K key, V value) {
if
(key ==
null
)
return
putForNullKey(value);
int
hash = hash(key);
int
i = indexFor(hash, table.length);
for
(Entry<k,v> e = table[i]; e !=
null
; e = e.next) {
Object k;
if
(e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(
this
);
return
oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return
null
;
}</k,v>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void
addEntry(
int
hash, K key, V value,
int
bucketIndex) {
if
((size >= threshold) && (
null
!= table[bucketIndex])) {
resize(
2
* table.length);
hash = (
null
!= key) ? hash(key) :
0
;
bucketIndex = indexFor(hash, table.length);
}
createEntry(hash, key, value, bucketIndex);
}
void
createEntry(
int
hash, K key, V value,
int
bucketIndex) {
Entry<k,v> e = table[bucketIndex];
table[bucketIndex] =
new
Entry<>(hash, key, value, e);
size++;
}</k,v>
面试题: hashMap的get过程? 这个过程比较简单,直接看代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public
V get(Object key) {
if
(key ==
null
)
return
getForNullKey();
int
hash = hash(key.hashCode());
for
(Entry<k,v> e = table[indexFor(hash, table.length)];
e !=
null
;
e = e.next) {
Object k;
if
(e.hash == hash && ((k = e.key) == key || key.equals(k)))
return
e.value;
}
return
null
;
}</k,v>
HashMap其实就是一个Entry数组,Entry对象中包含了键和值,其中next也是一个Entry对象 ,它就是用来处理hash冲突的,造成一个链表。
HashMap的底层主要是基于数组和链表来实现的,它之因此有至关快的查询速度主要是由于它是经过计算散列码来决定存储的位置。HashMap中主要是经过key的hashCode来计算hash值的,只要hashCode相]同,计算出来的hash值就同样。若是存储的对象对多了,就有可能不一样的对象所算出来的hash值是相同的,这就出现了所谓的hash冲突。学过数据结构的同窗都知道,解决hash冲突的方法有不少,HashMap底层是经过链表来解决hash冲突的。
图中,紫色部分即表明哈希表,也称为哈希数组,数组的每一个元素都是一个单链表的头节点,链表是用来解决冲突的,若是不一样的key映射到了数组的同一位置处,就将其放入单链表中。
保证hashmap线程安全
方法一:
优势:代码实现十分简单,一看就懂.
缺点:从锁的角度来看,方法一直接使用了锁住方法,基本上是锁住了尽量大的代码块.性能会比较差.
方法二:
优势:须要互斥的代码段比较少,性能会比较好. ConcurrentHashMap把整个Map切分红了多个块,发生锁碰撞的概率大大下降,性能会比较好.
缺点:代码实现稍稍复杂些.
HashMap和TreeMap区别
友情连接: Java中HashMap和TreeMap的区别深刻理解
HashMap冲突
友情连接: HashMap冲突的解决方法以及原理分析
友情连接: HashMap的工做原理
友情连接: HashMap和Hashtable的区别
友情连接: 2种办法让HashMap线程安全
HashMap,ConcurrentHashMap与LinkedHashMap的区别
ConcurrentHashMap是使用了锁分段技术技术来保证线程安全的 ,锁分段技术:首先将数据分红一段一段的存储 ,而后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其余段的数据也能被其余线程访问(其余线程也能够分别对每段进行访问)
ConcurrentHashMap 是在每一个段(segment)中线程安全的
LinkedHashMap维护一个双链表,能够将里面的数据按写入的顺序读出
ConcurrentHashMap应用场景
1:ConcurrentHashMap的应用场景是高并发 ,可是并不能保证线程安全,而同步的HashMap的是锁住整个容器 ,而加锁以后ConcurrentHashMap不须要锁住整个容器,只须要锁住对应的Segment就行了,因此能够保证高并发同步访问,提高了效率 。
2:能够多线程写。 ConcurrentHashMap把HashMap分红若干个Segmenet 1.get时,不加锁,先定位到segment而后在找到头结点进行读取操做 。而value是volatile变量 ,因此能够保证在竞争条件时保证读取最新的值,若是读到的value是null,则可能正在修改,那么就调用ReadValueUnderLock函数,加锁保证读到的数据是正确的。 2.Put时会加锁,一概添加到hash链的头部 。 3.Remove时也会加锁,因为next是final类型不可改变,因此必须把删除的节点以前的节点都复制一遍。 4.ConcurrentHashMap容许多个修改操做并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对Hash表的不一样Segment进行的修改。
ConcurrentHashMap可以保证每一次调用都是原子操做,可是并不保证屡次调用之间也是原子操做。
友情连接:Java集合—ConcurrentHashMap原理分析
Vector和ArrayList的区别
友情连接:Java中Vector和ArrayList的区别
ExecutorService service = Executors…. ExecutorService service = new ThreadPoolExecutor() ExecutorService service = new ScheduledThreadPoolExecutor();
ThreadPoolExecutor源码分析
线程池自己的状态:
等待任务队列和工做集: 正在被执行的hashset集合 等待被执行的是 阻塞队列
线程池的主要状态锁:
线程池的存活时间和大小:
1.2 ThreadPoolExecutor 的内部工做原理 有了以上定义好的数据,下面来看看内部是如何实现的 。 Doug Lea 的整个思路总结起来就是 5 句话: 1. 若是当前池大小 poolSize 小于 corePoolSize ,则建立新线程执行任务。 2. 若是当前池大小 poolSize 大于 corePoolSize ,且等待队列未满,则进入等待队列 3. 若是当前池大小 poolSize 大于 corePoolSize 且小于 maximumPoolSize ,且等待队列已满,则建立新线程执行任务。 4. 若是当前池大小 poolSize 大于 corePoolSize 且大于 maximumPoolSize ,且等待队列已满,则调用拒绝策略来处理该任务。 5. 线程池里的每一个线程执行完任务后不会马上退出,而是会去检查下等待队列里是否还有线程任务须要执行,若是在 keepAliveTime 里等不到新的任务了,那么线程就会退出。
Executor包结构
CopyOnWriteArrayList : 写时加锁,当添加一个元素的时候,将原来的容器进行copy,复制出一个新的容器,而后在新的容器里面写,写完以后再将原容器的引用指向新的容器,而读的时候是读旧容器的数据,因此能够进行并发的读,但这是一种弱一致性的策略。 使用场景:CopyOnWriteArrayList适合使用在读操做远远大于写操做的场景里,好比缓存。
Linux经常使用命令:cd,cp,mv,rm,ps(进程),tar,cat(查看内容),chmod,vim,find,ls
死锁的必要条件 1. 互斥 至少有一个资源处于非共享状态 2. 占有并等待 3. 非抢占 4. 循环等待 解决死锁,第一个是死锁预防,就是不让上面的四个条件同时成立。二是,合理分配资源。 三是使用银行家算法,若是该进程请求的资源操做系统剩余量能够知足,那么就分配。
进程间的通讯方式
管道( pipe ) :管道是一种半双工的通讯方式,数据只能单向流动,并且只能在具备亲缘关系的进程间使用 。进程的亲缘关系一般是指父子进程关系 。
有名管道 (named pipe) : 有名管道也是半双工的通讯方式,可是它容许无亲缘关系进程间的通讯。
信号量( semophore ) : 信号量是一个计数器,能够用来控制多个进程对共享资源的访问。它常做为一种锁机制,防止某进程正在访问共享资源时,其余进程也访问该资源。所以,主要做为进程间以及同一进程内不一样线程之间的同步手段。
消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识 。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
信号 ( sinal ) : 信号是一种比较复杂的通讯方式,用于通知接收进程某个事件已经发生。
共享内存( shared memory ) :共享内存就是映射一段能被其余进程所访问的内存,这段共享内存由一个进程建立,但多个进程均可以访问 。共享内存是最快的 IPC 方式,它是针对其余进程间通讯方式运行效率低而专门设计的。它每每与其余通讯机制,如信号量,配合使用,来实现进程间的同步和通讯。
套接字( socket ) : 套解口也是一种进程间通讯机制,与其余通讯机制不一样的是 ,它可用于不一样机器间的进程通讯。
进程与线程的区别和联系
进程概念
进程是表示资源分配的基本单位,又是调度运行的基本单位 。例如,用户运行本身的程序,系统就建立一个进程,并为它分配资源,包括各类表格、内存空间、磁盘空间、(读写)I/O设备等.
线程概念
线程是进程中执行运算的最小单位,亦即CPU执行处理机调度的基本单位 。若是把进程理解为在逻辑上操做系统所完成的任务,那么线程表示完成该任务的许多可能的子任务之一。例如,假设用户启动了一个窗口中的数据库应用程序,操做系统就将对数据库的调用表示为一个进程 。假设用户要从数据库中产生一份工资单报表,并传到一个文件中,这是一个子任务;在产生工资单报表的过程当中,用户又能够输人数据库查询请求,这又是一个子任务 。这样,操做系统则把每个请求――工资单报表和新输人的数据查询表示为数据库进程中的独立的线程。线程能够在处理器上独立调度执行,这样,在多处理器环境下就容许几个线程各自在单独处理器上进行
引入线程的好处
(1)易于调度 。
(2)提升并发性。经过线程可方便有效地实现并发性。进程可建立多个线程来执行同一程序的不一样部分 。
(3)开销少。建立线程比建立进程要快,所需开销不多 。。
(4)利于充分发挥多处理器的功能。经过建立多线程进程(即一个进程可具备两个或更多个线程),每一个线程在一个处理器上运行,从而实现应用程序的并发性,使每一个处理器都获得充分运行 。(例如多核CPU)
进程和线程的关系
(1)一个线程只能属于一个进程,而一个进程能够有多个线程 ,但至少有一个线程。线程是操做系统可识别的最小执行和调度单位。
(2)资源分配给进程,同一进程的全部线程共享该进程的全部资源 。 同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)。可是每一个线程拥有本身的栈段,栈段又叫运行时段,用来存放全部局部变量和临时变量。
(3)处理机分给线程 ,即真正在处理机上运行的是线程。
(4)线程在执行过程当中,须要协做同步。不一样进程的线程间要利用消息通讯的办法实现同步。
线程与进程的比较
线程具备许多传统进程所具备的特征,故又称为轻型进程(Light—Weight Process)或进程元;而把传统的进程称为重型进程(Heavy—Weight Process),它至关于只有一个线程的任务。在引入了线程的操做系统中,一般一个进程都有若干个线程,至少须要一个线程。下面,咱们从调度、并发性、 系统开销、拥有资源等方面,来比较线程与进程。
1.调度
在传统的操做系统中,拥有资源的基本单位和独立调度、分派的基本单位都是进程。而在引入线程的操做系统中,则把线程做为调度和分派的基本单位。而把进程做 为资源拥有的基本单位,使传统进程的两个属性分开,线程便能轻装运行,从而可显著地提升系统的并发程度。在同一进程中,线程的切换不会引发进程的切换,在 由一个进程中的线程切换到另外一个进程中的线程时,将会引发进程的切换。
2.并发性
在引入线程的操做系统中,不只进程之间能够并发执行,并且在一个进程中的多个线程之间,亦可并发执行,于是使操做系统具备更好的并发性,从而能更有效地使 用系统资源和提升系统吞吐量。例如,在一个未引入线程的单CPU操做系统中,若仅设置一个文件服务进程,当它因为某种缘由而被阻塞时,便没有其它的文件服 务进程来提供服务。在引入了线程的操做系统中,能够在一个文件服务进程中,设置多个服务线程,当第一个线程等待时,文件服务进程中的第二个线程能够继续运 行;当第二个线程阻塞时,第三个线程能够继续执行,从而显著地提升了文件服务的质量以及系统吞吐量。
3.拥有资源
不管是传统的操做系统,仍是设有线程的操做系统,进程都是拥有资源的一个独立单位,它能够拥有本身的资源。通常地说,线程本身不拥有系统资源(也有一点必 不可少的资源),但它能够访问其隶属进程的资源。亦即,一个进程的代码段、数据段以及系统资源,如已打开的文件、I/O设备等,可供问一进程的其它全部线 程共享。
4.系统开销
因为在建立或撤消进程时,系统都要为之分配或回收资源,如内存空间、I/o设备等。所以,操做系统所付出的开销将显著地大于在建立或撤消线程时的开销。类 似地,在进行进程切换时,涉及到整个当前进程CPU环境的保存以及新被调度运行的进程的CPU环境的设置。而线程切换只须保存和设置少许寄存器的内容,并 不涉及存储器管理方面的操做。可见,进程切换的开销也远大于线程切换的开销。此外,因为同一进程中的多个线程具备相同的地址空间,导致它们之间的同步和通讯的实现,也变得比较容易。在有的系统中,线程的切换、同步和通讯都无须
操做系统的进程调度算法
计算机系统的层次存储结构详解
数据库事务是指做为单个逻辑工做单元执行的一系列操做。
友情连接:数据库事务的四大特性以及事务的隔离级别
MySQL数据库优化总结
MYSQL 优化经常使用方法
MySQL存储引擎--MyISAM与InnoDB区别
关于SQL数据库中的范式
◆ 第一范式(1NF):强调的是列的原子性,即列不可以再分红其余几列 。
◆ 第二范式(2NF):首先是 1NF,另外包含两部份内容,一是表必须有一个主键;二是没有包含在主键中的列必须彻底依赖于主键,而不能只依赖于主键的一部分。
◆ 第三范式(3NF):首先是 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖 。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的状况。
第二范式(2NF)和第三范式(3NF)的概念很容易混淆,区分它们的关键点在于,2NF:非主键列是否彻底依赖于主键,仍是依赖于主键的一部分 ;3NF:非主键列是直接依赖于主键,仍是直接依赖于非主键列。
Hibernate的一级缓存是由Session提供的,所以它只存在于Session的生命周期中,当程序调用save(),update(),saveOrUpdate()等方法 及调用查询接口list,filter,iterate时,如Session缓存中还不存在相应的对象,Hibernate会把该对象加入到一级缓存中,当Session关闭的时候缓存也会消失。 Hibernate的一级缓存是Session所内置的 ,不能被卸载,也不能进行任何配置一级缓存采用的是key-value的Map方式来实现的 ,在缓存实体对象时,对象的主关键字ID是Map的key,实体对象就是对应的值 。 Hibernate二级缓存:把得到的全部数据对象根据ID放入到第二级缓存中 。Hibernate二级缓存策略,是针对于ID查询的缓存策略 ,删除、更新、增长数据的时候,同时更新缓存 。
更新于2017/3/9
Java I/O 总结
程序须要读取数据的时候,就会创建一个通向数据源的链接,这个数据源能够是文件,内存,或是网络链接。相似的,当程序须要写入数据的时候,就会创建一个通向目的地的链接。
是否须要转换流 是,就使用转换流,从Stream转化为Reader、Writer:InputStreamReader,OutputStreamWriter
是否须要缓冲提升效率 是就加上Buffered:BufferedInputStream, BufferedOuputStream, BufferedReader,
肯定是输入仍是输出 输入:输入流 InputStream Reader 输出:输出流 OutputStream Writer
明确操做的数据对象是不是纯文本 是:字符流 Reader,Writer 否:字节流 InputStream,OutputStream
明确具体的设备。
文件: 读:FileInputStream,, FileReader, 写:FileOutputStream,FileWriter
读的时候须要判断是否读到-1 证实读完 写的时候若是是Buffered 须要flush 才能写入 由于有缓冲区 或者close
JVM(8):JVM知识点总览-高级Java工程师面试必备
类加载
加载,查找并加载类的二进制数据,在Java堆中也建立一个java.lang.Class类的对象
链接,链接又包含三块内容:验证、准备、初始化。1)验证,文件格式、元数据、字节码、符号引用验证;2)准备,为类的静态变量分配内存,并将其初始化为默认值;3)解析,把类中的符号引用转换为直接引用
初始化,为类的静态变量赋予正确的初始值
使用,new出对象程序中使用
卸载,执行垃圾回收
类初始化时机 ?
、建立类的实例。例如new语句建立实例,或者经过反射、克隆及序列号手段来建立实例。
二、调用类的静态方法。
三、访问某个类或接口的静态变量或者对该静态变量赋值。
四、调用java API中某些反射方法,好比调用Class.forName("Worker")方法,加入Worker类尚未被初始化,那么forName()方法就会初始化Worker类,而后返回表明这个Worker类的Class实例。forName()方法是java.lang.Class类的静态方法。
五、初始化一个类的子类 。例如对Sub类的初始化,可看做是它对父类Base类的主动使用,所以会先初始化Base类。
六、java虚拟机启动时被注明为启动类的类。例如对于“java Sample”命令,Sample类就是启动类,java虚拟机会先初始化它。
•在以下几种状况下,Java虚拟机将结束生命周期
– 执行了System.exit()方法
– 程序正常执行结束
– 程序在执行过程当中遇到了异常或错误而异常终止
– 因为操做系统出现错误而致使Java虚拟机进程终止
类加载器
启动类加载器:Bootstrap ClassLoader,负责加载存放在JDK\jre\lib(JDK表明JDK的安装目录,下同)下,或被-Xbootclasspath参数指定的路径中的,而且能被虚拟机识别的类库
扩展类加载器:Extension ClassLoader,该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载DK\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的全部类库(如javax.*开头的类),开发者能够直接使用扩展类加载器。
应用程序类加载器:Application ClassLoader,该类加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者能够直接使用该类加载器
类加载机制
全盘负责 ,当一个类加载器负责加载某个Class时 ,该Class所依赖的和引用的其余Class也将由该类加载器负责载入,除非显示使用另一个类加载器来载入
父类委托 ,先让父类加载器试图加载该类,只有在父类加载器没法加载该类时才尝试从本身的类路径中加载该类
缓存机制,缓存机制将会保证全部加载过的Class都会被缓存,当程序中须要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为何修改了Class后,必须重启JVM,程序的修改才会生效
细数JDK里的设计模式
Java中建立对象的5种不一样方法
关于Java Collections的几个常见问题
类在何时加载和初始化
两个栈实现队列 两个队列实现栈
更新于2017/3/12
java collection.sort()根据时间排序list
单点登陆原理与简单实现
更新于2017/3/13
AQS详解
Java的concurrent包
Java 并发工具包 java.util.concurrent 用户指南
更新于2017/6/12
进程和线程的区别:
进程:每一个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1–n个线程。
线程:同一类线程共享代码和数据空间,每一个线程有独立的运行栈和程序计数器(PC),线程切换开销小。
线程和进程同样分为五个阶段:建立、就绪、运行、阻塞、终止。
多进程是指操做系统能同时运行多个任务(程序)。
多线程是指在同一程序中有多个顺序流在执行。
在java中要想实现多线程,有三种手段,一种是继续Thread类,另一种是实现Runable接口,还有就是实现Callable接口。
Switch可否用string作参数?
a.在 Java 7 以前, switch 只能支持byte,short,char,int 或者其对应的封装类以及 Enum 类型。在Java 7中,String 支持被加上了。
Object有哪些公用方法?
a.方法equals测试的是两个对象是否相等
b.方法clone进行对象拷贝
c.方法getClass返回和当前对象相关的Class对象
d.方法notify,notifyall,wait都是用来对给定对象进行线程同步的
e.toString 方法
Java的四种引用,强弱软虚,以及用到的场景
a.利用软引用和弱引用解决OOM问题:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。
b.经过软可及对象重获方法实现Java对象的高速缓存:好比咱们建立了一Employee的类,若是每次须要查询一个雇员的信息。哪怕是几秒中以前刚刚查询过的,都要从新构建一个实例,这是须要消耗不少时间的。咱们能够经过软引用和 HashMap 的结合,先是保存引用方面:以软引用的方式对一个Employee对象的实例进行引用并保存该引用到HashMap 上,key 为此雇员的 id,value为这个对象的软引用,另外一方面是取出引用,缓存中是否有该Employee实例的软引用,若是有,从软引用中取得。若是没有软引用,或者从软引用中获得的实例是null,从新构建一个实例,并保存对这个新建实例的软引用。
c.强引用:若是一个对象具备强引用,它就不会被垃圾回收器回收。即便当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。若是想中断强引用和某个对象之间的关联,能够显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。
d.软引用:在使用软引用时,若是内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。
e.弱引用:具备弱引用的对象拥有的生命周期更短暂。由于当 JVM 进行垃圾回收,一旦发现弱引用对象,不管当前内存空间是否充足,都会将弱引用回收。不过因为垃圾回收器是一个优先级较低的线程,因此并不必定能迅速发现弱引用对象。
f.虚引用:顾名思义,就是形同虚设,若是一个对象仅持有虚引用,那么它至关于没有引用,在任什么时候候均可能被垃圾回收器回收。
Hashcode的做用,与 equal 有什么区别?
a.一样用于鉴定2个对象是否相等的,java集合中有 list 和 set 两类,其中 set不容许元素重复实现,那个这个不容许重复实现的方法,若是用 equal 去比较的话,若是存在1000个元素,你 new 一个新的元素出来,须要去调用1000次 equal 去逐个和他们比较是不是同一个对象,这样会大大下降效率。hashcode其实是返回对象的存储地址,若是这个位置上没有元素,就把元素直接存储在上面,若是这个位置上已经存在元素,这个时候才去调用equal方法与新元素进行比较,相同的话就不存了,散列到其余地址上。
Override和Overload的含义以及区别
a.Overload顾名思义是从新加载,它能够表现类的多态性,能够是函数里面能够有相同的函数名可是参数名、返回值、类型不能相同;或者说能够改变参数、类型、返回值可是函数名字依然不变。
b.就是ride(重写)的意思,在子类继承父类的时候子类中能够定义某方法与其父类有相同的名称和参数,当子类在调用这一函数时自动调用子类的方法,而父类至关于被覆盖(重写)了。
具体可前往C++中重载、重写(覆盖)的区别实例分析 查看
抽象类和接口的区别
a.一个类只能继承单个类,可是能够实现多个接口
b.抽象类中能够有构造方法,接口中不能有构造方法
c.抽象类中的全部方法并不必定要是抽象的,你能够选择在抽象类中实现一些基本的方法。而接口要求全部的方法都必须是抽象的
d.抽象类中能够包含静态方法,接口中不能够
e.抽象类中能够有普通成员变量,接口中不能够
解析XML的几种方式的原理与特色:DOM、SAX、PULL
a.DOM:消耗内存:先把xml文档都读到内存中,而后再用DOM API来访问树形结构,并获取数据。这个写起来很简单,可是很消耗内存。要是数据过大,手机不够牛逼,可能手机直接死机 xml文档的层级结构, 能够进行增删操做
b.SAX:解析效率高,占用内存少,基于事件驱动的 :更加简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数作相应动做,而后继续一样的扫描,直至文档结束。
c.PULL:与 SAX 相似,也是基于事件驱动,咱们能够调用它的next()方法,来获取下一个解析事件(就是开始文档,结束文档,开始标签,结束标签),当处于某个元素时能够调用XmlPullParser的getAttributte()方法来获取属性的值,也可调用它的nextText()获取本节点的值。
wait()和sleep()的区别
sleep来自Thread类,和wait来自Object类
调用sleep()方法的过程当中,线程不会释放对象锁。而 调用 wait 方法线程会释放对象锁
sleep睡眠后不出让系统资源,wait让出系统资源其余线程能够占用CPU
sleep(milliseconds)须要指定一个睡眠时间,时间一到会自动唤醒
JAVA 中堆和栈的区别,说下java 的内存机制
a.基本数据类型比变量和对象的引用都是在栈分配的
b.堆内存用来存放由new建立的对象和数组
c.类变量(static修饰的变量) ,程序在一加载的时候就在堆中为类变量分配内存,堆中的内存地址存放在栈中
d.实例变量:当你使用java关键字new的时候,系统在堆中开辟并不必定是连续的空间分配给变量,是根据零散的堆内存地址,经过哈希算法换算为一长串数字以表征这个变量在堆中的”物理位置”,实例变量的生命周期–当实例变量的引用丢失后,将被GC(垃圾回收器)列入可回收“名单”中,但并非立刻就释放堆中内存
e.局部变量: 由声明在某方法,或某代码段里(好比for循环),执行到它的时候在栈中开辟内存,当局部变量一但脱离做用域,内存当即释放
JAVA多态的实现原理
a.抽象的来说,多态的意思就是同一消息能够根据发送对象的不一样而采用多种不一样的行为方式 。(发送消息就是函数调用)
b.实现的原理是动态绑定,程序调用的方法在运行期才动态绑定,追溯源码能够发现,JVM 经过参数的自动转型来找到合适的办法。