1.
1 2 3 4 5 6 7 8 9 10 |
|
此代码片段输出正确的值是()
-
A String is: g String is: g
-
B String is: 103 String is: g
-
C String is: g String is: 103
-
D String is: 103 String is: 103
正确答案:A
考点:String 中toString()、valueOf()方法的返回值类型
题解:
public static String toString(char c) { return String.valueOf(c); }
public static String valueOf(char c) { char data[] = {c}; return new String(data, true); }
返回的都是字符串,只有char变成 int 的时候才会变为对应的assic码
2. 下列程序执行后输出结果为( )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
-
A static BaseClass I’m BaseClass class static Base I’m Base class
-
B I’m BaseClass class I’m Base class static BaseClass static Base
-
C I’m BaseClass class static BaseClass I’m Base class static Base
-
D static BaseClass static Base I’m BaseClass class I’m Base class
正确答案:D
考点:静态代码块、代码块、构造函数在父类子类中的运行顺序~
题解:
执行顺序从左到右:
父类静态代码块 ->子类静态代码块 ->父类非静态代码块 -> 父类构造函数 -> 子类非静态代码块 -> 子类构造函数。
案例代码如下:
public class Father { static {
System.out.println("父类静态代码块"); }
{
System.out.println("父类非静态代码块"); } public Father(){
System.out.println("父类构造函数"); } }
public class Son extends Father{ static {
System.out.println("子类静态代码块"); }
{
System.out.println("子类非静态代码块"); } public Son(){
System.out.println("子类构造函数"); } public static void main(String[] args) {
Son son = new Son(); }
}
/*
结果为: 父类静态代码块
子类静态代码块
父类非静态代码块
父类构造函数
子类非静态代码块
子类构造函数
*/
3. 以下程序执行的结果是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
-
A ZYXX
-
B ZYXY
-
C YXYZ
-
D XYZX
正确答案:C
考点:初始化过程
题解:
初始化过程:
1 初始化父类的静态成员变量和静态代码块
2 初始化子类中的静态成员变量和静态代码块
3 初始化父类的普通成员变量和非静态代码块,再执行父类的构造方法
4 初始化子类的普通成员变量和代码块,再执行子类的构造方法
本题顺序:
(1) 初始化父类的普通成员变量和代码块,执行 Y y = new Y(); 输出Y
(2) 再执行父类的构造方法 输出X
(3) 初始化子类的普通成员变量和代码块,执行Y = new Y(); 输出Y
(4) 再执行子类的构造方法 输出Z
所以最后输出YXYZ
4. 有以下代码片段:
1 2 3 4 5 |
|
请问输出的结果是:
-
A true
-
B 都不对
-
C null
-
D false
正确答案:D
考点:字符串,常量池
题解:
1)String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。
2)String类底层是char数组来保存字符串的。
对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象
字符串常量池
在class文件中有一部分来存储编译期间生成的字面常量以及符号引用,这部分叫做class文件常量池,在运行期间对应着方法区的运行时常量池。
JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池
工作原理
当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。
实现前提
字符串常量池实现的前提条件就是Java中String对象是不可变的,这样可以安全保证多个变量共享同一个对象。如果Java中的String对象可变的话,一个引用操作改变了对象的值,那么其他的变量也会受到影响,显然这样是不合理的。
String str1 = "hello";
这里的str1指的是方法区中的字符串常量池中的“hello”,编译时期就知道的;
String str2 = "he" + new String("llo");
这里的str2必须在运行时才知道str2是什么,所以它是指向的是堆里定义的字符串“hello”,所以这两个引用是不一样的。
如果用str1.equal(str2),那么返回的是true;因为String类重写了equals()方法。
编译器没那么智能,它不知道"he" + new String("llo")的内容是什么,所以才不敢贸然把"hello"这个对象的引用赋给str2.
如果语句改为:"he"+"llo"这样就是true了。
new String("zz")实际上创建了2个String对象,就是使用“zz”通过双引号创建的(在字符串常量池),另一个是通过new创建的(在堆里)。只不过他们的创建的时期不同,一个是编译期,一个是运行期。
String s = "a"+"b"+"c";
语句中,“a”,"b", "c"都是常量,编译时就直接存储他们的字面值,而不是他们的引用,在编译时就直接将它们连接的结果提取出来变成"abc"了。
5. 下面有关 java 类加载器,说法正确的是?()
-
A 引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用C++来实现的
-
B 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。
-
C 系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类
-
D tomcat 为每个 App 创建一个 Loader,里面保存着此 WebApp 的 ClassLoader。需要加载 WebApp 下的类时,就取出 ClassLoader 来使用
正确答案:B C D
考点:java的类加载器
题解:
类的加载是由类加载器完成的,类加载器包括:根加载器(BootStrap)、扩展加载器(Extension)、系统加载器(System)和用户自定义类加载器(java.lang.ClassLoader 的子类)。从Java2(JDK1.2)开始,类加载过程采取了父亲委托机制(PDM)。PDM更好的保证了Java平台的安全性,在该机制中,JVM自带的BootStrap 是根加载器,其他的加载器都有且仅有一个父类加载器。类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载。JVM不会像Java程序提供对Bootstrap的引用。下面是关于几个类加载器的说明:
Bootstrap:一般用本地代码实现,负责加载JVM基础核心类库(rt.jar);
Extension:从java.ext.dirs 系统属性所指定的目录中加载类库,它的父加载器时Bootstap;
system class loader:又叫应用类加载器,其父类是Extension。它是应用最广泛的类加载器。它从环境变量classpath 或者系统属性 java.class.path 所指定的目录中加载类,是用户自定义加载器的默认父加载器。
用户自定义类加载器:java.lang.ClassLoader 的子类
父类委托机制是可以修改的,有些服务器就是自定义类加载器优先的。