yte b = (byte) raf.read();//raf.read()返回int类型
char c = (char)b;//字母能转为byte
if(c==’a’){
raf.seek(i)
raf.write(‘c’)
raf.close()
38:字节流和字符流
字节流处理的是计算机最基本的单位byte,它可以处理任何数据格式的数据。主要的操作对象是byte数组,通过read()和write()方法把byte数组的数据写入或读出
字符流有字节流包装而来,字符流创建时,一般要包装一个字节流;inputStreamReader提供字节流向字符流的转换,其构造函数中可以指定字符编码格式;
读取或输出文本一般用BufferedReader.readLine()和PrintWriter.println()方法;
PrintWriter和BufferedWriter同样提供可缓冲输出,但是PrintWriter可设置自动清除缓冲,不需要pw.flush()
PrintWriter pw = new PrintWriter(OutputStreamWirter(“d.txt”,”UTF-8”),true);//true表示自动清除缓冲
注意:①写时需要flush() ,PrintWriter可设定自动清除
②别忘了关闭流
39:序列化
Java可以通过序列化保存或传输一个对象。序列化本质上是把数据,变成一系列的字节数据。然后把这些字节数据写入到流中。
java.io.Serializable接口是可以进行序列化的类的标志性接口,该接口本身没有任何需要实现的方法,仅提供一个能唯一辨别一个类的serialVersionUID.作用是在序列化和反序列化过程中,起到辨别作用。在反序列过程中,若有两个相同类名的类,就通过serialVersionUID来判断到底反序列化成哪个类。
序列化:ObjectInputStream.readObject()
反序列化:ObjectOutputStream.writeObject()
40:进程与线程区别
① 线程隶属于某个进程
② 进程能独占资源,而线程不能
③ 线程是调度和分配的基本单位,进程是拥有资源的基本单位
④ 进程间通信困难,而线程间共享一块内存区域,通信方便
⑤ 创建销毁进程及进程切换系统开销大,而对于线程开销小
41:Runnable接口和Thread类的区别
两者都可以实现多线程编程,区别如下:
① 通过继承Thread方法定义线程就不能继承其他类,而实现Runnable接口方法可以
② Thread方法为“多线程多实例”;Runnable:当多个线程公用一个Runnable时为“多线程单实例”,这时可以共享一个变量,但可能有线程安全问题;当每个线程都有各自的Runnable,则为“多线程多实例”
③ Runnable可以方便的访问同一变量,而Thread需要用内部类实现。
ThreadLocal: 线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。一个ThreadLocal只能存放一个专有对象,若线程需要多个专有对象的话,必须设计多个ThreadLocal。ThreadLocal主要有两个方法set(Object) 和 get()
42:线程安全问题是指两方面的问题:变量安全和线程同步(见深入JDK206页)
解决变量安全的方法:1:多线程多实例 2:变量定义在方法中 3:使用ThreadLocal
解决线程同步问题用synchronized(监视器) 监视器默认为thi
(单实例,多线程中多个Thread基于同一个Runnable创建,Runnable中的变量为多个
Thread共享,所以存在变量安全问题)
ThreadLocal示例:(每个线程都实现从1~10累加)
ublic class Accumulator implements Runnable{
ThreadLocal threadLocal = new ThreadLocal();//创建threadlocal
ublic void run() {
for(int i=1;i<=10;i++){
if(threadLocal.get()==null){
threadLocal.set(new Integer(0))
int x = (Integer) threadLocal.get()
x = x+i
threadLocal.set(x)
try {
Thread.sleep(1000)
} catch (InterruptedException e) {
e.printStackTrace()
System.out.println(Thread.currentThread().getName()+
"\t累加和="+threadLocal.get())
ublic class Main {
ublic static void main(String[] args) {
Accumulator a = new Accumulator();//单实例多线程
Thread t1 = new Thread(a)
Thread t2 = new Thread(a)
t1.start()
t2.start()
说明:单实例多线程,假如不用ThreadLocal方法,在Accumulator中定义一个成员变量SUM保存每次累加和,则线程共享Runnable的变量SUM,会有变量安全问题;若改为多实例多线程则没有这问题;若将SUM定义在run()方法中也没有这样的问题;
43:同步锁Synchronized(括号内为可能发生同步冲突的监视器,默认为this)
当线程执行到Sychronized时候,检查传入的监视器对象,并得到该对象的同步锁,如果得不到(被占用),就会被加入到一个与该监视器对象相关联的等待线程池中,一直等待同步锁被释放,池中的等待线程就会得到该同步锁,然后继续执行下去,当线程执行完同步代码块,就会自动释放它占的同步锁。
44:协调运行—线程通信
wait()方法:使当前调用同步方法的线程等待,直到其他线程调用notify()或notifyAll()
otify():唤醒当前同步监视器(sychronized的参数)上正在等待的单个线程,如果有多个,随机唤醒一个。
otifyAll():唤醒当前同步监视器(sychronized的参数)上正在等待的所有线程
示例:(实现生产者消费者模式)
ublic class Store {//仓库类
rivate final int MAX_SIZE
rivate int count
ublic Store(int size,int c){
MAX_SIZE = size
count = c
//往仓库放货物
ynchronized public void add(){//synchronized默认的同步监视器为this即Store
if(count>=MAX_SIZE){
System.out.println("仓库满了")
try {
wait();//进入与Store实例相关联的等待线程池中
} catch (InterruptedException e) {
e.printStackTrace()
count++
System.out.println("put "+count)
otifyAll();//从线程池中唤醒所有等待线程,(若是producer被唤醒,则从等待处继续执行,(count++处)
//从仓库取货物
ynchronized public void get(){
if(count<=0){
System.out.println("仓库空了")
try {
wait()
} catch (InterruptedException e) {
e.printStackTrace()
System.out.println("get "+count)
count–
otifyAll()
ublic class Producer extends Thread{//生产者线程
rivate Store
ublic Producer(Store s){
this.s =
ublic void run(){
while(true){
.add()
try {
Thread.sleep(500)
} catch (InterruptedException e) {
e.printStackTrace()
ublic class Consumer extends Thread{//消费者线程
rivate Store
ublic Consumer(Store s){
this.s =
ublic void run(){
while(true){
.get()
try {
Thread.sleep(500)
} catch (InterruptedException e) {
e.printStackTrace()
ublic class Main {
ublic static void main(String[] args) {
Store s = new Store(5,0);//单实例多线程 共享仓库
Producer producer1 = new Producer(s)
Producer producer2 = new Producer(s)
Consumer consumer1 = new Consumer(s)
Consumer consumer2 = new Consumer(s)
roducer1.start()
roducer2.start()
consumer1.start()
consumer2.start()
45:JAVA实现线程池
思想:启动一个线程的开销是相当高的,利用线程池,程序向线程池传递一个实现Runnable接口的类的实例时,程序就会从线程池中启动一个空闲线程,并执行run()方法,run方法执行结束后,该线程又成为空闲线程,回到线程池,等待下一个Runnable对象,并执行对象的run()方法,从而大大提高了系统的性能。
通过java.util.concurrent包中的Executors类可以创建线程池对象,即创建线程
池类ExecutorService的实例。
示例:
ublic class Thread1 implements Runnable{
ublic void run() {
System.out.println("this is thread1")
ublic class Thread2 implements Runnable{
ublic void run(){
System.out.println("this is thread2")
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executor
ublic class Main {
ublic static void main(String[] args) {
//创建线程池对象
ExecutorService es = Executors.newFixedThreadPool(5)
es.submit(new Thread1());//传递Runnable接口实现类 这是利用回调吗?
es.submit(new Thread2())
es.shutdown();//关闭线程池对象
46:反射的原理:反射是为了能够动态的加载一个类,动态地调用一个方法,动态地访问
一个属等动态要求而设计的。它的出发点在于JVM会为每个类创建一个java.lang.Class类的实例,通过该对象可以获取这个类的信息,然后通过使用java.lang.reflect包下的API以达到各种动态要求。
类在以下情况下会被加载:
① 需要使用该类创建对象。如Student s = new Student() Student会被加载
② 访问该类的静态成员。 如system.out.println(Calendar.MONDAY)
③ 使用Class类的forName()方法
类一旦被加载,JVM就会为其创建一个Class对象,如何得到一个类的Class对象?
① Class.forName()返回就是一个Class对象
② 类名.cla
③ 对象名.getClass()
47:Field、Method、Construtor
Field通过Class类对象的getDeclaredField()和getDeclaredFields()方法得到;Field方法主要分为两大类:setXXX(object,value)和getXXX(object)其中object为实例对象。
Method通过Class类对象的getMethod()或getMethods()获得,Method最常用的方法是invoke(object,参数…)。
Constructor类通过Class类对象的getConstructor(参数类型.class…)获得。Constructor类最常用的方法是newInstance(),通过构造函数创建实例(Class对象也能通过newInstance()创建实例,但该类中提供无参构造函数)
获得一个类中私有变量:调用Field的setAccessible(true)
示例:
ublic class Person {
ublic String name
rivate int age
ublic Person(){}
ublic Person(String name,int age){
this.name = name
this.age = age
ublic void getInfo(){
System.out.println(name+":"+age)
ublic class Main {
ublic static void main(String[] args) {
Class personclass = Person.cla
try {
Constructor con = personclass.getConstructor(String.class,int.class)
Person person = (Person) con.newInstance("li",20)
Field f = personclass.getDeclaredField("name")
String name = (String) f.get(person)
Field f2 = personclass.getDeclaredField("age")
f2.setAccessible(true);//设置可以访问私有变量age
int age = (Integer) f2.get(person)
System.out.println(name+":"+age)
Method m = personclass.getDeclaredMethod("getInfo",null);//参数为null,可不写
m.invoke(person, null);//调用方法
} catch (Exception e) {
e.printStackTrace()
48:TCP通信特点
① 面向连接的传输
② 端到端的通信
③ 可靠性,确保传输数据的正确性,不出现丢失或乱序
④ 采用字节流方式,即以字节为单位传输字节序列
编程模型:
服务器端:①创建ServerSocket
②accept()等待客户请求
③获得输入流和输出流,并进行传输
④释放资源,关闭输入流输出流、Socket、ServerSocket
49:UDP通信特点
① UDP是一个无连接协议,当它想传送数据时就简单地抓取来自应用程序的数据,并尽可能快地把它扔到网络上
② 不需要维护连接状态,包括收发状态等
③ 字节开销很小,传输速度快,效率高
编程模型:(点对点,没有服务器与客户端之分;分为接收端和发送端)
接收端和客户端都需要有一下步骤:
① 创建DatagramSocket,指定一个端口号.
② 提供一个byte数组进行数据的存储;对于发送端,还需要提供对端的IP地址和端口号。
③ 调用DatagramPacket的receive()或send()方法进行数据的接收或发送
④ 调用DatagramPacket的getData()方法得到byte数组的数据。
⑤ 释放资源
说明: DatagramSocket ds = new DatagramSocket(port);//port为接收端口
接收:DatagramPacket dp = new DatagramPacket(buff,len)
ds.receive(dp)
发送: Datagrampacket dp = new DatagramPacket (str.getBytes() ,0,str.length(),InetAddress.getByName(“localhost”),sendPort);//参数:字节数组,offset,len,主机号或IP,对方接收端口号
ds.send(dp)
50:TCP实现web服务器
ublic class WebServer {
ublic static void main(String[] args) throws Exception{
ServerSocket ss = new ServerSocket(80)
Socket s = null
System.out.println("服务器已启动!")
while(true){
= ss.accept()
ew HTTPThread(s).start()
ublic class HTTPThread extends Thread{
rivate Socket socket
ublic HTTPThread(Socket s){
this.socket =
ublic void run(){
try{
OutputStream os = socket.getOutputStream()
PrintWriter pw = new PrintWriter(os)
w.println("")
w.println("")
w.println("hello world")
w.println("")
w.println("")
w.flush()
w.close()
ocket.close()
}catch(IOException e){
e.printStackTrace()
在浏览器输入http://localhost 会显示hello world
50:UDP实现一个即时聊天软件
QQ、MSN对安全的要求不是太高,一般会采用UDP的通信模式。UDP为点对点模式,没有服务器和客户端之分,两端都创建两个线程,SendThread(发送消息)还有ReceiveThread (接收消息)。代码如下:
ublic class ReceiveThread extends Thread{
rivate DatagramSocket d
ublic ReceiveThread(int recport){
try {
this.ds = new DatagramSocket(recport);//接收端口
} catch (SocketException e) {
e.printStackTrace()
ublic void run(){
try {
yte []buff = new byte[1024]
DatagramPacket dp = new DatagramPacket(buff,1024)
while(true){
ds.receive(dp);//接收数据
String str = new String (dp.getData(),0,dp.getLength())
System.out.println("receive:"+str)
} catch (IOException e) {
e.printStackTrace()
}finally{
ds.close()
ublic class SendThread extends Thread{
rivate DatagramSocket d
rivate int sendPort
ublic SendThread(int sendport,int otherPort){//发送、对方端口
this.sendPort = sendPort
try {
this.ds = new DatagramSocket(sendport);//发送端口
} catch (SocketException e) {
e.printStackTrace()
ublic void run(){
try{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in))
String str = null
while((str = br.readLine())!=null){
DatagramPacket dp = new DatagramPacket (str.getBytes(),0,str.length(),
InetAddress.getByName("localhost"),otherPort)
ds.send(dp)
System.out.println("send:"+str)
}catch(Exception ex){
ex.printStackTrace()
}finally{
ds.close()
ublic class Chat {
ublic static void main(String[] args) {
ew ReceiveThread(7000).start()
ew SendThread(7500,9000).start();//发送端口和对方接受端口
说明:在本机模拟执行时要两次运行Chat,并且设置好端口。
如第一次为:7000 7500 9000 第二次则为:9000 7600 7000
TCP实现聊天室思路:多线程实现,服务器维护一个socket的List,每次接收消息时遍历list将消息发送给每个客户端。
UDP实现聊天室思路:可以用UDP组播 MultiCastSocekt实现
51:使用JAVA访问WEB站点
网络爬虫的原理就是模拟浏览器挨个访问web站点,得到站点网页的映射
JAVA也可以用编程的方式去访问网站,步骤:
① 用URL创建一个资源定位对象
② 调用URL的openConnection()得到HttpURLConnection对象
③ 调用HttpURLConnection的connect()方法打开连接
④ 用getHeaderFields()方法得到响应结果的头信息
⑤ 用getInputStream()方法得到输入流对象,得到响应内容
ublic class HttpConnTest {
ublic static void main(String[] args) throws Exception{
//创建URL对象
URL url = new URL("http://www.baidu.com")
HttpURLConnection conn = (HttpURLConnection) url.openConnection()
conn.connect();//打开连接
//获取请求响应的头部信息
Map> header = conn.getHeaderFields()
for(String key:header.keySet()){
System.out.println(key+":"+header.get(key))
//获取响应内容
BufferedReader br = new BufferedReader(
ew InputStreamReader(conn.getInputStream(),"UTF-8"))
String str = null
while((str=br.readLine())!=null){
System.out.println(str)
conn.disconnect()
52:JDBC(java data base connectivity)工作原理
JDBC采用了一种驱动模式的设计,提供了两套的接口:开发者使用的API和数据库厂商使用的SPI(service provider interface 数据库厂商需要实现的接口),充分体现了面向接口编程的好处。程序员无需关心具体数据库的连接和调用,只需要使用JDK中提供的标准API编程即可,而具体的实现由特定的数据库生产商提供,也就是JDBC驱动。
53:JDBC编程步骤:
① 注册驱动程序。就是把驱动程序类加载到JVM,一般用Class.forName(“完整类名”)
② 获取数据库连接Connection conn = DriverManager.getConnection(“URL”,”用户名”,”密码”)
③ 创建会话Statement(用于向数据库发送SQL命令,并返回结果) 实际开发中用的更多的是PreparedStatement,它是一种预编译的会话,用占位符的方法效率高,且可以避免SQL注入
④ 执行SQL语句。 executeQuery()或executeUpdate()
⑤ 处理结果集。若是查询操作的话,会返回ResultSet 用其next()方法操作结果集
⑥ 关闭连接。关闭顺序ResultSet、Statement、Conectio
53:如何使用JDBC事务
事务特性:ACID(原子性、一致性、隔离性、持久性)
1. Atomicity(原子性)
原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。
2. Consistency(一致性)
一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务开始前是一个一致状态,事务结束后是另一个一致状态,事务将数据库从一个一致状态转移到另一个一致状态。
3. Isolation(独立性)
从字面上来说,独立性是其中最难理解的一点,但如果结合Oracle中的undo,也就不难理解了。所谓的独立性就是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务还未提交,它所访问的数据就不受未提交事务的影响。换句话说,一个事务的影响在该事务提交前对其它事务是不可见的。
注意:这里的Isolation跟隔离级别(Isolation Level)是无关的。
4. Durability(持久性)
持久性也不难理解,是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。
JDBC使用事务步骤:
① 关闭自动提及事务:conn.setAutoCommit(false)
② 捕获(try catch)执行代码,如果发生异常,在catch中conn.rollback()
③ 关闭连接。一般在finally{}中
54:如何使用可滚动的结果集
Statement stmt = conn.createStatement(sql,type,concurrency)
其中concurrency变量用于指定是否可更新的结果集,可取以下值:
① TYPE_FORWARD_ONLY:不允许滚动,只能向前(next())
② TYPE_SCROLL_INSENSITIVE:可滚动,对数据库变化不敏感,数据库查询生产结果集后若发生变化,结果集不发生变化
③ TYPE_SCROLL_SENSITIVE:可滚动,且对数据库变化敏感
可滚动的结果集方法:
rs.next()、rs.last();//到最后一行、rs.previous();//回一行
rs.absolute(6);//直接定位到第六行
55:如何使用可更新的结果集
当concurrency变量为以下值时:
① CONCUR_READ_ONLY:不能用于更新数据库
② CONCUR_UPDATABLE:结果集可用于更新数据库
如:
PreparedSatement pstmt = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE)
rs = pstmt.executeQuery()
rs.last()
//更新最后一行数据
rs.updateString(2,”aaaa”);//修改值
rs.updateRow();//更新
56:什么是Servlet
Servlet在JAVA Web服务器中充当了信息资源的最小表示单位,代表了一个用户可以通过浏览器获取的资源,Servlet可以进行无限的扩展,它可以使用java的所有类库资源,为用户返回文本、图片、视频等各类信息资源。
从编程角度看,Servlet是一个java类,这个类需要实现Servlet接口,提供一个公开的无参构造方法。有WEB容器来控制它的创建、初始化、提供服务、销毁等。它的各种行为方式通过在web.xml中配置决定。
说明:在实际开发中,servelt一般通过继承自javax.servlet.http.HttpServlet
来创建(HttpServlet也是Servlet的实现),它可以为开发者提供一些方法的默认实现,而且可以区别不同的请求方法(doGet() doPost())
57:Servlet生命周期
① 加载。Servlet类加载到JVM中,并且实例化。这个过程中,web容器会调用Servlet类的无参构造方法。默认下,Servlet是在第一次请求时被加载,但可通过在web.xml中配置标签设置在web容器启动时加载。
② 初始化。调用init()方法,如为Servelt配置的初始化参数是在init()中取得的。
③ 提供服务。当有HTTP请求时,调用service()方法。如果是继承自HttpServlet的话,service()会根据请求类型不同调用doGet()或doPost()方法
④ 销毁。当重新部署web应用,关闭web容器时被销毁并调用destroy()方法
Servlet运行时的基本原理
1)、当WEB客户请求Servlet服务或当WEB服务启动时,容器环境加载一个Java Servlet类。
2)、容器环境也将根据客房请求创建一个Servlet对象实例,或者创建多个Servlet对象实例,并把这些实例加入到Servlet实例池中。
3)、容器环境调用Servlet的初始化方法HttpServlet.init()进行Servlet实例化。在调用初始化时,要给init()方法传入一个ServletConfig对象,ServletConfig对象包含了初始化参数和容环境的信息,并负责向servlet传递信息,如果传递失败,则会发生ServletException。Servlet将不能正常工作。
4)、容器环境利用一个HttpServletRequest和HttpServletResponse对象,封装从Web客户接收到的HTTP请求和由Servlet生成的响应。
5)、容器环境把HttpServletRequest和HttpServletResponse对象传递给HttpServlet.Service()方法。这样,一个定制的Java Servlet就可以访问这种HTTP请求和响应接口。Servlet()方法可被多次调用,各调用过程运行在不同的线程中,互不干扰。
6)、定制的Java Servlet从HttpServletRequest对象读取HTTP请求数据,访问来自HttpSession或Cookie对象的状态信息,进行特定应用的处理,并且用HttpServletResponse对象生成HTTP响应数据。
7)、当WEB服务器和容器关闭时,会自动调用HttpServlet.destroy()方法关闭任何打开的资源,并进行一些关闭前的处理。
ervlet 的生命周期。
Servlet 运行在 Servlet 容器中,其生命周期由容器来管理。 Servlet 的生命周期通过 Servlet 接口中 init ()、 service ()、 destroy ()方法来表示。
Servlet 的生命周期包含了下面 4 个阶段。
(1) 加载和实例化
Servlet 容器负责加载和实例化 Servlet 。当 Servlet 容器启动时,或者在容器检查到需要这个 Servlet 来响应一个请求时,创建 Servlet 实例。当 Servlet 容器启动后,它必须要知道所需的 Servlet 类在什么位置, Servlet 容器可以从本地文件系统、远程文件系统或者其他网络服务器中通过类加载器加载 Servlet 类,成功加载后,容器创建 Servlet 实例。因为容器是通过 Java 的反射 API 来创建 Servlet 实例,调用的是 Servlet 的默认构造函数,也就是那个不带参数的构造函数,所以我们在编写 Servlet 类的时候,不应该提供带参数的构造函数。——这也就是为什么 Servlet 类可以不写构造函数的原因。
(2) 初始化
在 Servlet 实例化之后,容器必须调用 Servlet 的 init ()方法初始化这个对象。初始化的目的是为了让 Servlet 对象在处理客户请求前完成一些初始化工作,如建立数据库连接,获取配置信息等。对于每一个 Servlet 实例, init ()方法只能被调用一次。在初始化期间, Servlet 实例可以使用容器为它准备的 ServletConfit 对象从 web 应用程序的配置信息(在 web.xml 中配置)中获取初始化的参数信息。在初始化期间,如果发生错误, Servlet 实例可以抛出异常来通知容器。
(3) 请求处理
Servlet 容器调用 Servlet 的 service ()方法对请求进行处理。要注意的是,在 service ()方法调用之前, init ()方法必须成功执行。在 service ()方法中, servlet 实例通过 ServletRequest 对象得到客户端的相关信息和请求信息,在对请求进行处理后,调用 servletResponse 对象的方法设置响应信息。
(4) 服务终止
当容器检测在一个 Servlet 实例应该从服务中被移除的时候,容器就会调用实例的 destroy ()方法,以便让该实例可以释放它所使用的资源,保存数据到持久存储设备中。当需要释放内存或者容器关闭时,容器就会调用 Servlet 实例的 destroy ()方法。在调用 destroy ()方法后,容器会释放这个 Servlet 实例,该实例随后会被 java 的垃圾收集器回收。
在整个 Servlet 的生命周期过程中,创建 Servlet 实例、调用实例的 init ()和 destroy ()方法都只进行一次,当初始化完成后, Servlet 容器会将该实例保存在内存中,通过调用它的 service ()方法,为接收到的请求服务。
58:在web.xml中Servlet的标准配置
LoginServlet
com.abc.LoginServelt
0
LoginServlet
/*Servlet
59:Forward(直接转发或请求转发)和Redirect(间接转发或重定向)的区别
① 直接转发或请求转发:
RequestDspatcher rs = request.getRequestDispatcher(“url”)
Rs.forward(request,response)
本质上是一次请求,共享同一个request对象,地址栏地址不会改变
② 间接转发或重定向response.sendRedirect(“url”)
本质上是两次请求,对应两个不同request对象,请求信息不一样。
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。还有,转发是在web应用程序之内进行的,可以访问web应用程序所设定的内部目录,像是WEB-INF目录,只能在Web应用程序中进行,不能指定至其它的Web应用程序的地址。
redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来说浏览器会用刚才请求的所有参数重新请求,所以session,request参数都可以获取。web应用程序会要求客户端浏览器重新发出请求地址,客户端会重新连接至所指定的地址,因此浏览器的地址会出现重新导向的信息,重新导向后的请求由浏览器发出,所以不能访问Web应用程序中的隐藏目录,像是WEB-INF,重新是由浏览器重新要求一个网页,可以指定至其他的Web应用程序地址。
RequestDispatcher.forward()方法和HttpServletResponse.sendRedirect()方法的区别是:前者仅是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址,他是不会改变Request的值,如果你需要在下一个页面中能从中获取新的信息的话,你可以Request.setAttribute()来放置一些标志,这样从下一个页面中获取;后者则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的地址栏中可以看到跳转后的链接地址。所以,前者更加高效,在前者可以满足需要时,尽量使用RequestDispatcher.forward()方法,并且,这样也有助于隐藏实际的链接。在有些情况下,比如,需要跳转到一个其它服务器上的资源,则必须使用 HttpServletResponse.sendRequest()方法。
1、forward与include共亨Request范围内的对象,而redirect则不行,即:如果一个javabean被声明为request范围的话,则被forward到的资源也可以访
问这个javabean,而redriect则不行。
2、forward与include基本上都是转发到context内部的资源,而redirect可以重定向到外部的资源,如: req.sendRedriect
1、从地址栏显示来说
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送
的内容从哪里来的,所以它的地址栏还是原来的地址.
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
2、从数据共享来说
forward:转发页面和转发到的页面可以共享request里面的数据.
redirect:不能共享数据.
3、从运用地方来说
forward:一般用于用户登陆的时候,根据角色转发到相应的模块.
redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等.
4、从效率来说
forward:高.
redirect:低.
不要仅仅为了把变量传到下一个页面而使用session作用域,那会无故增大变量的作用域,转发也许可以帮助你解决这个问题。
redirect:以前的request中存放的变量全部失效,并进入一个新的request作用域。
forward:以前的request中存放的变量不会失效,就像把两个页面拼到了一起。
他们的调用分别如下:
request.getRequestDispatcher("apage.jsp").forward(request, response); //转发到apage.j
response.sendRedirect("apage.jsp"); //重定向到apage.j
在jsp页面中你也会看到通过下面的方式实现转发:
60:过滤器的作用和原理
过滤器是处于web容器内的一个组件,它会过滤特定请求和响应.当一个请求到来时,web容器判断是否有过滤器与该信息资源关联,若有,则交给过滤器—处理,然后交给目标资源。响应的时候则以相反的顺序交给过滤器,最后返回给用户。过滤器是一种很重要的设计模式(基于AOP思想)可以再不侵入原有代码的基础上为它们提供一些功能。Struts就是利用过滤器工作的。
过滤器要实现javax.servlet.Filter接口,并实现doFilter()方法。
ublic class MyFilter implements Filter{
//过滤器的业务逻辑方法
ublic void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//业务代码
chain.doFilter(request, response);//将请求转发给下一个过滤器或目标资源
ublic void init(FilterConfig arg0) throws ServletException {
//初始化代码
ublic void destroy() {
//释放资源代码
Web.xml中配置:
MyFilter
com.abc.MyFilter
MyFilter
/*Servlet
61:监听器的作用和工作原理
对于web应用程序来说,监听器是处于web容器内的一个组件,它会对web容器中的request,session和application 3种对象进行监听。当这些对象在创建或销毁时,web容器主动调用它们的初始化和销毁方法。
Request事件监听接口ServletRequestListener
Session事件监听接口HttpSessionListener
Application事件监听接口ServletContextListener
应用:当用户第一次访问web应用程序是,程序将在线人数加1
62:JSP的运行机制
JSP本质上是Servlet,但JSP的存在是必要的,因为Servlet在处理静态内容(如HTML标签)时非常笨拙,不得不以字符串形式进行拼接,而JSP可以很好的实现动态和静态内容的分离。
当客户端发出一次对某个JSP的请求,web容器处理该请求过程如下:
① web容器会检验JSP的语法是否正确
② 将JSP文件转换成Servlet的源代码文件
③ 编译该源代码文件称为class文件
④ 创建一个该Servlet类的对象实例,为请求提供服务
说明:JSP只会在第一次访问时才转换盒编译。以后的访问web容器就直接调用编译好的servlet对象实例了,如果JSP被修改过,整个过程重新执行一次。
63:JSP内置对象及用途(见文档)
request 类型 javax.servlet.ServletRequest 作用域 Request
response 类型 javax.servlet.SrvletResponse 作用域 Page
ageContext 类型 javax.servlet.jsp.PageContext 作用域 Page
ession 类型 javax.servlet.http.HttpSession 作用域 Sessio
application 类型 javax.servlet.ServletContext 作用域 Applicatio
out 类型 javax.servlet.jsp.JspWriter 作用域 Page
config 类型 javax.servlet.ServletConfig 作用域 Page
age 类型 javax.lang.Object 作用域 Page
exception 类型 javax.lang.Throwable 作用域 page
64:JSP作用域
JSP比Servlet多了一种页面范围(page),一共四种作用域:page,request,session和application。
Request范围指的是一次请求,如果请求指向一个单一的JSP文件,则此时的page和request的生命周期是一样的,但是如果一次请求经过多次请求转发(forward),则这个request周期可以为多个page周期之和
65:jsp中使用javabea
JavaBean规范:
① 是一个公开类
② 提供一个无参数的构造方法
③ 提供了公开的setXXX和getXXX
JSP使用javabean两种方法
① 纯JAVA代码,如Dog dog = new Dog()
② Jsp动作标签
Scope属性默认为page
66:表达式语言EL和JSTL(详见文档EL OGNL JSTL)
EL是一种数据表现语言 JSTL是一个标签库,而EL是从JSTL诞生出来的
EL用${people.name}方法 区别于OGNL{#person.name}或{person.name}(根对象)
67:Struts框架是如何体现MVC模式的?
Controller由ActionServlet、Action和Struts-config.xml组成。
Model由ActionForm来实现
View主要由JSP实现
一次典型的Struts请求是这样的:客户端(浏览器)发送请求,然后ActionServlet接收到请求后,会根据请求的路径和参数来判断由哪个Action来处理该次请求。等到Action处理完成以后,通常是Execute方法调用完成以后,Struts会根据该方法返回的ActionForward来判断由哪个JSP来作为最终响应。
68:Hibernate实体存在哪几种状态
瞬时态、持久态、脱管态
69:Hibernate继承关系的映射策略
有三个类 Animal Dog Cat
单表策略:当所有子类都在一张表中,只需建一个Animal.hbm.xml 用添加子类
//区别子类的字段
//子类
…
多表策略:当每个子类一张表,只需建一个Animal.hbm.xml 用添加子类
< joined-subclass name=”Dog” table=”dog”>//子类 需指明表名
//指明dog表的主键 同时为指向animal的外键
< joined-subclass …>…
这样数据库有三个表animal dog cat 其中dog,cat共同属性放在animal表中
单表策略:无需表连接,查询速度快,适合多态查询(查询有继承关系的类时,同时查询到多个子类),缺点是可能造成表太大的结果(因为每个子类属性不一样,造成很多NULL),不利于维护。
多表策略:数据存储比较紧凑,当查询某个子类的数据时速度比较快,缺点是可能会有很多的表连接,不太适合多态查询
69:AOP原理
AOP是一种对OOP有益补充的编程技术,它可以解决OOP和过程化方法不能够很好解决的横切问题,如事务,安全,日志等。随着软件系统变得越来越复杂,横切关注点成为一个大问题,AOP可以很轻松的解决横切关注点这个问题,Spring框架对AOP提供了很好的支持。简单来说,AOP就是一种功能比较复杂的拦截器。在代码真正达到目标以前,AOP可以对其进行拦截,提供一些通用的中间件的服务,例如,加上事务服务,记录日志等。Spring的声明式事务也就是基于AOP实现的。
70:打印1000以内的回文数字
for(int i=10;i<10000;i++){
int temp = i
int reverse = 0
while(temp>0){//反序
reverse = reverse*10+temp%10
temp=temp/10
if(i==reverse){
System.out.println(i)
//判断一个字符串是否回文
String str = "abababa"
StringBuffer str2 = new StringBuffer(str)
tr2 = str2.reverse()
if(str.equals(str2.toString())){
System.out.println("回文")
71:50个人围城一圈数到3和3的倍数时出圈,问剩下的人是谁,在原来的位置是多少?
ublic static void main(String []args) {
Listlist = new LinkedList()
for(int i=1;i<=50;i++){//模拟50人
list.add(i)
int index=-1;//模拟当前数的数字
while(list.size()>1){//多于一个人
//取余 如果数到最后一个人,循环
index = (index+3)%list.size();//
//因为删除一个元素后,后边元素自动前移,所以索引减一
list.remove(index–)
System.out.println(list.get(0))