第一题
1、简述java中String,StringBuffer,StringBuild的区别。
String是对象不是原始数据类型,是不可变对象,一旦被创建就不能修改它的值。对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去。String是final类,不能被继承。
StringBuffer是可变对象,当对它进行修改的时候不会像String那样重新建立对象,它只能通过构造函数来建立。如下形式:
StringBuffer sb = new StringBuffer();
不能通过赋值符号对它进行赋值。
sb = "this is wrong!";
对象被建立后,在内存中就会分配内存空间,并初始保存一个NULL,向StringBuffer中赋值的时候可以通过它的append方法:
sb.append("hello");
在字符串连接操作中StringBuffer的效率要比String高。
如果在程序中需要对字符串进行频繁的修改连接操作的话,使用StringBuffer的效率要高。
StringBuild与StringBuffer相似,不过StringBuffer是线程安全的,支持并发操作。而 StringBuild是非线程安全的,且不支持并发操作。
在不考虑线程安全的情况下,StringBuild的效率最高,StringBuffer次之,String最差。
2、java中要让一个方法不被子类覆盖,应该怎么定义。
1)使用final方法,final方法可以把方法锁定防止任何继承类修改它的意义和实现。高效,编译器在遇到调用final方法时会转入内嵌机制,大大提高执行效率。
2)父类的私有方法不能被子类覆盖。例:
class testbase { private String show() { return "base"; } public void shh() { System.out.println(show()); } } class testsub extends testbase{ public String show() { return "sub"; } }
当我们在Main方法中实例化一个子类的对象时,调用子类对象的ssh()方法时,打印base而不是打印sub。
3)父类的静态方法不能被子类覆盖为非静态方法。
还是上个例子,我们将其改为:
class testbase { pbulic static String show() { return "base"; } public void shh() { System.out.println(show()); } } class testsub extends testbase{ public String show() { return "sub"; } }
此时会提示子类方法不能覆盖父类show方法的错误。
4)同上,父类的非静态方法不能被子类覆盖为静态方法。
3、请说明java程序能在不同平台运行的原理是怎样的。
Java跨平台是通过java虚拟机实现的,首先java编译程序将源程序翻译为JVM可执行的字节码文件。Java解释器则通过即时编译及解释执行两种方式对字节码文件进行执行。JVM是一种用于计算机设备的规范,它是一个虚拟出来的计算机是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM包含一套字节码指令集,一组寄存器,一个栈一个垃圾回收堆和一个存储方法域。JVM屏蔽了与具体操作系统平台相关的信息,这样java程序只需要生成JVM所需要的字节码文件即可。JVM负责将字节码文件翻译为具体平台上执行的机器指令运行。也就保证了java程序能在不同平台实现运行。
第二题:找出第二大的数
假设有一个整数数组,请实现一个函数,找出其中第二大的数。(注:请给出你的解题思路和完整实现)
求一个整数数组的最大值时,我们可以通过一次遍历将最大值求出,时间复杂度为O(N),同样的我们可以在O(N)的时间复杂度内求出整数数组的第二大只。在这里我们需要两个变量用以记录最大值在数组中的下标及第二大数在数组中的下标。完整实现代码如下:
public int getSecondNum(int [] array) { int resultIndex = -1; int maxIndex = 0; if(array != null && array.length > 1) { int arrayLength = array.length; for(int i = 1; i < arrayLength; i++) { if(array[i] > array[maxIndex]) { resultIndex = maxIndex; maxIndex = i; } else if(array[i] > array[resultIndex] && array[i] != array[maxIndex]) { resultIndex = i; } } } return array[resultIndex]; }
第三题 求K阶斐波那契数列第N项的值
K阶斐波那契数列的定义为:
F(N) = F(N-1)+F(N-2)+....F(N-K);(N>=K,K>=2)
F(K-1) = 1;
F(m) = 0;(0<=m<K-1);
K阶斐波那契数列的递归实现
public void Fibb(int k, int n) { if(k < 2 || n < 0) { System.out.println("something is wrong!"); } else { System.out.println("第n项的值为:" + Fib(k,n)); } } public int Fib(int k,int n) { if(n < k-1) { return 0; } else if(n == k-1) { return 1; } else { int temp = 0; for(int i = 1; i <= k; i++) { temp = temp + Fib(k,n-i); } return temp; } }
K阶斐波那契数列的非递归实现
public int Fib(int k,int n) { int temp = 0; int [] a = new int[k]; if(n < k-1) { return 0; } else if(n == k-1) { return 1; } else { for(int i = 0; i < k;i++) { if(i == k-1) { a[i] = 1; } else a[i] = 0;; } while(n>=k) { n--; temp = 0; for(int i = 0;i<k;i++) { temp = temp + a[i]; } for(int i = 0;i<k-1;i++) { a[i] =a[i+1]; } a[k-1] = temp; } return temp; } }
第四题:日志类
我们在软件开发活动,特别是服务端程序中,为了分析程序的一些运行情况,经常需要在代码内插入一些日志记录语句。现在请你设计一个日志类KPLogs,方便开发使用。
(注:请给出你的设计思路,类定义和核心实现)
一个完备的日志系统框架通常应当包含如下基本特征:
所输出的日志拥有自己的分类,这样在调试时便于针对不同系统的不同模块进行查询,从而快速定位到发生日志事件的代码。
日志按照某种不同的标准分成不同的级别。分级后的日志可以用于同一分类下的日志筛选。
支持多线程。日志系统通常会在多线程的环境中执行,因此作为一种系统资源日志系统应当保证是线程安全的。
支持不同的记录媒介。不同的工程项目往往对日志系统的记录媒介要求不同。因此日志系统必须提供必要的开发接口。以保证能够比较容易的更换记录介质。
高性能,日志系统通常要提供高速的日志记录功能以应对大系统下大请求系统的正常运转
稳定性,日志系统必须保持高度的稳定性,不能因为日志系统内部错误导致主要业务代码的崩溃。
Java中有三类日志系统框架比较优秀:
1)Log4j
最早的java日志 框架之一由apache基金会发起提供灵活而强大的日志记录机制。但是其复杂的配置过程和内部概念往往令人望而却步。
2)JDK1.4 Logging Framework
继Log4j之后 JDK标准委员会将Log4j的基本思想吸收到JDK中,在JDK1.4中发布了第一个日志框架接口,并提供了一个简单实现。
3)Commons Logging Framework
该框架同样是Apache基金会项目。其出现主要是为了使得java项目能够在Log4j和JDK1.4 Logging Framework的使用上随意进行切换。因此该框架提供了统一的调用接口和配置方法。
日志系统框架可以分为日志记录模块和日志输出模块两大部分。日志记录模块负责创建和管理日志记录器(Logger),每一个Logger对象负责按照不同的级别接收各种记录了日志信息的日志对象,logger对象首先获取所有需要记录的日志,并且同步的将日志分派给日志输出模块。日志输出模块则负责日志输出器的创建和管理,以及日志的输出。系统中允许有多个不同的日志输出器,日志输出器负责将日志记录到存储介质中
系统通过保持多个Logger对象的方式来进行日志记录的分类。每个Logger对象代表一类日志分类,因此logger对象的名称属性是其唯一标识。通过名称属性来获取一个logger对象:
Logger logger = new Logger("LoggerName");
一般的,使用类名作为日志记录器的名称。这样做的好处是能够减少日志记录器命名之间的冲突,同时能够将日志记录分类的尽可能的精细。因此,假定有一UserManager类需要使用日志服务,则更一般的使用方式为:
Logger logger = new Logger.getLogger(UserManager.class);
对于日志级别定义在相应的接口中,以下是部分接口描述:
Public void debug(String msg);//输出调试信息
Public void info(String msg); //输出系统提示
Public void warn(String msg); //输出警告信息
Public void fatal(String msg);//输出系统错误
Public void error(String msg);//输出严重错误
日志类中可以采用工厂模式进行创建类的实例。加快设计进度,提高设计质量。
最后一题不会,瞎写的。