面试题汇总, 答案大部分来自于网上+自己的理解,整合了一下。留作标记,以后常来看看~如果有错,欢迎指出~
一、 选择题(每小题4分,少选得两分)
1. 表达式(15/2^2)的值是 (A)
A. 5
B. 15
C. 14
D. 0
解析:15/2为7.5,取整7,异或2,化成二进制为111异或010得到结果101,然后化成十进制为5
1.十进制转化为2进制:除2取余倒着排
2.异或:相同输出0,不同输出1
3.运算符相关知识:
运算符指明对操作数的运算方式。组成表达式的Java操作符有很多种。运算符按照其要求的操作数数目来分,可以有单目运算符、双目运算符和三目运算符,它们分别对应于1个、2个、3个操作数。运算符按其功能来分,有算术运算符、赋值运算符、关系运算符、逻辑运算符、位运算符和其他运算符。[1] 单目:+(取正)-(取负) ++(自增1) - -(自减1) 双目:+ - * / %(取余) 三目:a>b?true:false 说明:当a大于b的时候,为true(也就是冒号之前的值),否则为false;这整个运算符包括一个关系运算符(可以是“>”"<""!="等等),一个“?”,一个“:”,冒号前后需要有两个表达式或者是值或者是对象。 等于符号:==,不等于符号:!= ,大于符号:>,小于符号:<,大于等于符号:>= ,小于等于符号:<= 。 位运算符 与(&)、非(~)、或(|)、异或(^) &:双目运算符,运算时均把运算数转换为二进制再做比较,规则:当相同的位上均为1时结果为1,否则结果为0.如:1010&1101,转为二进制:10001001101&1111110010比较结果为:1000000转为十进制: 64所以1010&1101=64; | :当两边操作数的位有一边为1时,结果为1,否则为0。如1100|1010=1110 ~:0变1,1变0 ^:两边的位不同时,结果为1,否则为0.如1100^1010=0110 与(&&)、非(!)、或(||) = += -= *= /= %= &= ^= |= <<= >>= 该运算符是双目运算符,左面的操作元是一个对象,右面是一个类。当左面的对象是右面的类创建的对象时,该运算符运算结果是true,否则是false。 Java 的表达式就是用运算符连接起来的符合Java 规则的式子.运算符的优先级决定了表达式中运算执行的先后顺序.例如,x<y&&!z相当于(x<y)&&(!z),没有必要去记忆运算符号的优先级别,在编写程序时可尽量的使用括号来实现你想要的运算次序,以免产生难以阅读或含糊不清的计算顺序.运算符的结合性决定了并列相同级别的运算符的先后顺序,例如,加减的结合性是从左到右,8-5+3 相当于(8-5)+3.逻辑否运算符的结合性是右到左, x 相当于!(!x).表3.4是Java所有运算符的优先级和结合性。 << 带符号左移 >>带符号右移 >>> 无号右移 按优先级从高到低排列如下:[ ] ( ) ++ -- ! ~ instanceof * / % + - << >> >>> <> < = > \ == != &^& & || ? := op= 。
运算符操作 一、运算符"+",如果必要则自动把操作数转换为String型。如果操作数是一个对象,它可定义一个方法toString()返回该对象的String方式,例如floata=1.0print(“Thevalueofais”+a+“\n”);+运算符用到的例子Strings=“a=”+a;+=运算符也可以用于String。注意,左边(下例中的s1)仅求值一次。s1+=a;//s1=s1+a//若a非String型,自动转换为String型。 二、整数算术运算的异常是由于除零或按零取模造成的。它将引发一个算术异常。下溢产生零,上溢导致越界。例如:加1超过整数最大值,取模后,变成最小值。一个op=赋值运算符,和上表中的各双目整数运算符联用,构成一个表达式。整数关系运算符<,>,<=,>=,==和!=产生boolean类型的数据。 三、数组运算符数组运算符形式如下:<expression>[<expression>]可给出数组中某个元素的值。合法的取值范围是从0到数组的长度减1。 四、对象运算符双目运算符instanceof测试某个对象是否是指定类或其子类的实例。例如:if(myObjectinstanceofMyClass){MyClassanothermyObject=(MyClass)myObject;…}是判定myObject是否是MyClass的实例或是其子类的实例。 五、浮点运算符浮点运算符可以使用常规运算符的组合:如单目运算符++、--,双目运算符+、-、*和/,以及赋值运算符+=,-=,*=,和/=。此外,还有取模运算:%和%=也可以作用于浮点数,例如:a%b和a-((int)(a/b)*b)的语义相同。这表示a%b的结果是除完后剩下的浮点数部分。只有单精度操作数的浮点表达式按照单精度运算求值,产生单精度结果。如果浮点表达式中含有一个或一个以上的双精度操作数,则按双精度运算,结果是双精度浮点数。 六、布尔运算符布尔(boolean)变量或表达式的组合运算可以产生新的boolean值,fales和true(记得是小写)。单目运算符!是布尔非。双目运算符&,|和^是逻辑AND,OR和XOR运算符,它们强制两个操作数求布尔值。为避免右侧操作数冗余求值,用户可以使用短路求值运算符&&和||。 七、用户可以使用==和!=,赋值运算符也可以用&=、|=、^=。三元条件操作符和C语言中的一样。 八、++运算符用于表示直接加1操作。增量操作也可以用加运算符和赋值操作间接完成。++lvalue(左值表示lvalue+=1,++lvalue也表示lvalue=lvalue+1。 九、--运算符用于表示减1操作。++和--运算符既可以作为前缀运算符,也可以做为后缀运算符。双目整数运算符是:运算符操作**+加-减*乘/除%取模&位与|位或^位异或<<左移 >>右移(带符号) >>>添零右移整数除法按零舍入。除法和取模遵守以下等式:
&是位 &&是逻辑 当&两边是整数时执行的是位运算,而两边是boolean值时执行的是逻辑运算, 如: 3&6 就是执行的位运算,结果是一个整数:2 true&false 执行的就是逻辑运算,结果是一个boolean值:false &的逻辑运算和&&逻辑运算是存在一定不同的 &逻辑运算时两边都会计算的,而&&则在左边为假时则直接返的是false不再计算右边 举个例子: 1: int[] a={1,2,3}; if(a[0]==2&a[3]==4){System.out.println("true")} 2: int[] a={1,2,3}; if(a[0]==2&&a[3]==4){System.out.println("true")} 这两个例子中,第一个会抛出异常,而第二个则什么不会输出也不会抛异常 这是因为第一个例子中if语句中用的是&,所以两边的都会计算,当计算a[3]==4时抛出数组下标越界异常 第二个例子则在计算第一个式子a[0]==2发现结果为假则不再计算右边,直接返回false,所以该例子不会输出任何东西。 如果A=3成立的话结果是b,如果不成立的话结果是c; 在Java 中提供运算功能的就是运算符(Operator),算术运算符有加(+)、减(-)、乘(*)、除(/)这类的运算符。另外还有一个很常用的取模运算符(%)。这类以数学运算为主的运算符称为算术运算符(Arithmetic Operator)。 举几个算数运算的例子: int a = 5+4; //a=9 int b = a*2; //b=18 int c = b/4; //c=4 int d = b-c; //d=14 int e = -d; //e=-14 int f = e%4; //f=-2 这里简单说一下取模运算符(%),其实就是取除法后的余数,例子中的int f = e%4,就是-14对4取余数,结果为-2。与C、 C++不同,对取模运算符%来说,其操作数可以为浮点数,如 37.2%10=7.2 而且,Java对加运算符进行了扩展,使它能够进行字符串的连接,如"abc"+"de",得到字符串 "abcde"。但是这只是对于字符串连接的简单扩展,字符串并不支持诸如减法的其他运算。有趣的是,字符是支持加法和减法的,其参与运算的是这个字符的ASCII码值。例如b的ASCII码值比a大1,所以(‘b’-‘a’)的结果就是1。 JAVA左移:<<带符号右移:>> 无符号右移:>>>“ < <”, “> > ”, “> > > ”在Java中是左移、有符号右移和无符号右移运算符。位移运算符只对int值进行操作,如果不是int,编译器会报错。在Java中,一个int的长度始终是32bit,也就是4个字节。 1)左移动运算符: 会将操作的数向左边移动,移动的位的个数由指定,左移(2)右移动运算符: 反过来,把操作数向右移动,移动的位个数同样由右操作数指定。(3)无正负号的右移运算符(>>>): 采用0补充,意思就是说 Test { main(String[] args) { m=-7; System.out.println("m的二进制码是:"+Integer.toBinaryString(m)); System.out.println("m>>2的二进制码是:"+Integer.toBinaryString(m>>2)); System.out.println("(m>>2)="+(m>>2)); System.out.println("m<<2的二进制码是:"+Integer.toBinaryString(m<<2)); System.out.println("(m<<2)=:"+(m<<2)); System.out.println("m>>>24的二进制码是:"+Integer.toBinaryString(m>>>24)); System.out.println(" m>>>24 :"+ (m>>>24)); } } -7的反码:11111111111111111111111111111000 补码:11111111111111111111111111111001
|
2. 下列对final修饰符的描述,正确的有 (AD)
A. 被final修饰的class不能被继承
B. 被final修饰的方法不能被重载(Overload)
C. 被final修饰的变量只能在变量定义时初始化 构造方法
D. final不能用于修饰构造方法
解析:重写是子类的方法覆盖父类的方法,要求方法名和参数都相同
重载是在同一个类中的两个或两个以上的方法,拥有相同的方法名,但是参数却不相同,方法体也不相同,最常见的重载的例子就是类的构造函数,可以参考API帮助文档看看类的构造方法
final可用来修饰类,变量,方法。 1.final修饰变量:final修饰变量时,表示该变量一旦获得了初始值之后就不可改变。 1.修饰成员变量:与普通成员变量不同的是,final成员变量(实例属性和类属性)必须由程序员显示初始化,系统不会对final成员变量进行隐式初始化。 非final修饰的成员变量初始化过程:当进行静态初始化时,可对类属性初始化,当执行普通初始化块,构造器时可对实例属性初始化,因此:非final成员变量的初始值,可以在定义该变量时指定初始值,可以在初始化块,构造器中执行初始化值,否则成员变量的初始值是由系统自动分配的初始值。 final修饰的类属性,实例属性指定初始值的地方: 类属性:静态初始化块,声明该属性时指定初始值。 实例属性:非静态初始化块,构造器,声明该属性时指定初始化值。 2.final修饰局部变量: 1.系统不会对局部变量进行初始化,必须由程序员显示初始化。 如果在定义final变量时没有指定初始值,则可以在后面代码中进行对final变量赋初始值,但只能一次,不能重复赋值,,如果final修饰的局部变量在定义时已经指定默认值,则后面的代码中不能再对该变量赋值。 2.final修饰形参不能被赋值,因为形参在调用该方法时,有系统传入的参数来完成初始化。 3.final修饰基本类型变量与引用类型变量的区别: 1.final修饰基本类型变量时,不能对基本变量重新赋值,因为基本类型变量不能被改变。 2.final修饰引用类型变量时,仅仅保持的是这个引用所引用的地址不会改变,既一直引用同一个对象。但这个对象完全可以改变(对象的属性) 例如: final person p = new person(); //改变person对象的age属性,合法。 p.SetAge(23); //对p引用重新赋值,不合法。 p = null; 注意:如果final修饰变量是基本数据类型,且在编译时就可以确定该变量的值,于是把该变量当做常量来处理:常量命名规则:多个有意义的单词连接,所有字符大写,单词之间用下划线分割。 如果final修饰变量是引用类型,final变量无法在编译时就获得值,而必须在运行时才能得到值如:final TestClass t = new TestClass();编译时系统不会创建一个TestClass对象赋给 t 变量,所以t不需要当做常量来处理,无需使用常量命名规则。 4.final方法: 1.final修饰的方法不可被重写。 2.java提供的Object类有一个final方法:getClass(),因为java不希望任何一个类重写这个方法。 3.对于private 方法,仅在当前类中可见,子类无法访问,所以也就无法重写该方法,如果子类中定义了一个与父类private方法有相同方法名,相同形参列表,相同返回值类项的方法,也不是方法重写,只是重新定义了一个方法,因此使用final修饰的一个private 访问权限的方法,依然可以在其子类中定义与该方法有相同方法名,相同形参列表,相同返回值类型的方法。 4.final修饰的方法不能被重写但完全可以被重载。 5.final类: 1.final修饰的类不可有子类,java.lang.Math类就是一个final类,它不可以有子类。
|
3. 下列对static修饰符的描述,正确的有 (BD)
A. static不能作为class的修饰符
B. 被static修饰的成员变量和成员方法独立于该类的任何对象
C. 被static修饰的成员(类、方法、成员变量)不能再使用private进行修饰
D. static代码块(静态代码块),在类的构造函数之前被执行
解析:static可以修饰内部类,普通类不行;执行顺序:static代码块,普通代码块,构造函数;static成员变量和static成员方法都可以使用private进行修饰
static 修饰符可以用来修饰类的成员变量,成员方法和代码块。 class StaticTest{ class StaticBlock{ 静态方法必须被实现
|
4. 下列的网络协议中,面向连接的的协议是 (B)
A. 用户数据报协议 UDP
B. 传输控制协议 TCP
C. 网际协议 IP
D. 网际控制报文协议 ICMP
解析:
TCP/IP协议介绍 TCP/IP的通讯协议 这部分简要介绍一下TCP/IP的内部结构,为讨论与互联网有关的安全问题打下基础。TCP/IP协议组之所以流行,部分原因是因为它可以用在各种各样的信道和底层协议(例如T1和X.25、以太网以及RS-232串行接口)之上。确切地说,TCP/IP协议是一组包括TCP协议和IP协议,UDP(User Datagram Protocol)协议、ICMP(Internet Control Message Protocol)协议和其他一些协议的协议组。 TCP/IP整体构架概述 TCP/IP协议并不完全符合OSI的七层参考模型。传统的开放式系统互连参考模型,是一种通信协议的7层抽象的参考模型,其中每一层执行某一特定任务。该模型的目的是使各种硬件在相同的层次上相互通信。这7层是:物理层、数据链路层、网路层、传输层、话路层、表示层和应用层。而TCP/IP通讯协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。这4层分别为: 应用层:应用程序间沟通的层,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。 传输层:在此层中,它提供了节点间的数据传送服务,如传输控制协议(TCP)、用户数据报协议(UDP)等,TCP和UDP给数据包加入传输数据并把它传输到下一层中,这一层负责传送数据,并且确定数据已被送达并接收。 互连网络层:负责提供基本的数据封包传送功能,让每一块数据包都能够到达目的主机(但不检查是否被正确接收),如网际协议(IP)。 网络接口层:对实际的网络媒体的管理,定义如何使用实际网络(如Ethernet、Serial Line等)来传送数据。 TCP/IP中的协议 以下简单介绍TCP/IP中的协议都具备什么样的功能,都是如何工作的:
|
1. IP 网际协议IP是TCP/IP的心脏,也是网络层中最重要的协议。 IP层接收由更低层(网络接口层例如以太网设备驱动程序)发来的数据包,并把该数据包发送到更高层---TCP或UDP层;相反,IP层也把从TCP或UDP层接收来的数据包传送到更低层。IP数据包是不可靠的,因为IP并没有做任何事情来确认数据包是按顺序发送的或者没有被破坏。IP数据包中含有发送它的主机的地址(源地址)和接收它的主机的地址(目的地址)。 高层的TCP和UDP服务在接收数据包时,通常假设包中的源地址是有效的。也可以这样说,IP地址形成了许多服务的认证基础,这些服务相信数据包是从一个有效的主机发送来的。IP确认包含一个选项,叫作IP source routing,可以用来指定一条源地址和目的地址之间的直接路径。对于一些TCP和UDP的服务来说,使用了该选项的IP包好象是从路径上的最后一个系统传递过来的,而不是来自于它的真实地点。这个选项是为了测试而存在的,说明了它可以被用来欺骗系统来进行平常是被禁止的连接。那么,许多依靠IP源地址做确认的服务将产生问题并且会被非法入侵。
|
2. TCP 如果IP数据包中有已经封好的TCP数据包,那么IP将把它们向‘上’传送到TCP层。TCP将包排序并进行错误检查,同时实现虚电路间的连接。TCP数据包中包括序号和确认,所以未按照顺序收到的包可以被排序,而损坏的包可以被重传。 TCP将它的信息送到更高层的应用程序,例如Telnet的服务程序和客户程序。应用程序轮流将信息送回TCP层,TCP层便将它们向下传送到IP层,设备驱动程序和物理介质,最后到接收方。 面向连接的服务(例如Telnet、FTP、rlogin、X Windows和SMTP)需要高度的可靠性,所以它们使用了TCP。DNS在某些情况下使用TCP(发送和接收域名数据库),但使用UDP传送有关单个主机的信息。
|
3.UDP UDP与TCP位于同一层,但对于数据包的顺序错误或重发。因此,UDP不被应用于那些使用虚电路的面向连接的服务,UDP主要用于那些面向查询---应答的服务,例如NFS。相对于FTP或Telnet,这些服务需要交换的信息量较小。使用UDP的服务包括NTP(网落时间协议)和DNS(DNS也使用TCP)。 欺骗UDP包比欺骗TCP包更容易,因为UDP没有建立初始化连接(也可以称为握手)(因为在两个系统间没有虚电路),也就是说,与UDP相关的服务面临着更大的危险。
|
4.ICMP ICMP与IP位于同一层,它被用来传送IP的的控制信息。它主要是用来提供有关通向目的地址的路径信息。ICMP的‘Redirect’信息通知主机通向其他系统的更准确的路径,而‘Unreachable’信息则指出路径有问题。另外,如果路径不可用了,ICMP可以使TCP连接‘体面地’终止。PING是最常用的基于ICMP的服务。 |
5. TCP和UDP的端口结构 TCP和UDP服务通常有一个客户/服务器的关系,例如,一个Telnet服务进程开始在系统上处于空闲状态,等待着连接。用户使用Telnet客户程序与服务进程建立一个连接。客户程序向服务进程写入信息,服务进程读出信息并发出响应,客户程序读出响应并向用户报告。因而,这个连接是双工的,可以用来进行读写。 两个系统间的多重Telnet连接是如何相互确认并协调一致呢?TCP或UDP连接唯一地使用每个信息中的如下四项进行确认: 源IP地址发送包的IP地址。 目的IP地址接收包的IP地址。 源端口源系统上的连接的端口。 目的端口目的系统上的连接的端口。 端口是一个软件结构,被客户程序或服务进程用来发送和接收信息。一个端口对应一个16比特的数。服务进程通常使用一个固定的端口,例如,SMTP使用25、Xwindows使用6000。这些端口号是‘广为人知’的,因为在建立与特定的主机或服务的连接时,需要这些地址和目的地址进行通讯。 |
http://blog.chinaunix.net/uid-26833883-id-3627644.html |
5.在linux系统中能解压test.Z压缩文件的命令是 D
A. tar
B. ungzip
C. compress
D. uncompress
解析:
linux下解压命令大全
.tar 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName (注:tar是打包,不是压缩!) ——————————————— .gz 解压1:gunzip FileName.gz 解压2:gzip -d FileName.gz 压缩:gzip FileName
.tar.gz 和 .tgz 解压:tar zxvf FileName.tar.gz 压缩:tar zcvf FileName.tar.gz DirName ——————————————— .bz2 解压1:bzip2 -d FileName.bz2 解压2:bunzip2 FileName.bz2 压缩: bzip2 -z FileName
.tar.bz2 解压:tar jxvf FileName.tar.bz2 压缩:tar jcvf FileName.tar.bz2 DirName ——————————————— .bz 解压1:bzip2 -d FileName.bz 解压2:bunzip2 FileName.bz 压缩:未知
.tar.bz 解压:tar jxvf FileName.tar.bz 压缩:未知 ——————————————— .Z 解压:uncompress FileName.Z 压缩:compress FileName .tar.Z
解压:tar Zxvf FileName.tar.Z 压缩:tar Zcvf FileName.tar.Z DirName ——————————————— .zip 解压:unzip FileName.zip 压缩:zip FileName.zip DirName ——————————————— .rar 解压:rar x FileName.rar 压缩:rar a FileName.rar DirName ——————————————— .lha 解压:lha -e FileName.lha 压缩:lha -a FileName.lha FileName ——————————————— .rpm 解包:rpm2cpio FileName.rpm | cpio -div ——————————————— .deb 解包:ar p FileName.deb data.tar.gz | tar zxf - ——————————————— .tar .tgz .tar.gz .tar.Z .tar.bz .tar.bz2 .zip .cpio .rpm .deb .slp .arj .rar .ace .lha .lzh .lzx .lzs .arc .sda .sfx .lnx .zoo .cab .kar .cpt .pit .sit .sea 解压:sEx x FileName.* 压缩:sEx a FileName.* FileName
sEx只是调用相关程序,本身并无压缩、解压功能,请注意!
gzip 命令 减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间。gzip 是在 Linux 系统中经常使用的一个对文件进行压缩和解压缩的命令,既方便又好用。
语法:gzip [选项] 压缩(解压缩)的文件名该命令的各选项含义如下:
-c 将输出写到标准输出上,并保留原有文件。-d 将压缩文件解压。-l 对每个压缩文件,显示下列字段: 压缩文件的大小;未压缩文件的大小;压缩比;未压缩文件的名字-r 递归式地查找指定目录并压缩其中的所有文件或者是解压缩。-t 测试,检查压缩文件是否完整。-v 对每一个压缩和解压的文件,显示文件名和压缩比。-num 用指定的数字 num 调整压缩的速度,-1 或 --fast 表示最快压缩方法(低压缩比),-9 或--best表示最慢压缩方法(高压缩比)。系统缺省值为 6。指令实例:
gzip *% 把当前目录下的每个文件压缩成 .gz 文件。gzip -dv *% 把当前目录下每个压缩的文件解压,并列出详细的信息。gzip -l *% 详细显示例1中每个压缩的文件的信息,并不解压。gzip usr.tar% 压缩 tar 备份文件 usr.tar,此时压缩文件的扩展名为.tar.gz。 |
6.下列对TCP协议的描述正确的有(AB)
A. TCP协议能保证可靠传输
B. TCP协议建立连接需要进行3次握手
C. TCP协议释放连接需要进行3次握手
D. TCP协议是一个应用层协议 传输层
解析:建立连接需要3次握手,结束需要4次握手;可靠传输
7.下列对变量的定于语句中合法的有 (AD)
A. char c = '我'
B. String str = '我'
C. byte b = 128
D. float f = 1
8.下列操作属于DDL的有 (B)
A. select
B. drop
C. insert
D. update
E. alert.
解析:create drop alter 都属于DDL操作
9.以下数据结构中不属于线性数据结构的是 (C)
线性表和链表之外其他的都不属于线性数据结构
A. 队列
B. 线性表
C. 二叉树
D. 栈
10.下列对JSP中forward 和redirect的描述正确的有 (AC)
A.forward操作不会在用户浏览器里展现跳转地址
B. redirect操作不会在用户浏览器里展现跳转地址
C.forward操作会把原始请求数据转发给跳转地址
D. redirect操作会把原始请求数据转发给跳转地址
解析:
forward内部跳转和redirect重定向跳转的区别 1.从地址栏显示来说 forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址. redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL. 2.从数据共享来说 forward:转发页面和转发到的页面可以共享request里面的数据. redirect:不能共享数据. 3.从运用地方来说 forward:一般用于用户登陆的时候,根据角色转发到相应的模块. redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等. 4.从效率来说 forward:高. redirect:低.
|
二、 简单题(20分)
1. 请列举至少3个JDK安装目录下的可执行程序(如javac),并列举几个常用的命令行参数。(6分)
java -version
javac -classpath -sourcepath -version
javadoc
jar
jdb 用来debug
2. 请分析命题:“Java采用自动垃圾回收技术(GC) ,因此不会出现内存泄露”。(6分)
我认为此命题是错误的。内存泄漏指你用new申请了一块内存,但是没有将内存释放,导致这块内存一直处于占用状态
java有垃圾回收机制自动管理内存的回收。因此开发人员不需要调用方法来释放内存。但是不表明java就不会出现内存泄露,有些情况也会导致java编写的程序出现内存泄露的问题。
举例说明:
Vector v = newVector(10);
for (int i = 1;i<100; i++){
Object o = new Object();
v.add(o);
o = null;
}
o对象是不能被回收的,因为实际上v引用了这些对象,还被引用的对象GC是没有办法回收的,这样就很可能导致内存的泄露。
3. 请简单描述单子模式(单例模式)的几种不同实现方式,及各自优缺点。请列举至少2种其他的设计模式及应用场景。(8分)
工厂模式,实例化对象;适配器模式等
(1)
/* 线程安全 但效率比较低 一开始就要加载类new一个 对象
这是饿汉方式的单例模式*/
public class Singleton1 {
private Singleton1(){
}
private static finalSingleton1 instance=newSingleton1();
public static Singleton1 getInstancei(){
return instance;
}
}
(2)
// 饱汉方式的单例模式 但是有多个线程访问时就不是安全的 返回的不是同一个对象
public class Singleton {
private Singleton(){
}
private static Singleton instance;
public static Singleton getInstance() {
if (instance == null)
instance= new Singleton();
return instance;
}
}
(3)
//虽然是安全的 但是效率非常低在一个时候只有一个线程能访问 同时返回一个对象
public class Singleton2 {
private Singleton2(){
}
private static Singleton2 instance;
public static synchronizedSingleton2 getInstance() {
if (instance == null)
instance= new Singleton2();
return instance;
}
}
(4)
/* 线程安全 并且效率高 能有多个线程访问*/
public class Singleton3 {
private static Singleton3 instance;
private Singleton3() {
}
public static Singleton3 getIstance() {
if (instance == null) {
synchronized (Singleton3.class) {
if (instance == null) {
instance= new Singleton3();
}
}
}
return instance;
}
}
三、 程序阅读题(18分)
1. 下面程序片段的输出结果是(4分)
public static void main(String[]args) {
int x = 3;
int y = 1;
if (x = y)System.out.println("Not equal");
elseSystem.out.println("Equal");
}
报错
解析:==表示的是数学中的等号,相当于equal;而=表示的是赋值
2. 在{1}处添加什么代码,可以确保程序输出值是100(6分)
class B implements Runnable{
int i;
public void run() {
try {Thread.sleep(1000);} catch (InterruptedException e) {}
i = 100;
}
}
public class Test {
public static void main(String[] args) throws Exception{
B b = new B();
Thread t = new Thread (b);
t.start();
// {1}
int j= b.i;
System.out.println(j);
}
}
A. a.wait();
B. t.wait(); 报错
C. t.join();
D. t.yield(); 0
E. t.notify(); 报错
F. a.notify();
G. t.interrupt(); 0
(C)
解析:合并线程
3. 请指出下列程序片段的输出结果(8分)
public static voidmain(String[] args) throws Exception {
String str = "中国";
System.out.println(str.getBytes("UTF-8").length);
System.out.println(str.getBytes("GBK").length);
System.out.println(str.getBytes("ISO-8859-1").length);
System.out.println(newString(str.getBytes("ISO-8859-1"), "ISO-8859-1"));
System.out.println(newString(str.getBytes("UTF-8"), "UTF-8"));
System.out.println(new String(str.getBytes("GBK"),"GBK"));
}
解析:结果如下
6
4
2
??
中国
中国
Unicode、UTF-8 和 ISO8859-1区别 属于单字节编码,最多能表示的字符范围是0-255,应用于英文系列。比如,字母a的编码为0x61=97。很明显,iso8859-1编码表示的字符范围很窄,无法表示中文字符。但是,由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,仍旧使用iso8859-1编码来表示。而且在很多协议上,默认使用该编码。比如,虽然"中文"两个字不存在iso8859-1编码,以gb2312编码为例,应该是"d6d0 cec4"两个字符,使用iso8859-1编码的时候则将它拆开为4个字节来表示:"d6 d0 ce c4"(事实上,在进行存储的时候,也是以字节为单位处理的)。而如果是UTF编码,则是6个字节"e4 b8 ad e6 96 87"。很明显,这种表示方法还需要以另一种编码为基础。 这就是汉字的国标码,专门用来表示汉字,是双字节编码,而英文字母和iso8859-1一致(兼容iso8859-1编码)。其中gbk编码能够用来同时表示繁体字和简体字,而gb2312只能表示简体字,gbk是兼容gb2312编码的。
|
四、 编程题(12分)
1.请使用二分查找算法查找字符串数组{"a","b","c","d","e","f","g","h"}中"g"元素。(12分)
解析:
//使用递归算法
public static <E extends Comparable<E>> int binarySearch(E[] array, int from, int to, E key) throws Exception {
if (from < 0 || to < 0) {
throw new IllegalArgumentException("params from & length must larger than 0 .");
}
if (from <= to) {
int middle = (from >>> 1) + (to>>> 1); // 右移即除2
E temp = array[middle];
if (temp.compareTo(key) > 0) {
to = middle - 1;
} else if (temp.compareTo(key) < 0) {
from = middle + 1;
} else {
return middle;
}
}
return binarySearch(array,from, to, key);
}
Socket编程,写一个Socket客户端和一个Socket服务端,客户端向服务端发送一个“Hello,World”消息。(12分)
解析:
public class SendClass {
public static void main(String[] args) {
// while(true)
// {
// try {
// //step1:建立发送对象
// DatagramSocket sendScocket = newDatagramSocket();
// //step2:建立发送包(buf数据byte[],lenght:数据长度,address:地址,port:端口号)
// System.out.print("发送信息:");
// String strIn = newScanner(System.in).nextLine();
// byte[] bMsg = strIn.getBytes();
// //准备ip地址
// StringstrIp = "192.168.0.105";
// InetAddress address =InetAddress.getByName(strIp);//String=>InetAddress
// //发送host的port:8888
// DatagramPacket pack = newDatagramPacket(bMsg, bMsg.length,address,8888);
// //step3:发送包
// sendScocket.send(pack);
// //step4:关闭
// sendScocket.close();
//
// if(strIn.equals("bye"))
// {
// System.out.println("我不再发包了");
// break;
// }
//
// } catch (SocketException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// } catch (UnknownHostException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
try{
ServerSocket server = new ServerSocket(9999);
Socket client = server.accept();
InputStream is = client.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader clientIn = newBufferedReader(isr);
OutputStream os = client.getOutputStream();
PrintWriter clientOut = new PrintWriter(os);
Scanner sc = new Scanner(System.in);
clientOut.println(sc.nextLine());
clientOut.flush();
String str = clientIn.readLine();
clientIn.close();
clientOut.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
package com.javahis.ui.bil;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
public class ReceiveClass {
/**
* @param args
*/
public static void main(String[] args) {
// while(true)
// {
// try {
// System.out.println("建立接收对象>>>>>>>>>>>>");
// //step1:建立接收对象
// DatagramSocket receiveSocket = newDatagramSocket(8888);
// //step2:定义接收包(buf=byte[], length)
// byte[] buf = new byte[1000];
// DatagramPacket pack = new DatagramPacket(buf,buf.length);
// //step3:接收方法
// System.out.println("收到信息>>>>>>>>>>>>>");
// receiveSocket.receive(pack);//阻塞
// //step4:显示接收信息
// String str = new String(buf);
// System.out.println("["+str+"]");
// //step5:释放资源
// receiveSocket.close();
//
//
// if(str.indexOf("bye")!=-1)
// {
// System.out.println("我不再接收包了");
// break;
// }
// } catch (SocketException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
try {
Socket client = new Socket("192.168.8.105",9999);
System.out.println("服务器端连接成功!");
BufferedReader clientIn = new BufferedReader(newInputStreamReader(client.getInputStream()));
PrintWriter clientOut = new PrintWriter(clientIn.readLine());
System.out.println("服务器说:【"+clientIn.readLine()+"】");
Scanner sc = new Scanner(System.in);
System.out.println("客户端说:");
clientOut.print(sc.nextLine());
clientOut.flush();
clientIn.close();
clientOut.close();
} catch (UnknownHostException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
}
1.请使用Java语言实现多线程模式下的生产者与消费者问题。(10分)
/*@author
* 生产者与消费者模型中,要保证以下几点:
* 1 同一时间内只能有一个生产者生产 生产方法加锁sychronized
* 2 同一时间内只能有一个消费者消费 消费方法加锁sychronized
* 3 生产者生产的同时消费者不能消费 生产方法加锁sychronized
* 4 消费者消费的同时生产者不能生产 消费方法加锁sychronized
* 5 共享空间空时消费者不能继续消费 消费前循环判断是否为空,空的话将该线程wait,释放锁允许其他同步方法执行
* 6 共享空间满时生产者不能继续生产 生产前循环判断是否为满,满的话将该线程wait,释放锁允许其他同步方法执行
*/
//主类
class ProducerConsumer
{
public static voidmain(String[] args)
{
StackBasket s = new StackBasket();
Producer p = new Producer(s);
Consumer c = new Consumer(s);
Thread tp = new Thread(p);
Thread tc = new Thread(c);
tp.start();
tc.start();
}
}
//
class Mantou
{
private int id;
Mantou(int id){
this.id = id;
}
public StringtoString(){
return "Mantou :" + id;
}
}
//共享栈空间
class StackBasket
{
Mantou sm[] = newMantou[6];
int index = 0;
/**
* show 生产方法.
* show 该方法为同步方法,持有方法锁;
* show 首先循环判断满否,满的话使该线程等待,释放同步方法锁,允许消费;
* show 当不满时首先唤醒正在等待的消费方法,但是也只能让其进入就绪状态,
* show 等生产结束释放同步方法锁后消费才能持有该锁进行消费
* @param m 元素
* @return 没有返回值
*/
public synchronized voidpush(Mantou m){
try{
while(index == sm.length){
System.out.println("!!!!!!!!!生产满了!!!!!!!!!");
this.wait();
}
this.notify();
}catch(InterruptedException e){
e.printStackTrace();
}catch(IllegalMonitorStateException e){
e.printStackTrace();
}
sm[index] = m;
index++;
System.out.println("生产了:" + m + " 共"+ index + "个馒头");
}
/**
* show 消费方法
* show 该方法为同步方法,持有方法锁
* show 首先循环判断空否,空的话使该线程等待,释放同步方法锁,允许生产;
* show 当不空时首先唤醒正在等待的生产方法,但是也只能让其进入就绪状态
* show 等消费结束释放同步方法锁后生产才能持有该锁进行生产
* @param b true 表示显示,false表示隐藏
* @return 没有返回值
*/
public synchronized Mantoupop(){
try{
while(index == 0){
System.out.println("!!!!!!!!!消费光了!!!!!!!!!");
this.wait();
}
this.notify();
}catch(InterruptedException e){
e.printStackTrace();
}catch(IllegalMonitorStateException e){
e.printStackTrace();
}
index--;
System.out.println("消费了:---------" + sm[index] + " 共"+ index + "个馒头");
return sm[index];
}
}
class Producer implements Runnable
{
StackBasket ss = newStackBasket();
Producer(StackBasketss){
this.ss = ss;
}
/**
* show 生产进程.
*/
public void run(){
for(int i = 0;i < 20;i++){
Mantou m = new Mantou(i);
ss.push(m);
// System.out.println("生产了:" + m + " 共"+ ss.index + "个馒头");
// 在上面一行进行测试是不妥的,对index的访问应该在原子操作里,因为可能在push之后此输出之前又消费了,会产生输出混乱
try{
Thread.sleep((int)(Math.random()*500));
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable
{
StackBasket ss = newStackBasket();
Consumer(StackBasketss){
this.ss = ss;
}
/**
* show 消费进程.
*/
public void run(){
for(int i = 0;i < 20;i++){
Mantou m = ss.pop();
// System.out.println("消费了:---------" + m + " 共"+ ss.index + "个馒头");
// 同上 在上面一行进行测试也是不妥的,对index的访问应该在原子操作里,因为可能在pop之后此输出之前又生产了,会产生输出混乱
try{
Thread.sleep((int)(Math.random()*1000));
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
数据库设计题((12分)
请使用关系型数据库结构简单设计移动梦网的梦网服务订购管理系统。
功能描述:用户必须注册(梦网)服务才能使用,即:系统需要管理用户资源。用户使用具体的一项梦网服务前,需要单独订购。系统需要提供统计功能,如:按月统计、按用户订购的服务总数统计等。(8分)
请按你的设计给出如下查询功能:
1) 统计每个月的注册用户数量(2分)
2) 统计订购了超过两项梦网服务的用户信息(2分)
用户信息表
Userinfo(user_id,regist_date)
梦网服务表
Service(service_id,order_time)
订单表
user_service(user_id,service_id)
中间表
(1)
SELECTCOUNT(*)
FROMuserinfo
WHEREregist_date BETWEEN TO_DATE('05/08/201314:08:40',
'MM/DD/YYYYHH24:MI:SS'
)
ANDTO_DATE('06/08/201314:08:40',
'MM/DD/YYYYHH24:MI:SS'
)
(2)
SELECT A.USER_ID
FROMUSERINFO A,
(SELECT COUNT (*)ASCOUNT,USER_ID
FROMUSER_SERVICE
GROUPBYUSER_ID) B
WHERE A.USER_ID=B.USER_IDANDB.COUNT>=2