每周练习题1
1.下面有关JVM内存,说法错误的是?
程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,是线程隔离的
虚拟机栈描述的是Java方法执行的内存模型,用于存储局部变量,操作数栈,动态链接,方法出口等信息,是线程隔离的
方法区用于存储JVM加载的类信息、常量、静态变量、以及编译器编译后的代码等数据,是线程隔离的
原则上讲,所有的对象都在堆区上分配内存,是线程之间共享的
正确答案: C 你的答案: C (正确)
参考解析:方法区在JVM中也是一个非常重要的区域,它与堆一样,是被 线程共享 的区域。 在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。大多数 JVM 将内存区域划分为 Method Area(Non-Heap)(方法区) ,Heap(堆) , Program Counter Register(程序计数器) , VM Stack(虚拟机栈,也有翻译成JAVA 方法栈的),Native Method Stack ( 本地方法栈 ),其中Method Area 和 Heap 是线程共享的 ,VM Stack,Native Method Stack 和Program Counter Register 是非线程共享的。为什么分为 线程共享和非线程共享的呢?请继续往下看。首先我们熟悉一下一个一般性的 Java 程序的工作过程。一个 Java 源程序文件,会被编译为字节码文件(以 class 为扩展名),每个java程序都需要运行在自己的JVM上,然后告知 JVM 程序的运行入口,再被 JVM 通过字节码解释器加载运行。那么程序开始运行后,都是如何涉及到各内存区域的呢?
概括地说来,JVM初始运行的时候都会分配好 Method Area(方法区) 和Heap(堆) ,而JVM 每遇到一个线程,就为其分配一个 Program Counter Register(程序计数器) , VM Stack(虚拟机栈)和Native Method Stack (本地方法栈), 当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。这也是为什么我把内存区域分为线程共享和非线程共享的原因,非线程共享的那三个区域的生命周期与所属线程相同,而线程共享的区域与JAVA程序运行的生命周期相同,所以这也是系统垃圾回收的场所只发生在线程共享的区域(实际上对大部分虚拟机来说知发生在Heap上)的原因。
2.下面有关jdbc statement的说法错误的是?
JDBC提供了Statement、PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedStatement 用于执行参数化查询,而 CallableStatement则是用于存储过程
对于PreparedStatement来说,数据库可以使用已经编译过及定义好的执行计划,由于 PreparedStatement 对象已预编译过,所以其执行速度要快于 Statement 对象”
PreparedStatement中,“?” 叫做占位符,一个占位符可以有一个或者多个值
PreparedStatement可以阻止常见的SQL注入式攻击
正确答案: C 你的答案: C (正确)
参考解析:
1.Statement、PreparedStatement和CallableStatement都是接口(interface)。
2.Statement继承自Wrapper、PreparedStatement继承自Statement、CallableStatement继承自PreparedStatement。3.
Statement接口提供了执行语句和获取结果的基本方法;
PreparedStatement接口添加了处理 IN 参数的方法;
CallableStatement接口添加了处理 OUT 参数的方法。
4.
a.Statement:
普通的不带参的查询SQL;支持批量更新,批量删除;
b.PreparedStatement:
可变参数的SQL,编译一次,执行多次,效率高;
安全性好,有效防止Sql注入等问题;
支持批量更新,批量删除;
c.CallableStatement:
继承自PreparedStatement,支持带参数的SQL操作;
支持调用存储过程,提供了对输出和输入/输出参数(INOUT)的支持;
Statement每次执行sql语句,数据库都要执行sql语句的编译 ,
最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement。
PreparedStatement是预编译的,使用PreparedStatement有几个好处
1. 在执行可变参数的一条SQL时,PreparedStatement比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率要高。
2. 安全性好,有效防止Sql注入等问题。
3. 对于多次重复执行的语句,使用PreparedStament效率会更高一点,并且在这种情况下也比较适合使用batch;
4. 代码的可读性和可维护性。
3.下面有关SPRING的事务传播特性,说法错误的是?
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行
PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就抛出异常
PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起
PROPAGATION_NESTED:支持当前事务,新增Savepoint点,与当前事务同步提交或回滚
正确答案: B 你的答案: C (错误)
参考解析:
Spring的API设计很不错,基本上根据英文翻译就能知道作用:Required:必须的。说明必须要有事物,没有就新建事物。supports:支持。说明仅仅是支持事务,没有事务就非事务方式执行。mandatory:强制的。说明一定要有事务,没有事务就抛出异常。required_new:必须新建事物。如果当前存在事物就挂起。not_supported:不支持事物,如果存在事物就挂起。never:绝不有事务。如果存在事物就抛出异常
4.下面有关servlet和cgi的描述,说法错误的是?
servlet处于服务器进程中,它通过多线程方式运行其service方法
CGI对每个请求都产生新的进程,服务完成后就销毁
servlet在易用性上强于cgi,它提供了大量的实用工具例程,例如自动地解析和解码HTML表单数据、读取和设置HTTP头、处理Cookie、跟踪会话状态等
cgi在移植性上高于servlet,几乎所有的主流服务器都直接或通过插件支持cgi
正确答案: D 你的答案: B (错误)
参考解析:
CGI(Common Gateway Interface),通用网关接口
通用网关接口,简称CGI,是一种根据请求信息动态产生回应内容的技术。通过CGI,Web 服务器可以将根据请求不同启动不同的外部程序,并将请求内容转发给该程序,在程序执行结束后,将执行结果作为回应返回给客户端。也就是说,对于每个请求,都要产生一个新的进程进行处理。因为每个进程都会占有很多服务器的资源和时间,这就导致服务器无法同时处理很多的并发请求。另外CGI程序都是与操作系统平台相关的,虽然在互联网爆发的初期,CGI为开发互联网应用做出了很大的贡献,但是随着技术的发展,开始逐渐衰落。
Java平台上得到实现,现在提起Servlet,指的都是Java Servlet。Java Servlet要求必须运行在Web服务器当中,与Web服务器之间属于分工和互补关系。确切的说,在实际运行的时候Java Servlet与Web服务器会融为一体,如同一个程序一样运行在同一个Java虚拟机(JVM)当中。与CGI不同的是,Servlet对每个请求都是单独启动一个线程,而不是进程。这种处理方式大幅度地降低了系统里的进程数量,提高了系统的并发处理能力。另外因为Java Servlet是运行在虚拟机之上的,也就解决了跨平台问题。如果没有Servlet的出现,也就没有互联网的今天。
在Servlet出现之后,随着使用范围的扩大,人们发现了它的一个很大的一个弊端。那就是
为了能够输出HTML格式内容,需要编写大量重复代码,造成不必要的重复劳动。为了解决这个问题,基于Servlet技术产生了JavaServet
Pages技术,也就是JSP。Servlet和JSP两者分工协作,Servlet侧重于解决运算和业务逻辑问题,JSP则侧重于解决展示问题。
Servlet与JSP一起为Web应用开发带来了巨大的贡献,后来出现的众多Java Web应用开发框架都是基于这两种技术的,更确切的说,都是基于Servlet技术的。
--------------------分割线-------------------------
Servlet处于服务器进程中,它通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其实例一般不会销毁。
而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于Servlet 。
Servlet 与 CGI 的比较
和CGI程序一样,Servlet可以响应用户的指令(提交一个FORM等等),也可以象CGI程序一样,收集用户表单的信息并给予动态反馈(简单的注册信息录入和检查错误)。
然而,Servlet的机制并不仅仅是这样简单的与用户表单进行交互。传统技术中,动态的网页建立和显示都是通过CGI来实现的,但是,有了Servlet,您可以大胆的放弃所有CGI(perl?php?甚至asp!),利用Servlet代替CGI,进行程序编写。
对比一:当用户浏览器发出一个Http/CGI的请求,或者说
调用一个CGI程序的时候,服务器端就要新启用一个进程
(而且是每次都要调用),调用CGI程序越多(特别是访问量高的时候),就要消耗系统越多的处理时间,只剩下越来越少的系统资源,对于用户来说,只能是漫长的等待服务器端的返回页面了,这对于电子商务激烈发展的今天来说,不能不说是一种技术上的遗憾。
而Servlet充分发挥了服务器端的资源并高效的利用。每次调用Servlet时并不是新启用一个进程
,而是在一个Web服务器的进程敏感词享和分离线程,而线程最大的好处在于可以共享一个数据源,使系统资源被有效利用。
对比二:传统的CGI程序,不具备平台无关性特征,系统环境发生变化,CGI程序就要瘫痪,而Servlet具备Java的平台无关性,在系统开发过程中保持了系统的可扩展性、高效性。
对比三:传统技术中,一般大都为二层的系统架构,即Web服务器+数据库服务器,导致网站访问量大的时候,无法克服CGI程序与数据库建立连接时速度慢的瓶颈,从而死机、数据库死锁现象频繁发生。而我们的Servlet有连接池的概念,它可以利用多线程的优点,在系统缓存中事先建立好若干与数据库的连接,到时候若想和数据库打交道可以随时跟系统"要"一个连接即可,反应速度可想而知。
5.下面有关servlet service描述错误的是?
不管是post还是get方法提交过来的连接,都会在service中处理
doGet/doPost 则是在 javax.servlet.GenericServlet 中实现的
service()是在javax.servlet.Servlet接口中定义的
service判断请求类型,决定是调用doGet还是doPost方法
正确答案: B 你的答案: D (错误)
参考解析:doGet/doPost 则是在 javax.servlet.http.HttpServlet 中实现的
6.下列有关Servlet的生命周期,说法不正确的是?
在创建自己的Servlet时候,应该在初始化方法init()方法中创建Servlet实例
在Servlet生命周期的服务阶段,执行service()方法,根据用户请求的方法,执行相应的doGet()或是doPost()方法
在销毁阶段,执行destroy()方法后会释放Servlet 占用的资源
destroy()方法仅执行一次,即在服务器停止且卸载Servlet时执行该方法
正确答案: A 你的答案: C (错误)
参考解析:创建Servlet的实例是由Servlet容器来完成的,且创建Servlet实例是在初始化方法init()之前
Servlet的生命周期 1.加载:容器通过类加载器使用Servlet类对应的文件来加载Servlet 2.创建:通过调用Servlet的构造函数来创建一个Servlet实例 3.初始化:通过调用Servlet的init()方法来完成初始化工作,这个方法是在Servlet已经被创建,但在向客户端提供服务之前调用。 4.处理客户请求:Servlet创建后就可以处理请求,当有新的客户端请求时,Web容器都会创建一个新的线程来处理该请求。接着调用Servlet的 Service()方法来响应客户端请求(Service方***根据请求的method属性来调用doGet()和doPost()) 5.卸载:容器在卸载Servlet之前需要调用destroy()方法,让Servlet释放其占用的资源。7.下面有关servlet中init,service,destroy方法描述错误的是?
init()方法是servlet生命的起点。一旦加载了某个servlet,服务器将立即调用它的init()方法
service()方法处理客户机发出的所有请求
destroy()方法标志servlet生命周期的结束
servlet在多线程下使用了同步机制,因此,在并发编程下servlet是线程安全的
正确答案: D 你的答案: D (正确)
参考解析:
servlet在多线程下其本身并不是线程安全的。如果在类中定义成员变量,而在service中根据不同的线程对该成员变量进行更改,那么在并发的时候就会引起错误。最好是在方法中,定义局部变量,而不是类变量或者对象的成员变量。由于方法中的局部变量是在栈中,彼此各自都拥有独立的运行空间而不会互相干扰,因此才做到线程安全。
Servlet是线程不安全的,在Servlet类中可能会定义共享的类变量,这样在并发的多线程访问的情况下,不同的线程对成员变量的修改会引发错误
init方法: 是在servlet实例创建时调用的方法,用于创建或打开任何与servlet相的资源和初始 化servlet的状态,Servlet规范保证调用init方法前不会处理任何请求 service方法:是servlet真正处理客户端传过来的请求的方法,由web容器调用, 根据HTTP请求方法(GET、POST等),将请求分发到doGet、doPost等方法 destory方法:是在servlet实例被销毁时由web容器调用。Servlet规范确保在destroy方法调用之 前所有请求的处理均完成,需要覆盖destroy方法的情况:释放任何在init方法中 打开的与servlet相关的资源存储servlet的状态8.下面有关struts1和struts2的区别,描述错误的是?
Struts1要求Action类继承一个抽象基类。Struts 2 Action类可以实现一个Action接口
Struts1 Action对象为每一个请求产生一个实例。Struts2 Action是单例模式并且必须是线程安全的
Struts1 Action 依赖于Servlet API,Struts 2 Action不依赖于容器,允许Action脱离容器单独被测试
Struts1 整合了JSTL,Struts2可以使用JSTL,但是也支持OGNL
正确答案: B 你的答案: B (正确)
参考解析:
Struts1和Struts2的区别和对比:
Action 类:
? Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口,而struts2的Action是接口。
? Struts 2
Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去
实现 常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。
线程模式:
? Struts1
Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。
? Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)
Servlet 依赖:
? Struts1 Action 依赖于Servlet API
,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。
? Struts 2
Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2
Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。
可测性:
? 测试Struts1
Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)。
? Struts 2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。
捕获输入:
? Struts1
使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存
在的JavaBean(仍然会导致有冗余的javabean)。
? Struts
2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过
web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种
ModelDriven 特性简化了taglib对POJO输入对象的引用。
表达式语言:
? Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。
?
Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation
Language" (OGNL).
9.关于AWT和Swing说法正确的是?
Swing是AWT的子类
AWT在不同操作系统中显示相同的风格
AWT不支持事件类型,Swing支持事件模型
Swing在不同的操作系统中显示相同的风格
正确答案: D 你的答案: B (错误)
参考解析:
AWT,抽象窗口工具包,是Java提供的建立图形用户界面的工具集,可用于生成现代的、鼠标控制的图形应用接口,且无需修改,就可以在各种软硬件平台上运行。 而swing是Java语言在编写图形用户界面方面的新技术,Swing采用模型-视图-控制设计范式,Swing可以使Java程序在同一个平台上运行时能够有不同外观以供用户选择。 两者不同在于一个是初代工具集,一个是进化版的工具集,用户不会再满足于初始的功能,而是更加注重于附加价值,明显从这点上,Swing是比AWT要好很多。 写法上,Swing的头文件引用包需要用到Javax,组件调用时也需要在AWT的基础上加上“J”。 AWT :是通过调用操作系统的native方法实现的,所以在Windows系统上的AWT窗口就是Windows的风格,而在Unix系统上的则是XWindow风格。 AWT 中的图形函数与 操作系统 所提供的图形函数之间有着一一对应的关系,我们把它称为peers。 也就是说,当我们利用 AWT 来构件图形用户界面的时候,我们实际上是在利用 操作系统 所提供的图形库。由于不同 操作系统 的图形库所提供的功能是不一样的,在一个平台上存在的功能在另外一个平台上则可能不存在。为了实现Java语言所宣称的"一次编译,到处运行"的概念,AWT 不得不通过牺牲功能来实现其平台无关性,也就是说,AWT 所提供的图形功能是各种通用型操作系统所提供的图形功能的交集。由于AWT 是依靠本地方法来实现其功能的,我们通常把AWT控件称为重量级控件。 Swing :是所谓的Lightweight组件,不是通过native方法来实现的,所以Swing的窗口风格更多样化。但是,Swing里面也有heaveyweight组件。比如JWindow,Dialog,JFrame Swing是所谓的Lightweight组件,不是通过native方法来实现的,所以Swing的窗口风格更多样化。但是,Swing里面也有heaveyweight组件。比如JWindow,Dialog,JFrame Swing由纯Java写成,可移植性好,外观在不同平台上相同。所以Swing部件称为轻量级组件( Swing是由纯JAVA CODE所写的,因此SWING解决了JAVA因窗口类而无法跨平台的问题,使窗口功能也具有跨平台与延展性的特性,而且SWING不需占有太多系统资源,因此称为轻量级组件!!!)10.看以下代码:文件名称:forward.jsp
<html> <head><title> 跳转 title> head> <body> <jsp:forward page="index.htm"/> body> html>
如果运行以上jsp文件,地址栏的内容为
http://127.0.0.1:8080/myjsp/forward.jsp
http://127.0.0.1:8080/myjsp/index.jsp
http://127.0.0.1:8080/myjsp/index.htm
http://127.0.0.1:8080/myjsp/forward.htm
正确答案: A 你的答案: C (错误)
参考解析:
redirect:请求重定向:客户端行为,本质上为2次请求,地址栏改变,前一次请求对象消失。举例:你去银行办事(forward.jsp),结果告诉你少带了东西,你得先去***局办(index.html)临时身份证,这时你就会走出银行,自己前往***局,地址栏变为index.html.
forward:请求转发:服务器行为,地址栏不变。举例:你把钱包落在出租车上,你去警察局(forward.jsp)报案,警察局说钱包落在某某公司的出租车上(index.html),这时你不用亲自去找某某公司的出租车,警察局让出租车自己给你送来,你只要在警察局等就行。所以地址栏不变,依然为forward.jsp11.下面哪一项不是加载驱动程序的方法?
通过DriverManager.getConnection方法加载
调用方法 Class.forName
通过添加系统的jdbc.drivers属性
通过registerDriver方法注册
正确答案: A 你的答案: D (错误)
参考解析:
DriverManager.getConnection方法返回一个Connection对象,这是加载驱动之后才能进行的
加载驱动方法 1.Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); 2. DriverManager.registerDriver(new com.mysql.jdbc.Driver()); 3.System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver");创建一个以JDBC连接数据库的程序,包含7个步骤: 1、加载JDBC驱动程序: 在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机), 这通过java.lang.Class类的静态方法forName(String className)实现。 例如: try{ //加载MySql的驱动类 Class.forName("com.mysql.jdbc.Driver"); } catch(ClassNotFoundException e) { System.out.println("找不到驱动程序类 ,加载驱动失败!"); e.printStackTrace(); } 成功加载后,会将Driver类的实例注册到DriverManager类中。 2、提供JDBC连接的URL
- 连接URL定义了连接数据库时的协议、子协议、数据源标识。
- 书写形式:协议:子协议:数据源标识
- 协议:在JDBC中总是以jdbc开始
- 子协议:是桥连接的驱动程序或是数据库管理系统名称。
- 数据源标识:标记找到数据库来源的地址与连接端口。 jdbc:mysql: //localhost:3306/test?useUnicode=true&characterEncoding=gbk; useUnicode=true:表示使用Unicode字符集。 如果characterEncoding设置为gb2312或GBK,本参数必须设置为true &characterEncoding=gbk;字符编码方式。 3、创建数据库的连接
- 要连接数据库,需要向java.sql.DriverManager请求并获得Connection对象,该对象就代表一个数据库的连接。
- 使用DriverManager的getConnectin(String url , String username , String password )方法传入指定的欲连接的数据库的路径、数据库的用户名和密码来获得。 例如: //连接MySql数据库,用户名和密码都是root String url = "jdbc:mysql://localhost:3306/test" ; String username = "root" ; String password = "root" ; try{ Connection con = DriverManager.getConnection(url , username , password ) ; }catch(SQLException se){ System.out.println("数据库连接失败!"); se.printStackTrace() ; } 4、创建一个Statement
- 要执行SQL语句,必须获得java.sql.Statement实例,Statement实例分为以下3 种类型:
- 执行静态SQL语句。通常通过Statement实例实现。
- 执行动态SQL语句。通常通过PreparedStatement实例实现。
- 执行数据库存储过程。通常通过CallableStatement实例实现。 具体的实现方式: Statement stmt = con.createStatement() ; PreparedStatement pstmt = con.prepareStatement(sql) ; CallableStatement cstmt = con.prepareCall("{CALL demoSp(? , ?)}") ; 5、执行SQL语句
- Statement接口提供了三种执行SQL语句的方法:executeQuery 、executeUpdate和execute
- ResultSet executeQuery(String sqlString):执行查询数据库的SQL语句,返回一个结果集(ResultSet)对象。
- int executeUpdate(String sqlString):用于执行INSERT、UPDATE或 DELETE语句以及SQL DDL语句,如:CREATE TABLE和DROP TABLE等
- execute(sqlString):用于执行返回多个结果集、多个更新计数或二者组合的 语句。 ResultSet rs = stmt.executeQuery("SELECT * FROM ...") ; int rows = stmt.executeUpdate("INSERT INTO ...") ; boolean flag = stmt.execute(String sql) ;
- 1
- 2
- 3 6、处理结果
- 两种情况:
- 执行更新返回的是本次操作影响到的记录数。
- 执行查询返回的结果是一个ResultSet对象。
- ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这些 行中数据的访问。
- 使用结果集(ResultSet)对象的访问方法获取数据: while(rs.next()){ String name = rs.getString("name") ; String pass = rs.getString(1) ; // 此方法比较高效 }
- 1
- 2
- 3
- 4 (列是从左到右编号的,并且从列1开始) 7、关闭JDBC对象 操作完成以后要把所有使用的JDBC对象全都关闭,以释放JDBC资源,关闭顺序和声 明顺序相反: 1、关闭记录集 2、关闭声明 if(rs != null){ // 关闭记录集 try{ rs.close() ; }catch(SQLException e){ e.printStackTrace() ; } } if(stmt != null){ // 关闭声明 try{ stmt.close() ; }catch(SQLException e){ e.printStackTrace() ; } } if(conn != null){ // 关闭连接对象 try{ conn.close() ; }catch(SQLException e){ e.printStackTrace() ; } }
12.关于sleep()和wait(),以下描述错误的一项是( )
sleep是线程类(Thread)的方法,wait是Object类的方法;
sleep不释放对象锁,wait放弃对象锁
sleep暂停线程、但监控状态仍然保持,结束后会自动恢复
wait后进入等待锁定池,只有针对此对象发出notify方法后获得对象锁进入运行状态
正确答案: D 你的答案: B (错误)
参考解析:
Java中的多线程是一种抢占式的机制,而不是分时机制。抢占式的机制是有多个线程处于可运行状态,但是只有一个线程在运行。共同点 :
1. 他们都是在多线程的环境下,都可以在程序的调用处阻塞指定的毫秒数,并返回。
2. wait()和sleep()都可以通过interrupt()方法 打断线程的暂停状态 ,从而使线程立刻抛出InterruptedException。
如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法。如果此刻线程B正在wait/sleep/join,则线程B会立刻抛出InterruptedException,在catch() {} 中直接return即可安全地结束线程。
需要注意的是,InterruptedException是线程自己从内部抛出的,并不是interrupt()方法抛出的。对某一线程调用 interrupt()时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。但是,一旦该线程进入到 wait()/sleep()/join()后,就会立刻抛出InterruptedException 。
不同点 :
1.每个对象都有一个锁来控制同步访问。Synchronized关键字可以和对象的锁交互,来实现线程的同步。
sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
2.wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
3.sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常 4.sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。 5.wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
13.根据下面的程序代码,哪些选项的值返回true?
public class Square { long width; public Square(long l) { width = l; } public static void main(String arg[]) { Square a, b, c; a = new Square(42L); b = new Square(42L); c = b; long s = 42L; } }
a == b
s == a
b == c
a.equals(s)
正确答案: C 你的答案: C (正确)
这题考的是引用和内存。 //声明了3个Square类型的变量a, b, c //在stack中分配3个内存,名字为a, b, c Square a, b, c; //在heap中分配了一块新内存,里边包含自己的成员变量width值为48L,然后stack中的a指向这块内存 a = new Square(42L); //在heap中分配了一块新内存,其中包含自己的成员变量width值为48L,然后stack中的b指向这块内存 b = new Square(42L); //stack中的c也指向b所指向的内存 c = b; //在stack中分配了一块内存,值为42 long s = 42L;
来看4个选项:
A: a == b 由图可以看出a和b指向的不是同一个引用,故A错 B:s == a 一个Square类型不能与一个long型比较,编译就错误,故B错 c:b == c 由图可以看出b和c指向的是同一个引用,故C正确 d:a equal s 程序会把s封装成一个Long类型,由于Square没有重写Object的equals方法, 所以调用的是Object类的equals方法,源码如下1 2 3 |
public boolean equals(Object obj) {
return ( this == obj);
}
|
14.在jdk1.5的环境下,有如下4条语句:
Integer i01 = 59; int i02 = 59; Integer i03 =Integer.valueOf(59); Integer i04 = new Integer(59);
以下输出结果为false的是:
System.out.println(i01 == i02);
System.out.println(i01 == i03);
System.out.println(i03 == i04);
System.out.println(i02 == i04);
正确答案: C 你的答案: B (错误)
参考解析:
Integer i01=59 的时候,会调用 Integer 的 valueOf 方法,
public static Integer valueOf(int i) { assert IntegerCache.high>= 127; if (i >= IntegerCache.low&& i <= IntegerCache.high) return IntegerCache.***[i+ (-IntegerCache.low)]; return new Integer(i); }
这个方法就是返回一个 Integer 对象,只是在返回之前,看作了一个判断,判断当前 i 的值是否在 [-128,127] 区别,且 IntegerCache 中是否存在此对象,如果存在,则直接返回引用,否则,创建一个新的对象。
在这里的话,因为程序初次运行,没有 59 ,所以,直接创建了一个新的对象。
int i02=59 ,这是一个基本类型,存储在栈中。
Integer i03 =Integer.valueOf(59); 因为 IntegerCache 中已经存在此对象,所以,直接返回引用。
Integer i04 = new Integer(59) ;直接创建一个新的对象。
System. out .println(i01== i02); i01 是 Integer 对象, i02 是 int ,这里比较的不是地址,而是值。 Integer 会自动拆箱成 int ,然后进行值的比较。所以,为真。
System. out .println(i01== i03); 因为 i03 返回的是 i01 的引用,所以,为真。
System. out .println(i03==i04); 因为 i04 是重新创建的对象,所以 i03,i04 是指向不同的对象,因此比较结果为假。
System. out .println(i02== i04); 因为 i02 是基本类型,所以此时 i04 会自动拆箱,进行值比较,所以,结果为真。
15.下面哪个不对?
RuntimeException is the superclass of those exceptions that can be thrown during the normal operation of the Java Virtual Machine.
A method is not required to declare in its throws clause any subclasses of RuntimeExeption that might be thrown during the execution of the method but not caught
An RuntimeException is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.
NullPointerException is one kind of RuntimeException
正确答案: C 你的答案: B (错误)
四个选项都来自于Java API原文. A选项是RuntimeException的定义; B选项是把Error的第二段定义拿来改掉换成RuntimeException,但这样说对于RuntimeException也没错; C选项也是把Error的定义换成了RuntimeException,但这里的"indicates serious problems"不应该用在RuntimeException上,Error才表示严重的错误,RuntimeException并不是. D选项显然.运行时异常: 都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
非运行时异常 (编译异常):
是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
16.关于以下程序代码的说明正确的是?
1. public class HasStatic{ 2. private static int x=100; 3. public static void main(String args[]){ 4. HasStatic hs1=new HasStatic(); 5. hs1.x++; 6. HasStatic hs2=new HasStatic(); 7. hs2.x++; 8. hs1=new HasStatic(); 9. hs1.x++; 10. HasStatic.x--; 11. System.out.println("x="+x); 12. } 13. }
程序通过编译,输出结果为:x=103
10行不能通过编译,因为x是私有静态变量
5行不能通过编译,因为引用了私有静态变量
程序通过编译,输出结果为:x=102
正确答案: D 你的答案: A (错误)
参考解析:
main是HasStatic的静态方法,在其内部可直接访问静态变量,不存在因为私有变量不能通过编译的问题;如果在其他类中,包括HasStatic的派生类中,均不能访问其私有静态变量
当static作用于某个字段时,肯定会改变数据创建的方式(因为一个static字段对每个类来说都只有一份储存空间,而非static字段则是对每个对象有一个储存空间);
所以无论是HasStatic类的对象hs1,hs2,或是直接通过类名修改static作用的字段,都是一个,因此选择D
17.关于struts项目中的类与MVC模式的对应关系,说法错误的是
Jsp文件实现视图View的功能
ActionServlet这一个类是整个struts项目的控制器
ActionForm、Action都属于Model部分
一个struts项目只能有一个Servlet
正确答案: C D 你的答案: B (错误)
Struts工作原理
MVC即Model-View-Controller的缩写,是一种常用的设计模式。MVC 减弱了业务逻辑接口和数据接口之间的耦合,以及让视图层更富于变化。
Struts 是MVC的一种实现,它将 Servlet和
JSP 标记(属于 J2EE
规范)用作实现的一部分。Struts继承了MVC的各项特性,并根据J2EE的特点,做了相应的变化与扩展。
控
制:有一个XML文件Struts-config.xml,与之相关联的是Controller,在Struts中,承担MVC中Controller角
色的是一个Servlet,叫ActionServlet。ActionServlet是一个通用的控制组件。这个控制组件提供了处理所有发送到
Struts的HTTP请求的入口点。它截取和分发这些请求到相应的动作类(这些动作类都是Action类的子类)。另外控制组件也负责用相应的请求参数
填充 Action
From(通常称之为FromBean),并传给动作类(通常称之为ActionBean)。动作类实现核心商业逻辑,它可以访问java
bean 或调用EJB。最后动作类把控制权传给后续的JSP
文件,后者生成视图。所有这些控制逻辑利用Struts-config.xml文件来配置。
视图:主要由JSP生成页面完成视图,Struts提供丰富的JSP 标签库:
Html,Bean,Logic,Template等,这有利于分开表现逻辑和程序逻辑。
模 型:模型以一个或多个java
bean的形式存在。这些bean分为三类:Action Form、Action、JavaBean or EJB。Action
Form通常称之为FormBean,封装了来自于Client的用户请求信息,如表单信息。Action通常称之为ActionBean,获取从
ActionSevlet传来的FormBean,取出FormBean中的相关信息,并做出相关的处理,一般是调用Java
Bean或EJB等。
流程:在Struts中,用户的请求一般以*.do作为请求服务名,所有的*.do请求均被指向
ActionSevlet,ActionSevlet根据Struts-config.xml中的配置信息,将用户请求封装成一个指定名称的
FormBean,并将此FormBean传至指定名称的ActionBean,由ActionBean完成相应的业务操作,如文件操作,数据库操作等。
每一个*.do均有对应的FormBean名称和ActionBean名称,这些在Struts-config.xml中配置。
核心:Struts的核心是ActionSevlet,ActionSevlet的核心是Struts-config.xml。
18.下面有关jsp中静态include和动态include的区别,说法错误的是?
动态INCLUDE:用jsp:include动作实现
静态INCLUDE:用include伪码实现,定不会检查所含文件的变化,适用于包含静态页面<%@ include file="included.htm" %>
静态include的结果是把其他jsp引入当前jsp,两者合为一体;动态include的结构是两者独立,直到输出时才合并
静态include和动态include都可以允许变量同名的冲突.页面设置也可以借用主文件的
正确答案: D 你的答案: D (正确)
参考分析: 动态 INCLUDE 用 jsp:include 动作实现静态 INCLUDE 用 include 伪码实现 , 定不会检查所含文件的变化 , 适用于包含静态页面 <%@ include file="included.htm" %> 。先将文件的代码被原封不动地加入到了主页面从而合成一个文件,然后再进行翻译,此时不允许有相同的变量。
以下是对 include 两种用法的区别 , 主要有两个方面的不同 ;
一 : 执行时间上 :
<%@ include file="relativeURI"%> 是在翻译阶段执行
二 : 引入内容的不同 :
<%@ include file="relativeURI"%>
引入静态文本 (html,jsp), 在 JSP 页面被转化成 servlet 之前和它融和到一起 .
19.给定以下JAVA代码,这段代码运行后输出的结果是()
public class Test { public static int aMethod(int i)throws Exception { try{ return i / 10; } catch (Exception ex) { throw new Exception("exception in a Method"); } finally{ System.out.printf("finally"); } } public static void main(String [] args) { try { aMethod(0); } catch (Exception ex) { System.out.printf("exception in main"); } System.out.printf("finished"); } }
exception in mainfinished
finallyfinished
exception in mainfinally
finallyexception in mainfinished
正确答案: B 你的答案: D (错误)
参考分析: i / 10;无论i是多少,永远不会抛出异常,所以catch语句不会执行。 而finally语句是必定执行的语句。 所以先指向aMathod()的finally代码块,输出finally 然后执行main()方法的最后一条输出语句,输出finished20.对于JVM内存配置参数:
-Xmx10240m -Xms10240m -Xmn5120m -XXSurvivorRatio=3
,其最小内存值和Survivor区总大小分别是()
5120m,1024m
5120m,2048m
10240m,1024m
10240m,2048m-Xmx:最大堆大小 -Xms:初始堆大小 -Xmn:年轻代大小 -XXSurvivorRatio:年轻代中Eden区与Survivor区的大小比值 年轻代5120m, Eden:Survivor=3,Survivor区大小=1024m(Survivor区有两个,即将年轻代分为5份,每个Survivor区占一份),总大小为2048m。 -Xms初始堆大小即最小内存值为10240m -Xms -Xmx分别设置堆的最小值和最大值,如果要设置成堆的大小可变,那么可以将最大值和最小值设置成不一样,如果要将堆大小固定,那么只需将最大值和最小值设置成一样的就行。 jvm中分为堆和方法区 堆又进一步分为新生代和老年代 方法区为永久代 堆中区分的新生代和老年代是为了垃圾回收,新生代中的对象存活期一般不长,而老年代中的对象存活期较长,所以当垃圾回收器回收内存时,新生代中垃圾回收效果较好,会回收大量的内存,而老年代中回收效果较差,内存回收不会太多。 基于以上特性,新生代中一般采用复制算法,因为存活下来的对象是少数,所需要复制的对象少,而老年代对象存活多,不适合采用复制算法,一般是标记整理和标记清除算法。 因为复制算法需要留出一块单独的内存空间来以备垃圾回收时复制对象使用,所以将新生代分为eden区和两个survivor区,每次使用eden和一个survivor区,另一个survivor作为备用的对象复制内存区。 综上: -Xmn设置了新生代的大小为5120m,而-XXSurvivorRatio=3,所有将新生代共分成5分,eden占三份,survivor占两份,每份1/5