牛客刷题笔记--(java基础201-300)

201 哪个类可用于处理 Unicode? (A)

InputStreamReader

BufferedReader

Writer

PipedInputStream

InputStreamReader可以指定字符编码格式
A、 InputStreanReader的构造函数:
InputStreamReader(InputStream in)
创建一个使用默认字符集的 InputStreamReader。
InputStreamReader(InputStream in, Charset cs)
创建使用给定字符集的 InputStreamReader。
InputStreamReader(InputStream in, CharsetDecoder dec)
创建使用给定字符集解码器的 InputStreamReader。
InputStreamReader(InputStream in, String charsetName)
创建使用指定字符集的 InputStreamReader。

B、BufferedReader的构造函数:
BufferedReader(Reader in)
创建一个使用默认大小输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int sz)
创建一个使用指定大小输入缓冲区的缓冲字符输入流。

C、Writer的构造函数:
protected Writer()
创建一个新的字符流 writer,其关键部分将同步 writer 自身。
protected Writer(Object lock)
创建一个新的字符流 writer,其关键部分将同步给定的对象。

D、PipedInputStream的构造函数:
PipedInputStream()
创建尚未连接的PipedInputStream。
PipedInputStream(int pipeSize)
创建一个尚未连接的PipedInputStream,并对管道缓冲区使用指定的管道大小。
PipedInputStream(PipedOutputStream src)
创建PipedInputStream,使其连接到管道输出流src。
PipedInputStream(PipedOutputStream src, int pipeSize)
创建一个PipedInputStream,使其连接到管道输出流src,并对管道缓冲区使用指定的管道大小。

202 What is the result of compiling and executing the following fragment of code: (C)

Boolean flag = false;
if (flag = true)
{
    System.out.println(true);
}
else
{
    System.out.println(false);
}
The code fails to compile at the “if” statement.

An exception is thrown at run-time at the “if” statement.

The text“true” is displayed.

The text“false”is displayed.

Nothing is displayed.

我觉得在
if(flag=true){
}
中,只是一个赋值语句=======》隐含条件为
if((flag=true)==true){
}
203 在jdk1.5之后,下列 java 程序输出结果为______。 B

int i=0;
Integer j = new Integer(0);
System.out.println(i==j);
System.out.println(j.equals(i));

true,false

true,true

false,true

false,false

对于不同的环境结果不同

程序无法执行

解释
i==j ,这个是基本类型与 Integer 的比较, j 会自动拆箱成 int 类型,然后比较的是值。因此返回真。

j.equals(i) ,调用 equals 方法后,这个 i 会自动装箱成 Integer 类型,然后再比较值,所以也返回真。


==如果是primitive主类型,那么比较值;如果是对象,那么比较引用地址
equals需要根据具体对象的实现来判断,在Integer里面是判断值是否相等

一般说来,如果是两个Integer类型进行==比较,就是比较两个Integer对象的地址。但是有一点需要注意的是在
-128127这个区间,如果创建Integer对象的时候(1)Integer i = 1;2) Integer i = Integer.valueOf(1); 如果是这两种情况创建出来的对象,那么其实只会创建一个对象,这些对象已经缓存在一个
叫做IntegerCache里面了,所以==比较是相等的。
如果不在-128127这个区间,不管是通过什么方式创建出来的对象,==永远是false,也就是说他们的地址永远不
会相等。

204 检查程序,是否存在问题,如果存在指出问题所在,如果不存在,说明输出结果。(A)

package algorithms.com.guan.javajicu;  
public class Inc {  
    public static void main(String[] args) {  
       Inc inc = new Inc();  
       int i = 0;  
       inc.fermin(i);  
       i= i ++;  
       System.out.println(i); 
   
    }  
    void fermin(int i){  
       i++;  
    }  
}  
0

1

2

3

如果你理解JVM的内存模型,就不难理解为什么答案返回的是0,而不是1。

int i = 0; i = i++;
Java虚拟机栈(JVM Stack)描述的是Java方法执行的内存模型,而JVM内存模型是基于“栈帧”的,每个栈帧中都有 局部变量表 和 操作数栈 (还有动态链接、return address等),那么JVM是如何执行这个语句的呢?通过javap大致可以将上面的两行代码翻译成如下的JVM指令执行代码。
0: iconst_0
1: istore_1
2: iload_1
3: iinc 1, 1
6: istore_1
7: iload_1
接下来分析一下JVM是如何执行的:
第0:将int类型的0入栈,就是放到操作数栈的栈顶
第1:将操作数栈栈顶的值0弹出,保存到局部变量表 index (索引)值为1的位置。(局部变量表也是从0开始的,0位置一般保存当前实例的this引用,当然静态方法例外,因为静态方法是类方法而不是实例方法)
第2:将局部变量表index 1位置的值的副本入栈。(这时局部变量表index为1的值是0,操作数栈顶的值也是0)
第3:iinc是对int类型的值进行自增操作,后面第一个数值1表示,局部变量表的index值,说明要对此值执行iinc操作,第二个数值1表示要增加的数值。(这时局部变量表index为1的值因为执行了自增操作变为1了,但是操作数栈中栈顶的值仍然是0)
第6:将操作数栈顶的值弹出(值0),放到局部变量表index为1的位置(旧值:1,新值:0),覆盖了上一步局部变量表的计算结果。
第7:将局部变量表index 1位置的值的副本入栈。(这时局部变量表index为1的值是0,操作数栈顶的值也是0)

总结:从执行顺序可以看到,这里第1和第6执行了2次将0赋值给变量i的操作(=号赋值),i++操作是在这两次操作之间执行的,自增操作是对局部变量表中的值进行自增,而栈顶的值没有发生变化,这里需要注意的是保存这个初始值的地方是操作数栈而不是局部变量表,最后再将栈顶的值覆盖到局部变量表i所在的索引位置中去。

有兴趣的同学可以去了解一下JVM的栈帧(Stack Frame)

关于第二个陷阱(为什么 fermin方法没有影响到i的值 )的解答看下面。
inc.fermin(i);

  1. java方法之间的参数传递是 值传递 而不是 引用传递
  2. 每个方法都会有一个栈帧,栈帧是方法运行时的数据结构。这就是说每个方法都有自己独享的局部变量表。(更严谨的说法其实是每个线程在执行每个方法时都有自己的栈帧,或者叫当前栈帧 current stack frame)
  3. 被调用方法fermin()的形式参数int i 实际上是调用方法main()的实际参数 i 的一个副本。
  4. 方法之间的参数传递是通过局部变量表实现的,main()方法调用fermin()方法时,传递了2个参数:
    第0个隐式参数是当前实例(Inc inc = new Inc(); 就是inc引用的副本,引用/reference 是指向对象的一个地址,32位系统这个地址占用4个字节,也就是用一个Slot来保存对象reference,这里传递的实际上是reference的一个副本而不是 reference本身 );
    第1个显示参数是 i 的一个副本。所以 fermin()方法对 i 执行的操作只限定在其方法独享或可见的局部变量表这个范围内,main()方法中局部变量表中的i不受它的影响;

如果main()方法和fermin()方法共享局部变量表的话,那答案的结果就会有所不同。 其实你自己思考一下,就会发现, JVM虚拟机团队这么设计是有道理的。

Java使用了中间缓存变量机制:
i=i++;等同于:
temp=i; (等号右边的i)
i=i+1; (等号右边的i)
i=temp; (等号左边的i)
而i=++i;则等同于:
i=i+1;
temp=i;
i=temp;


首先运行这个程序,在c/c++和java会发现不一样,在c/c++中答案是1,在java中答案是0。为什么呢?
原因:jvm里面有两个存储区,一个是暂存区(是一个堆栈,以下称为堆栈),另一个是变量区。jvm会这样运行这条语句, JVM把count值(其值是0)拷贝到临时变量区。 步骤2 count值加1,这时候count的值是1。 步骤3 返回临时变量区的值,注意这个值是0,没修改过。 步骤4 返回值赋值给count,此时count值被重置成0。 c/c++中没有另外设置一个临时变量或是临时空间来保存i,所有操作都是在一个内存空间中完成的,所以在c/c++中是1。

205 实现或继承了Collection接口的是(BCE)

Map

List

Vector

Iterator

Set

在这里插入图片描述 在java.util包中提供了一些集合类,常用的有List、Set和Map类,其中List类和Set类继承了Collection接口。这些集合类又称为容器,长度是可变的,数组用来存放基本数据类型的数据,集合用来存放类对象的引用。
List接口、Set接口、Map接口以及Collection接口的主要特征如下:

Collection接口是List接口和Set接口的父接口,通常情况下不被直接使用。
List接口继承了Collection接口,List接口允许存放重复的对象,排序方式为按照对象的插入顺序。 
Set接口继承了Collection接口,Set接口不允许存放重复的对象,排序方式为按照自身内部的排序规则。 
Map接口以键值对(key—value)的形式存放对象,其中键(key)对象不可以重复,值(value)对象可以重复,排
序方式为按照自身内部的规则。 

C:Vector实现了List接口,即间接实现Collection接口
D:Iterator是Java迭代器最简单的实现,没有实现Collection接口

206 关于静态方法的描述(ABC)

A:静态方法是一个属于类而不属于对象(实例)的方法。(√)
B:静态方法只能访问静态数据。无法访问非静态数据(实例变量)。(√)
C:静态方法只能调用其他静态方法,不能从中调用非静态方法。(√)
D:静态方法不能通过类名直接访问,也不需要任何对象。(×) 静态方法可以直接用类名访问。

207 建立Statement对象的作用是?(C)

连接数据库

声明数据库

执行SQL语句

保存查询结果

1、Statement对象用于执行不带参数的简单SQL语句。
2、Prepared Statement 对象用于执行预编译SQL语句。
3、Callable Statement对象用于执行对存储过程的调用。

208关于下面一段代码,以下说法正确的是: (ACD)

public class Test {
    private synchronized void a() {
    }
    private void b() {
        synchronized (this) {
        }
    }
    private synchronized static void c() {
    }
    private void d() {
        synchronized (Test.class) {
        }
    }
}
同一个对象,分别调用方法a和b,锁住的是同一个对象

同一个对象,分别调用方法a和c,锁住的是同一个对象

同一个对象,分别调用方法b和c,锁住的不是同一个对象

同一个对象,分别调用方法a、b、c,锁住的不是同一个对象

修饰非静态方法 锁的是this 对象

修饰静态方法 锁的是class对象

同步代码块(synchronized(this),synchronized(类实例对象),锁是小括号()中的实例对象)
同步非静态方法(synchronized method),锁的是当前对象的实例对象 

获取类锁

同步代码块(synchronized(类.class)),锁是最小括号 () 中的类对象(Class对象)
同步静态方法(synchronized static method),锁是当前对象的类对象(Class 对象) 

总结

有线程访问对象的同步代码块时,另外的线程可以访问该对象的非同步代码块
若锁住的是同一个对象,一个线程在访问对象的同步代码块时,另一个访问对象的同步代码块的线程会被阻塞。
若锁住的是同一个对象,一个线程在访问对象的同步方法时,另一个访问对象的同步方法的线程会被阻塞。
若锁住的是同一个对象,一个线程在访问对象的同步代码块时,另一个访问对象同步方法的线程会被阻塞,反之亦然。
同一个类的不同对象的锁互不干扰
类锁由于也是一种特殊的对象锁,因此表现和上述一致,而由于一个类只有一把对象锁,所以同一个类的不同对象使用类锁将会是同步的
类锁和对象锁互不干扰 

209 假设 A 类有如下定义,设 a 是 A 类同一个包下的一个实例,下列语句调用哪个是错误的?(C)

 class A{

int  i;

static  String  s;

void  method1() {   }

static  void  method2()  {   }

} 
System.out.println(a.i);

a.method1();

A.method1();

A.method2()

非静态方法只能通过实例对象来调用,不能直接通过类名调用。静态方法(static)才能通过类名直接调用.

类中变量:除了private权限外,其他权限的变量(没有表示默认default),均可以用“对象.变量名”来调用。对于private变量,即使使用static,也不能用“类.变量名”来调用私有变量。只能通过类中的public get()方法来调用。
类中方法:除了private权限外,其他权限的方法(没有表示默认default),均可以用“对象.方法名”来调用。private方法可以用java反射机制调用。当然如果用 private修饰方法,该方法只在类的内部调用。其中比较著名的就是单例模式中的私有构造方法。
static属性:static方法在编译期就已经生成了,其他方法在运行期生成。非私有的static方法可以用“类.方法名”调用。但是私有的static变量和方法都是不可能被调用的,虽然private static这种写法很少见,但仍然存在,且编译器不会报错。题中static void method2() { }的权限是默认权限,所以可以用“类.方法名”来调用。如果题目中写成private static void method2(){ } ,那么D选项也是错误的。

210 执行下列程序的输出结果为( D )

public class Test {
 public static void main(String[] args) {
 String s1 = "HelloWorld";
 String s2 = new String("HelloWorld");
 if (s1 == s2) {
 System.out.println("s1 == s2");
 } else {
 System.out.println("s1 != s2");
 }
 if (s1.equals(s2)) {
 System.out.println("s1 equals s2");
 } else {
 System.out.println("s1 not equals s2");
 }
 }
 }
s1 == s2
s1 not equals s2

s1 == s2
s1 equals s2

s1 != s2
s1 not equals s2

s1 != s2
s1 equals s2
 1.==equals():
(1)==” 用于比较基本数据类型时比较的是值,用于比较引用类型时比较的是引用指向的地址。
(2)Object 中的equals() 与 “==” 的作用相同,但String类重写了equals()方法,比较的是对象中的内容。 

s1直接指向常量池中的字符串变量(没有就在常量池创建一个) s2是指向堆里的一个字符串对象,对象里面有常量池中字符串对象的引用

 ==
如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;
如果作用于引用类型的变量,则比较的是所指向的对象的地址

对于复合数据类型(类),使用equals()和“==”效果是一样的,两者比较的都是对象在内存中的存放地址(确切的说,是堆内存地址)。

equals
注意:equals方法不能作用于基本数据类型的变量
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。 

211 下列关于计算机系统和Java编程语言的说法,正确的是(C)

计算机是由硬件、操作系统和软件组成,操作系统是缺一不可的组成部分。

Java语言编写的程序源代码可以不需要编译直接在硬件上运行。

在程序中书写注释不会影响程序的执行,可以在必要的地方多写一些注释。

Java的集成开发环境(IDE),如Eclipse,是开发Java语言必需的软件工具。

裸机也可以跑,以前搞嵌入式的时候,并不一定要安装操作系统,直接操作寄存器就可以了,操作系统不是必须的
计算机是由硬件和软件组成,操作系统是软件部分。

软件分为系统软件和应用软件

没有IDE,用txt和javac不能写java吗??

212 给出以下代码 ,请给出结果:(B)

public class TestObj{ 
    public static void main(String[] args){
        Object o=new Object(){
            public boolean equals(Object obj){
                return true;
            }
        }; 
        System.out.println(o.equals(“Fred”));
    }
} 
运行时抛出异常

true

Fred

第三行编译错误

本题涉及匿名内部类、多态和覆盖三个知识点。 语句

Object o=new Object(){
            public boolean equals(Object obj){
                return true;
            }
        };

创建了一个匿名内部类,并将所创建的匿名对象赋给 Object (多态:子类对象赋给超类引用)。同时,该匿名内部类重写了 Object 类的 equals 方法。

在执行语句

o.equals(“Fred”)

时,根据多态及覆盖原则,会调用匿名内部类重写后的 equals 方法。
关于 “Java 内部类 ” 和 “Java 继承、多态与类的复用” 的更详细的阐述,请查看我的两篇博文 “http://blog.csdn.net/justloveyou_/article/details/53245561” 和 “http://blog.csdn.net/justloveyou_/article/details/52798666”。

213以下代码输出的是: (A)

public class SendValue{
	public String str="6";
	public static void main(String[] args) {
		SendValue sv=new SendValue();
		sv.change(sv.str);
		System.out.println(sv.str);
	}
	public void change(String str) {
		str="10";
	}
}
6

10

都不对

16

补充Java内存管理知识:

  1. 内存分配策略

按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的。

静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间。这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求。

栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的。和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,但是规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存。和我们在数据结构所熟知的栈一样,栈式存储分配按照先进后出的原则进行分配。

静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例。堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放。

  1. JVM中的堆和栈

JVM是基于堆栈的虚拟机。JVM为每个新创建的线程都分配一个堆栈,也就是说,对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。

java把内存分两种:一种是栈内存,另一种是堆内存

栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。

栈(stack):是一个先进后出的数据结构,通常用于保存方法(函数)中的参数,局部变量。

堆(heap):是一个可动态申请的内存空间(其记录空闲内存空间的链表由操作系统维护),是一个运行时数据区,C中的malloc语句所产生的内存空间就在堆中。

  1. 堆和栈优缺点比较

栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。

堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。

  1. Java中的数据类型有两种

一种是基本类型

共有8种,即int, short, long, byte, float, double, boolean, char(注意,并没有string的基本类型)。

这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的,称为自动变量。值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。

另外,栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

int a = 3;
int b = 3;
编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。

特别注意的是,这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对象引用变量也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例,我们定义完a与b的值后,再令a=4;那么,b不会等于4,还是等于3。在编译器内部,遇到a=4;时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存放4的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。

另一种是包装类数据

如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中,Java用new()语句来显示地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。

String是一个特殊的包装类数据。即可以用String str = new String(“abc”);的形式来创建,也可以用String str = “abc”;的形式来创建(作为对比,在JDK 5.0之前,你从未见过Integer i = 3;的表达式,因为类与字面值是不能通用的,除了String。而在JDK 5.0中,这种表达式是可以的!因为编译器在后台进行Integer i = new Integer(3)的转换)。前者是规范的类的创建过程,即在Java中,一切都是对象,而对象是类的实例,全部通过new()的形式来创建。Java中的有些类,如DateFormat类,可以通过该类的getInstance()方法来返回一个新创建的类,似乎违反了此原则。其实不然。该类运用了单例模式来返回类的实例,只不过这个实例是在该类内部通过new()来创建的,而getInstance()向外部隐藏了此细节。那为什么在String str = “abc”;中,并没有通过new()来创建实例,是不是违反了上述原则?其实没有。

5.String在内存中的存放

String是一个特殊的包装类数据,可以用用以下两种方式创建:

String str = new String(“abc”);第一种创建方式是用new()来新建对象的,它会存放于堆中。每调用一次就会创建一个新的对象。

String str = “abc”; 第二种创建方式先在栈中创建一个对String类的对象引用变量str,然后在栈中查找有没有存放值为”abc”的地址,如果没有,则开辟一个存放字面值为”abc”的地址,接着创建一个新的String类的对象o,并将o的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为”abc”的地址,则查找对象o,并返回o的地址,最后将str指向对象o的地址。

值得注意的是,一般String类中字符串值都是直接存值的。但像String str = “abc”;这种场合下,其字符串值却是保存了一个指向存在栈中数据的引用!

6.数组在内存中的存放

int x[] 或者int []x 时,在内存栈空间中创建一个数组引用,通过该数组名来引用数组。

x = new int[5] 将在堆内存中分配5个保存int型数据的空间,堆内存的首地址放到栈内存中,每个数组元素被初始化为0。

7.static变量在内存中的存放

用 static的修饰的变量和方法,实际上是指定了这些变量和方法在内存中的“固定位置”-static storage。既然要有“固定位置”那么他们的 “大小”似乎就是固定的了,有了固定位置和固定大小的特征了,在栈中或堆中开辟空间那就是非常的方便了。如果静态的变量或方法在不出其作用域的情况下,其引用句柄是不会发生改变的。

  1. java中变量在内存中的分配

1、类变量(static修饰的变量)

在程序加载时系统就为它在堆中开辟了内存,堆中的内存地址存放于栈以便于高速访问。静态变量的生命周期一直持续到整个”系统”关闭

2、实例变量

当你使用java关键字new的时候,系统在堆中开辟并不一定是连续的空间分配给变量(比如说类实例),然后根据零散的堆内存地址,通过哈希算法换算为一长串数字以表征这个变量在堆中的”物理位置”。 实例变量的生命周期–当实例变量的引用丢失后,将被GC(垃圾回收器)列入可回收“名单”中,但并不是马上就释放堆中内存

3、局部变量

局部变量,由声明在某方法,或某代码段里(比如for循环),执行到它的时候在栈中开辟内存,当局部变量一但脱离作用域,内存立即释放
发表于 2017-10-27 13:45:47

在这里插入图片描述java中的方法传递都是值传递,java中的数据类型有基本类型和引用类型,他们都是值传递方式。基本类型传递的是它的值,因此方法中的改变参数的值,不会影响方法外。引用类型传递的是一个地址,因为引用类型在生成对象实例时,里面的值是一个地址,指向了对象实例。在传值的时候实际上传的是一个地址,他们指向了同一块地址,所以在方法内的改变会影响方法外的参数。 这里比较乱人心的是包装类型,因为包装类型也是引用类型,这里应该就是和包装类型的实现有关了,在包装类型中,比如Integer a=1,有一个自动装箱的操作。其实a=1,如果现在令a=2,不会令2覆盖1(即1本身是不会变的),真正改变的是a被赋给了一个新地址,这个地址指向了2。因此方法内的改变包装类型的值就相当于改变了形参里面的地址,相当于重新new了一遍。而方法外面的实参仍旧指向含1的那个地址,一次方法内的改变不会影响方法外的实参。

214 以下哪项不属于java类加载过程?(B)

生成java.lang.Class对象

int类型对象成员变量赋予默认值

执行static块代码

类方法解析

类的加载包括:加载,验证,准备,解析,初始化。
选项A:生成java.lang.Class对象是在加载时进行的。生成Class对象作为方法区这个类的各种数据的访问入口。
选项B:既然是对象成员,那么肯定在实例化对象后才有。在类加载的时候会赋予初值的是类变量,而非对象成员。
选项C:这个会调用。可以用反射试验。
选项D:类方法解析发生在解析过程。
在这里插入图片描述215 What will be printed when you execute the following code? (B)

class C {
    C() {
        System.out.print("C");
    }
}

class A {
    C c = new C();

    A() {
        this("A");
        System.out.print("A");
    }

    A(String s) {
        System.out.print(s);
    }
}

class Test extends A {
    Test() {
        super("B");
        System.out.print("B");
    }

    public static void main(String[] args) {
        new Test();
    }
}

BB

CBB

BAB

None of the above

首先new了一个子类对象,那么就要调用构造方法来初始化该子类对象,但是该类继承自A,所以要先调用父类的构造方法,这里通过super(“B”)显示的调用了父类的带参构造。执行父类的带参构造前要先对父类中的对象进行初始化,对父类中的c成员进行初始化,调用了C类的无参构造,所以调用顺序为:
先调用C类的无参构造
再调用A类的带参构造
最后调用调用子类的构造

初始化过程是这样的:
1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化;
2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化;
3.其次,初始化父类的普通成员变量和代码块,在执行父类的构造方法;
4.最后,初始化子类的普通成员变量和代码块,在执行子类的构造方法;

(1)初始化父类的普通成员变量和代码块,执行 C c = new C(); 输出C
(2)super(“B”); 表示调用父类的构造方法,不调用父类的无参构造函数,输出B
(3) System.out.print(“B”);
所以输出CBB

注意三种情况:
1)输出CAAB
Test() {
super();
System.out.print(“B”);
}
2)输出CAAB
Test() {
System.out.print(“B”);
}
3)编译报错
Test() {
System.out.print(“B”);
super(); //Constructor call must be the first statement in a constructor
}
总结:java为了保证父类F 可以被构造,子类C的构造函数的第一行代码会插插插!!!!入F的构造函数
216 问这个程序的输出结果。(D)

package Wangyi;
class Base
{
    public void method()
    {
        System.out.println("Base");
    } 
}
class Son extends Base
{
    public void method()
    {
        System.out.println("Son");
    }
    
    public void methodB()
    {
        System.out.println("SonB");
    }
}
public class Test01
{
    public static void main(String[] args)
    {
        Base base = new Son();
        base.method();
        base.methodB();
    }
}
Base SonB

Son SonB

Base Son SonB

编译不通过

这类多态问题中,无论向上或向下转型,都记住一句话就可以了。
编译看左边,运行看右边。意思编译时候,看左边有没有该方法,运行的时候结果看 new 的对象是谁,就调用的谁。

Base base = new Son();
这句new 了一个派生类,赋值给基类,所以下面的操作编译器认为base对象就是Base类型的
Base类中不存在methodB()方法,所以编译不通过

Base base=new Son(); 是多态的表示形式。父类对象调用了子类创建了Son对象。
base调用的method()方法就是调用了子类重写的method()方法。
而此时base还是属于Base对象,base调用methodB()时Base对象里没有这个方法,所以编译不通过。
要想调用的话需要先通过SON son=(SON)base;强制转换,然后用son.methodB()调用就可以了。

217 Java 中的集合类包括 ArrayList 、 LinkedList 、 HashMap 等,下列关于集合类描述正确的是?(ABD)

ArrayList和LinkedList均实现了List接口

ArrayList访问速度比LinkedList快

随机添加和删除元素时,ArrayList的表现更加快速

HashMap实现Map接口,它允许任何类型的键和值对象,并允许将NULL用作键或值

A、HashMap实现了Map接口的,它的Key和Value都可以是null,但是Hashtable种,Key和Value都不能是null。
B、ArrayList与LinkedList都实现了List接口,继承了AbstractList类。
C、ArrayList底层是动态数组是实现,随机位置添加和删除,都需要移动数组的数据,而LinkedList底层是双向链表,只需要修改Node节点的引用。
D、随机访问数组要比链表块。
下面放一张ArrayList和LinkedList的区别表:

在这里插入图片描述218 下面有关java threadlocal说法正确的有?(ABCD)

ThreadLocal存放的值是线程封闭,线程间互斥的,主要用于线程内共享一些数据,避免通过参数来传递

从线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收

在Thread类中有一个Map,用于存储每一个线程的变量的副本

对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式

ThreadLocal类用于创建一个线程本地变量
在Thread中有一个成员变量ThreadLocals,该变量的类型是ThreadLocalMap,也就是一个Map,它的键是threadLocal,值为就是变量的副本。通过ThreadLocal的get()方法可以获取该线程变量的本地副本,在get方法之前要先set,否则就要重写initialValue()方法。
ThreadLocal的使用场景:
数据库连接:在多线程中,如果使用懒汉式的单例模式创建Connection对象,由于该对象是共享的,那么必须要使用同步方法保证线程安全,这样当一个线程在连接数据库时,那么另外一个线程只能等待。这样就造成性能降低。如果改为哪里要连接数据库就来进行连接,那么就会频繁的对数据库进行连接,性能还是不高。这时使用ThreadLocal就可以既可以保证线程安全又可以让性能不会太低。但是ThreadLocal的缺点时占用了较多的空间。

ThreadLocal不是一个线程而是一个线程的本地化对象。当工作于多线程环境中的对象采用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程分配一个独立的副本。每个线程都可以独立的改变自己的副本,而不影响其他线程的副本。

219 设三个整型变量 x = 1 , y = 2 , z = 3,则表达式 y+=z--/++x 的值是( A )。

3

3.5

4

5

y是2,返回的结果是2+(z–/++x),再来看z–/++x,结果应该是3/2,但是因为x,y,z都是int型的,所以最后的返回值只能是int,这时候z–/++x的值就是1,那么最终的结果就是2+1=3
强制int型为向下取整,如果是3.5,(int)3.5后结果为3
220下面哪段程序能够正确的实现了GBK编码字节流到UTF-8编码字节流的转换:(B)
byte[] src,dst;

dst=String.fromBytes(src,"GBK").getBytes("UTF-8")

dst=new String(src,"GBK").getBytes("UTF-8")

dst=new String("GBK",src).getBytes()

dst=String.encode(String.decode(src,"GBK"))"UTF-8" )

操作步骤就是先解码再编码
用new String(src,“GBK”)解码得到字符串
用getBytes(“UTF-8”)得到UTF8编码字节数组

221Java语言中,下面哪个语句是创建数组的正确语句?( ABDE)

float f[][] = new float[6][6];

float []f[] = new float[6][6];

float f[][] = new float[][6];

float [][]f = new float[6][6];

float [][]f = new float[6][];

二维数组定义,一维长度必须定义,二维可以后续定义
第一个框一定要有值

但是C++中是可以省略行数,不能省略列数

222 以下JAVA程序的运行结果是什么( D )

public static void main(String[] args) {
Object o1 = true ? new Integer(1) : new Double(2.0);
Object o2;
if (true) {
             o2 = new Integer(1);
} else {
o2 = new Double(2.0);
}
System.out.print(o1);
System.out.print(" ");         
System.out.print(o2);
}
1 1

1.0 1.0

1 1.0

1.0 1

三元操作符类型的转换规则:
1.若两个操作数不可转换,则不做转换,返回值为Object类型
2.若两个操作数是明确类型的表达式(比如变量),则按照正常的二进制数字来转换,int类型转换为long类型,long类型转换为float类型等。
3.若两个操作数中有一个是数字S,另外一个是表达式,且其类型标示为T,那么,若数字S在T的范围内,则转换为T类型;若S超出了T类型的范围,则T转换为S类型。
4.若两个操作数都是直接量数字,则返回值类型为范围较大者

符合4,所以选D.

三元操作符如果遇到可以转换为数字的类型,会做自动类型提升。
比如

Object o1 = (false) ? new Double(1.0) : new Integer(2);
System.out.println(o1);

会打印2.0

三元运算符会对两个结果的数据类型,进行自动的类型提升。
因此,可以把
Object o1 = true ? new Integer(1) : new Double(2.0);
看作
Object o1 = true ? new Double(1.0) : new Double(2.0);

223 J2EE中,当把来自客户机的HTTP请求委托给servlet时,会调用HttpServlet的(A )方法

service

doget

dopost

init

HttpServlet容器响应Web客户请求流程如下:

1)Web客户向Servlet容器发出Http请求;

2)Servlet容器解析Web客户的Http请求;

3)Servlet容器创建一个HttpRequest对象,在这个对象中封装Http请求信息;

4)Servlet容器创建一个HttpResponse对象;

5)Servlet容器调用HttpServlet的service方法,这个方法中会根据request的Method来判断具体是执行doGet还是doPost,把HttpRequest和HttpResponse对象作为service方法的参数传给HttpServlet对象;

6)HttpServlet调用HttpRequest的有关方法,获取HTTP请求信息;

7)HttpServlet调用HttpResponse的有关方法,生成响应数据;
8)Servlet容器把HttpServlet的响应结果传给Web客户。

doGet() 或 doPost() 是创建HttpServlet时需要覆盖的方法.

Servlet生命周期分为三个阶段:

1.初始化阶段 调用init()方法

2.响应客户请求阶段  调用service()方法

3.终止阶段  调用destroy()方法

224 下面有关java final的基本规则,描述错误的是?(B)

final修饰的类不能被继承

final修饰的成员变量只允许赋值一次,且只能在类方法赋值

final修饰的局部变量即为常量,只能赋值一次。

final修饰的方法不允许被子类覆盖

final修饰的成员变量为基本数据类型是,在赋值之后无法改变。当final修饰的成员变量为引用数据类型时,在赋值后其指向地址无法改变,但是对象内容还是可以改变的。
final修饰的成员变量在赋值时可以有三种方式。1、在声明时直接赋值。2、在构造器中赋值。3、在初始代码块中进行赋值。

final修饰的方法,不允许被子类覆盖。
final修饰的类,不能被继承。
final修饰的变量,不能改变值。
final修饰的引用类型,不能再指向别的东西,但是可以改变其中的内容。

225 运用下列哪个命令能够获取JVM的内存映像(B)

jinfo

jmap

jhat

jstat

1、jps:查看本机java进程信息。

2、jstack:打印线程的栈信息,制作线程dump文件。

3、jmap:打印内存映射,制作堆dump文件

4、jstat:性能监控工具

5、jhat:内存分析工具

6、jconsole:简易的可视化控制台

7、jvisualvm:功能强大的控制台

226 执行以下程序后的输出结果是(D)

public class Test {
    public static void main(String[] args) {
        StringBuffer a = new StringBuffer("A"); 
        StringBuffer b = new StringBuffer("B"); 
        operator(a, b); 
        System.out.println(a + "," + b); 
    } 
    public static void operator(StringBuffer x, StringBuffery) 
    { 
        x.append(y); y = x; 
    }
}
A,A

A,B

B,B

AB,B

Java参数,不管是原始类型还是引用类型,传递的都是副本(有另外一种说法是传值,但是说传副本更好理解吧,传值通常是相对传址而言)。 如果参数类型是原始类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值,这个跟之前所谈的传值是一样的。如果在函数中改变了副本的 值不会改变原始的值. 如果参数类型是引用类型,那么传过来的就是这个引用参数的副本,这个副本存放的是参数的地址。如果在函数中没有改变这个副本的地址,而是改变了地址中的 值,那么在函数内的改变会影响到传入的参数。如果在函数中改变了副本的地址,如new一个,那么副本就指向了一个新的地址,此时传入的参数还是指向原来的 地址,所以不会改变参数的值。

所以x.append(y)改变了x的值,会影响a的值
y=x只是改变了地址,不会影响b的值

StringBuffer a = newStringBuffer(“A”);
StringBuffer b = newStringBuffer(“B”);

此时内存中的状态如下图所示
在这里插入图片描述 publicstaticvoidoperator(StringBuffer x, StringBuffer y) {
x.append(y); y = x;
}
进入如下方法后,内存中的状态为:
在这里插入图片描述x.append(y);
这条语句执行后,内存的状态为:
在这里插入图片描述y = x;
这条语句执行后,内存的状态为:
在这里插入图片描述当operator方法执行完毕后内存中的状态为:因为方法执行完毕,局部变量消除。
在这里插入图片描述a和x是同个地址,b和y是同个地址,然后执行x.append(y)就把y的值放在x的地址里面此时a地址和x是同一个所以a就是AB了,接着执行y=x是把x的地址给y,这时候axy属于同一个地址。

227 下列说法正确的是©

WebLogic中开发消息Bean的non-persistent 方式可以保证消息的可靠

EJB容器发生错误,non-persistent方式下JMS容器仍然会将消息发送

EJB容器发生错误,persistent方式下JMS容器仍然会将消息发送

EJB容器发生错误,两种方式下JMS容器仍会在MDB可用的时候将消息发送

weblogic中开发消息Bean时的persistent与non-persisten的差别:

persistent方式的MDB可以保证消息传递的可靠性,也就是如果EJB容器出现
问题而JMS服务器依然会将消息在此MDB可用的时候发送过来。
non-persistent方式的消息将被丢弃。

J2EE中容器充当中间件的角色,主要的容器包括:

WEB容器:给处于其中的应用程序组件(jsp,servlet)提供一个环境,使jsp,servlet直接与容器中的环境变量接***互,不必关注其它系统问题。主要由WEB服务器来实现。 例如:tomcat,weblogic,websphere等

EJB容器:Enterprise java bean容器。供给运行在其中的组件EJB各种管理功能,满足J2EE规范的EJB放入该容器,马上就会被容器进行高效率的管理,并且可以通过现成的接口来获得系统级别的服务。例如邮件服务、事务管理。

WEB容器更多的是跟基于HTTP的请求打交道。而EJB容器更多的和数据库、其它服务打交道。但他们都是把与外界的交互实现从而减轻应用程序的负担。例如SERVLET不用关心HTTP的细节,直接引用环境变量session,request,response就行、EJB不用关心数据库连接速度、各种事务控制,直接由容器来完成。

228 下面程序段的时间复杂度是(B)

i = k = 0;
while( k < n ){
   i ++ ;
k += i ;
}
O(n)

O(n^1/2)

O(n*i)

O(n+i)

i= 1, 2, 3, 4, 5, 6, 7, 8
k=1, 3, 6, 10, 15, 21, 28, 36
把k的数字两个两个一起看的话, 也就是(1,3), (6,10), (15, 21), (7,8), 求和后可以发现规律(1+3=4), (6+10=16), (15+21=36), (28+36=64)
也就是2^2, 4^2, 6^2, 8^2…偶数的平方
循环在x^2>=n时终止, 可得x等于根号n,也就是n^(1/2)
循环的次数是x/2, 时间复杂度为O((1/2)n^(1/2)), 一般而言时间复杂度认为常系数为1, 所以答案就是O(n^(1/2))

229 常用的servlet包的名称是?(BD)

java.servlet

javax.servlet

servlet.http

javax.servlet.http

230 下面哪项技术可以用在WEB开发中实现会话跟踪实现?(ABCD)

session

Cookie

地址重写

隐藏域

解析:实现会话跟踪的机制

Cookies,URL重写,隐藏式表单域,Session机制

Cookies

Cookies是使用最广泛的会话跟踪机制,Cookies是有服务器创建,并把Cookies信息保存在用户机器上的硬盘上,下次用户再次访问该站点服 务器的时候,保存在用户机器上硬盘的Cookies信息就被送回给服务器。一般Cookies一般不多于4KB,且用户的敏感信息如信用卡账号密码不应该 保存在Cookies中。

URL重写

URL重用户在每个URL结尾附加标识回话的数据,与标识符关联的服务器保存有关与会话的数据,如我们访问某个新闻的时候,在地址栏我们一般会看到这样的 信息:http://www.XXX.com/news?id=??,通常的话id后面的问号表示该条新闻在后台数据库中的新闻表的id。URL重写能够 在客户端停用cookies或者不支持cookies的时候仍然能够发挥作用。

隐藏表单域

通常,在表单中我们使用隐藏表单域的时候会有这么一句代码:。通过给type属性赋值为hidden值来实现隐藏,这样用户在浏览的时候看不到这行代码的数据,但是当用户通过查看 源代码还是可以看到的。

Session机制

这个机制要慎用,特别是对于访问量很大的站点,因为这种机制是吧Session信息保存在服务器端。如果访问量特别大的话,对于服务器的承受力的要求有多高是可想而知的。

231 以下二维数组声明合法的是( C)

char[2][3] ch = new char[][]

char[2][] ch = new char[][3]

char[][] ch = new char[2][3]

char[][] ch = new [2]char[3]

定义数组,等号左边不能出现数字,也就是数组的不管什么大小 不能出现在左边
第一个就是为什么左边不用标大小,而右边需要标大小?
首先数组一个对象,它不属于任何类,由jvm在运行期间在堆中创建并继承object,同时添加length属性。由于数组对象所占的内存在堆上,所以在声明时应明确告诉jvm自己所占的大小,方便分配,又因为数组对象的引用在栈中,所以声明时左边就无需标大小,之所以写成2个括号,就是为了表明这个引用指向堆中的二维数组。
第二个就是为什么右边数组可以只声明几行,无需声明每行的大小?
大概jvm在运行期间会根据行数分配对应的可扩展空间,方便每一行进行扩充。其实又可以按c语言那样理解,行其实又是一种引用,行首地址又代表一个一维数组。

// 数据类型[][] 数组名;
int [][] table = new int[2][2];
int [][] table = new int[2][];
int [] table [] = new int[2][2]; 
int [] table [] = new int[2][];

都是正确的 new int[2][];
若未确定每行的长度 打印出来 为空
在这里插入图片描述232 此代码片段输出正确的值是(A)

public class CharToString {
 public static void main(String[] args)
 {
  char myChar = 'g';
  String myStr = Character.toString(myChar);
  System.out.println("String is: "+myStr);
  myStr = String.valueOf(myChar);
  System.out.println("String is: "+myStr);
 }
}
String is: g
String is: g

String is: 103
String is: g

String is: g
String is: 103

String is: 103
String is: 103

String.valueOf(myChar); //是将char类型的myChar转化成String类型
返回的都是字符串,只有char变成 int 的时候才会变为对应的ASCII码

233下列关于JAVA多线程的叙述正确的是(BC)

调用start()方法和run()都可以启动一个线程

CyclicBarrier和CountDownLatch都可以让一组线程等待其他线程

Callable类的call()方法可以返回值和抛出异常

新建的线程调用start()方法就能立即进行运行状态

A,start是开启线程,run是线程的执行体,run是线程执行的入口。
B,CyclicBarrier和CountDownLatch都可以让一组线程等待其他线程。前者是让一组线程相互等待到某一个状态再执行。后者是一个线程等待其他线程结束再执行。
C,Callable中的call比Runnable中的run厉害就厉害在有返回值和可以抛出异常。同时这个返回值和线程池一起用的时候可以返回一个异步对象Future。
D,start是把线程从new变成了runnable

234 下面哪些赋值语句是正确的(ABD)

long test=012

float f=-412

int other =(int)true

double d=0x12345678

byte b=128

A和B中long和float,正常定义需要加l和f,但是long和float属于基本类型,会进行转化,所以不会报出异常。AB正确
boolean类型不能和任何类型进行转换,会报出类型异常错误。所以C错。
D选项可以这样定义,D正确。
E选项中,byte的取值范围是-128—127。报出异常: cannot convert from int to byte.所以E选项错误。

235 以下哪种方式实现的单例是线程安全的(ABCD)

枚举

静态内部类

双检锁模式

饿汉式

Java中四种线程安全的单例模式实现方式
1.饿汉式(线程安全,调用效率高,但是不能延时加载); 2.懒汉式(线程安全,调用效率不高,但是能延时加载); 3.Double CheckLock实现单例:DCL也就是双重锁判断机制(由于JVM底层模型原因,偶尔会出问题,不建议使用); 4.静态内部类实现模式(线程安全,调用效率高,可以延时加载); 5.枚举类(线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化调用)。

单例模式的八种写法比较
236 下面有关 JAVA 异常类的描述,说法正确的有(ABC)

异常的继承结构:基类为 Throwable,Error 和 Exception 。实现 Throwable, RuntimeException 和 IOException 等继承 Exception

非 RuntimeException 一般是外部错误(不考虑Error的情况下),其可以在当前类被 try{}catch 语句块所捕获

Error 类体系描述了 Java 运行系统中的内部错误以及资源耗尽的情形,Error 不需要捕捉

RuntimeException 体系包括错误的类型转换、数组越界访问和试图访问空指针等等,必须 被 try{}catch 语句块所捕获

都是Throwable的子类:
1.Exception(异常) :是程序本身可以处理的异常。
2.Error(错误): 是程序无法处理的错误。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,一般不需要程序处理。

3.检查异常(编译器要求必须处置的异常) : 除了Error,RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
4.非检查异常(编译器不要求处置的异常): 包括运行时异常(RuntimeException与其子类)和错误(Error)。

237 关于Java中的数组,下面的一些描述,哪些描述是准确的:( ACF )

数组是一个对象,不同类型的数组具有不同的类

数组长度是可以动态调整的

数组是一个连续的存储结构

一个固定长度的数组可类似这样定义: int array[100]

两个数组用equals方法比较时,会逐个便利其中的元素,对每个元素进行比较

可以二维数组,且可以有多维数组,都是在Java中合法的

A 数组是对象,因为可以调用方法,不同类型的数组具有不同的类
B 数组长度是不能动态调整的
C Java中的数组中的数据是连续存储在一块内存中的,所以可以通过下标(即偏移量)的方式访问
D 正确的声明方式
int[] array=new int [100]; int array[]=new int [100];
E 查看源码可以知道数组的equals方法是object的equals,比较的是内存地址
F java可以有***数组
Arrays.equal()可以比较数组元素。

238 下列代码中的错误是(D)

 (1)   public class Test

(2)   {

(3)       public static void main(String [] args)

(4)       {

(5)           int i;

(6)           i+=1;
(7)       }
(8)     }
非法的表达式 i+=1

找不到符号i

类不应为public

尚未初始化变量i

在方法内定义的变量在使用之前必须初始化,否则报错
类变量(静态变量)在类加载过程的准备阶段会进行一次赋值,一般是空值或constantValue属性值,同时在初始化阶段会调用类构造器再进行一次赋值。而实例变量在创建对象时会调用实例构造器进行一次赋值。因此无论是类变量还是实例变量,在使用前都是非空的。而局部变量没有初始化过程,在使用前必须赋值。

局部变量:方法定义中或者方法声明上。
局部变量:在内存的栈中。
局部变量:随方法的调用而存在,随着方法的调用完毕而消失。
局部变量:没有默认值,必须定义,赋值,然后才能使用

239程序的输出是?(D)

class Foo {
    final int i;
    int j;
    public void doSomething() {
        System.out.println(++j + i);
    }
}
0

1

2

不能执行,因为编译有错

final作为对象成员存在时,必须初始化;但是,如果不初始化,也可以在类的构造函数中初始

因为java允许将数据成员声明为final,却不赋初值。但是,blank finals必须在使用之前初始化,且必须在构造函数中初始化

亲自测试了一下,类的final成员变量必须满足以下其中一个条件
1、在构造函数中赋值
2、初始化赋值

240 一个文件中的数据要在控制台上显示,首先需要( C)。

System.out.print (buffer[i]);

FileOutputStream fout = new FileOutputStream(this.filename);

FileInputStream fin = new FileInputStream(this.filename);。

System.in.read(buffer)

一个文件中的数据要在控制台显示,首先需要获取文件中的内容,使用FileInputStream fin = new FileInputStream(this.filename);

241 某程序要求每次输入只能是正整数,并且每次输入的数值要求必须是100的倍数且小于等于500,则下列哪个是正确的无效等价类( C)

0100)、(100200)、(200300)、(300400)、(400500)、(500+∞);500+∞)

(500+∞)、任意大于0小于500的非100倍数的整数;

(-∞,100)、(100200)、(200300)、(300400)、(400500)、(500+∞);

无效等价类是指对于软件规格说明而言,是没有意义的、不合理的输入数据集合。利用无效等价类可以找出程序异常说明情况,检查程序的功能和性能的实现是否有不符合规格说明要求的地方。
有效等价类是指输入数据完全满足程序输入的规格说明,是有效、有意义的输入数据所构成的集合。利用有效等价类可以检验程序是否满足规格说明所规定的功能和性能。
应该选 C,因为C的后面一句话是已经排除了负数中的100的整数倍了

242 在J2EE中,使用Servlet过滤器,需要在web.xml中配置()元素(AB)

<filter>

<filter-mapping>

<servlet-filter>

<filter-config>

在这里插入图片描述243 下面有关java类加载器,说法正确的是?(ABCD)

引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的

扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。

系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类

tomcat为每个App创建一个Loader,里面保存着此WebApp的ClassLoader。需要加载WebApp下的类时,就取出ClassLoader来使用

在这里插入图片描述bootstrap classloader -引导(也称为原始)类加载器,它负责加载Java的核心类。 extension classloader -扩展类加载器,它负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统属性指定的)中JAR的类包。 system classloader -系统(也称为应用)类加载器,它负责在JVM被启动时,加载来自在命令java中的-classpath或者java.class.path系统属性
或者 CLASSPATH*作系统属性所指定的JAR类包和类路径。

244 下面哪些情况可以引发异常:(ABC)

数组越界

指定URL不存在

使用throw语句抛出

使用throws语句

1、throws出现在方法头,throw出现在方法体 2、throws表示出现异常的一种可能性,并不一定会发生异常;throw则是抛出了异常,执行throw则一定抛出了某种异常。 3、两者都是消极的异常处理方式,只是抛出或者可能抛出异常,是不会由函数处理,真正的处理异常由它的上层调用处理。

245 类之间存在以下几种常见的关系:(ABC)

“USES-A”关系

“HAS-A”关系

“IS-A”关系

“INHERIT-A”关系

USES-A:依赖关系,A类会用到B类,这种关系具有偶然性,临时性。但B类的变化会影响A类。这种在代码中的体现为:A类方法中的参数包含了B类。
关联关系:A类会用到B类,这是一种强依赖关系,是长期的并非偶然。在代码中的表现为:A类的成员变量中含有B类。
HAS-A:聚合关系,拥有关系,是关联关系的一种特例,是整体和部分的关系。比如鸟群和鸟的关系是聚合关系,鸟群中每个部分都是鸟。
IS-A:表示继承。父类与子类,这个就不解释了。
要注意:还有一种关系:组合关系也是关联关系的一种特例,它体现一种contains-a的关系,这种关系比聚合更强,也称为强聚合。它同样体现整体与部分的关系,但这种整体和部分是不可分割的。

246下面的程序将来打印什么?(A)

public class TestIncr {
    public static void main(String args[]) {
        int i = 0;
        i = i++ + i;
        System.out.println("I =" +i);
    }
}
I = 1

I = 2

I = 3

编译出错

i = i++ + i ->0 , 再i 自增 -> 1.

247 关于访问权限说法正确 的是 ? (B )

外部类前面可以修饰public,protectedprivate

成员内部类前面可以修饰public,protectedprivate

局部内部类前面可以修饰public,protectedprivate

以上说法都不正确

Java 内部类、成员类、局部类、匿名类等

可以把局部内部类当做一个局部变量,所以它是不需要加任何修饰符的
局部内部类前不能用修饰符public和private,protected

内部类就随意了。

对于外部类而言,它也可以使用访问控制符修饰,但外部类只能有两种访问控制级别: public 和默认。因为外部类没有处于任何类的内部,也就没有其所在类的内部、所在类的子类两个范围,因此 private 和 protected 访问控制符对外部类没有意义。

2 )内部类的上一级程序单元是外部类,它具有 4 个作用域:同一个类( private )、同一个包( protected )和任何位置( public )。
( 3 ) 因为局部成员的作用域是所在方法,其他程序单元永远不可能访问另一个方法中的局部变量,所以所有的局部成员都不能使用访问控制修饰符修饰。

248对于JVM内存配置参数: ,其最小内存值和Survivor区总大小分别是(D)

-Xmx10240m -Xms10240m -Xmn5120m -XXSurvivorRatio=3 
5120m,1024m

5120m,2048m

10240m,1024m

10240m,2048m

-Xmx:最大堆大小
-Xms:初始堆大小
-Xmn:年轻代大小
-XXSurvivorRatio:年轻代中Eden区与Survivor区的大小比值
年轻代5120m, Eden:Survivor=3,Survivor区大小=1024m(Survivor区有两个,即将年轻代分为5份,每个Survivor区占一份),总大小为2048m。
-Xms初始堆大小即最小内存值为10240m

-Xms -Xmx分别设置堆的最小值和最大值,如果要设置成堆的大小可变,那么可以将最大值和最小值设置成不一样,如果要将堆大小固定,那么只需将最大值和最小值设置成一样的就行。
jvm中分为堆和方法区
堆又进一步分为新生代和老年代
方法区为永久代
堆中区分的新生代和老年代是为了垃圾回收,新生代中的对象存活期一般不长,而老年代中的对象存活期较长,所以当垃圾回收器回收内存时,新生代中垃圾回收效果较好,会回收大量的内存,而老年代中回收效果较差,内存回收不会太多。
基于以上特性,新生代中一般采用复制算法,因为存活下来的对象是少数,所需要复制的对象少,而老年代对象存活多,不适合采用复制算法,一般是标记整理和标记清除算法。
因为复制算法需要留出一块单独的内存空间来以备垃圾回收时复制对象使用,所以将新生代分为eden区和两个survivor区,每次使用eden和一个survivor区,另一个survivor作为备用的对象复制内存区。
综上:
-Xmn设置了新生代的大小为5120m,而-XXSurvivorRatio=3,所有将新生代共分成5分,eden占三份,survivor占两份,每份1/5

249 关于Java的一些概念,下面哪些描述是正确的:( BF)

所有的Java异常和错误的基类都是java.lang.Exception, 包括java.lang.RuntimeException

通过trycatchfinally语句,finally中的语句部分无论发生什么异常都会得到执行

java中所有的数据都是对象

Java通过垃圾回收回收不再引用的变量,垃圾回收时对象的finallize方法一定会得到执行

Java是跨平台的语言,无论通过哪个版本的Java编写的程序都能在所有的Java运行平台中运行

Java通过synchronized进行访问的同步,synchronized作用非静态成员方法和静态成员方法上同步的目标是不同的

A、java异常和错误的基类Throwable,包括Exception和Error
B、try…catch…finally finally不管什么异常都会执行
C、java是面向对象的,但是不是所有的都是对象,基本数据类型就不是对象,所以才会有封装类的;
D、如果是等待清理队列中如果又被调用,则不会执行finallize方法
E、JAVA跨平台性 实现在任意平台的java程序都可以在其他平台运行
F、synchronized实现方式:三种
非静态锁的是实例的对象:多个非静态方法同时加了synchronized,互不影响
静态锁的是类:多个静态方法加了synchronized,如果其中一个方法被锁了,其他的静态方法是拿不到锁的,没法执行,只有等该方法执行结束,其它静态方法才能拿到锁
A.错误(Error)的基类是Throwable
C.基本类型不是对象
D.垃圾回收器并不总是工作,只有当内存资源告急时,垃圾回收器才会工作;即使垃圾回收器工作,finalize方法也不一定得到执行,这是由于程序中的其他线程的优先级远远高于执行finalize()函数线程的优先级。(这是楼下的答案)
E.低版本JRE无法运行高版本JRE

250 下面这三条语句 的输出结果分别是? ( D)

System.out.println(“is ”+ 100 + 5);
System.out.println(100 + 5 +“ is”);
System.out.println(“is ”+ (100 + 5))
is 1005, 1005 is, is 1005

is 105, 105 is, is 105

is 1005, 1005 is, is 105

is 1005, 105 is, is 105

出现字符串之前就直接计算相加得到的值,若出现了字符串,则后面的数字都直接拼接,除非有括号

1."is"说明后面的内容都会被强制转换为string,所以是最后结果是拼接起来的
2.100+5先得到105,然后与is拼接
3.先算括号内的

先出现字符串,后面的内容自动强制转换为string进行拼接 先出现数字,则进行加减运算 先算括号里面,数字

在java中,“+” 和 “+=” 是经过重载的运算符,而java不允许程序员进行运算符的重载。如果 “+” 之前是String,那么此时,“+” 的作用就是连接两个字符串;若此时 “+” 后面是基本数据类型的话,可以直接进行连接,若是引用数据类型的话,则会调用该对象的toString()方法。

251 如下代码的输出结果是什么? (D)

public class Test { 
    public int aMethod(){
        static int i = 0;
        i++; 
        return i;
    } 
public static void main(String args[]){
    Test test = new Test(); 
    test.aMethod(); 
    int j = test.aMethod();
    System.out.println(j);
    } 
}
0

1

2

编译失败

Java中静态变量只能在类主体中定义,不能在方法中定义。 静态变量属于类所有而不属于方法。

252 下列叙述中,错误的是(B )

File类能够存储文件属性

File类能够读写文件

File类能够建立文件

File类能够获取文件目录信息

能够读写文件的是数据流(OutputStream和InputStream)
File类使用详解
在这里插入图片描述253 jre 判断程序是否执行结束的标准是(A)

所有的前台线程执行完毕

所有的后台线程执行完毕

所有的线程执行完毕

和以上都无关

main()函数即主函数,是一个前台线程,前台进程是程序中必须执行完成的,而后台线程则是java中所有前台结束后结束,不管有没有完成,后台线程主要用与内存分配等方面
前台线程和后台线程的区别和联系:
1、后台线程不会阻止进程的终止。属于某个进程的所有前台线程都终止后,该进程就会被终止。所有剩余的后台线程都会停止且不会完成。
2、可以在任何时候将前台线程修改为后台线程,方式是设置Thread.IsBackground 属性。
3、不管是前台线程还是后台线程,如果线程内出现了异常,都会导致进程的终止。

4、托管线程池中的线程都是后台线程,使用new Thread方式创建的线程默认都是前台线程。
说明:
应用程序的主线程以及使用Thread构造的线程都默认为前台线程
使用Thread建立的线程默认情况下是前台线程,在进程中,只要有一个前台线程未退出,进程就不会终止。主线程就是一个前台线程。而后台线程不管线程是否结束,只要所有的前台线程都退出(包括正常退出和异常退出)后,进程就会自动终止。一般后台线程用于处理时间较短的任务,如在一个Web服务器中可以利用后台线程来处理客户端发过来的请求信息。而前台线程一般用于处理需要长时间等待的任务,如在Web服务器中的监听客户端请求的程序,或是定时对某些系统资源进行扫描的程序
254 java8中,下面哪个类用到了解决哈希冲突的开放定址法 ©

LinkedHashSet

HashMap

ThreadLocal

TreeMap

threadlocalmap使用开放定址法解决haah冲突,hashmap使用链地址法解决hash冲突
什么是开发地址法:https://cloud.tencent.com/developer/article/1361248

255 Which two statements are true if this class is compiled and run? (EG)

public class NameList
{
    private List names = new ArrayList();
    public synchronized void add(String name)
    {
        names.add(name);
    }
    public synchronized void printAll()     {
        for (int i = 0; i < names.size(); i++)
        {
            System.out.print(names.get(i) + ””);
        }
    }

    public static void main(String[]args)
    {
        final NameList sl = new NameList();
        for (int i = 0; i < 2; i++)
        {
            new Thread()
            {
                public void run()
                {
                    sl.add(“A”);
                    sl.add(“B”);
                    sl.add(“C”);
                    sl.printAll();
                }
            } .start();
        }
    }
}
An exception may be thrown at runtime.

The code may run with no output, without exiting.

The code may run with no output, exiting normally(正常地).

The code may rum with output “A B A B C C “, then exit.

The code may rum with output “A B C A B C A B C “, then exit.

The code may ruin with output “A A A B C A B C C “, then exit.

The code may ruin with output “A B C A A B C A B C “, then exit.

在每个线程中都是顺序执行的,所以sl.printAll();必须在前三句执行之后执行,也就是输出的内容必有(连续或非连续的)ABC。
而线程之间是穿插执行的,所以一个线程执行 sl.printAll();之前可能有另一个线程执行了前三句的前几句。
E答案相当于线程1顺序执行完然后线程2顺序执行完。
G答案则是线程1执行完前三句add之后线程2插一脚执行了一句add然后线程1再执行 sl.printAll();输出ABCA。接着线程2顺序执行完输出ABCABC
输出加起来即为ABCAABCABC。
这个题目的结果是有规律的: 规律如下: 1 第一个线程输出的元素个数大于等于3个,小于等于6个。 2 第二个线程(最后执行的线程)输出的元素个数必须等于6个。 3 输出的所有元素中取出最后6个,剩下的元素的顺序和最后6个的顺序相同(从头往后比较)。 如:AABBCCAABBCC 取出最后6个AABBBCC剩下的元素顺序和这个一样。还有我执行的结果 A B A C B C A B A C B C 最后6个元素ABACBC,剩下的元素顺序也一样。还有ABCAABCABC取出最后6个元素,剩下ABCA顺序也一样。 有了这样的规律,可以很容易的判断出输出的是否正确。 其实这个规律的原理很简单,只要注意,线程内顺序执行,线程间交叉执行。 手机写的,写了好几次都没了。还有就是客户端刷新慢,前面一个连着点了好几次。
第一次println的字符个数肯定大于等于3,小于等于6;第二次println的字符个数肯定等于6;所以输出的字符中,后6位肯定是第二次输出的,前面剩下的就是第一次输出的。而且第一次的输出结果肯定是第二次输出结果的前缀。所以选E、G。

256 String str1 = “abc”,“abc”分配在内存哪个区域?(C)

堆

栈

字符串常量区

寄存器

用new创建的对象在堆区
函数中的临时变量在栈去
java中的字符串在字符串常量区

栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中

堆:存放用new产生的数据

静态域:存放在对象中用static定义的静态成员

常量池:存放常量

非RAM存储:硬盘等永久存储空间

257 当你编译和运行下面的代码时,会出现下面选项中的哪种情况?B

public class Pvf{
    static boolean Paddy;
    public static void main(String args[]){
        System.out.println(Paddy);
    }
}
编译时错误

编译通过并输出结果false

编译通过并输出结果true

编译通过并输出结果null

类中声明的变量有默认初始值;方法中声明的变量没有默认初始值,必须在定义时初始化,否则在访问该变量时会出错。
boolean类型默认值是false
final static 变量必须初始化

在这里插入图片描述257 given the following code,what will be the output? A

class Value{
    public int i=15;
}
public class Test{
    public static void main(String argv[]){
        Test t=new Test( );
        t.first( );
    }

public void first( ){
    int i=5;
    Value v=new Value( );
    v.i=25;
    second(v,i);
    System.out.println(v.i);
}

public void second(Value v,int i){
    i = 0;
    v.i = 20;
    Value val = new Value( );
    v = val;
    System.out.println(v.i+" "+i);
   }
}
15 0 20

15 0 15

20 0 20

0 15 20

这题选A,考察的是值传递与引用传递,Java中原始数据类型都是值传递,传递的是值得副本,形参的改变不会影响实际参数的值, 引用传递传递的是引用类型数据,包括String,数组,列表, map,类对象等类型,形参与实参指向的是同一内存地址,因此形参改变会影响实参的值

可能有人会选择B,包括我刚开始也是。总以为v不是已经指向了val了吗??为什么还是20呢?不应该是15吗?
其实,原因很简单。现在我们把second()换一下
publicvoidsecond(Value tmp,inti){
i = 0;
tmp.i = 20;
Value val = newValue( );
tmp = val;
System.out.println(tmp.i+" "+i);
}
这个tmp其实相当于是一个指向原来first中的V这个对象的指针,也就是对v对象的引用而已。但是引用是会改变所指的地址的值的。
所以在second中当tmp.i= 20的时候,就把原来first中的v的i值改为20了。接下来,又把tmp指向了新建的一个对象,所以在second中的tmp
现在指的是新的对象val,i值为15.
当执行完毕second后,在first中在此输出v.i的时候,应为前面second中已经把该位置的i的值改为了20,所以输出的是20.
至于疑惑v指向了val,其实只是名字的问题,在second中的v实践也是另外的一个变量,名字相同了而已,这个估计也是纠结的重点。

258 下列关于容器集合类的说法正确的是?C

LinkedList继承自List

AbstractSet继承自Set

HashSet继承自AbstractSet

WeakMap继承自HashMap

LinkedList是继承自AbstractSequentialList(抽象类,实现了List接口)的,并且实现了List接口。所以A错误。
B.AbstractSet是实现了Set接口的,本身是一个抽象类。继承自AbstractCollection(抽象类,实现了Collection接口)。所以B错误。
C.HashSet是继承自AbstractSet,实现了Set接口。所以C正确。
D.WeakMap不存在于java集合框架的。只有一个叫做WeakHashMap(继承自AbstractMap)。
在这里插入图片描述
259 关于匿名内部类叙述正确的是? (B )

匿名内部类可以继承一个基类,不可以实现一个接口

匿名内部类不可以定义构造器

匿名内部类不能用于形参

以上说法都不正确

由于构造器的名字必须与类名相同,而匿名类没有类名,所以匿名类不能有构造器

匿名内部类的创建格式为: new 父类构造器(参数列表)|实现接口(){
//匿名内部类的类体实现
}

使用匿名内部类时,必须继承一个类或实现一个接口
匿名内部类由于没有名字,因此不能定义构造函数
匿名内部类中不能含有静态成员变量和静态方法 

在使用匿名内部类的过程中,我们需要注意如下几点:

  1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。

 2、匿名内部类中是不能定义构造函数的。

 3、匿名内部类中不能存在任何的静态成员变量和静态方法。

  4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。

 5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。

260 以下代码段执行后的输出结果为D

public class Test {
public static void main(String[] args) {
System.out.println(test());

}
private static int test() {
int temp = 1;
try {
System.out.println(temp);
return ++temp;
} catch (Exception e) {
System.out.println(temp);
return ++temp;
} finally {
++temp;
System.out.println(temp);
}
}
}
1,2,2

1,2,3

1,3,3

1,3,2

执行顺序为:
输出try里面的初始temp:1;
temp=2;
保存return里面temp的值:2;
执行finally的语句temp:3,输出temp:3;
返回try中的return语句,返回存在里面的temp的值:2;
输出temp:2。

finally代码块在return中间执行。return的值会被放入临时空间,然后执行finally代码块,如果finally中有return,会刷新临时空间的值,方法结束返回临时空间值。

261 Java的Daemon线程,setDaemon(A )设置必须要?

在start之前

在start之后

前后都可以

解释:setDaemon()方法必须在线程启动之前调用,当线程正在运行时调用会产生异常。

java线程基础知识----java daemon线程

java线程是一个运用很广泛的重点知识,我们很有必要了解java的daemon线程.

1.首先我们必须清楚的认识到java的线程分为两类: 用户线程和daemon线程

A.  用户线程: 用户线程可以简单的理解为用户定义的线程,当然包括main线程(以前我错误的认为main线程也是一个daemon线程,但是慢慢的发现原来main线程不是,因为如果我再main线程中创建一个用户线程,并且打出日志,我们会发现这样一个问题,main线程运行结束了,但是我们的线程任然在运行).

B.  daemon线程: daemon线程是为我们创建的用户线程提供服务的线程,比如说jvm的GC等等,这样的线程有一个非常明显的特征: 当用户线程运行结束的时候,daemon线程将会自动退出.(由此我们可以推出下面关于daemon线程的几条基本特点)

2. daemon 线程的特点:

A.  守护线程创建的过程中需要先调用setDaemon方法进行设置,然后再启动线程.否则会报出IllegalThreadStateException异常.(个人在想一个问题,为什么不能动态更改线程为daemon线程?有时间一个补上这个内容,现在给出一个猜测: 是因为jvm判断线程状态的时候,如果当前只存在一个线程Thread1,如果我们把这个线程动态更改为daemon线程,jvm会认为当前已经不存在用户线程而退出,稍后将会给出正确结论,抱歉!如果有哪位大牛看到,希望给出指点,谢谢!)

B.  由于daemon线程的终止条件是当前是否存在用户线程,所以我们不能指派daemon线程来进行一些业务操作,而只能服务用户线程.

C.  daemon线程创建的子线程任然是daemon线程.

262 有程序片段如下,以下表达式结果为 true 的是(B )

 Float  s=new  Float(0.1f);

Float  t=new  Float(0.1f);

Double  u=new  Double(0.1); 
s==t

s.equals(t)

u.equals(s)

t.equals(u)

Float的==比较的是地址,只有同一个类才会返回true,但是equals不是,Float的equals被重写了,只校验类型是不是Float以及值是否相同即可
一般情况下,浮点数是不直接进行判等比较的,因为浮点数存在精度问题。要比较两个浮点数,一般的比较方法是设定一个精度,当二者的差小于某个精度时,认为二者相等。例如:
if (Math.abs(s - t) < 0.001) {
System.out.println(“equal”);
}else {
System.out.println(“not equal”);
}

263 在Jdk1.7中,下述说法中抽象类与接口的区别与联系正确的有哪些?ABCD

抽象类中可以有普通成员变量,接口中没有普通成员变量。

抽象类和接口中都可以包含静态成员常量。

一个类可以实现多个接口,但只能继承一个抽象类

抽象类中可以包含非抽象的普通方法,接口中的方法必须是抽象的,不能有非抽象的普通方法。

在这里插入图片描述264 以下哪些方法可以取到http请求中的cookie值(BD)?

request.getAttribute

request.getHeader

request.getParameter

request.getCookies

下面的方法可用在 Servlet 程序中读取 HTTP 头。这些方法通过 HttpServletRequest 对象可用:

1)Cookie[] getCookies()
返回一个数组,包含客户端发送该请求的所有的 Cookie 对象。

2)Object getAttribute(String name)
以对象形式返回已命名属性的值,如果没有给定名称的属性存在,则返回 null。

3)String getHeader(String name)
以字符串形式返回指定的请求头的值。Cookie也是头的一种;

4)String getParameter(String name)
以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。
265 以下哪些类是线程安全的(ADE)

Vector

HashMap

ArrayList

StringBuffer

Properties

A,Vector相当于一个线程安全的List
B,HashMap是非线程安全的,其对应的线程安全类是HashTable
C,Arraylist是非线程安全的,其对应的线程安全类是Vector
D,StringBuffer是线程安全的,相当于一个线程安全的StringBuilder
E,Properties实现了Map接口,是线程安全的

难道我们只能单纯的背java的那个类是线程安全的,那个类不是线程安全的么?
这和授人以鱼有何区别呢?难道就没有一种方法授人以渔?直接教我们如何去判断一个类是否是线程安全的?
java中的线程安全是什么:
就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法进行访问
什么叫线程安全:
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
线程安全问题都是由全局变量及静态变量引起的
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全

A:AD的说法一致
D:StringBuffer是线程安全的(同步),StringBuilder是不保证线程,(每次操作一次就是安全的)
E:Properties类是Hashtable的一个子类,hashTable是线程安全的,所以properotes是线程安全的

266 判断对错。List,Set,Map都继承自继承Collection接口。(错)

在这里插入图片描述267 请问输出的结果是:(D)

 String str1="hello";

String str2="he"+ new String("llo");

System.out.println(str1==str2); 
true

都不对

null

false

解析:

String str1="hello";    这样创建字符串是存在于常量池中
String str2=new String("hello");    str2存在于堆中,
==是验证两个对象是否是一个(内存地址是否相同)
用+拼接字符串时会创建一个新对象再返回。 

=1)String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法
2)String类底层是char数组来保存字符串的, 对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象

字符串常量池
在class文件中有一部分来存储编译期间生成的字面常量以及符号引用,这部分叫做class文件常量池,在运行期间对应着方法区的运行时常量池。
JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池

工作原理

当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。

实现前提

字符串常量池实现的前提条件就是Java中String对象是不可变的,这样可以安全保证多个变量共享同一个对象。如果Java中的String对象可变的话,一个引用操作改变了对象的值,那么其他的变量也会受到影响,显然这样是不合理的。

268 It is an important feature of the Java language that it always provides a default constructor to a class.(false)
事实上只有在我们没有显示声明任何构造方法时java才会为我们提供一个默认的无参构造函数

269 下面有关JVM内存,说法错误的是?©

程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,是线程隔离的

虚拟机栈描述的是Java方法执行的内存模型,用于存储局部变量,操作数栈,动态链接,方法出口等信息,是线程隔离的

方法区用于存储JVM加载的类信息、常量、静态变量、以及编译器编译后的代码等数据,是线程隔离的

原则上讲,所有的对象都在堆区上分配内存,是线程之间共享的

JVM介绍
深入理解java虚拟机

解释
方法区域存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中通过Class对象中的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域,同时方法区域也是全局共享的,在一定的条件下它也会被GC,当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息

270 下面代码片段叙述正确的是(c)

byte b1=1,b2=2,b3,b6; 
final byte b4=4,b5=6; 
b6=b4+b5; 
b3=(b1+b2); 
System.out.println(b3+b6);
输出结果:13

语句:b6=b4+b5编译出错

语句:b3=b1+b2编译出错

运行期抛出异常

== 被final修饰的变量是常量,这里的b6=b4+b5可以看成是b6=10;在编译时就已经变为b6=10了
而b1和b2是byte类型,java中进行计算时候将他们提升为int类型,再进行计算,b1+b2计算后已经是int类型,赋值给b3,b3是byte类型,类型不匹配,编译不会通过,需要进行强制转换。
Java中的byte,short,char进行计算时都会提升为int类型==。

没有final修饰的变量相加后会被自动提升为int型,与目标类型byte不相容,需要强制转换(向下转型)。
在这里插入图片描述
271 Test.main()函数执行后的输出是( B)

class Test {
    public static void main(String[] args) {
        System.out.println(new B().getValue());
    }
    static class A {
        protected int value;
        public A (int v) {
            setValue(v);
        }
        public void setValue(int value) {
            this.value= value;
        }
        public int getValue() {
            try {
                value ++;
                return value;
            } finally {
                this.setValue(value);
                System.out.println(value);
            }
        }
    }
    static class B extends A {
        public B () {
            super(5);
            setValue(getValue()- 3);
        }
        public void setValue(int value) {
            super.setValue(2 * value);
        }
    }
}
6 7 7

22 34 17

22 74 74

11 17 34

https://blog.csdn.net/guanmao4322/article/details/85680465

272 以下关于Integer与int的区别错误的是(D)

int是java提供的8种原始数据类型之一

Integer是java为int提供的封装类

int的默认值为0

Integer的默认值为1

int 是八大基本数据类型之一(byte,char,short,int,long,float,double,boolean)
Integer 是 int 包装类;
int是基本数据类型,默认值为0,
Integer 是类,默认值为null;
Integer 表示的是对象,用一个引用指向这个对象,
int是基本数据类型,直接存储数值。

integer 包装类 属于引用数据类型 所以 为赋值时 默认为null
273 下列哪些语句关于内存回收的说明是正确的? (B )

程序员必须创建一个线程来释放内存

内存回收程序负责释放无用内存

内存回收程序允许程序员直接释放内存

内存回收程序可以在指定的时间释放内存对象

A、JVM一旦启动,就会创建一个守护线程来监测是否需要有对象内存被释放。
C、无法直接释放。
D、不可以指定时间,System.gc(),只是提醒JVM可以进行一次Full GC,但是什么时候真正执行,还是不知道的。
在这里插入图片描述
在空闲时间以不定时的方式动态回收无任何引用的对象占据的内存空间

274 以下哪个方法用于定义线程的执行体? (C)

start()

join()

run()

synchronized(

run()方法是用来定义这个线程在启动的时候需要做什么,但是,直接执行run()方法那就不是线程,必须使用start()启动,那样才是线程。

start()方法是启动线程,启动线程后执行的run()方法
start()方法时执行线程
join()方法是停止当前正在运行的线程,运行该线程,知道结束
run()方法是线程所执行的方法体
synchronized是同步代码块加锁解锁用的

275 下面有关servlet中init,service,destroy方法描述错误的是?(D)

init()方法是servlet生命的起点。一旦加载了某个servlet,服务器将立即调用它的init()方法

service()方法处理客户机发出的所有请求

destroy()方法标志servlet生命周期的结束

servlet在多线程下使用了同步机制,因此,在并发编程下servlet是线程安全的

servlet在多线程下其本身并不是线程安全的。
如果在类中定义成员变量,而在service中根据不同的线程对该成员变量进行更改,那么在并发的时候就会引起错误。最好是在方法中,定义局部变量,而不是类变量或者对象的成员变量。由于方法中的局部变量是在栈中,彼此各自都拥有独立的运行空间而不会互相干扰,因此才做到线程安全

init方法: 是在servlet实例创建时调用的方法,用于创建或打开任何与servlet相的资源和初始 化servlet的状态,Servlet规范保证调用init方法前不会处理任何请求
service方法:是servlet真正处理客户端传过来的请求的方法,由web容器调用, 根据HTTP请求方法(GET、POST等),将请求分发到doGet、doPost等方法
destory方法:是在servlet实例被销毁时由web容器调用。Servlet规范确保在destroy方法调用之 前所有请求的处理均完成,需要覆盖destroy方法的情况:释放任何在init方法中 打开的与servlet相关的资源存储servlet的状态

Servlet是线程不安全的,在Servlet类中可能会定义共享的类变量,这样在并发的多线程访问的情况下,不同的线程对成员变量的修改会引发错误。

276 关于Java以下描述正确的有( A )

native关键字表名修饰的方法是由其它非Java语言编写的

能够出现在import语句前的只有注释语句

接口中定义的方法只能是public

构造方法只能被修饰为public或者default

C是错的。接口是更抽象的东西,属性默认是:public static final的,方法默认是public abstract的!

A:native是由调用本地方法库(如操作系统底层函数),可以由C,C++实现,A正确
B:import是用于导包语句,其前面可以出现package,用来声明包的,B错误
C:接口方法的修饰符可以是:public,abstract,default,static(后两者需要有{}),C正确
D:构造方法可以用private,protected,default,private,D错误

277 Servlet的生命周期可以分为初始化阶段,运行阶段和销毁阶段三个阶段,以下过程属于初始化阶段是(ACD)。

加载Servlet类及.class对应的数据

创建servletRequest和servletResponse对象

创建ServletConfig对象

创建Servlet对象

Servlet的生命周期一般可以用三个方法来表示:

init():仅执行一次,负责在装载Servlet时初始化Servlet对象
service() :核心方法,一般HttpServlet中会有get,post两种处理方式。在调用doGet和doPost方法时会构造servletRequest和servletResponse请求和响应对象作为参数。
destory():在停止并且卸载Servlet时执行,负责释放资源

初始化阶段:Servlet启动,会读取配置文件中的信息,构造指定的Servlet对象,创建ServletConfig对象,将ServletConfig作为参数来调用init()方法。所以选ACD。B是在调用service方法时才构造的

在这里插入图片描述
Servlet的生命周期可以分为初始化阶段,运行阶段和销毁阶段三个阶段,以下过程属于初始化阶段是

  1. 加载Servlet类及.class对应的数据
  2. 创建ServletConfig对象
  3. 创建Servlet对象

每一次请求来到容器时,会产生HttpServletRequest与HttpServlceResponse对象,并在调用service()方法时当做参数传入。
在WEB容器启动后,会读取Servlet设置信息,将Servlet类加载并实例化,并为每个Servlet设置信息产生一个ServletConfig对象,而后调用Servlet接口的init()方法,并将产生的ServletConfig对象当作参数传入。

278 下面关于Spring的说法中错误的是(D)

Spring是一系列轻量级Java EE框架的集合

Spring中包含一个“依赖注入”模式的实现

使用Spring可以实现声明式事务

Spring提供了AOP方式的日志系统

解释一下答案A
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。

核心容器,Spring上下文,Spring AOP, Spring DAO, Spring ORM, Spring Web, Spring MVC。

答案:D
spring没有提供AOP方式的日志系统
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态***实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
Spring通过对AOP的支持,借助log4j等Apache开源组件实现了日志系统。

279 当我们需要所有线程都执行到某一处,才进行后面的的代码执行我们可以使用?(A)

CountDownLatch

CyclicBarrier

Semaphore

Future

CountDownLatch 是等待一组线程执行完,才执行后面的代码。此时这组线程已经执行完。
CyclicBarrier 是等待一组线程至某个状态后再同时全部继续执行线程。此时这组线程还未执行完。

CountDownLatch 允许一个线程或多个线程等待特定情况,同步完成线程中其他任务。举例:百米赛跑,就绪运动员等待发令枪发动才能起步。
CyclicBarrier 和CountDownLatch一样都可以协同多个线程,让指定数量的线程等待期他所有的线程都满足某些条件之后才继续执行。举例:排队上摩天轮时,每到齐四个人,就可以上同一个车厢。

280 假设 a 是一个由线程 1 和线程 2 共享的初始值为 0 的全局变量,则线程 1 和线程 2 同时执行下面的代码,最终 a 的结果不可能是(D)

boolean isOdd = false;
for(int i=1;i<=2;++i)
{
if(i%2==1)isOdd = trueelse isOdd = false;
a+=i*(isOdd?1:-1)} 
-1

-2

0

1

每个线程对a 均做了两次读写操作,分别是 “ +1 ” 和 “ -2 ”
而题目问了是最终a 的结果,所以 a 的结果取决于各自线程对 a 的先后读写的顺序
结论:a的可能取值为-1、0、-2
在这里插入图片描述 首先,每个线程对a做的操作都是+1或者-2
其次,线程对a做的操作有可见不可见的问题.

  1. 如果线程A 做了+1,-2,结果是-1,此时如果该结果对于线程B 可见,那么再执行+1,-2,结果是-2;
  2. 如果线程A做了+1,-2,结果是-1,但是该结果对线程B并没有见到,那么线程B 最后依然以a==0开始计算,结果是0+1-2=-1,之前线程A 的结果也是-1,此时无论A和B谁的计算结果被最后刷新到公共内存,最后a的值都是-1;
  3. 如果线程A做了+1,该结果立即被B看到,B开始进行+1,-2,结果是0,如果该结果被刷新到内存的时机晚于线程A的计算结果,那么结果就是0.

假设两线程为A、B,设有3种情况:
1.AB不并发:此时相当于两个方法顺序执行。A执行完后a=-1,B使用-1作为a的初值,B执行完后a=-2
2.AB完全并发:此时读写冲突,相当于只有一个线程对a的读写最终生效。相同于方法只执行了一次。此时a=-1
3.AB部分并发:假设A先进行第一次读写,得到a=1;之后A的读写被B覆盖了。B使用用1作为a的初值,B执行完后a=0

首先,每个线程对a做的操作都是+1或者-2
其次,线程对a做的操作有可见不可见的问题.

  1. 如果线程A 做了+1,-2,结果是-1,此时如果该结果对于线程B 可见,那么再执行+1,-2,结果是-2;
  2. 如果线程A做了+1,-2,结果是-1,但是该结果对线程B并没有见到,那么线程B 最后依然以a==0开始计算,结果是0+1-2=-1,之前线程A 的结果也是-1,此时无论A和B谁的计算结果被最后刷新到公共内存,最后a的值都是-1;
  3. 如果线程A做了+1,该结果立即被B看到,B开始进行+1,-2,结果是0,如果该结果被刷新到内存的时机晚于线程A的计算结果,那么结果就是0.

281在Java语言中,下列关于字符集编码(Character set encoding)和国际化(i18n)的问题,哪些是正确的?(CD)

每个中文字符占用2个字节,每个英文字符占用1个字节

假设数据库中的字符是以GBK编码的,那么显示数据库数据的网页也必须是GBK编码的。

Java的char类型,通常以UTF-16 Big Endian的方式保存一个字符。

实现国际化应用常用的手段是利用ResourceBundle类
 A 显然是错误的,Java一律采用Unicode编码方式,每个字符无论中文还是英文字符都占用2个字节。
B 也是不正确的,不同的编码之间是可以转换的,通常流程如下:
将字符串S以其自身编码方式分解为字节数组,再将字节数组以你想要输出的编码方式重新编码为字符串。
例:String newUTF8Str = new String(oldGBKStr.getBytes("GBK"), "UTF8");
C 是正确的。Java虚拟机中通常使用UTF-16的方式保存一个字符
D 也是正确的。ResourceBundle能够依据Local的不同,选择性的读取与Local对应后缀的properties文件,以达到国际化的目的。 

282使用mvc模式设计的web应用程序具有以下优点,除了?(D)

可维护行强

可扩展性强

代码重复少

大大减少代码量

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
MVC只是将分管不同功能的逻辑代码进行了隔离,增强了可维护和可扩展性,增强代码复用性,因此可以减少代码重复。但是不保证减少代码量,多层次的调用模式还有可能增加代码量

一般来讲,使用设计模式都会增加代码量。

在这里插入图片描述
283 有以下一个对象,将此对象序列化为文件,并在另外一个JVM中读取文件,进行反序列化,请问此时读出的Data0bject对象中的word和i的值分别为:(D)

public class DataObject implements Serializable{
    private static int i=0;
    private String word=" ";
    public void setWord(String word){
        this.word=word;
    }
    public void setI(int i){
        Data0bject. i=I;
     }
}

创建一个如下方式的DataObject:

DataObject object=new Data0bject ( );
object. setWord("123");
object. setI(2); 

D,序列化保存的是对象的状态,静态变量属于类的状态,因此,序列化并不保存静态变量。所以i是没有改变的

序列化的是对象,不是类,类变量不会被序列化

Java在序列化时不会实例化static变量和transient修饰的变量,因为static代表类的成员,transient代表对象的临时数据,被声明这两种类型的数据成员不能被序列化。

284以下代码段执行后的输出结果为©

public class Test {
public static void main(String args[]) {
int i = -5;
i =  ++(i++);
System.out.println(i);
}
}
-7

-3

编译错误

-5

答案是 编译错误。
这题编译错误在于这一句: i = ++(i++);
++( ) 括号里面必须是一个变量,而 i ++ 是一个字面量。

我的理解是:
1.先执行括号中的i++ 在执行i++的时候 Java会将i先存放到一个临时变量中去 并返回该临时变量的值(假设为temp)
2.所以 这句可以拆成 temp = i (值为-5) 并返回temp的值 然后 i自加1 此时 i 的值为-4 但是之后 执行就会出现问题 由于返回了temp的值 继续执行的表达式为 i = ++(-5); 单目运算符无法后跟一个字面量 所以在IDEA编辑器中提示Variable expected(此处应为变量) 故选择C选项
我的理解是:
1.先执行括号中的i++ 在执行i++的时候 Java会将i先存放到一个临时变量中去 并返回该临时变量的值(假设为temp)
2.所以 这句可以拆成 temp = i (值为-5) 并返回temp的值 然后 i自加1 此时 i 的值为-4 但是之后 执行就会出现问题 由于返回了temp的值 继续执行的表达式为 i = ++(-5); 单目运算符无法后跟一个字面量 所以在IDEA编辑器中提示Variable expected(此处应为变量) 故选择C选项

java中的i++和++i在java语言层面上来看使用中间量机制,i=i++,i不变,i=++i相当于++i,而结合在一个语句里使用则会报错,因为++后应该跟变量。同理,i=(++i)++也是不对的。

285Java类Demo中存在方法func0、func1、func2、func3和func4,请问该方法中,哪些是不合法的定义?(AD )

public class Demo{
  float func0()
  {
    byte i=1;
    return i;
  }
  float func1()
  {
    int i=1;
    return;
  }
  float func2()
  {
    short i=2;
    return i;
  }
  float func3()
  {
    long i=3;
    return i;
  }
  float func4()
  {
    double i=4;
    return i;
  }
}
func1

func2

func3

func4

这道题考的是数据类型转换问题。由大到小需要强制转换,由小到大不需要。
A:return; 没有返回值,错误
B:short → float 无须强制转换,正确

C:long → float 无须强制转换(这个最选项容易出错),正确。

float占4个字节为什么比long占8个字节大呢,因为底层的实现方式不同。
浮点数的32位并不是简单直接表示大小,而是按照一定标准分配的。
第1位,符号位,即S
接下来8位,指数域,即E。
剩下23位,小数域,即M,取值范围为[1 ,2 ) 或[0 , 1)
然后按照公式: V=(-1)^s * M * 2^E
也就是说浮点数在内存中的32位不是简单地转换为十进制,而是通过公式来计算而来,通过这个公式虽然,只有4个字节,但浮点数最大值要比长整型的范围要大。

D:double → float 没有强制转换,错误。

long到float不用强转,因为float表示的范围确实比long表示的范围大,虽然它只占4个字节,而long占8个字节
数据类型的转换,分为自动转换和强制转换。自动转换是程序在执行过程中 “ 悄然 ” 进行的转换,不需要用户提前声明,一般是从位数低的类型向位数高的类型转换;强制类型转换则必须在代码中声明,转换顺序不受限制。

自动数据类型转换

自动转换按从低到高的顺序转换。不同类型数据间的优先关系如下:
低 ---------------------------------------------> 高
byte,short,char-> int -> long -> float -> double
运算中,不同类型的数据先转化为同一类型,然后进行运算,转换规则如下:
在这里插入图片描述 强制数据类型转换
强制转换的格式是在需要转型的数据前加上 “( )” ,然后在括号内加入需要转化的数据类型。有的数据经过转型运算后,精度会丢失,而有的会更加精确

286 有关线程的叙述正确的是(CD)

可以获得对任何对象的互斥锁定

通过继承Thread类或实现Runnable接口,可以获得对类中方法的互斥锁定

线程通过使用synchronized关键字可获得对象的互斥锁定

线程调度算法是平台独立的

线程的互斥锁机制:synchronized,lock,condition
Ref:http://blog.csdn.net/vking_wang/article/details/9952063

A,“任何对象”锁定,太绝对了,你能锁住你没有权限访问的对象吗?
B,前半句话讲的是创建线程的方式,后半句讲的是锁定,驴头不对马嘴。
C,正确。
D,线程调度分为协同式调度和抢占式调度,Java使用的是抢占式调度,也就是每个线程将由操作系统来分配执行时间,线程的切换不由线程本身来决定(协同式调度)。这就是平***立的原因。
以上,选CD

线程通过调用对象的synchronized方法可获得对象的互斥锁定。
2. 线程调度算法是平***立的。
3. 通过继承Thread类或实现Runnable接口来创建线程。

287以下哪个接口的定义是正确的?(D )

interface  B
{  void print()  {  } ;}

interface  B
{ static void print() ;}

abstract  interface  B  extends  A1, A2  //A1、A2为已定义的接口
{ abstract  void  print(){  };}

interface  B
 {  void  print();}

A,接口中方法的默认修饰符时public abstract,抽象方法可是没有方法体的,没有大括号{}
B,JDK8中,接口中的方法可以被default和static修饰,但是!!!被修饰的方法必须有方法体。
C,注意一下,接口是可以多继承的。整个没毛病,和A选项一样,抽象方法不能有方法体

jdk1.8新特性,接口中的方法可以用static,default修饰,且二者修饰的方法要求有方法体

接口中的方法默认为public abstract,属性默认为public static final。接口中的方法不能有实现,Java中类只支持单继承,而接口可以支持多继承。A、C中方法不能有方法体,B中方法前不能有static

288以下程序的运行结果是:( C )

TreeSet<Integer> set = new TreeSet<Integer>();
 TreeSet<Integer> subSet = new TreeSet<Integer>();
 for(int i=606;i<613;i++){
 if(i%2==0){
 set.add(i);
 }
 }
 subSet = (TreeSet)set.subSet(608,true,611,true);
 set.add(629);
 System.out.println(set+" "+subSet);
编译失败

发生运行时异常

[606, 608, 610, 612, 629] [608, 610]

[606, 608, 610, 612, 629] [608, 610,629]

subList 得到的引用是指向原数据的,对subList修改会修改原List。
subSet也一样,和subList都是返回元数据结构的一个视图。
比如,最后添加的是609,不是629的话,结果是:
[606, 608, 609, 610, 612] [608, 609, 610]

subset(form,true,to,true)是Treeset的非静态方法,该方法返回从form元素到to元素的一个set集合,两个boolean类型是确认是否包含边境值用的。

 //结果为:[606, 608, 610, 612, 629] [608, 610]  ,选C
public class Test3 {
        public static void main(String argv[]){
            TreeSet<Integer> set = new TreeSet<Integer>();
            TreeSet<Integer> subSet = new TreeSet<Integer>();
             for(int i=606;i<613;i++){
                 if(i%2==0){
                     set.add(i);//将i%2==0成立的i值,存放到set集合里
                         }
                 }//满足条件的参数最终值为612,此时set数组组成为:[606, 608, 610, 612]             
             /**subSet(Integer, boolean, Integer, boolean)
              * subset(form,true,to,true)     表示取值范围从form值到to的值
              * set.subSet(form,true,to,true) 表示从set数组取出范围在form值到to值的值
              * set.subSet(form,false,to,true) 表示从set数组取出数组最小值到to值的值
              * set.subSet(form,true,to,false) 表示从set数组取出范围在form值到数组最大值的值
              * */       
             subSet = (TreeSet)set.subSet(608,true,611,true);//[608, 610]
             set.add(629);//此时set数组组成为:[606, 608, 610, 612, 629]
             System.out.println(set+" "+subSet);
        }
    }

289 off-heap是指那种内存(B)

JVM GC能管理的内存

JVM进程管理的内存

在JVM老年代内存区

在JVM新生代内存

off-heap叫做堆外内存,将你的对象从堆中脱离出来序列化,然后存储在一大块内存中,这就像它存储到磁盘上一样,但它仍然在RAM中。对象在这种状态下不能直接使用,它们必须首先反序列化,也不受垃圾收集。序列化和反序列化将会影响部分性能(所以可以考虑使用FST-serialization)使用堆外内存能够降低GC导致的暂停。堆外内存不受垃圾收集器管理,也不属于老年代,新生代。

1)程序计数器

几乎不占有内存。用于取下一条执行的指令。

2)堆

所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx和-Xms来控制。堆被划分为新生代和旧生

代,新生代又被进一步划分为Eden和Survivor区,最后Survivor由FromSpace和ToSpace组成,结构图如下所示:

新生代。新建的对象都是用新生代分配内存,Eden空间不足的时候,会把存活的对象转移到Survivor中,新生代大小可以由-Xmn来控制,也可以用-XX:SurvivorRatio来控制Eden和Survivor的比例旧生代。用于存放新生代中经过

多次垃圾回收仍然存活的对象。

在这里插入图片描述3)栈

每个线程执行每个方法的时候都会在栈中申请一个栈帧,每个栈帧包括局部变量区和操作数栈,用于存放此次方法调用过程中的临时变量、参数和中间结果。

4)本地方法栈

用于支持native方法的执行,存储了每个native方法调用的状态

5)方法区

存放了要加载的类信息、静态变量、final类型的常量、属性和方法信息。JVM用永久代(PermanetGeneration)

来存放方法区,(在JDK的HotSpot虚拟机中,可以认为方法区就是永久代,但是在其他类型的虚拟机中,没有永久代

的概念,有关信息可以看周志明的书)可通过-XX:PermSize和-XX:MaxPermSize来指定最小值和最大值。

堆外内存意味着把内存对象分配在Java虚拟机的堆以外的内存,这些内存直接受操作系统管理(而不是虚拟机)。不属于老年代和新生代。
JVM GC回收堆和方法区,排除法选择 B
这样做的结果就是能保持一个较小的堆,以减少垃圾收集对应用的影响。使用堆外内存能够降低GC导致的暂停。

堆外内存,它和内存池一样,也能缩短垃圾回收时间,但是它适用的对象和内存池完全相反。内存池往往适用于生命期较短的可变对象,而生命期中等或较长的对象,正是堆外内存要解决的。堆外内存有以下特点:

对于大内存有良好的伸缩性
对垃圾回收停顿的改善可以明显感觉到
在进程间可以共享,减少虚拟机间的复制
当然堆外内存也有它自己的问题,最大的问题就是你的数据结构变得不那么直观,如果数据结构比较复杂,就要对它进行串行化(serialization),而串行化本身也会影响性能。另一个问题是由于你可以使用更大的内存,你可能开始担心虚拟内存(即硬盘)的速度对你的影响了。

堆外内存(off-heap)、堆内内存(on-heap)

290 在各自最优条件下,对N个数进行排序,哪个算法复杂度最低的是? (A)

插入排序

快速排序

堆排序

归并排序

插入排序:最佳O(N)
快速排序:最佳O(NlogN)
堆 排序:最佳O(NlogN)
归并排序:最佳O(NlogN)
因此选择插入排序。

对于插入排序,最优条件就是本身有序,所以循环一遍就好了

在这里插入图片描述
291 在Java中,HashMap中是用哪些方法来解决哈希冲突的?©

开放地址法

二次哈希法

链地址法

建立一个公共溢出区

以上方法都是解决哈希填冲突的策略,但是在java.util.HashMap中,总体来说是使用的链地址法来解决冲突的。
当然了,使用链地址***导致get的效率从o(1)降至o(n),所以在Java8中,使用的是平衡树来解决提高效率的。
决哈希冲突常用的两种方法是:开放定址法和链地址法
开放定址法:当冲突发生时,使用某种探查(亦称探测)技术在散列表中形成一个探查(测)序列。沿此序列逐个单元地查找,直到找到给定 的关键字,或者碰到一个开放的地址(即该地址单元为空)为止(若要插入,在探查到开放的地址,则可将待插入的新结点存人该地址单元)。查找时探查到开放的 地址则表明表中无待查的关键字,即查找失败。
链地址法:将所有关键字为同义词的结点链接在同一个单链表中。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数 组T[0…m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。

常见的哈希冲突解决方法:
1.开放地址法
2.链地址法(拉链法)
3.再散列
4.建立一个公共溢出区

这里只说了hashmap

292 设m和都是int类型,那么以下for循环语句的执行情况是( D)

for (m = 0, n = -1; n = 0; m++, n++)
n++;
循环体一次也不执行 循环体执行一次 是无限循环 有限次循环 循环结束判断条件不合法 运行出错

循环体执行一次 是无限循环

有限次循环

循环结束判断条件不合法

==for 循环的结束判定条件 是 boolean型 n = 0 是 int 类型 会有编译异常 ==

上来就是一个D我也是醉了
n = 0不是boolean型的所以语法错误
for(初始化语句;判断条件语句;控制条件语句){
循环体语句;
}
293 关于下面的程序Test.java说法正确的是( D )。

public class Test {
    static String x="1";
    static int y=1;
    public static void main(String args[]) {
        static int z=2;
        System.out.println(x+y+z);
    }
}
3

112

13

程序有编译错误

被static修饰的变量称为静态变量,静态变量属于整个类,而局部变量属于方法,只在该方法内有效,所以static不能修饰局部变量 ,static 修饰的变量属于类,只能定义在类中方法外

294 以下类型为Final类型的为(BC)

HashMap

StringBuffer

String

Hashtable

关于为什么StringBuffer是final值却可以改变这个,想起之前做过的笔记:final修饰的成员变量为基本数据类型时,赋值后无法改变。当final修饰的为引用变量时,在赋值后其指向地址无法改变,但对象内容可以改变。感觉应该有一定关系 另外,对于该题,final修饰类只是限定类不可被继承,而非限定了其对象是否可变,
StringBuilder , StringBuffer ,String 都是 final 的,但是为什么StringBuilder , StringBuffer可以进行修改呢,因为不可变包括的是,引用不可变以及对象不可变,而这三个都是属于引用不可变,(也就是地址不要变,里面的内容随心所欲),而StringBuilder , StringBuffer 中都包含右append方法,可对对象中的内容进行增加。
而String a=“123”+new String(“456”);实际上底层是用了一个StringBuffer 进行append;
通过阅读源码可以知道,string与stringbuffer都是通过字符数组实现的。
其中string的字符数组是final修饰的,所以字符数组不可以修改。
stringbuffer的字符数组没有final修饰,所以字符数组可以修改。
string与stringbuffer都是final修饰,只是限制他们所存储的引用地址不可修改。
至于地址所指内容能不能修改,则需要看字符数组可不可以修改。
295 关于下面这段Java程序,哪些描述是正确的:(C )

public class ThreadTest extends Thread {
public void run() {
System.out.println("In run");
yield();
System.out.println("Leaving run");
}
public static void main(String []argv) {
(new ThreadTest()).start();
}
}
```java
程序运行输出只有In run

程序运行输出只有Leaving run

程序运行输出先有In run后有Leaving run

程序运行输出先有Leaving run后有In run

程序没有任何输出就退出了

程序将被挂起,只能强制退出

Thread.yield()方法作用是:暂停当前正在执行的线程对象,并执行其他线程。

yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。

结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。

yield是线程礼让, 没有多个线程,不需要礼让

296 如果一个list初始化为{5,3,1},执行以下代码后,其结果为(B)?

nums.add(6);
nums.add(0,4);
nums.remove(1);
[5, 3, 1, 6]

[4, 3, 1, 6]

[4, 3, 6]

[5, 3, 6]

list{5,3,1}
nums.add(6); //往后边加一个6,{5,3,1,6}
nums.add(0,4);//往下标为0的数加一个4,{4,5,3,1,6}
nums.remove(1); // 移除下标为1 的元素,{4,3,1,6}

297关于抽象类与最终类,下列说法错误的是? D

抽象类能被继承,最终类只能被实例化。

抽象类和最终类都可以被声明使用

抽象类中可以没有抽象方法,最终类中可以没有最终方法

抽象类和最终类被继承时,方法可以被子类覆盖

最终类就是被final修饰的类,最终方法就是被final修饰的方法。最终类不能被继承,最终方法不能被重写

对于选项B. 抽象类和最终类都可以被声明使用。
这里只是说“声明”,并没有说“实例化”;如果只是声明是可以的,最常见的使用方式就是:
1、父类类型的引用指向子类的对象;
2、 接口类型的引用指向该接口的实现类的对象;
以上两种使用方式也就是所谓的“向上转型”。

1,抽象类中可以有抽象方法,也可以没有抽象方法。
2,抽象类当然可以被继承,因为它就是用来继承的,
3,继承抽象类,若有抽象方法,则子类必须将其抽象方法实现,
4,抽象类中的非抽象方法可以被重写。

最终类和抽象类正好相反
5,加上final的类就叫最终类,加上final的方法就叫最终方法,
6,最终类中可以有最终方法也可以没有
7,最终类不能有子类,最终方法不能被重写

298 关于访问权限,说法正确的是? (A )

类A和类B在同一包中,类B有个protected的方法testB,类A不是类B的子类(或子类的子类),类A可以访问类B的方法testB

类A和类B在同一包中,类B有个protected的方法testB,类A不是类B的子类(或子类的子类),类A不可以访问类B的方法testB

访问权限大小范围:public > 包权限 > protected > private

访问权限大小范围:public > 包权限 > private > protected

在这里插入图片描述
private 权限限于同一个类中; default 权限限于同一个包中,即包权限=default权限; protected权限限于同一个包中,以及不在同一个包中的子类 public 权限在不同包中都可以

在这里插入图片描述

**299 以下 b 的值是: byte b = (byte)129;(B) **

-126

-127

-128

-129

一、强制转换(主要涉及各个类型占几个字节,这里我只简单说一下byte型占一个字节,也就是8位,int型4个字节,32位);二、在计算机系统中,数值一律用补码来表示(存储)
正数:补码=反码=原码(当然以二进制形式表达)
129 int类型(4个字节)二进制: 00000000 00000000 00000000 10000001
强制转换byte型后,只有一个字节即 10000001(注意这里从二进制角度看,第一位是符号位,即求负数的补码接下来)
只要求出上面原码对应的补码就行了,然后再转换对应的int型数值(因为题干所给的答案都是比较int型)
10000001(原码) 对应的反码为1111 1110
又补码等于反码+1
即1111 1111 该二进制转换int型刚好是-127(1+2+4+8+16+32+64)

普及一下:正数原码,反码,补码相同
负数反码除了符号位不变,其他位取反,补码=反码+1;

300 下面几个关于Java里queue的说法哪些是正确的(AC)?

LinkedBlockingQueue是一个可选有界队列,不允许null值

PriorityQueue,LinkedBlockingQueue都是线程不安全的

PriorityQueue是一个无界队列,不允许null值,入队和出队的时间复杂度是O(log(n))

PriorityQueue,ConcurrentLinkedQueue都遵循FIFO原则

答案解析
A、LinkedBlockingQueue是一个基于节点链接的可选是否有界的阻塞队列,不允许null值。
B、LinkedBlockingQueue是一个线程安全的阻塞队列,实现了先进先出等特性。
C、PriorityQueue是一个***队列,不允许null值,入队和出队的时间复杂度是O(log(n))。
D、PriorityQueue是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素。ConcurrentLinkedQueue是一个基于链接节点的***线程安全队列,该队列的元素遵循FIFO原则。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值