Java 2015-2016 期末
1. 何谓面向对象的程序设计?与面向过程的程序设计相比有哪些优势?
2. 方法覆盖(Override)和方法重载(Overload)的区别和联系是什么?
3. 接口与抽象类有何相似之处,又有哪些区别?
4. Java的事件处理机制是如何实现的?
- Event(事件):用户对组件的一次操作称为一个事件,以类的形式出现。例如,键盘操作对应的事件类是 KeyEvent。
- Event Source(事件源):事件发生的场所,通常就是各个组件,例如按钮 Button。
- Event Handler(事件处理者):接收事件对象并对其进行处理的对象事件处理器,通常就是某个Java类中负责处理事件的成员方法。
事件处理者也称为监听器,监听器时刻监听事件源上所有发生的事件类型,一旦该事件类型与自己所负责处理的事件类型一致,就马上进行处理。授权模型(事件源可以把在其自身上所有可能发生的事件分别授权给不同的事件处理者来处理)把事件的处理委托给外部的处理实体进行处理,实现了将事件源和监听器分开的机制。
5. 何谓缓冲流?它的工作机理和用途是什么?
不带缓冲流的工作原理:
读取一个字节/字符,就会向用户指定的路径写出去,读一个写一个,频繁的读写增加了读写次数,降低了效率
带缓冲流的工作原理:
读取到一个字节/字符,先不输出,等凑足了缓冲的最大容量后一次性写出去,减少了读写次数,提高了效率
6. 与传统的容错纠错机制相比较,异常处理有哪些优势?
1.当发生错误时,程序不至于崩溃。
2.当发生错误时,可以在短时间内找到错误所在行,节省时间。
7. final, finally, finalize各自有何含义,作用分别是什么?
final:
1. final修饰成员变量,意为不可改变。
2. final声明的类不能派生子类,即不能作为父类使用。
3. final修饰的方法,不可以在子类中重写。
注:final修饰的变量是对象时,对象的值可以改变。(因为final修饰的变量指的是引用不可变,对象值是可变的。)
finally:
必须定义在异常捕获机制的最后,它可以保证内部的代码一定执行,无论try块中的代码是否出现异常。
通常会将诸如释放资源等操作放在finally中。(注:finally中不要写return否则一定返回这里的内容。)
finalize:
finalize是Object中定义的方法,所有的类都有该方法,该方法是JVM调用,当一个对象即将被GC释放时调用该方法,方法调用完毕意味着该对象的资源被释放,finalize 方法在垃圾回收器清除对象之前调用。
8.阅读给出的程序段,指出其中的错误并改正之。
class CA {
public CA() { }
}
class CB extends CA {
public CB(String Info) {
System.out.println(“CB Info: ” + Info);
super();
}
}
interface IA {
int num = 1;
void method();
}
interface IB {
int num = 3;
void method();
}
class CC extends CA, CB implements IA, IB {
public static void main(String[] args) {
System.out.println(“num = ” + num);
method();
}
public void method() {
System.out.println(“method() called”);
}
}
public CB(String Info) {
System.out.println(“CB Info: ” + Info);
super();
}
//应该是
public CB(String Info) {
super();
System.out.println(“CB Info: ” + Info);
}
class CC extends CA, CB implements IA, IB
//不支持多继承
//如果选择继承CB的话还要声明含参构造函数
System.out.println("num = " + num);
//两个接口有同名常量,需要显式指定接口名
System.out.println("num = " + IA.num);
method();
//非静态方法,要用对象调用
new CC().method();
注意,如果实现多个接口中有重名方法且它们仅仅是返回类型不同(其他情况下这两个方法被识别为不同,可以分别重写),那么就不能同时实现两个接口方法(返回类型相同显然实现前面那个就行,类只需要一个这样的方法),可以通过两个内部类分别实现来解决
package Java_15;
public class C{
public static void main(String[] args) {
new C().d.method();
new C().e.method();
}
private D d = new D();
private E e = new E();
class D implements A
{
@Override
public void method() {
System.out.println("AAA");
}
}
class E implements B
{
@Override
public int method()
{
System.out.println("BBB");
return 0;
}
}
}
9(易错). 阅读给出的程序段,写出其运行结果。
public class TestMainClass {
public static void main(String[] args) {
A[] oArray = new B[6];
int sum1=0, sum2=0;
for (int i=0; i<oArray.length; i++) {
oArray[i] = new B(i);
sum1 += oArray[i]._value;
sum2 += ((B)oArray[i])._value;
}
System.out.println("Sum1 = " + sum1);
System.out.println("Sum2 = " + sum2);
A aa = new A();
A ab = new B(10);
aa.go();
ab.go();
}
}
class A {
public int _value = 1;
public A() {
_value = 2;
}
public void go() {
System.out.println("A-go");
System.out.println("value = " + _value);
}
}
class B extends A {
public int _value = 3;
public B(int value) {
_value = value;
}
public void go() {
System.out.println("B-go");
System.out.println("value = " + _value);
}
}
Sum1 = 15 Sum1 = 12
Sum2 = 18 Sum2 = 15
A-go
value = 2
B-go
value = 10
易错点!!!
对于new B(0);
这个对象的value是通过B的有参构造器赋值,故value为0
但当将其存入A类引用的数组时,由于父类引用指向子类对象只能访问父类数据成员、子类重写方法与父类其它方法(下面会解释为什么),所以oArray[i]
访问的永远都是2**(因为B类构造方法调用前会默认调用父类缺省构造方法)。或许可以理解为oArray[]
中放的都是A类引用指向B类对象(getClass获得的一定是B),因此oArray[i] = new B(i);
这句话干的事情是:第i个A类引用现在指向这个新的B,那么显然当我们试图使用oArray[i]
去访问这个对象时只能访问A的数据成员和B中的重写方法及A的其它方法**,而刚才的赋值是隐式调用父类构造方法给value赋了2,放到子类对象的super空间的value域(见下图);子类构造方法赋了B类对象的value属性,放在子类内容的value域。
而对于sum2 += ((B)oArray[i])._value;
亲测这个强转并不会调用构造方法,那么它干的事情就是把oArray[i]
从一个装A类引用的数组转成一个装B类引用的数组,指向的还是B类对象,那么此时对象的数据成员就可以访问了(值在第一步已经赋进去了,只是A类引用访问不到而已),所以是0加到5。
关于为什么父类引用访问不到子类数据成员,我的理解是多态中数据成员和方法的绑定方式是不同的,对于方法而言
如果创建的是一个B类对象,那么里面就会有父类的同名方法,通过虚拟方法表在被访问时映射过来。**但是对于数据成员而言,其实使用的是静态绑定。**例如Father father = new Son();
在编译期间 father就是个Father对象,系统不知道实际上它是一个 Son对象,这得在运行期间由JVM判断(父类的静态方法和数据成员遵循相同的规则),因此自然是编译期它是什么类型就访问什么类型的数据成员。
10.阅读下面的程序,指出该程序实现了哪些功能。
import java.io.*
import java.net.*
public class TestCode2 {
public static void main(String[] args) throws MalformedURLException {
URL url = new URL(“http://cs.whu.edu.cn”);
File file = new File(“C://page.html”);
try {
URLConnection connection = url.openConnection();
BufferedInputStream iStream = new BufferedInputStream(connection.getInputStream);
BufferedOutputStream oStream = new BufferedOutputStream(new FileOutputStream(file));
byte[] buff = new byte[1024];
int len = 0;
do {
len = iStream.read(buff);
oStream.write(buff, 0, len);
} while(len > 0)
iStream.close();
oStream.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
功能显然是复制html页面存到本地文件,实际上这个题更应该出成改错题,以下为错误:
BufferedInputStream iStream = new BufferedInputStream(connection.getInputStream);
//正确写法是
BufferedInputStream iStream = new BufferedInputStream(connection.getInputStream());
URL url = new URL(“http://cs.whu.edu.cn”);
File file = new File(“C://page.html”);
//用的都是中文引号
iStream.close();
oStream.close();
//先开后关,后开先关
do {
len = iStream.read(buff);
oStream.write(buff, 0, len);
} while(len > 0)
//这么些就会报java.lang.ArrayIndexOutOfBoundsException,len在里面被赋-1怎么可能write
//正确写法是
while ((len = iStream.read(buff)) != -1)
{
oStream.write(buff, 0, len);
}
11.定义用于计算的Sum类和Prod类,它们实现各自的calc()方法(同名方法),在Sum实现的calc()中计算输出1到n的和,Prod实现的calc()中计算输出1~n的乘积。要求用抽象类和接口两种方法分别实现。
package Java_15;
public interface Calculate {
void calc(int n);
}
package Java_15;
public class Sum implements Calculate{
int sum = 0;
@Override
public void calc(int n) {
for (int i = 1; i <= n; i++)
{
sum += i;
}
System.out.println(sum);
}
public static void main(String[] args) {
new Sum().calc(15);
new Prod().calc(15);
}
}
package Java_15;
public class Prod implements Calculate{
int prod = 1;
@Override
public void calc(int n) {
for (int i = 1; i <= n; i++)
{
prod *= i;
}
System.out.println(prod);
}
}
12.编写程序,将一个文本文件中的内容以行为单位,按行调整为倒序排列(即第一行为最后一行)。
package Java_15;
import java.io.*;
public class SwitchLine {
public static void main(String[] args) throws IOException {
File file = new File("D:/org.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file,true)));
String[] s = new String[100];
String temp;
int count = 0;
while((temp = reader.readLine()) != null)
{
s[count] = temp;
count++;
}
for(count--; count >= 0; count--)
{
writer.write(s[count]);
writer.newLine();
}
writer.close();
reader.close();
}
}