JavaWeb相关
1、编码问题(Get\POST)
2、集合(map) List 有序(存取), Set无序
3、常用类(String、servlet、异常类、集合、Thread、Number、Double、system)
4、request、response
5、字符转换===>网络中传输的是字节数组,String编码成字节数组,收到后解码显示
6、转发与重定向
7、参数传递
8、会话跟踪的四种实现方式
9、cookie
10、session
11、表单域
12、URL重写
13、Servlet
14、Filter
15、对象的初始化
16、Error.jsp
17、Properties
18、日志
19、\ 和 /
20、反射(xml、)
21、内联函数
22、Volatile
23、ThreadLocal:线程局部变量
24、transient
25、JVM相关(类的加载和执行)
26、版本区别(可变参数、枚举)
27、数据库(JDBC、DBMS)
28、Web容器
30、常用API(String、集合、Thread)
31、JSP
32、事件处理模型
33、java特点
34、多线程(thread、runnable、collable、condition)
35、良好的代码习惯
36、Java的三大注解( 由虚拟器控制给出注解,提示开发人员注意编码规则 )
37、内联函数
38、存根类(Stub)
39、扩展方法
40、数组复制
41、设计模式 42、项目 43、框架
准备明年开始找工作,所有刷了牛客app上的900多道Java相关的笔试题,
整理了答案下面的 精华知识,以备不时之需。如有不合理之处,万望知会。
QQ:510629167
JavaWeb相关:集合、多线程、JVM、常用类、版本区别、
1、编码问题(Get\POST)
① html页面:浏览器会根据
② Request :request.setCharacterEncoding(“UTF-8”)应用于通过getParameter()获取字符串,只对POST有效。必须设置在servlet中getParameter()方法被调用之前,原因是:只有在第一次调用getParameter()方法时会查询encoding编码格式,后续的getParameter将不再查询编码格式。
对于GET提交,get提交的内容存在URL中,需在Tomcat的server.xml设置,在Connector标签中设置生成URI时的编码格式 URIEncoding=”UTF-8”。(个人理解为 针对URI这一特殊类型数据,在server中统一设置编码格式,不管是在JSP还是Servlet中出现,都使用统一的解码方式,避免了乱码的发生)。默认为ISO8859-1。
③ Resopnse :response.setContentType(“text/html”;charset=”UTF-8”)是指定HTTP响应的编码,同时指定浏览器(JSP)的显示编码,显示编码不一定在JSP中有效果,因为JSP中设置的编码格式优先级更高。
response.setCharacterEncoding(“UTF-8”)的作用是设置HTTP的响应编码,设置应在getWriter和response被提交之前。(个人理解为 此编码的设置是针对要返回的数据进行编码生成response,再返回)。
④ JSP:<%@page ContentType=”text/html;charset=UTF-8”%>
<%@page pageEncoding=”charset=UTF-8”%>
以上两种编码只有一种有效,用于设置 页面的显示编码。
如果页面中使用include标签导入了其他的JSP,<%@ include file=”BB.jsp”%>设置的BB.jsp中不能再设置编码,
对于URL和URI的区别。请看:https://www.cnblogs.com/hust-ghtao/p/4724885.html
2、集合(map) List 有序(存取), Set无序
集合主要有Vector、HashTable、ArrayList、HashMap、stack
1) Vector 默认初始化容量为10,扩容为1倍扩容。比ArrayList多了同步机制,效率较低,线程安全,在内存中占用连续的空间,当数据量大时,会分配更大的连续空间。如果Vector定义为Object类型,则可以存放任意类型,已弃用。
2) HashTable 默认初始化容量为11,扩容为2倍。比hashmap多了同步机制,是线程安全的,对整张哈希表加锁。key、value都不可为null,存储的key为对象的hashcode,已弃用。
3) concurrentHashMap提供一组和HashMap功能相同但线程安全的方法。将Hash表分为16桶(segment),每次只对需要的桶加锁。在JDK1.8之后,可以做到读取不加锁,其内部结构可以在写操作时将锁粒度尽量的小,锁区变小。ConcurrentHashMap并不再是分段锁,而是更细粒度的锁,只是在修改map时对链表头加锁。(红黑树根)
4) HashMap 默认初始化容量为16,扩容为2倍+1。未进行同步考虑,是线程不安全的,key、value都可以为null,判断key=null;的键是否存在,应该用containsKey方法,并不能用get方法。因为get返回null,即可表示null键也可表示不存在。存储的key重新计算hash值(+salt?).
采用快速失败机制(Fail-Fast),
5) HashSet内部使用Map保存数据,即将HashSet的数据hashcode做key,添加一次须比较两次,hashcode、equals。
6) ArrayList 实现了List接口,内部基于数组结构实现存储,随机访问速度快。默认初始化容量为10,扩容为1.5倍扩容。
ArrayList在删除元素后,剩余元素会依次向前移动,因此下标会变。
有三个构造函数。
Arraylist()构造一个初始化容量为10的空列表。
Arraylist(Collection extends E> c)构造一个包含指定collection的元素列表,按迭代器返回它们的顺序。?
Arraylist(int initialCapacity)构造一个指定容量列表的空列表。
其他方法:
remove()方法调用的是remove(int index);而不是remove(Object o); 因此删除index索引出元素。
7) LinkedList实现了List接口,内部基于链表结构实现存储,增删快。
8) LinkedBlockingQueue:基于链接节点的可选限定的blocking queue(先进先出)。头部最长,尾部最短,链接队列通常具有比基于阵列的队列更高的吞吐量,但在并发应用程序中可预测性能较低。
blocking queue:说明不接受null元素,可能是容量有限的,表示不再添加项目实现是线程安全的。
9) PriorityQueue:基于优先级堆的无限优先级queue。优先级队列的元素根据它们的有序natural ordering或由一个Comparator在队列构造的时候提供,这取决于所使用的构造方法。优先级队列不允许null元素,自然排序的优先级队列也不允许插入不可比较的对象(可能导致ClassCastException)。此实现不同步,多线程不应同时访问PriorityQueue实例,而应该使用PriorityBlockingQueue类(线程安全)。
10) ConcurrentLinkedQueue :基于链接节点的无界并发deque(deque是双端队列),并发插入,删除和访问可以跨多个线程安全执行,不允许null元素。
7)AbstractSet类实现了set接口,HashSet继承AbstractSet类,同时实现set接口。
6) stack堆栈类,继承了vector.
7) enumeration 枚举,相当于迭代器
集合的实现问题图:
Map:
8) 对于线程不安全且使用迭代器的集合,采用快速失败机制(fail-Fast)。多线程访问中如果使用迭代器过程中,有其他线程修改了集合对象结构,可能会抛出ConcurrentModificationException,所谓快速失败机制。在迭代器创建之后,如果从结构上对映射进行修改,除非使用迭代器本身的remove方法。
9) HashTable 和 HashMap的区别:
1) 继承不同
public class HashTable extends Dictionary implements Map
public class HashMap extends AbstractMap implements Map
2) 同步问题
HashTable 中方法是同步的,而HashMap中方法在缺省的情况下是同步的,需要自己添加同步。
3) null 的问题:
HashTable中,key、value都不允许出现null值,
HashMap中,null可以作为键,这样的键只有一个,可以有多个value=null,需要自己增加同步。
4) 遍历方式不同:
HashTable、HashMap都使用了Iterator,而由于历史原因,HashTable还使用了Enumeration的方式,
5) 哈希值不同:
HashTable直接使用对象的hashcode,而HashMap重新计算hash值。
6) 初始化和扩容:
HashTable和HashMap内部实现都是数组初始化大小和扩容方式。
HashTable的Hash数组默认为11,扩容为old*2+1;
HashMap的hash数组默认值为16,而且一定是2的指数扩容。
Java.util.Collection是一个集合接口,提供了对集合对象进行基本操作的通用接口方法,Collection接口的意义是为各种具体的集合提供最大化的统一操作方式。
Java.util.Collections是一个包装类,包括有各种有关集合操作的静态方法,不能实例化,就是一个工具类,服务于Java的Collection框架。
Collections 类提供了sychronizedXxx()方法,可以将指定集合包装成线程安全的集合。
比如:List list = Collections.synchronizedList(new ArrayList());
Set set = Collections.synchronizedSet(new HashSet());
3、常用类(String、servlet、异常类、集合、Thread、Number、Double、system)
String : 用char[]数组实现,结尾不用”\0”。
String str = “he”+new String(); 运行期间生成的--->指向堆内存???
new String(“22”) 实际上创建了2个String对象,字符串常量池--存在方法区和堆中
String s=”a”+”b”+”c”; 编译期完成。
String类是final类,成员方法默认为final方法,底层是char()数组来保存,没有“/0”
对String对象的任何改变都不会影响到原对象。
当代码中出现字面量形式创建字符串对象时,JVM首先会对字面量进行检查,如果常量池存在相同内容引用,则将引用返回,否则新的字符串对象被创建,然后将对象放到字符串常量池,并返回此引用。
方法:
(1) String.toUpperCase();==>转换为大写,有返回值
(2) string.replace(‘f’,’F’); ==>用F替代f,无返回值(参数为char和charSequence)
(3) string.replaceAll(‘regex’,’’);==>all 匹配的是正则表达式(.匹配各个字符)
(4) string.equals()==>String 重写了Object类的方法
Servlet 相关:
GenericServlet 抽象类给出了设计servlet的一些骨架,定义了servlet的生命周期,还有一些得到名字、配置、初始化参数的方法,设计与应用层无关。
service 方法是在servlet生命周期中的服务器,默认在HttpServlet类中实现,根据Http请求方法,将请求分发到doGet、doPost等方法实现。
javax.servlet.GenericServlet接口实现了javax.servlet.Servlet接口,且javax.servlet.http.HttpServlet是javax.servlet.GenericServlet子类。
Servlet的生命周期:
**************************************************************
***********
****此处贴图 Servlet的生命周期图
servlet处于服务器进程中,通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其一般不会销毁,而CGI对每个请求都产生新的线程,服务完成后就销毁,效率低,且不可移植。
异常:try-catch-finally try/catch 抛出异常会增加更大的开销。
如果try的return有执行语句,例如:return i--; i--会执行,而return不会执行,进入finally。(finally一定会执行,除非try/catch中有 system.exit(0))退出。
finally中的语句不能影响try/catch中已经确定的i值,(可以说try/catch可以传递值到finally中,finally就像一个方法,i值就像一个参数,并不能把值传递回去)。最后从try中返回出i在try中的值。
结论:return 并不是函数的最终出口,也就是说遇到return要考虑是否还有finally要执行。如果存在funally代码块,会在return之前执行finally中的代码。
①. try、catch、finally都有return语句,返回finally的值。(try会执行return之后的语句,例如:i--);
②. 仅try、catch中有return语句。没有异常,执行完finally,返回i在try块中的值。
③. try中抛出异常,try、catch、finally中都有return,返回finally中的值。
④. try中抛出异常,try、catch中都有return,返回catch中的值。
⑤. try、catch中都出现异常,在finally中有返回,返回finally中的值。
finally中不建议放return语句,return语句可以放在try和catch里面和函数的最后。
finally语句中一般放置 释放资源、关闭数据库、关闭文件等操作语句。
当一个方法在运行时出现未catch的异常,则这个方法终止,但整个程序不终止。
异常分类:
所有的异常都继承自java.lang.Exception类。
检查性异常:不处理编译出错,===》非运行时异常 一般dao中throws抛,service中catch
非检查性异常:如果有抛出直接抛到控制台,==》RuntimeException 运行时异常Java编译器不会检查。
异常分类图
异常指程序运行时(非编译)所发生的错误,jvm将错误以异常形式抛出。
error类主要是运行时,逻辑错误导致的,jvm停止,
exception表示可恢复异常,包括检查性异常和运行性异常
检查性异常多包括IO异常、SQl异常,多发生在编译期,通过try/catch捕捉。
运行性异常一般都上抛,直到遇到处理代码,多线程用run()抛出,单线程用main()抛出。
Thread类可以被继承,用于创建线程。
Number类可以被继承,Integer和Float都是其子类。
Double和Math类都被final修饰,不可继承。
ClassLoader可以被继承,用户可以自定义类加载器。
Math类的方法:
Math.cos为计算弧度的余弦值,Math.toRadians 方法将角度转换为弧度。
java.lang 包是java语言的核心包,lang是language的缩写,包括:基本的类型、包装类型等,Integer、String等,由解释器引入。
4、request、response
request.getParameter(“xxx”);获取http提交的数据,返回值为字符串。
request.getAttibute(“xxx”);获取request域中存在的对象,返回对象。
5、字符转换===>网络中传输的是字节数组,String编码成字节数组,收到后解码显示
字符流 = 字节流 + 编码集
1)GBK编码字节流到UTF-8编码字节流的转换:dst=new String(src,”GBK”).getBytes(“UTF-8”);
new String(src,”GBK”):将一个字节数组编码成一个String。===> 字符串具有
str.getBytes(“UTF-8”): 将一个string解码成一个数组数组。 ===> 编码格式
2)将ISO-8859-1字符串转换成GB2312编码:
new String(“ISO-8859-1”.getBytes(“ISO-8859-1”),”GB2312”); 字符串==>字节数组==>字符串
String UTF-8str = new String(oldGBKStr.getBytes(“GBK”),”UTF-8”);
字符串解码成字符数组,字节数组编码成字符串。
实际的编码国际化常用手段利用ResourceBundler类,根据Local的不同,选择性选取与Local对应后缀的Properties文件。
6、转发与重定向
forward(请求转发):发送一次请求,将表单数据或封装到url中的数据一并转发到新页面。
redirect(重定向):发送两次请求,一次请求会收到302状态码,第二次请求收到新地址。
1)response.setStatus(302);response.addHeader("Location","URL");
2)response.sendRedirect("URL");
1)从地址栏显示看:
forward是服务器请求资源,服务器直接访问目标中的URI获取响应,经响应发送给浏览器。
redirect服务器发送一个状态码302,告诉浏览器去请求地址(location),url可以是其他应用。
2)从数据共享来说:
forward转发页面和转发到的页面可以共享request中的内容。redirect不能共享。
3)从运用应用方面:
forward 用于登录注册页面
redirect 用于注销登录返回主页面或跳转其他网站,不再使用response输出数据,否则会异常。
4)从效率看
forward 效率高
redirect 效率低
7、参数传递
基本类型传递值,引用类型传递地址,在方法中,可根据地址改变引用类型的成员变量值。
值传递不可以改变原变量的内容和地址(仅副本做局部变量)。
引用传递不可以改变原变量地址,但可通过引用改变值。
一个方法不能修改一个基本数据类型的参数(数值、布尔),===>值传递
一个方法可以改变一个对象(引用)的值,一个方法不可改变对象的原引用。==>引用类型
若将一个变量(常量)赋值给一个引用类型,则等于new一次引用类型对象,与方法外没有关系。????
8、会话跟踪的四种实现方式
1) 表单域:,非常适合需要大量数据存储的会话应用
2) URL重写:URL可以在后面附加参数,和服务器的请求一起发送,url&name=value
3) Cookie:Cookie是一个小的,已命名的数据元素,服务器使用set-Cookie头标记它为HTTP响应的一部分,发送给客户端,客户端保存cookie的值,在对同一服务器的后续请求中使用cookie将内容返回给服务器,cookie保存在客户端,可设置保存时间。(session的Id存储在cookie中)。
4) session:使用setAttribute(String str,Object obj)方法将对象捆绑到一个会话上。
每个session对象有一个唯一的Id,保存在客户端的Cookie中,关闭浏览器SessionId消失。
如果客户端禁用cookie,可以使用url重写的方法实现会话跟踪。
session用来表示用户会话,session对象在服务端维护。
cookie存放在客户端,可以分为内存cookie和磁盘cookie,超时消失。
隐藏域在页面中对于用户是不可见的,在表单中插入的目的是收集和发送消息。
9、cookie
10、session
11、表单域
12、URL重写
13、Servlet
14、Filter
servlet中的过滤器格式:
filter-mapping可映射到一个或者多个servlet或JSP文件,
15、对象的初始化
16、Error.jsp
17、Properties
Properties实现了Map接口,是线程安全的。(setProperties方法中有synchronized)
18、\ 和 /
19、日志
日志的级别大小关系:ALL log4j建议只使用四个级别:优先级从高到低:ERROR>WARN>INFO>DEBUG 20、反射(xml、) 反射破坏了原有的访问修饰符的访问限制。 21、内联函数 java中的内联函数从空间换时间,===》递归适宜用内联(原理是使用方法时不需要再调用) final关键字会告诉编译器,可以将final函数视为内联函数,但编译器最终会权衡性能再做确定。final有助于锁定方法和提高效率。缺点是占用空间,消耗内存。 22、Volatile volatile 修饰成员变量被线程访问时,都强迫线程从共享内存中重读该成员变量的值。而且,当其值发生变化,强迫线程将变化之后的值写到共享内存中。故两个线程总是能看到同一个值。如此一来,一个volatile对象的引用可能为null,(提示该变量的值已经改变,需要从原始内存地址中读取该值) 使用地方: 1. 中断服务程序中修改的供其他程序检测的变量加 volatile 另外:还要考虑数据的完整性(相关联的几个标志读了一半被打断重写) Volatile修饰的作用: 1)可见性:指在一个线程中对该变量的修改会马上由工作内存(高速缓存、独享内存)写会到主内存(共享内存),马上反应在其它线程读取中。 2)禁止指令重排序优化:由于编译器优化,在实际执行中语句的执行顺序可能不同,这在单线程执行可保证结果一致,在多线程中可能导致严重的问题,volatile可以防止代码优化。 在JDK1.5之前,volatile不起作用,双重检查锁形式的单例模式无法保证线程安全,?? 23、ThreadLocal:线程局部变量 java.lang.ThreadLocal是TLS技术实现。 线程局部变量不能解决静态变量的存取冲突,故变量仍需同步。可解决多线程中对同一变量的访问冲突。 24、transient 25、JVM相关(类的加载和执行) 1、JVM的功能: a.通过ClassLoader寻找和装载class文件 b.解释字节码成为指令并运行,提供class文件运行环境 c.进行运行期间垃圾回收 d.提供与硬件交互的平台 2、垃圾回收: 1)虚拟器线程等待JVM到达安全点之后出现,操作必须在独立的线程里执行,因为当堆修改无法进行时,线程需要JVM位于安全点。VMThread包括stop-the-world垃圾回收、线程栈dump、线程暂停、线程偏向锁(basicObjectLock)解除。 2)safePoint安全点可以挂起线程,防止线程无限运行,一般位于循环末尾(防止大循环)、方法返回前、调用方法的call之后、抛出异常的位置。 3)safepoint 只能处理一些正在运行的线程,对于一些sleep()或block()的线程会被添加到safe region区域。标记safe region。当它被唤醒时,应该先检查GC是否完成操作。 4)GC的时候,所有进入safepoint的线程会在一个Thread.lock锁阻塞,直到当JVM的GC完成操作,JVM释放锁,阻塞的JAVA线程才能运行。 5)GC线程:这些线程支持JVM中不同的垃圾回收活动。 6)对象的回收:对象、数组存放在JVM堆中,分为新生代和老年代。新生代分为三个区,一个Eden、两个survivor,对象创建之后存在Eden(容量很大的对象可以创建到老年代)。新生代会执行MinorGC,98%的对象会被回收,不被回收的对象转移(复制算法)到一个survivor中,然后等待下一次MinorGC,GC之后Eden剩下的对象和survivor中的对象都被转移到另一个servivor中,对象就在两个survivor中不断转换。直到经历15次MinorGC才能进入老年代(old)。old中会执行FullGC,但比MinorGC的执行频率要低很多。FullGC一般耗时为MinorGC的22.89倍。新生代一般18M,老年代一般42M。 7)垃圾回收由新生代和年长代协作,称为分代回收,分别采用复制算法和标记整理算法。 复制算法:两个区域A和B,初始化对象在A,继续存活的对象被转移到另一个区。用在新生代的回收上。新生代分为一个Eden、两个survivor区。 标记整理算法:一块区域,对所有的对象进行标记(可达性标记),然后回收不可达对象,因为不是复制转移算法,所以会出现碎片。整理算法可以将碎片空间进行整理,整理出更大的内存空间存放更大的独享。 7)对象的回收机制:当前对象是否回收,主要是采用可达性分析,如果不可达,会进行一个F-Queue队列之中,在finalize方法执行过程中,会进行第二次标记是否可达,选择自救还是回收。垃圾回收线程在jvm中优先级相当的低。 8)程序开发者只能推荐JVM进行回收,但何时回收,回收哪些不能控制,-->可通过system.gc()来建议gc回收。垃圾回收只是回收不再被使用的JVM内存,与内存是否溢出没有直接关系。 9)真正宣布一个对象死亡:第一次标记-->调用finalize方法-->第二次gc回收。 10)各版本的垃圾回收器: 单线程收集器,在进行垃圾收集时,必须暂停其他所有的工作线程,直到它搜集结束。 多线程收集器, jdk1.3 Serial New收集器:针对新生代,单线程收集器(使用复制收集算法) jdk1.4 Parallel New收集器:并行回收,多线程收集器(新生代和年长代采用不同的算法)。 jdk1.4 Paraller Scavenge:并行,新生代多线程,吞吐量最大化,精确控制吞吐量。 吞吐量=运行用户代码/CPU运行时间(用户代码+垃圾回收) jdk1.5 CMS(Concurrent Mark Sweep)目标:最短回收停顿时间。(标记-清除) jdk1.5 Serial Old老年代版本,它同样是一个单线程收集器,(使用标记整理算法) jdk1.6 Parallel Old并行,注重吞吐量以及CPU资源敏感的场合,可以优先考虑Parallel Scavenge+Parallel Old收集器组合。 jdk1.7 G1并行与并发、分代收集、空间整合、可预测的停顿,有意代替GMS。(整体标记整理,局部采用复制) 11)内存泄漏(Memory leak)是指一个不再被使用的对象或者变量还在内存中占用存储空间,在java语言中引入垃圾回收机制,有GC负责进行回收不再使用的对象,释放内存。但还是会出现内存泄漏,主要有两个情况:1)堆中申请的空间没有释放,2)对象仍保留连接引用(例如数据库连接) 12)内存泄漏的原因:如数据库连接、网络连接、IO连接,不再使用时如果连接不释放容易造成内存泄漏。释放对象时往往没有删除响应的监听器,可能造成内存泄漏。 13)内存溢出(OOM)是指程序在申请内存时没有足够的内存供使用,进而导致程序奔溃。内存泄漏最终导致内存溢出。 2、JVM维护了一个数据结构,记录了所有的线程,所以它可以快速检查所有线程的状态。 3、JVM通过控制主内存与每个线程的本地方法内存之间的交互,为java提供内存可见性(保证线程通信)。 4、如果使用jconsole或其他调试器,会看到很多线程在后台运行,主要有JVM线程、触发main方法的主线程以及主线程创建的其他线程一起运行。 5、JVM有两种执行方法:解释型和编译型(JIT) 在JIT执行方式下,将safepoint的检查代码加入到本地代码,当JVM需要线程进入safepoint时,只需要设置标志位,运行到标志位,如果标志位被设置则进入safepoint。 在解释型执行下,JVM会设置一个2字节的dispatch tables解释器,执行过程中会经常检查这个dispatch tables,当有请求发生时,则让线程进入safepoint。 6、周期性任务线程:该线程负责定时器事件(也就是中断),用来调度周期性操作的执行。 7、编译器线程:这些线程在运行时将字节码动态编译成本地平台相关的机器码。 8、信号分发线程:这个线程接收发送到JVM的信号并调用适应的JVM方法处理。 虚拟机中的线程图示: 操作系统分配给每一个线程2G的内存,2G = 堆内存+方法区+程序计数器+本地栈+线程栈 一般线程栈有1000-2000栈帧就够用于递归,如果发生内存溢出==没有多余的内容分配给新对象,可以适当的减少栈的容量,来扩大堆的容量。 26、版本区别(可变参数、枚举) JDK1.5版本变化:可变参数、condition锁、 JAVA支持传递同类型的可变参数给一个方法,一个方法只能指定一个位于参数末尾的可变参数;...在类型和参数名之间;以数组形式存在。 JDK1.7版本变化:字符串常量池、 字符串常量池从方法区移到堆中。 新增了多个catch的功能:先小后大 JDK1.8版本变化: 废弃永久代(Perm Gen)整个常量池从方法区移除,方法区使用元空间(Meta-Space)实现。 接口中的方法可以由static和default修饰。static修饰的方法由接口直接调用,默认修饰符的方法只能由接口的实现类调用,提供了可选功能。 抽象类的访问权限由Protected变为default。 JDK1.9版本变化: 接口的方法修饰符可以为private 27、数据库(JDBC、DBMS) JDBC:JNDI--DataSource---连接池(c3p0\dbcp\Proxool)----DriverManager---connection oracle的数据库驱动:oracle.jdbc.driver.OracleDrive mysql 的数据库驱动:com.mysql.jdbc.Driver 数据库连接方式有两种: 1.建立JDBC--ODBC桥接器(微软提供)依赖平台, 2.直连纯Java数据库驱动(数据库厂家提供例如 mysql的mysql-connector-java.jar) 数据库实现查询功能: 经过优化之后: (1) 使用数据库连接池对连接进行管理 (2) SQL语句统一存放到配置文件中 (3) SQL语句变量和传入参数的映射以及动态SQL (4) 动态SQL语句处理 (5) 对数据库操作结果的映射和结果缓存 (6) SQL语句的重复 驱动的加载方法有: a、调用方法class.forName b、通过添加系统的jdbc.drive属性 c、通过registerDriver方法注册 DriverManger.getConnection方法返回一个Connection对象,这是加载驱动之后才能进行的。 PreparedStatement和Statement的区别: 创建时: 1) Statement statement = conn.creatStatement(); 2) PrepareStatement preStatement = conn.PrepareStatement(sql); 执行时: 1) ResultSet rSet = statement.executeQuery(sql); 2) ResultSet pSet=preStatement.executeQuery(); PreStatement 有预编译过程,已经绑定sql,之后无论执行什么遍,都不会再去编译。 而statement不同,如果执行多遍,就需要编译多遍,所以prestatement效率比较高。 3)安全性:prepareStatement是预编译的,所以可以有效的防止SQL注入等问题。 4)可读和维护:后期维护prepareStatement也比较好读。 JDBC-ODBC方式: 建立JDBC-ODBC桥接器,(使用java.lang中的class类,使用静态方法forName加载驱动) 创建ODBC数据源, 建立与ODBC的连接(可能异常) DBMS:数据库管理系统,事务具有持久性、一致性、原子性、隔离性。 持久性实现恢复管理子系统,一致性实现并发控制子系统, 原子性实现完整子系统,隔离性实现安全控制管理子系统。 一般关系数据模型和对象数据模型之间有以下对应关系:表对应类、记录对应对象、字段对应属性,ORMapping只是规定了结构和集的映射。 28、Web容器 web容器给处于其中的应用程序组件(JSP、Servlet)提供一个环境,使JSP、Servlet直接依靠容器中的环境变量交互,不用关注其他系统问题,主要由WEB服务器实现。 J2EE中的WEB容器主要有: EJB容器(Enterprise java bean)提供给运行在其中的组件EJB各种管理功能,满足J2EE的组件被高效率的管理,并且可以通过现成的接口获得系统级别服务,例如:邮件服务,事务管理 JNDI(Java Naming&Directory Interface):Java命名目录服务。功能:提供一个目录级,让其它各地的应用程序在其上留下自己的索引,从而满足快速查找和定位分布式应用程序的功能。 JMS(Java Message Service):主要实现各个应用程序之间的通讯,包括点对点和广播。 JTA(JAVA Transcation API):Java事务服务,提供各种分布式事务服务,应用程序只需要调用其提供的接口。 JAF(Java Action FrameWork):Java安全认证框架,让开发者通过各种部署和自定义实现自己的个性安全控制。 RMI/IIOP(Remote Method Invocation/internet对象请求中介协议):主要用于远程调用服务。异构系统通过一定的规范才可实现调用。RMI是Java特有的。(Stub和Skeleton) JMX(Java Management Extensions) Java 管理扩展是一个为应用程序、设备、系统等植入管理功能的框架,可以跨越一系列异构操作系统平台、系统体系结构和网络传输协议,灵活的开发无缝集成系统、网络和服务管理应用。1.3之后开始支持。 Swing提供了3种顶层容器类:JFrame、JDialog、JApplet。 Maven 的核心功能就是合理叙述项目间的依赖关系,通过pom.xml配置jar包信息。一般使用三种方式:本地仓库、第三方仓库、中央仓库。 29、常用API(String、集合、Thread) 30、JSP 1、JSP的九大内置对象及四个作用域 request 请求对象 类型:javax.servlet.servletRequest 作用域: Request response 响应对象 javax.servlet.servletResponse Page pageContext 页面上下文对象 javax.servlet.jsp.PageContext Page session 会话对象 javax.servlet.http.HttpSession Session application 应用程序对象 javax.servlet.servletContext Application out 输出对象 javax.servlet.jsp.JSPWriter Page config 配置对象 javax.servlet.ServletConfig Page page 页面对象 javax.lang.Object Page exception 例外对象 javax.lang.Throwable Page JSP的四大域: Page作用域代表当前页面有效,一旦JSP页面结束,page中的数据将消失。 Request 作用域是请求过程,从JSP页面发出请求,到页面跳转转发,服务器servlet处理,发回响应。在forward转发的JSP页面都可以使用request中的数据。 Session作用域是会话,从打开浏览器就会创建一个session对象存储在浏览器,在浏览器关闭之前都可以使用session(用户独享)。 Application 作用域是应用,从开启一个应用到应用结束,都可以使用Application(在服务器的运行过程中都可以使用,可以说是所有用户共用) 九大内置对象: response的作用: 1.构建响应信息: 设置http头标、返回数据类型、 方式一:response.setHeader("Content-type","test/html;charset=utf-8"); 方式二:response.setContentType("text/html;charset=utf-8"); 2.构建响应实体: 输出返回数据 方式一:response.getOutputStream().write("xxx".getBytes());string转成 字节数组 这是一个字节流,是什么字节输出什么字节,而浏览器默认用平台字节码打开服务器发送的数据,如果服务器端使用了非平台码去输出字符的字节数据就需要明确的指定浏览器编码时所用的码表,以防止乱码问题, 方式二:response.getWriter().write("xxx") 这是一个字符流,response会将此字符进行转码操作后输出到浏览器,这个过程默认使用ISO8859-1码表,而ISO8859-1中没有中文,于是转码过程中用?代替了中文,导致乱码问题。可以指定response在转码过程中使用的目标码表,防止乱码。 response.addHeader("Content-type","text/html;charset=utf-8")/response.setContentType("text/html;charset=utf-8");指定转码过程使用的码表。 PageContext(页面上下文)可对页面JSP中所有对象及名字空间访问页面功能集大成者。 context.getParameter()获取POST/GET传递的参数(一般jsp到servlet传值) context.getInitParameter()获取Tomcat的server.xml中Context的初始化参数 context.getAttribute()获取对象容器中的数据值===>用于页面之间传值(servlet到jsp传值) context.getRequestDispatcher()是请求转发 exception 代表JSP文件运行时所产生的例外对象,此对象不能在一般JSP中使用,而只能在有此标签标示<% page isErrorPage = “true” %> 的JSP文件中使用。 当isErrorPage = “false”时,用errorPage = “error.jsp”。(isErrorPage默认为false)。 当isErrorPage = “true”时,页面会使用Exception。在当前页面使用异常处理。所以error.jsp页面一定要有isErrorPage属性且值为true。 JSP的EL表达式 JSP中的EL表达式作用: 1) 获取数据: 2) 执行运算 3) 获取web开发常用对象 4) 调用java方法 <% expression %> 语句块(脚本) <% = expression %> 表达式 <% !变量.方法 %> 声明 <%!-- xxxxxx --> 注释 WEB容器 web容器在启动时为每个web应用创建一个ServletContext对象,ServletConfig对象维护了ServletContext的引用,开发人员在编写servlet时,可通过ServletConfig.getServletContext方法获取ServletContext方法ServletContext对象。所有Servlet共享一个ServletContext,因此Servlet对象可通过其完成通讯,也称为context域对象。 1) 在InitServlet的service方法中利用ServletContext对象存入需要共享的数据。 ServletContext context = this.getServletContext(); context.setAttribute(“name”,”haha”); 在其他servlet中可获得数据: ServletContext context = this.getServletContext(); context.getAttribute(“name”); 2) 获取WEB应用的初始化参数,在DemoServlet的doPost方法中测试获取初始化参数: ServletContext context = this.getServletContext(); String url = context.getInitAttribute(“url”); 31、事件处理模型 Java提供的事件处理模型是一种人机交互模型,有三个基本要素。 1) 事件源:事件发生的场所,指各个组件,如按钮。 2) 事件: 事件封装了组件上发生的事件,比如按钮单击、按钮松开等。 3) 事件监听器:负责监听事件源上发生的特定类型的事件,当事件到来时,还必须负责处理响应的事件。 32、java特点 一处编写,到处运行。 Java并不完全是编译型语言,编译的字节码文件运行时是解释执行的, Java和C++的类也不都是完全静态绑定的,java的父子类调用==C++的虚函数。 33、多线程(thread、runnable、collable、condition) 1、守护线程(daemon):通过调用void setDaemon(boolean on)方法将自己设置成一个守护线程。thread.setDaemon(true); 当所有的用户线程执行结束后,即使守护线程的run()方法还有未执行语句,也会立刻结束线程。 2、从JDK1.5开始,Java提供了三种方式来创建线程: 继承Thread类创建多线程,重写run()方法作为线程执行体。(不能再继承其他类\每一条线程都是Thread子类的实例共享数据复杂) 实现Runnable接口来创建线程,重写run()方法作为线程执行体。Thread(Runnable in); 实现Callable接口创建线程,重写run()方法作为线程执行体。实现Callable可返回结果,可抛出异常,通过futureTask.get(),方法获取结果,如果没有结果返回,可能会阻塞主线程。 3、线程知识 t.start(); 方法启动一个线程,使其处于就绪状态,得到CPU就执行,而调用run()相当于普通的方法调用。start()方法将“新建”状态下的线程加入“就绪”队列中等待CPU,run()方法属于Thread(),没有内容,需要重写。调用start()会默认调用run()。 ************************** *********************** ******此处 缺一个 线程状态转换图 **** (1)对象与线程之间完全解耦or弱解耦(用构造方法创建线程实现联系) (2)线程同步用sychronized修饰方法 (3)协调同步用wait()等待其他线程完成工作(释放CPU资源) (4)线程联合,A联合B,A立刻停止,让B先执行 (5)守护线程做一些不重要的工作,一旦所有线程停止工作,守护线程立刻停止 4、常用方法:start()、run()、sleep(ms)、isAlive()===>false true false wait()、sleep()都需要try/catch包裹,或是抛出InterruptedException(检查异常)。 sychronized(同步锁)的目标与wait()方法的目标不一致,会抛出IllegalMonitorSateException,不过InterruptExcprion会先出现。wait()和notify()方法必须采用当前锁调用,必须采用synchronized中的对象。 wait()、notify()、notifyAll()都是Object类中的final方法,被所有类继承且不允许重写,不可以在非同步方法中出现。 Thread.currentThread() 返回正在实行的线程名称 Thread.interrupt() 用于将当前线程的中断标志位设置为true,如果是wait、sleep、join造成的阻塞,会重新将标志位设置为false,抛出interruptedException异常。如果是IO阻塞会抛出异常,如果是轮询,直接返回。如果是非阻塞的线程,进入阻塞会按照阻塞来处理,非阻塞中断标志位为true的线程遇到wait、join、sleep,直接抛出interruptException,中断标记被清除,设置中断标志位为false。 CyclicBarrier(栅栏)让一组线程等待一个或一些线程,countDownLatch(闭锁)让一组线程等待某个事件。 CopyOnWriterArrayList适合使用在读操作远远大于写操作的场景中,比如缓存。 ReadWriteLock当写操作时,其他线程无法读取或写入数据,而当读操作时,其他线程无法写入数据,但可以读,适用于读取远远大于写入的场景。 Thread.stop()已经弃用。 Thread.suspend()和resume()方法:suspend()使线程进入阻塞状态,并不会自恢复,调用其resume()方法才能使其进入就绪队列。 线程安全问题出现的情况: 1,多个线程使用共用数据时 2,操作共享数据的线程代码 当一个线程在执行操作共享数据的多条代码的过程中,其他线程参与了运算。就会导致线程的安全问题。 解决思路: 就是将多条操作共享数据的线程封装起来,在有线程在执行这些代码的时候,其他线程是不可以参与运算的。 Synchronized :同步代码块: Synchronize(对象) { 需要被同步的代码; } 同步的好处和弊端: 解决了线程的安全问题。 效率有一点点低。因为同步外的线程都会判断同步锁。 同步的使用前提:多线程才使用同步,多线程使用的为同一个锁才使用。 同步代码块:同步代码块的锁是任意的。 同步函数:主线程开启线程后,占用CPU,执行完语句。同步函数使用的锁是当前的对象 this。 4、同步监视器: 任何线程进入同步方法,同步代码块之前,必须先获得同步方法,同步代码块对应的同步监视器。对于同步代码块,程序必须显式的为它指定同步监视器。 对于非静态同步方法,该方法的同步监视器是this--调用该方法的对象, 对于静态的同步方法,该方法的同步监视器是类。 Static Synchronized 是一个类的共用监视器,synchronized 是针对拥有同步方法的类 而存在的当前实例的监视器。 1、线程中锁:conditon 线程的阻塞队使用的是 condition互斥锁。 Condition是在JDK1.5中才出现,Condition的作用是对锁进行更精确的控制,拥有await()、signal()、signalAll()、用来替代传统的Object()的wait()、notify()、notifyAll()。不同的是,Object中的wait(),notify(),notifyAll()方法是和"同步锁"(synchronized关键字)捆绑使用的;而Condition是需要与"互斥锁"/"共享锁"捆绑使用的。调用await()和signal()都必须在lock.lock()和lock.unlock()之间有效。 2、线程调度分为协同调度和抢占性调度,Java使用的是抢占性调度,每个线程由操作系统分配执行时间。协同式调度是指调度线程由线程自身确定。 3、可能会抛出InterruptedException的方法:java.lang.Object类的wait方法, java.lang.Thread类的sleep方法, java.lang.Thread的join方法。 Thread.suspend容易造成死锁,已过时,被打断不会抛出InterruptedException()。 4、线程结束的三个原因: 1)run方法执行完成,线程正常结束。 2)线程抛出一个未捕获的Exception或Error 3)调用该线程的stop方法结束线程(容易死锁) 4)thread-clean-pop 抛出一个例外,线程终止,也可以通过其他线程调用thread-cancel()来终止另一个线程。 34、良好的代码习惯 1、面向接口编程:List myList = new ArrayList(); === 接口名 xxx = new 接口实现类 Map map = new HashMap(); (1)程序规范化设计 (2)团队协同开发 (3)转换为组件 (4)代码复用 2、Java中路径用 “/” 才是正确的,如果使用了 “\”表示路径,需要转义。”\”也是转义符。 35、Java的三大注解( 由虚拟器控制给出注解,提示开发人员注意编码规则 ) (1)@SuppressWarnings(“deprecation”); ==>屏蔽相应的警告,(一般在方法上标注) (2)@Override; 指定被注解的方法需要覆写超类的方法(1.5实现接口方法不能写,6.0可写) (3)@Deprecated;表明程序调用一个废弃元素(方法),编译器应该显示警告(不能被使用) 元注解(Meta-Annotations,Java注解类型):Target、Retention、Documented、inherited。 @Target:注解表明注解类型适用于哪种目标元素,@Target(ElementType TYPE)适用任何类的元素包括:元素字段、方法、参数、构造函数、局部变量、类型本身。 36、内联函数 37、存根类(Stub) Stub是一个类,它实现了一个接口。继承该类就可以使用(间接)接口的方法,(不用全实现)。RMI采用Stub和Skeletons来进行远程对象的通讯,Stub充当客户端代理(运行在本地虚拟机),远程对象的调用实际上是通过调用该对象的客户端代理Stub来完成的。 每一个远程对象都包含一个代理对象Stub,当运行在本地虚拟机上的程序想调用远程Java虚拟机上的方法时,1)在本地创建该对象的代理对象Stub,然后调用代理对象上的方法,在远程有一个skeleton对象与Stub呼应,接受来自Stub对象的调用。(运行时动态链接??) 38、扩展方法 扩展方法只能访问所扩展类的public成员。 39、数组(数组复制) (1)System.arrayCopy用本地方法(C语言)实现==>使用java间接操作硬件 (2)clone() 定义:protected native Object clone() throws CloneNotSupportedException{} (3)arrays.CopyOf 调用了system.arraycopy 方法实现 (4)用for循环实现,效率最低 40、设计模式: 单例:多线程下的单例 饿汉式单例在单例类被加载时候,就实例化一个对象交给自己的引用;而懒汉式在调用取得实例方法的时候才会实例化对象。 chinese.getInstance(); 每次获取的都是同一个对象。 41、JavaWeb项目: 1.测试 2.梳理 42、SSM:Spring + SpringMVC + MyBatis 1、Spring是一个开源的Java/ Java EE全功能栈应用程序框架。轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。可通过AOP和log4j实现自定义日志系统。 ①、基于JavaBeans 的采用控制反转的配置管理,使得应用程序的组建更加快捷简易。 ②、一个可用于从applet到JavaEE不同运行环境的核心Bean工厂。 Spring: 依赖注入是一种思想,或者说是一种设计模式,在java中通过反射机制实现,与具体框架无关,依赖注入(DI)有三种方式:接口注入、Setter注入、构造方法注入。 Spring: 基于xml文件配置