欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java SE综合练习题错误总结

程序员文章站 2024-03-08 09:49:04
...

Java SE练习题错误总结

一、String类的引用

  1. 指出下列程序运行的结果 (B)
    
    public class Example {
         String str = new String("good");
     char[] ch = { 'a', 'b', 'c' };
     public static void main(String args[]) {
             Example ex = new Example();
             ex.change(ex.str, ex.ch);
             System.out.print(ex.str + " and ");
             System.out.print(ex.ch);
         }
     public void change(String str, char ch[]) {
             str = "test ok";
             ch[0] = 'g';
         }
     }
    
    
    A、 good and abc
    B、 good and gbc
    C、 test ok and abc
    D、 test ok and gbc  
    

    ​ 大家可能以为Java中String和数组都是对象所以肯定是对象引用,然后就会选D,其实这是个很大的误区:因为在java里没有引用传递,只有值传递

    ​ 这个值指的是实参的地址的拷贝,得到这个拷贝地址后,你可以通过它修改这个地址的内容(引用不变),因为此时这个内容的地址和原地址是同一地址,但是你不能改变这个地址本身使其重新引用其它的对象,也就是值传递。内存图分析如下:

Java SE综合练习题错误总结

​ 可以看到。change方法中的String str只是一个根据类中的str创造的一个副本,他的地址值和类中的str的地址值并不一样,但是在执行chage方法之前,他的指向和成员变量中的str是相同的,都是指向good。

Java SE综合练习题错误总结

​ 但是在执行change方法之后,修改只是chage方法中的这个str副本变量,改变了他的指向,而并没有改变成员变量str的指向。但是对于ch[0],表示的是字符数组中’a’的地址,修改了它也就修改了字符数组的第一个元素,这个改变在change函数返回之后也会存在。

说明:不管是对象、基本类型还是对象数组、基本类型数组,在函数中都不能改变其实际地址但能改变其中的内容。

  1. public class J_Test {
        
    public static void mb_method(StringBuffer x, StringBuffer y) {
    x.append(y);
    y = x;
    	}
        
    public static void main(String[] args) {
    StringBuffer a = new StringBuffer("A");
    StringBuffer b = new StringBuffer("B");
    mb_method(a, b);
    System.out.println(a + "," + b);
    	}
    }
    
    请问输出结果:
    AB,B
    

    根据内存图分析:

    1. 当进入mb_method方法前:

Java SE综合练习题错误总结

  1. 当进入mb_method方法且未执行x.append(y)时:

Java SE综合练习题错误总结

  1. 执行x.append(y)方法之后:

Java SE综合练习题错误总结
4. 执行完y = x:

Java SE综合练习题错误总结

  1. 方法mb_method执行完毕,局部变量消除,此时内存状况为:

Java SE综合练习题错误总结
结合图和上一题的理解,a,b是对象的引用,指向堆内存。将a,b两个引用传给x,y,执行x.append(y)方法之后改变了x 引用指向的堆内存的存储内容,变为了AB。y=x,表示引用y指向了引用x指向的存储区域,没有改变引用b指向的存储空间的内容。所以输出为:AB,B

二、抽象类相关问题

23. 选项中哪一行代码可以替换题目中//add code here而不产生编译错误?(A)

public abstract class MyClass {
public int constInt = 5;
//add code here
     public void method() {
     }
}

A public abstract void method(int a);
B constInt = constInt + 5;
//变量可以初始化或不初始化但不能初始化后在抽象类中重新赋值或操作该变量(只能在子类中改变该变量)。 
C public int method();
//已经存在method方法,重载必须要改变参数而不是返回值
D public abstract void anotherMethod() {}
//抽象方法不能实现

抽象类遵循的原则:

(1)abstract关键字只能修饰类和方法,不能修饰字段。

(2)抽象类不能被实例化(无法使用new关键字创建对象实例),只能被继承。

(3)抽象类可以包含属性,方法,构造方法,初始化块,内部类,枚举类,和普通类一样,普通方法一定要实现,变量可以初始化或不初始化但不能初始化后在抽象类中重新赋值或操作该变量(只能在子类中改变该变量)。

(4)抽象类中的抽象方法(加了abstract关键字的方法)不能实现。

(5)含有抽象方法的类必须定义成抽象类。

三、序列化相关问题

24. 阅读Shape和Circle两个类的定义。在序列化一个Circle的对象circle到文件时,下面哪个字段会被保存到文件中? ( B )

class Shape {
   public String name;
}
class Circle extends Shape implements Serializable{
   private float radius;
   transient int color;
   public static String type = "Circle";
}

A.name
B. radius
C. color
D. type

​ 序列化需要注意以下几点:

  1. 如果子类实现Serializable接口而父类未实现时,父类不会被序列化;
  2. 如果父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
  3. 静态变量不管有没有被transient修饰,都无法进行序列化。

四、父子类构造方法调用次序

25.下面是People和Child类的定义和构造方法,每个构造方法都输出编号。在执行new Child("mike")的时候都有哪些构造方法被顺序调用?请选择输出结果 (D)

class People {
    String name;
public People() {
        System.out.print(1);
    }
public People(String name) {
        System.out.print(2);
this.name = name;
    }
}class Child extends People {
    People father;
public Child(String name) {
        System.out.print(3);
this.name = name;
        father = new People(name + ":F");
    }
public Child() {
        System.out.print(4);
    }

}

 A 312        
 B 32              
 C 432             
 D 132

子类没有显示调用父类构造函数,不管子类构造函数是否带参数都默认调用父类无参的构造函数,若父类没有则编译出错。

五、基本数据类型相关问题

  1. switch 语句能否作用在byte 上?能否作用在 long 上?能否作用在 String 上?

    ​ 答:在 switch( expr1)中, expr1 只能是一个整数表达式或者枚举常量,整数表达式可以是 int基本类型或 Integer 包装类型,由于byte,short,char 都可以隐含转换为 int,所以,这些类型以及这些类型的包装类型也是可以的。显然, long 和 String 类型都不符合 switch 的语法规定,并且不能被隐式转换成 int类型,所以,它们不能作用于 swtich 语句中。

  2. char 型变量中能不能存贮一个中文汉字?为什么?
    答:char 型变量是用来存储Unicode 编码的字符的, unicode 编码字符集中包含了汉字,所以, char 型变量中当然可以存储汉字。

    ​ 不过,如果某个特殊的汉字没有被包含在 unicode 编码字符集中,那么,这个 char型变量中就不能存储这个特殊汉字。补充说明: unicode 编码占用两个字节,char 类型的变量也是占用两个字节。

  3. 静态变量和实例变量的区别?

    ​ 答:1.在语法定义上的区别:静态变量前要加 static 关键字,而实例变量前则不加。
    ​ 2.在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,
    要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间
    ,静态变量就可以被使用了。
    ​ 总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

  4. 构造器 Constructor 是否可被 override?
    必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,
    要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间
    ,静态变量就可以被使用了。
    ​ 总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

  5. 构造器 Constructor 是否可被 override?
    答:构造器Constructor 不能被继承,因此不能重写 Override,但可以被重载 Overload。