内置对象 | 对应Servlet类 | 作用 |
---|---|---|
request | javax.servlet.http.HttpServletRequest | 客户端的请求信息:Http协议头信息、Cookie、请求参数等 |
response | javax.servlet.http.HttpServletResponse | 用于服务器响应客户端请求返回数据 |
pageContext | javax.servlet.jsp.PageContext | 页面的上下文 |
session | javax.servlet.http.HttpSession | 客户端与服务器之间的会话 |
application | javax.servlet.ServletContext | 用于获取服务器应用生命周期的信息 |
out | javax.servlet.jsp.JspWriter | 用于服务器传输内容到客户端的输出流 |
config | javax.servlet.ServletConfig | 初始化时,JSP引擎向JSP页面传递的信息 |
page | java.lang.Object | 指向JSP页面本身 |
exception | java.lang.Throwable | 页面发生异常,产生的异常对象 |
名称 | 作用域 |
---|---|
application | 在所有的应用程序中有效 |
session | 在当前会话中有效 |
request | 在当前请求中有效 |
page | 在当前页面有效 |
一个Http请求的处理可能需要多个Servlet合作,而这几个Servlet之间可以通过某种方式传递信息,但这个信息在请求结束后就无效了。request里的变量可以跨越forward前后的两页,但是只要刷新页面,它们就重新计算了。
如果把变量放到request里,就说明它的作用域是request,它的有效范围是当前请求周期。
所谓请求周期,就是值指从http请求发起,到服务器处理结束,返回响应的整个过程。在这个过程中可能使用forward的方式跳转了多个jsp页面,在这些页面里你都可以使用这个变量。
Servlet之间的信息共享是通过HttpServletRequest接口的两个方法来实现的:
void setAttribute(String name, Object value) //将对象value以name为名称保存到request作用域中。
Object getAttribute(String name) //从request作用域中取得指定名字的信息。
JSP中的doGet()、doPost()方法的第一个参数就是HttpServletRequest对象,使用这个对象的 setAttribute()方法即可传递信息。那么在设置好信息之后,要通过何种方式将信息传给其他的Servlet呢?这就要用到RequestDispatcher接口的forward()方法,通过它将请求转发给其他Servlet。
RequestDispatcher ServletContext.getRequestDispatcher(String path) //取得Dispatcher以便转发,path为转发的目的Servlet。
void RequestDispatcher.forward(ServletRequest request, ServletResponse response)//将request和response转发
因此,只需要在当前Servlet中先通过setAttribute()方法设置相应的属性,然后使用forword()方法进行跳转,最后在跳转到的Servlet通过使用getAttribute()方法即可实现信息传递。
注意:
转发不是重定向,转发是在Web应用内部进行的。
转发对浏览器是透明的,也就是说,无论在服务器上如何转发,浏览器地址栏中显示的仍然是最初那个Servlet的地址。
default:项目部署的处理
clean:项目清理的处理
site:项目站点文档创建的处理
构建生命周期都由不同的阶段(Phase)构成
例如:default 生命周期由以下阶段构成:
validate:验证项目是否正确且所有必须信息是可用的
compile:编译项目源码
test:使用合适的测试框架对编译好的源码尽心测试,这些测试不应要求源码被打包或部署
package:根据指定的格式打包编译好的源码,如JAP
verify:对集成测试的结果进行检查,以保证质量达标
install:安装打包的项目到本地仓库,以供其他项目使用
deploy:在构建环境中完成,将最后的包复制到远程仓库,以便与其他开发人员和项目共享
为了完成default生命周期,这些阶段(包括其他未在上面罗列的生命周期阶段)将被按顺序地执行。
命令行调用:在开发环境中,使用 mvn install 、mvn clean deploy等命令进行构建,安装工程到本地仓库
1. ID选择器 #id
描述:根据给定的id匹配一个元素, 返回单个元素(注:在网页中,id名称不能重复)
示例:$("#test") 选取 id 为 test 的元素
2. 类选择器 .class
描述:根据给定的类名匹配元素,返回元素集合
示例:$(".test") 选取所有class为test的元素
3. 元素选择器 element
描述:根据给定的元素名匹配元素,返回元素集合
示例:$("p") 选取所有的<p>元素
4. *
描述:匹配所有元素,返回元素集合
示例:$("*") 选取所有的元素
5. selector1,selector2,...,selectorN
描述:将每个选择器匹配到的元素合并后一起返回,返回合并后的元素集合
示例:$("p,span,p.myClass") 选取所有<p>,<span>和class为myClass的<p>标签的元素集合
id可以重复
一个对象产生
s1 == s2 false
String s3 = “123”
?s1 == s3 true
String s4 = new String(“123”);
s2 == s4 false
构造对象—>init->service->doGet/doPost->destroy
clean :清理
compile:编译
test:测试
package:打包
install:安装
deploy:部署
包名:公司域名.项目名.模块名称
com.fy.myshop.user.controller
<groupId>com.fy</groupId>
<artifactId>myshop</artifactId>
<version>0.0.1.SNAPTSHOT</version>
<scope>compile</scope>
maven的依赖范围包括: compile,provide,runtime,test,system。
compile:表示编译范围,指A在编译时依赖B,该范围为默认依赖范围。编译范围的依赖会用在编译,测试,运行,由于运行时需要,所以编译范围的依赖会被打包。
provide:provide依赖只有当jdk或者一个容器已提供该依赖之后才使用。provide依赖在编译和测试时需要,在运行时不需要。例如:servlet api被Tomcat容器提供了。
runtime:runtime依赖在运行和测试系统时需要,但在编译时不需要。例如:jdbc的驱动包。由于运行时需要,所以runtime范围的依赖会被打包。
test:test范围依赖在编译和运行时都不需要,只在测试编译和测试运行时需要。例如:Junit。由于运行时不需要,所以test范围依赖不会被打包。
system:system范围依赖与provide类似,但是必须显示的提供一个对于本地系统中jar文件的路径。一般不推荐使用。
ArrayList与Vector的区别主要包括两个方面:.
(1)同步性:
(2)数据增长:
LinkedList :底层是双向链表,删除和修改快 O(n)
ArrayList:查询快 O(1)
401:未授权
403:禁止
404:文件找不到
503:服务器内部错误
200:成功
302:重定向
PreparedStatement extends Statement
采用占位符,防止sql注入
性能高
select * from login where name like ‘%admin%’ limit 0,10
Spring是一个项目管理框架,同时也是一套Java EE解决方案。
Spring是众多优秀设计模式的组合(工厂、单例、代理、适配器、包装器、观察者、模板、策略)。
Spring并未替代现有框架产品,而是将众多框架进行有机整合,简化企业级开发,俗称"胶水框架"。
官方网站:https://spring.io/
下载地址:http://repo.spring.io/release/org/springframework/spring/
set注入
构造注入
自动注入
list <list><value></value></list>
set <set></set>
map <map><entry key="" value=""/></map>
properties <props><prop></prop></props>
byName
byType
动态代理:jdk + cglib
Connection
Class.forName("驱动名")
Connection conn = DriverManager.getConnection(url, username, password);
作用:让Spring可以创建复杂对象、或者无法直接通过反射创建的对象。
切面(Aspect):由切点和通知组成,将横切逻辑织入切面所指定的连接点中。
概念:AOP(Aspect Oriented Programming),即面向切面编程,利用一种称为"横切"的技术,剖开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
AOP开发术语:
连接点(Joinpoint):连接点是程序类中客观存在的方法,可被Spring拦截并切入内容。
切入点(Pointcut):被Spring切入连接点。
通知、增强(Advice):可以为切入点添加额外功能,分为:前置通知、后置通知、异常通知、环绕通知等。
目标对象(Target):代理的目标对象
引介(Introduction):一种特殊的增强,可在运行期为类动态添加Field和Method。
织入(Weaving):把通知应用到具体的类,进而创建新的代理类的过程。
代理(Proxy):被AOP织入通知后,产生的结果类。
切面(Aspect):由切点和通知组成,将横切逻辑织入切面所指定的连接点中。
前置通知:MethodBeforeAdvice://在业务方法执行前执行
最终通知:AfterAdvice //不管业务方法是否有异常,都会执行的通知
后置通知:AfterReturningAdvice //有异常不执行,方法会因异常而结束,无返回值
异常通知:ThrowsAdvice //目标对象执行出现异常才会执行的通知
环绕通知:MethodInterceptor//环绕通知
isolation
隔离级别
名称 | 描述 |
---|---|
default | (默认值)(采用数据库的默认的设置) (建议) |
read-uncommited | 读未提交 |
read-commited | 读提交 (Oracle数据库默认的隔离级别) |
repeatable-read | 可重复读 (MySQL数据库默认的隔离级别) |
serialized-read | 序列化读 |
隔离级别由低到高为:read-uncommited < read-commited < repeatable-read < serialized-read
问题 | 描述 |
---|---|
脏读 (Dirty Read) | 一个事务读取到另一个事务还未提交的数据。大于等于 read-commited 可防止 |
不可重复读(Non-repeatable Read) | 一个事务内多次读取一行数据的相同内容,其结果不一致。大于等于 repeatable-read 可防止 |
幻读(Phantom Read) | 一个事务内多次读取一张表中的相同内容,其结果不一致。serialized-read 可防止 |
Cookie数据存储在客户端的浏览器中,默认是放在浏览器的缓存中,所以关闭浏览器就被删除了,我们也可以设置Cookie的有效期,这个时候就会将Cookie数据存储在本地磁盘中,通过Http协议实现Cookie的传递。
动态代理:JDK、cglib
日志、事务、权限控制
工厂、单例、代理、模板模式
JdbcTemplate
doGet:GET方法会把键值对追加在请求的URL后面,因为URL对字符数目有限制,进而限制了用在客户端请求的参数值的数目,并且请求中的参数值是可见的,因此,敏感信息不能用这种方式传递。
doPost:POST方法通过请求参数值放在请求体中克服GET方法的限制,因此,可以发送的参数的数目是无限制的。最后,通过POST请求传递的敏感信息对外部客户端是不可见的。
1.配置事务管理器
<bean id="tx" class="DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
2.配置事务特性
<tx:advice id="txAdvice" transaction-manager="tx">
<tx:attributes>
<td:method name="delete*" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
3.配置事务切面
<aop:config>
<aop:pointcut expression="" id="xx">
<aop:advisor adivce-ref="txAdvice" pointcut-ref='xx'>
</aop:config>
重写:继承,
重载:同一类中定义多个同名的方法,参数列表要不同
抽象类:抽象类是指这个对象是什么
接口:接口是指这个对象能做什么
举例: 定义一个狗类(抽象类):哈士奇,金毛都属于狗类(实现类)狗:睡觉,拆家…可以定义一个接口,让实现类去实现接口
因此在Java语言中,一个类只能继承一个类(抽象类)(正如狗不可能同时是生物和非生物),但是接口可以多继承,一个类能够实现多个接口。
接口中的所有方法是抽象的(abstract修饰)而抽象类是声明方法而不去实现它的类。
接口可以多继承,抽象类单继承
接口定义方法,不能实现,而抽象类可以实现部分方法
接口中的基本数据类型为static,而抽象类不是。
注:
抽象类的功能远超过接口,但是,定义抽象类的代价比较高。因为高级语言来说(从实际设计出发也是),每个类只能继承一个类。在这个类中你必须继承或编写出其所有子类的所有共性。虽然接口在功能上会弱化许多,但是接口是针对一个动作的实现,而且一个类能够继承多个接口,在设计中难度会相对降低。
throw:产生异常
throws:抛出异常
DQL
DML
DDL
DCL
delete删除数据
truncate删除数据,表内存结构
drop删除表,删库
@RequestMapping
@ResponseBody
@PathVariable
@SessionAtrributes
@Controller/@Service/@Repository/@Component/@Autowired/@Resource/@Value
@Controller
Controller控制器是通过服务接口定义的提供访问应用程序的一种行为,它解释用户的输入,将其转换成一个模型然后将试图呈献给用户。
@RequestMapping
@RequestMapping 注解将URL映射到整个类或特定的处理方法上。
@PathVariable
可以使用 @PathVariable 注解方法参数并将其绑定到URI模板变量的值上。
@RequestParam
@RequestParam将请求的参数绑定到方法中的参数上
@RequestBody
@RequestBody是指方法参数应该被绑定到HTTP请求Body上。
@ResponseBody
@ResponseBody与@RequestBody类似,它的作用是将返回类型直接输入到HTTP response body中。
@ModelAttribute
@ModelAttribute可以作用在方法或方法参数上,当它作用在方法上时,标明该方法的目的是添加一个或多个模型属性(model attributes)。
新建状态(New):至今尚未启动的线程的状态。线程刚被创建,但尚未启动。如:Thread t = new MyThread();
就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
等待阻塞—位于对象等待池中的阻塞状态(Blocked in object’s wait pool):当线程处于运行状态时,如果执行了某个对象的wait()方法,Java虚拟机就会把线程放到这个对象的等待池中,这涉及到“线程通信”的内容。
同步阻塞 --位于对象锁池中的阻塞状态(Blocked in object’s lock pool):当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,Java虚拟机就会把这个线程放到这个对象的锁池中,这涉及到“线程同步”的内容。【线程在获取synchronized同步锁失败(因为锁被其它线程所占用)】
其他阻塞状态(Otherwise Blocked):当前线程执行了sleep()方法,或者调用了其他线程的join()方法,或者发出了I/O请求时,就会进入这个状态。线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
== : 它的作用是判断两个对象的地址是不是相等的,即判断两个对象是不是同一个对象。(基本数据类型 == 比较的是值,引用数据类型 == 比较的是地址)
equals():它的作用是判断两个对象是否相等。但它一般有两种情况:
- 类没有覆盖 equals() 方法,则通过 equals() 比较该类的两个对象时,等价于通过 “==” 比较这两个对象。
- 类覆盖了equals() 方法。 一般,我们都覆盖 equals() 方法来比较两个对象的内容相等,若内容相等,则返回true(即,认为这两个对象相等)
序列化:将 Java 对象转换成字节流的过程。
反序列化:将字节流转换成 Java 对象的过程。
当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java 对象进行序列化处理。
序列化的实现:类实现 Serializable 接口,这个接口没有需要实现的方法。实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化。
注意事项:
- 某个类可以被序列化,则其子类也可以被序列化
- 声明为 static 和 transient 的成员变量,不能被序列化。
- static 成员变量是描述类级别的属性,transient 表示临时数据
- 反序列化读取序列化对象的顺序要保持一致
length
length()
概念:JVM 是可运行 Java 代码的假想计算机 ,包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收,堆 和一个存储方法域。JVM 是运行在操作系统之上的,它与硬件没有直接的交互。
⑴ 原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
⑵ 一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态 变换到 另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
⑶ 隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到。
⑷ 持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。
不能,因为String是被final修饰,所以不能被继承
不一定。解析如下:
(1)hashCode()的作用是获取哈希值,也称为散列码,它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode()定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode()函数。
(2)散列表存储的是键值对(key-value),它的特点是根据“键”快速的检索出对应的“值”。这其中就利用到了散列码(可以快速找到所需要的对象)
(1)以“HashSet如何检查重复”为例:HashSet 会先计算对象的 hashCode 值来判断对象加入的位置,同时也会与加入的对象的 hashCode 值作比较,如果没有相符的hashCode,HashSet会假设对象没有重复出现。但是如果发现有相同的 hashCode 值的对象,这时会调用equals() 方法来检查 hashCode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入成功。如果不同的话,就会重新散列到其他位置。这样就大大减少了equals的次数,相应就大大提高了执行速度。
(2)hashCode()与equals() 相关的规定
对象的相等比较的是内存中存放的内容是否相等;而引用相等比较的是他们指向的内存地址是否相等。
Java中的ThreadLocal类允许我们创建只能被同一个线程读写的变量。因此,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们也无法访问到对方的ThreadLocal变量。
就是当我们只想在本身的线程内使用的变量,可以用 ThreadLocal 来实现,并且这些变量是和线程的生命周期密切相关的,线程结束,变量也被销毁。所以说 ThreadLocal 不是为了解决线程间的共享变量问题的,如果是多线程都需要访问的数据,那需要用全局变量加同步机制。
例如:
(1)比如用来存储用户 Session。Session 的特性很适合 ThreadLocal ,因为 Session 之前当前会话周期内有效,会话结束便销毁。
(2)通过threadlocal 传递session,token等。
start():启动线程
run():线程执行
sleep():设置时间,不会释放锁
wait():唤醒,释放锁、notify/notifyall
forward:内部转发
redirect:重定向
详细请看:https://blog.csdn.net/zhu_fangyuan/article/details/108820874
session:数据存储在服务端,各种数据类型,无大小限制,session默认基于cookie实现的
cookie:存储在客户端, 字符串,有大小限制
详细解析:https://blog.csdn.net/zhu_fangyuan/article/details/108628743
page->request->session->application
JSP的本质就是Servlet,JVM只能识别java的类,不能识别JSP的代码,Web容器将JSP的代码编译成JVM能够识别的java类。
JSP 工作原理:
JSP页面在执行的时候都会被服务器端的JSP引擎转换为Servelet(.java),然后又由JSP引擎调用Java编译器,将Servelet(.java)编译为Class文件(.class),并由Java虚拟机(JVM)解释执行。下面验证这一点:
有一个JSP页面Test.jsp,在浏览器地址栏中输入http://localhost:8080/Test.jsp,将会出现执行结果。同时在%CATALINA_HOME%/work/Catalina/localhost下多出两个文件:_Test_jsp.java和_Test_jsp.class,他们分别就是Servelet和Class文件。
.Servlet的应用逻辑是在Java文件中,从Java代码中动态输出HTML,并且完全从表示层中的HTML里分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。JSP侧重于视图,Servlet主要用于控制逻辑。
- 作用:提高查询效率 全表扫描
- 索引原理:采用某种数据结构存储索引,二叉树、平衡树、Hash表、BTree、B+Tree
- 主键索引(聚集索引)、唯一索引、联合索引、普通索引
create unique index 索引名(字段)
共同:都是接口,都可以对集合进行迭代
不同:
- Enumeration一般对Hashtable和Vector这种安全类型的集合进行迭代
- Iterator可以对实现了Collection接口的集合进行迭代
- Iterator支持fail-fast(Concurrent Modification Exception), 推荐使用Iterator
select 字段 from 表1 join 表2 on 链表条件 where 筛选条件 group by 分组字段 having 分组过滤 order by 排序字段 limit xxx
A-》B
A->B->A
<bean id="a" class="A">
<property name="b" ref=“b”>
</bean>
<bean id=“b” class="B">
<property name="a" ref="a">
</bean>
json对象-》string JSON.stringify(json对象)
string-》json对象 JSON.parse(json字符串)
for:通过下标
for-each:采用迭代器进行迭代
NullPointerException
CastClassException
RuntimeException
IOException
SQLException
SocketException
ClassNotFoundException
ArrayIndexOutOfException
NumberFormatException
FileNotFoundException
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/login"/>
<bean class="拦截器">
</mvc:interceptor>
</mvc:interceptors>
学生表:| 学号 | 姓名 | 专业 | 班级 |
成绩表:| 学号 | 课程编号 | 成绩 |
查找显示成绩表中"学号"字段的全部数据,要求查询结果中不包含重复记录
select distinct 学号 from 成绩;
在成绩表中,找出02号课程成绩中的最高分
select max(成绩) from 成绩表 where 课程编号=‘02’ ;
在学生表中找出姓刘或姓李的学生
select *from 学生表 where 姓名 like ‘刘%’ or 姓名 like ‘李%’
查找01号课程成绩介于60与80之间的学生记录
select * from 学生表 where 学号 in (
select 学号 from 成绩 where 课程编号=01 and 成绩 between 60 and 80)
select 学生表.* from 学生表 join 成绩表 on 学生表.学号=成绩表.学号
where 成绩表.课程编号=01 and 成绩表.成绩 between 60 and 80
把成绩表中课程编号='01’的所有学生记录按成绩从高到低排列显示出来
select * from 学生表 where 学号 in(
select 学号 from 成绩表 where 课程编号=01 order by 成绩 desc)
统计每个课程的平级成绩
select 课程编号, avg(成绩) from 成绩表 group by 课程编号
找出挂科最多的课程
select 课程编号,count(*) 个数 from 成绩表 where 成绩 < 60 group by 课程编号 order by 个数 desc limit 0,1
在成绩表中,计算每个学生各门功课的总成绩和平均成绩,并按照总成绩降序排列
select sum(成绩) 总成绩,avg(成绩) 平均成绩 from 成绩表 group by 学号 order by 总成绩 desc;
查询01号课程成绩进前三名的同学的课程编号,成绩
select 课程编号,成绩 from 成绩表where 课程编号=01 order by 成绩 desc limit 0, 3;
将课程编号='01’中最高分的学员姓名显示出来
select 姓名 from 学生表 join 课程表 on 学生表.学号=成绩表.学号 where 课程编号=01 order by 成绩 desc limit 0,1
select max_salary,
CASE
WHEN max_salary >15000 then ‘高工资’
WHEN max_salary >10000 then ‘一般水平’
else ‘低水平’
END 等级
from t_jobs
collection是用来关联实体类的,assosication是用来关联集合的,
也就是平时的一对一(assocication),一对多(collection)
所以association是用于一对一和多对一,而collection是用于一对多的关系
- 一级缓存
Mybatis的一级缓存是指Session缓存。一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存。
也就是在同一个SqlSession中,执行相同的查询SQL,第一次会去数据库进行查询,并写到缓存中;第二次以后是直接去缓存中取。
当执行SQL查询中间发生了增删改的操作,MyBatis会把SqlSession的缓存清空。
一级缓存的范围有SESSION和STATEMENT两种,默认是SESSION,如果不想使用一级缓存,可以把一级缓存的范围指定为STATEMENT,这样每次执行完一个Mapper中的语句后都会将一级缓存清除。
- 二级缓存
Mybatis的二级缓存是指mapper映射文件。二级缓存的作用域是同一个namespace下的mapper映射文件内容,多个SqlSession共享。Mybatis需要手动设置启动二级缓存。
二级缓存是默认启用的(要生效需要对每个Mapper进行配置),如想取消,则可以通过Mybatis配置文件中的元素下的子元素来指定cacheEnabled为false。
当需要加载一个类的时候,子类加载器并不会马上去加载,而是依次去请求父类加载器加载,一直往上请求到最高类加载器:启动类加载器。
当启动类加载器加载不了的时候,依次往下让子类加载器进行加载。当达到最底下的时候,如果还是加载不到该类,就会出现ClassNotFound的情况。
好处:保证了程序的安全性。例子:比如我们重新写了一个String类,加载的时候并不会去加载到我们自己写的String类,因为当请求上到最高层的时候,启动类加载器发现自己能够加载String类,因此就不会加载到我们自己写的String类了。
synchroniezed:关键词,通过JVM的底层实现,
锁的升级过程(无锁-》偏向锁-》轻量级锁-》重量级锁)
Lock:接口,通过代码实现锁的过程,状态+CAS+链表(ABC),公平锁和非公平锁,可中断锁
Lock lock = new ReentrantLock();//默认是非公平锁
try{
lock.lock();//上锁
//执行上锁的代码
}finally{
lock.unlock();//释放锁
}
(1)super:它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中的成员数据或函数),基类与派生类中有相同成员定义时如:super.变量名,super.成员函数名(实参)
(2)this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需要用this来指明成员变量名)
(3)super()和this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其他构造方法。
(4)super()和this()均需放在构造方法内第一行。尽管可以使用this调用一个构造器,但却不能调用两个。
(5)this和super不能同时出现在一个构造方法中,因为this必然会调用其他的构造函数,其他的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
(6)this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
(7)从本质上讲,this是一个指向本对象的指针,然而super是一个Java关键字。
静态包含:<%@ include file=“文件”%>
动态包含:<jsp:include page=“文件” />
true
原因:泛型擦除,在程序运行中是没有泛型类型
InnoDB:支持事务、主外键,效率要低,(B+Tree)索引结构不同(索引和数据在一起)
MyISAM:都不支持,效率高(索引和数据是分开)
乐观锁:版本号 v 1
悲观锁: select *from 表 where 条件 for update
地址:https://blog.csdn.net/zhu_fangyuan/article/details/108545790
区别:
- Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
- synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
- Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
- 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
- Lock可以提高多个线程进行读操作的效率。
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。- synchronized实现的机理依赖于软件层面上的JVM,synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。
- ReentantLock继承接口Lock并实现了接口中定义的方法,除了能完成synchronized所能完成的所有工作外,还提供了诸如可响应中断锁、可轮询锁请求、定时锁等避免多线程死锁的方法。
- 尽管Java实现的锁机制有很多种,并且有些锁机制性能也比synchronized高,但还是强烈推荐在多线程应用程序中使用该关键字,因为实现方便,后续工作由JVM来完成,可靠性高。只有在确定锁机制是当前多线程程序的性能瓶颈时,才考虑使用其他机制,如ReentrantLock等。
- ReentrantLock通过方法lock()与unlock()来进行加锁与解锁操作,与synchronized会被JVM自动解锁机制不同,ReentrantLock加锁后需要手动进行解锁。为了避免程序出现异常而无法正常解锁的情况,使用ReentrantLock必须在finally控制块中进行解锁操作。
CAS是compare and swap的缩写,即我们所说的比较交换。cas是一种基于锁的操作,而且是乐观锁。在java中锁分为乐观锁和悲观锁。悲观锁是将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。而乐观锁采取了一种宽泛的态度,通过某种方式不加锁来处理资源,比如通过给记录加version来获取数据,性能较悲观锁有很大的提高。
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存地址里面的值和A的值是一样的,那么就将内存里面的值更新成B。CAS是通过无限循环来获取数据的,若果在第一轮循环中,a线程获取地址里面的值被b线程修改了,那么a线程需要自旋,到下次循环才有可能机会执行。
加载-》连接(验证-》准备-》解析)-》初始化-》使用-》卸载
Comparable和Comparator都是用来实现集合中元素的比较、排序的。
Comparable是在集合内部定义的方法实现的排序,位于java.lang下。
Comparator是在集合外部实现的排序,位于java.util下。
Comparable是一个对象本身就已经支持自比较所需要实现的接口,如String、Integer自己就实现了Comparable接口,可完成比较大小操作。自定义类要在加入list容器中后能够排序,也可以实现Comparable接口,在用Collections类的sort方法排序时若不指定Comparator,那就以自然顺序排序。所谓自然顺序就是实现Comparable接口设定的排序方式。
Comparator是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足要求时,可写一个比较器来完成两个对象之间大小的比较。Comparator体现了一种策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。
总而言之Comparable是自已完成比较,Comparator是外部程序实现比较。
目前主流的虚拟机实现都采用了分代收集的思想,把整个堆区划分为新生代和老年代;新生代又被划分成Eden 空间、 From Survivor 和 To Survivor 三块区域。
我们把Eden : From Survivor : To Survivor 空间大小设成 8 : 1 : 1 ,对象总是在 Eden 区出生, From Survivor 保存当前的幸存对象, To Survivor 为空。
一次 gc 发生后:
1)Eden 区活着的对象 + From Survivor 存储的对象被复制到 To Survivor ;
2)清空 Eden 和 From Survivor ;
3)颠倒 From Survivor 和 To Survivor 的逻辑关系: From 变 To , To 变 From 。可以看出,只有在 Eden 空间快满的时候才会触发 Minor GC 。而 Eden 空间占新生代的绝大部分,所以 Minor GC 的频率得以降低。当然,使用两个 Survivor 这种方式我们也付出了一定的代价,如 10% 的空间浪费、复制对象的开销等。
readyState 属性表示Ajax请求的当前状态。它的值用数字代表。
0 代表未初始化。 还没有调用 open 方法
1 代表正在加载。 open 方法已被调用,但 send 方法还没有被调用
2 代表已加载完毕。send 已被调用。请求已经开始
3 代表交互中。服务器正在发送响应
4 代表完成。响应发送完毕
常用状态码(status)及其含义:
404 没找到页面(not found)
403 禁止访问(forbidden)
500 内部服务器出错(internal service error)
200 一切正常(ok)
304 没有被修改(not modified)(服务器返回304状态,表示源文件没有被修改 )
newCachedThreadPool创建一个可缓存线程池程
newFixedThreadPool 创建一个定长线程池
newScheduledThreadPool 创建一个定长线程池
newSingleThreadExecutor 创建一个单线程化的线程池
不一定。解析如下:
(1)hashCode()的作用是获取哈希值,也称为散列码,它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode()定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode()函数。
(2)散列表存储的是键值对(key-value),它的特点是根据“键”快速的检索出对应的“值”。这其中就利用到了散列码(可以快速找到所需要的对象)
(1)以“HashSet如何检查重复”为例:HashSet 会先计算对象的 hashCode 值来判断对象加入的位置,同时也会与加入的对象的 hashCode 值作比较,如果没有相符的hashCode,HashSet会假设对象没有重复出现。但是如果发现有相同的 hashCode 值的对象,这时会调用equals() 方法来检查 hashCode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入成功。如果不同的话,就会重新散列到其他位置。这样就大大减少了equals的次数,相应就大大提高了执行速度。
(2)hashCode()与equals() 相关的规定
HTTP1.0定义了三种请求方法: GET、POST 和 HEAD方法。
HTTP1.1新增了五种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。
地址:https://blog.csdn.net/zhu_fangyuan/article/details/108739935
String类常用方法 | 用法 |
---|---|
indexOf() | 返回指定字符得索引 |
charAt() | 返回指定索引处得字符 |
repalce() | 字符串替换 |
trim() | 去除字符串两端的空白 |
split() | 分割字符串 返回分割后的字符串数组 |
getBytes() | 返回字符串的byte类型数组 |
length() | 返回字符串的长度 |
toLowerCase() | 字符串转小写 |
toUpperCase() | 字符串转大写 |
substring() | 截取字符串 |
equals() | 字符串比较 |
Dispatcher->HandlerMapping->HanderAdapter->Handler->ViewResolver->View
不相等,两个不同的对象
一级缓存
Mybatis的一级缓存是指Session缓存。一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存。
也就是在同一个SqlSession中,执行相同的查询SQL,第一次会去数据库进行查询,并写到缓存中;第二次以后是直接去缓存中取。当执行SQL查询中间发生了增删改的操作,MyBatis会把SqlSession的缓存清空。
一级缓存的范围有SESSION和STATEMENT两种,默认是SESSION,如果不想使用一级缓存,可以把一级缓存的范围指定为STATEMENT,这样每次执行完一个Mapper中的语句后都会将一级缓存清除。
二级缓存
- Mybatis的二级缓存是指mapper映射文件。二级缓存的作用域是同一个namespace下的mapper映射文件内容,多个SqlSession共享。Mybatis需要手动设置启动二级缓存。
- 二级缓存是默认启用的(要生效需要对每个Mapper进行配置),如想取消,则可以通过Mybatis配置文件中的元素下的子元素来指定cacheEnabled为false。
git init
git add
git commit
git push
git pull
git clone
git checkout
git branch 分支名称
冲突是如何产生的
我们都知道,Git的实现途径是1棵树。比如有一个节点树(point1),
我们基于point1进行开发,开发出了结点point2;
我们基于point1进行开发,开发出了结点point3;
如果我们在point2和point3内操作了同一类元素,那么势必会导致冲突的存在。
冲突是如何解决的?
解决冲突通常使用如下的步骤即可:
情况1 无冲突
先拉取远端的代码,更新本地代码。然后提交自己的更新代码即可。
情况2 有冲突
拉取远端代码。存在冲突,会报错。
此时我们需要将本地代码暂存起来 stash;
更新本地代码,将本地代码版本更新和远端的代码一致即可;
将暂存的代码合并到更新后的代码后,有冲突解决冲突(需要手动进行解决冲突);
提交解决冲突后的代码。
开启一个bug分支
master:主分支,对外发布
dev:开发分支
test:测试分支
bug:修复bug分支
feature:特性分支
hotfixes:热线分支
相等,string 性能优化
String a =“a”+“b”+“c”+“d”;
a、防止执行指令重排序
b、内存可见性
AtomicInteger
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
//var1:当前对象
//var2:原有内存值
//var4:需要自增的值
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);//获取当前内存值
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
if(var2 == var5){
var5 = var5+var4;
return true;
}
return false;
return var5;
}
CAS原理:获取旧的内存值V,获取当前内存值A, 只有当V==A,才将内存值修改成B,原子变量都是基于CAS实现的
AtomicInteger,AtomitLong
问题:ABA问题,通过版本号
A a -> b->a
B a->a->c
public class MyTest1 {
public static void main(String[] args) {
AtomicDemo demo = new AtomicDemo();
for(int i=0; i<8; i++){
new Thread(demo).start();
}
}
}
class AtomicDemo implements Runnable{
//private int num = 0;
private AtomicInteger num = new AtomicInteger(0);//原子变量
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(num.getAndIncrement());//原子操作
//int temp;
//temp = num;
//temp = temp + 1;
//num = temp
}
}
? 假如你创建的代码如下:List<Map<String,Object>> data=new ArrayList<Map<String,Object>>();
? 那么为了解决这个线程安全问题你可以这么使用Collections.synchronizedList(),如:
? List<Map<String,Object>> data=Collections.synchronizedList(new ArrayList<Map<String,Object>>());
//简单选择排序算法
private void selectSort(int[] datas){
int length = datas.length;
for(int i=0;i<length;i++){
int min = i;
for(int j=i+1;j<length;j++){
int a = datas[min];
int b = datas[j];
if(a>b){//这里为升序,如果要降序则直接这里改成小于即可
min = j;
}
}
int temp = datas[min];
datas[min] = datas[i];
datas[i] = temp;
Log.i("sort", Arrays.toString(datas)+" i:"+i);
}
}
//冒泡排序算法
private void bubbleSort(int[] datas) {
int length = datas.length;
boolean flag;
for (int i = 0; i < length - 1; i++) {
flag = false;//使用flag对冒泡排序进行优化
for (int j = 0; j < length - i-1; j++) {
if (datas[j] > datas[j+1]) {//这里为升序,如果要降序则直接这里改成小于即可
int temp = datas[j];
datas[j] = datas[j+1];
datas[j+1] = temp;
flag = true;
}
Log.i("sort", Arrays.toString(datas) + " j:" + j + " length-i:" + (length - i));
}
if(!flag){//如果这里flag为false,表示现在数据已经是有序的了,则可以直接退出for循环了
break;
}
}
}
? a、try,catch
? b、抛出检测异常
? c、数据库引擎MyISAM
数据库的引擎是Innodb
?主键索引:索引的叶子节点中存储行数据
?普通索引:索引的叶子节点存储的是主键值,存在二次索引过程
?主键索引建议用自增
问题 | 描述 |
---|---|
脏读 (Dirty Read) | 一个事务读取到另一个事务还未提交的数据。大于等于 read-commited 可防止 |
不可重复读(Non-repeatable Read) | 一个事务内多次读取一行数据的相同内容,其结果不一致。大于等于 repeatable-read 可防止 |
幻读(Phantom Read) | 一个事务内多次读取一张表中的相同内容,其结果不一致。serialized-read 可防止 |
1、JavaScript防止表单重复提交(主要用于网络延迟情况下用户点击多次submit按钮导致表单重复提交)
在jsp页面中,添加JavaScript代码来防止表单的重复提交。主要是针对在网络延迟情况下用户有时间点击多次submit按钮导致表单重复提交,使用javascript控制Form表单只能提交一次。
2、**将提交按钮设置为不可用,**让用户点击第一次提交之后,没有机会点击第二次提交按钮的机会。(也可以将提交按钮隐藏起来,在点击第一次之后,将提交按钮隐藏起来)
3、利用Session防止表单重复提交(主要用于表单提交之后,点击浏览器刷新按钮导致表单重复提交,以及点击浏览器返回按钮退回到表单页面后进行再次提交)
(1)表单页面由servlet程序(服务器端)生成,servlet为每次产生的表单页面分配一个唯一的随机标识号(Token令牌),并在FORM表单的一个隐藏字段中设置这个标识号,同时在当前用户的Session域中保存这个标识号。
(2)当用户提交FORM表单时,负责处理表单提交的serlvet得到表单提交的标识号,并与session中存储的标识号比较,如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。如果不一致,就是重复提交了,此时服务器端就可以不处理重复提交的表单了。
(3)服务器程序将拒绝用户提交的表单请求情况如下:
1):存储Session域中的表单唯一的标识号与表单提交的标识号不同
2):当前用户的Session中不存在表单标识号
3):用户提交的表单数据中没有标识号字段
(4)创建标识号
String token = TokenProccessor.getInstance().makeToken();
(5)在服务器端使用Session保存标识号
request.getSession().setAttribute(“token”,token);
(6)、在form表单中也就是JSP页面中,使用隐藏域来存储标识号(Token令牌)
//第一步,创建XMLHttpRequest对象
var xmlHttp = new XMLHttpRequest();
function CommentAll() {
//第二步,注册回调函数
xmlHttp.onreadystatechange =callback1;
//{
// if (xmlHttp.readyState == 4)
// if (xmlHttp.status == 200) {
// var responseText = xmlHttp.responseText;
// }
//}
//第三步,配置请求信息,open(),get
//get请求下参数加在url后,.ashx?methodName = GetAllComment&str1=str1&str2=str2
xmlHttp.open("post", "/ashx/myzhuye/Detail.ashx?methodName=GetAllComment", true);
//post请求下需要配置请求头信息
//xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//第四步,发送请求,post请求下,要传递的参数放这
xmlHttp.send("methodName = GetAllComment&str1=str1&str2=str2");//"
}
//第五步,创建回调函数
function callback1() {
if (xmlHttp.readyState == 4)
if (xmlHttp.status == 200) {
//取得返回的数据
var data = xmlHttp.responseText;
//json字符串转为json格式
data = eval(data);
$.each(data,
function(i, v) {
alert(v);
});
}
}
//后台方法
private void GetAllComment(HttpContext context)
{
//Params可以取得get与post方式传递过来的值。
string methodName = context.Request.Params["methodName"];
//QueryString只能取得get方式传递过来的值。
string str1 = context.Request.Form["str1"];
//取得httpRequest传来的值,包括get与post方式
string str2 = context.Request["str2"];
List<string> comments = new List<string>();
comments.Add(methodName);
comments.Add(str1);
comments.Add(str2);
//ajax接受的是json类型,需要把返回的数据转给json格式
string commentsJson = new JavaScriptSerializer().Serialize(comments);
context.Response.Write(commentsJson);
}
区别:
ArrayList非安全,Vector安全
?扩容ArrayList 1.5倍 Vector 2倍
List:有序
?Set:无序
?Map:key->value(key 不可以重复;value 可以重复)
数组+链表+红黑树
不能保证线程安全
禁止进行指令的重排序(volatile关键字能确保变量在线程中的操作不会被重排序而是按照代码中规定的顺序进行访问) 有序性
在使用volatile关键字时要慎重,并不是只要简单类型变量使用volatile修饰,对这个变量的所有操作都是原来操作,当变量的值由自身的上一个决定时,如n=n+1、n++等,volatile关键字将失效,只有当变量的值和自身上一个值无关时对该变量的操作才是原子级别的,如n = m + 1,这个就是原级别的。所以在使用volatile关键时一定要谨慎,如果自己没有把握,可以使用synchronized来代替volatile。
Hashtable
ConcurrentHashMap
简单理解下悲观锁:当一个事务锁定了一些数据之后,只有当当前锁提交了事务,释放了锁,其他事务才能获得锁并执行操作。
乐观锁是首先假设数据冲突很少,只有在数据提交修改的时候才进行校验,如果冲突了则不会进行更新。
1NF:一个表中每个字段都是独立
2NF:表中的每一行数据都是唯一的,所有非主键字段都和主键字段关联,不能存在间接依赖
3NF:表中不能存在传递依赖
非公平锁
1100
HashMap
Hashtable
CocurrentHashMap->分段锁segement(RetreenLock)->synchronized+cas+红黑色
改进一:取消segments字段,直接采用
transient volatile HashEntry<K,V> table
保存数据,采用table数组元素作为锁,从而实现了对每一行数据进行加锁,进一步减少并发冲突的概率。
改进二:将原先table数组+单向链表的数据结构,变更为table数组+单向链表+红黑树的结构。对于hash表来说,最核心的能力在于将key hash之后能均匀的分布在数组中。如果hash之后散列的很均匀,那么table数组中的每个队列长度主要为0或者1。但实际情况并非总是如此理想,虽然ConcurrentHashMap类默认的加载因子为0.75,但是在数据量过大或者运气不佳的情况下,还是会存在一些队列长度过长的情况,如果还是采用单向列表方式,那么查询某个节点的时间复杂度为O(n);因此,对于个数超过8(默认值)的列表,jdk1.8中采用了红黑树的结构,那么查询的时间复杂度可以降低到O(logN),可以改进性能。
singleton
prototype
request
session
application
set注入
?构造注入
?自动注入
last_insert_id()
接口中定义Default和static
?函数式接口@FunctionInterface
?lambda表达式 ()->{}
?stream流
?日期时间
?Optional
Java中的集合(Collection)有两类,一类是List,再有一类是Set。前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。
要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?这就是Object.equals方法了。但是,如果每增加一个元素就检查一 次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它 就要调用1000次equals方法。这显然会大大降低效率。
于是,Java采用了哈希表的原理。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。
如果这个位置上没有元素,它就可以 直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了;不相同,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashcode的对象放到这个单链表上去,串在一起。
所以这里存在一个冲突解决的问题(很少出现)。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。
所以,Java对于eqauls方法和hashCode方法是这样规定的:
如果两个对象相等,那么它们的hashCode值一定要相等;
如果两个对象的hashCode相等,它们并不一定相等。 上面说的对象相等指的是用eqauls方法比较。
深拷贝和浅拷贝都是对象拷贝
for(String key :map.keySet()){
System.out.println(key+":"+map.get(key));
}
for(String val : map.values()){
System.out.println(val);
}
for(Map.Entry<String,String> e : map.entrySet()){
System.out.println(e.getKey()+":"+e.getValue());
}
Set<Map.Entry<String, String>> set = map.entrySet();
Iterator<Map.Entry<String, String>> iterator = set.iterator();
while(iterator.hasNext()){
Map.Entry<String, String> next = iterator.next();
System.out.println(next.getKey()+":"+next.getValue());
}
String newStr = new String(str.getBytes(“GB2312”), “ISO-8859-1”);
主体-》SecurityManager-》认证器(Authentication)-》Realm实现具体认证过程
?主体-》SecurityManager-》授权器(Authorization)-》Realm实现具体的授权过程
LinkedList
Lock
?原子变量:AtomicInteger
?ConcurrentHashMap
?Executor
InnoDB->内存->6
?MyISAM->文件->8
AQS:AbstractQueuedSynchronizer
抽象队列同步器,实现锁机制(CAS+FIFO)
ReentrantLock
类型 | 字节 | 取值范围 | 描述 |
---|---|---|---|
boolean | 1字节 | true/false | 仅可描述“真”或者“假” |
可直接赋值true/false
也可以直接赋值一个结果为true/false的表达式
boolean result = 3 > 2;
//注:Java中的boolean不能参与算术运算
类型 | 字节 | 取值范围(无符号数) | 字符编码 |
---|---|---|---|
char | 2字节 | 0~65535 | Unicode字符集(万国码) |
char :character
1). 应额嗯对应的ASCCI编码,中文或者其他国家语言对应Unicode编码。
2). 每个字符都有对应的整数变现形式。
3). 赋值:char c1 = ‘A’; 或者 char c2 = 65; 或者 char c3 = ‘\u0041’;
Unicode 字符集支持ASCII编码(美国标准信息交换码)。
Unicode中每个字符都对应一个十进制整数,从而可以使用多种方式赋值。
字符赋值:char c1 = ‘A’;(通过’'描述字符赋值)
整数赋值:char c2 = 65;(通过十进制65在字符集中对应的字符赋值)
进制赋值:char c3 = ‘\u0041’;(通过十六进制数41在字符集中对应的字符赋值)
如果需要在程序中输出一个单引号字符,该如何完成?
package demo;
public class TestChar {
public static void main(String[] args) {
char c = '\'';
System.out.println(c);
}
}
转义字符 | 描述 |
---|---|
\n | 换行符 |
\t | 缩进(制表符) |
\\ | 反斜线 |
\’ | 单引号 |
\’’ | 双引号 |
class Demo {
public static void main(String[] args) {
char c1 = 'A';
char c2 = 'B';
char c3 = 67;
char c4 = '好';
//char c5 = "K";
/* Demo.java:12: 错误: 不兼容的类型: String无法转换为char
char c5 = "K";
^
1 个错误
*/
char c6 = '\u0041';
char c7 = '\'';//转义字符
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println((int)c4);
/*System.out.println(c5);
Demo.java:30: 错误: 找不到符号
System.out.println(c5);
^
符号: 变量 c5
位置: 类 Demo
1 个错误
*/
System.out.println(c6);
System.out.print("Hello\n");
System.out.print("world");
}
}
类型 | 字节 | 取值范围(二进制) | 取值范围(十进制) |
---|---|---|---|
byte | 1字节 | -27~27-1 | -128~127 |
short | 2字节 | -215~215-1 | -32768~32767 |
int | 4字节 | -231~231-1 | -2147483648~2147483647 |
long | 8字节 | -263~263-1 | -9223372036854775808~9223372036854775807 |
类型 | 字节 | 负数取值范围 | |
---|---|---|---|
float | 4字节 | -3.4E+38~1.4E-45 | 1.4E-45~3.4E+38 |
double | 8字节 | -1.7E+3.8~-4.9E-324 | 4.9E-45~3.4E+38 |
ABA问题,简单描述就是存在一个变量值为A,第一个线程把变量值从A改成了B,第二个线程又把变量值从B改成了A,这样,后面的线程读取这个变量的时候就会以为变量值没有发生过任何变化。
CAS:Compare and Swap,即比较再交换,它是一条CPU并发原语。
它的功能是判断内存某个位置的值是否为预期值,如果是,则更改为最新值,这个过程是原子的。
CAS并发原语体现在Java语言中的sun.misc.Unsafe类中的各个方法,调用Unsafe类中的CAS方法,JVM会帮我们实现CAS汇编指令,它是一种完全依赖于硬件的功能,通过它实现了原子操作,再次强调,由于CAS是一种系统原语,原语属于操作系统用语的范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。
jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronzied同步锁的一种乐观锁。JDK 5之前Java语言是靠synchronized关键字保证同步的,这是一种独占锁,也是是悲观锁。
对CAS的理解,CAS是一种无锁算法,CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
长连接: 长连接(HTTP persistent connection ,也有翻译为持久连接),指数据传输完成了保持TCP连接不断开(不发RST包、不四次握手),等待在同域名下继续用这个通道传输数据;相反的就是短连接。
Host域
带宽优化
消息传递
缓存
代码示例:
//list to array
List<String> list = new ArrayList<String>();
list.add("123");
list.add("456");
list.toArray();
//array to list
String[] array = new ArrayList<String>();
Arrays.asList(array);
Iterator 提供遍历任何Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭代器实例。迭代器取代了Java 集合框架中的 Enumeration,迭代器允许调用者在迭代过程中移除元素。
Iterator 使用代码如下:
List<String> list = new ArrayList();
Iterator<String> it = List.iterator();
while(it.hasNext()) {
String obj = it.next();
System.out.println(obj);
}
Iterator 的特点是只能单项遍历,但是更安全,因为它可以确保在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException 异常。
边遍历边修改 Collection 的唯一正确方式是使用 Iterator.remove()方法,如下:
Iterator<Integer> it = list.iterator(); while(it.hasNext()){ //do something it.remove(); }
一种常见的的错误代码:
for(Integer i :list) { list.remove(i); }
运行以上错误代码会报 ConcurrentModificationException 异常。这是因为当使用 foreach(for(Integer i : list)) 语句时,会自动生成一个 Iterator 来遍历该 list,但同时该list 正在被 Iterator.remove()修改。Java一般不允许一个线程在遍历Collection 时另外一个线程修改它。
- Iterator 可以遍历 Set 和 List 集合,而 ListIterator 只能遍历LIst。
- Iterator 只能单向遍历,而 ListIterator 可以上双向遍历(向前/向后遍历)
- ListIterator 实现 Iterator 接口,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。
HashSet 是基于HashMap 实现的,HashSet的值存放于 HashMap 的 key 上,HashMap 的 value 统一为 PRESENT,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。
- 向 HashSet 中add()添加元素时,判断元素是否存在的依据,不仅要比较hash值,同时还要结合equals 方法比较。
- HashSet() 中的 add() 方法会使用 HashMap 的 put() 方法。
- HashMap的 key 是唯一的,由源码可以看出 HashSet 添加进去的值就是作为 HashMap 的key,并且在HashMap 中如果 K/V 相同时,会用新的V覆盖掉旧的V,然后返回旧的V。所以不会重复(HashMap 比较 key 是否相同时先比较 hashcode 再比较 equals)。
HashSet 部分源码:
private static final Object PRESENT = new Object();
private transient HashMap<E,Object> map;
public HashSet() {
map = new HashMap<>();
}
public boolean = add(E e) {
return map.put(e,PRESENT) == null;
}
- 如果两个对象相等,则hashCode一定也是相同的
- 两个对象相等,对两个equals方法返回为true
- 两个对象有相同的hashCode值,它们也不一定是相等的
- 综上,equals方法被覆盖过,则hashCode方法也必须被覆盖
- hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该class 的对象无论如何都不会相等(即使这两个对象指向形同的数据)。
- == 是判断两个变量或者实例是不是指向同一个内存空间 equals 是判断两个变量或者实例所指向的内存空间的值是不是相同。
- == 是指对内存地址进行比较 equals()是对字符串的内容进行比较。
- == 指引用是否相同 equals 指的的是值是否相同
HashMap | HashSet |
---|---|
实现了Map接口 | 实现了set接口 |
存储键值对 | 仅存储对象 |
调用put()向map 中添加元素 | 调用 add() 方法向set中添加元素 |
HashMap 使用键(Key)计算 HashCode | HashSet使用成员对象来计算 hashCode 值,对于两个对象来说 hashCode 可能相同,所以 equals() 方法用来判断对象的相等性,如果两个对象不同的话,那么返回false |
HashMap 相对于HashSet较快,因为它是使用唯一的键获取对象 | HashSet 较 HashMap来说比较慢 |
- HashMap 概述:HashMap 是基于哈希值的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
- HashMap的数据结构:在Java编程语言中,最基本的结构就是两种,一个数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个"链表散列"的数据结构,即数组和链表的结合体。
- 当我们往 HashMap 中 put 元素时,利用 key 的hashCode 重新 hash 计算出当前对象的元素在数组中的下标。
- 存储时,如果出现 hash 值相同的key,此时有两种情况:(1)如果 key 相同,则覆盖原始值。(2)如果 key 不同(出现冲突),则将当前的 key-value 放入链表中。
- 获取时,直接找到 hash 值对应的下标,再进一步判断 key 是否相同,从而找到对应值。
- 理解了以上过程不难明白 HashMap 的实现是如何解决hash冲突的问题,核心就是使用了数组的存储方式,然后将冲突的key的对象放入链表中,一旦发生冲突就在链表中作进一步的对比。
- JDK1.8中对HashMap的实现做了优化,当链表中的节点数超过8个之后,该链表会转为红黑树来提高效率。