2021年08月10日 java2

考点1:构造方法

以下不属于构造方法特征的是()

  • A 构造方法名与类名相同
  • B 构造方法不返回任何值,也没有返回类型
  • C 构造方法在创建对象时调用,其他地方不能显式地直接调用
  • D 每一个类只能有一个构造方法

解析

显示答案/隐藏答案正确答案: D

考点2:类定义

有以下程序片段,下列哪个选项不能插入到第一行 。( )。

1
2
3
4
1.
2. public class A{
3. //do sth
4. }
  • A public class MainClass{ }
  • B package mine;
  • C class ANotherClass{ }
  • D import java.util.*;

解析

显示答案/隐藏答案正确答案: A

Java一个源程序只能有一个public类存在,且类名与文件名相同。
Java程序是从main方法开始执行的,public为类加载器提供入口,然后找到public类中的main方法开始执行。
如果存在多个public类,程序将不知道该从哪里执行。
注意,内部类可以是 public的,因为内部类是作为外部类的成员存在的

考点3:可信数据

后端获取数据,向前端输出过程中,以下描述正确的是

  • A 对于前端过滤过的参数,属于可信数据,可以直接输出到前端页面
  • B 对于从数据库获得的数据,属于可信数据,可以直接输出到前端页面
  • C 对于从用户上传的Excel等文件解析出的数据,属于可信数据,可以直接输出到前端页面
  • D 其它选项都不属于可信数据,输出前应该采用信息安全部发布的XSSFilter做进行相应编码

解析

显示答案/隐藏答案正确答案: D

考点4:线程 线程执行体 run(),start(),join()方法

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

  • A start()
  • B join()
  • C run()
  • D synchronized()

解析

显示答案/隐藏答案正确答案: C

run()方法是用来定义这个线程在启动的时候需要做什么,但是,直接调用线程的run()方法只会执行一遍函数体,而不会开辟线程,必须使用star()来启动线程。

线程B.join()方法是停止当前正在运行的线程,先转去运行调用join()方法的线程B,直到线程B运行结束后。再返回运行当前线程。

考点5:抽象类 abstract,final,static关键字

以下关于 abstract 关键字的说法,正确的是()

  • A abstract 可以与final 并列修饰同一个类。
  • B abstract 类中不可以有private的成员。
  • C abstract 类中必须全部是abstract方法。
  • D abstract 方法必须在abstract类或接口中。

解析

显示答案/隐藏答案正确答案: D
  1. abstract类不能与final,static使用。final修饰方法,子类可以调用,但不能覆盖。
  2. 抽象类可以有private成员,但最好不要有private,因为私有和抽象放在一起,子类如果想重写父类的私有方法根本继承不过来,也就无法重写
  3. 抽象类中可以有非抽象方法
  4. 抽象类中可以都是非抽象的,但是抽象方法一定要在类和接口
  • abstract类是需要被继承使用的,所以它不能被final使用,所以A错,
  • 也可以有private属性,B错,
  • 也可以有普通方法 甚至所有都可以是普通方法,当然这样也就失去了abstract类的意义,C错,
  • interface属于特殊的abstract类,也是abstract类,所以D对
  1. abstract类不能使用final,static修饰。
    • abstract类就是要被继承实现。
    • final修饰的类不能被继承,所以abstract不能和final共同修饰一个类
      • final修饰方法,子类可以调用,但不能覆盖。
      • final修饰的变量不能修改,既是常量。
    • static修饰的类只能是内部类static不能修饰外部类
      • 抽象类是不能实例化的,即不能被分配内存;
    • static修饰的方法在类实例化之前就已经别分配了内存,这样一来矛盾就出现了。所以abstract不能和static共同修饰同一个类,在abstract类里面,可以不能定义static内部类
  2. 最好不要有private因为私有和抽象放在一起,子类如果想重写父类的私有方法根本继承不过来,也就无法重写 。但是抽象类中是可以有私有的成员。
  3. 抽象类中可以有非抽象方法
  4. 抽象类中可以都是非抽象的,但是抽象方法一定要在抽象类和接口中。普通类可以被实例化,而抽象方法本身不能被调用,如果普通类有抽象方法,那么该方法被调用就会出错。

static不能修饰外部类

1
2
3
static class A{

}

报错:

1
Illegal modifier for the class A; only public, abstract & final are permitted

外部类只能是public,abstract,或者final修饰

abstract和static不能共同修饰方法

1
2
3
public abstract class B {
abstract static void method();
}

报错:

1
The abstract method method in type B can only set a visibility modifier, one of public or protected

abstract方法只能被public或protected修饰

1
private abstract void method();

报错:

1
The abstract method method in type B can only set a visibility modifier, one of public or protected

考点6:

下面关于JAVA的垃圾回收机制,正确的是( )

  • A 当调用”System.gc()“来强制回收时,系统会立即回收垃圾
  • B 垃圾回收不能确定具体的回收时间
  • C 程序可明确地标识某个局部变量的引用不再被使用
  • D 程序可以显式地立即释放对象占有的内存

解析

显示答案/隐藏答案正确答案: B

java提供了一个系统级的线程,即垃圾回收器线程。用来对每一个分配出去的内存空间进行跟踪。当JVM空闲时,自动回收每块可能被回收的内存,GC是完全自动的,不能被强制执行。程序员最多只能用System.gc()来建议执行垃圾回收器回收内存,但是具体的回收时间,是不可知的。当对象的引用变量被赋值为null,可能被当成垃圾。

考点7:hibernate延迟加载

下面有个hibernate延迟加载,说法错误的是?

  • A Hibernate2延迟加载实现:a)实体对象 b)集合(Collection)
  • B Hibernate3 提供了属性的延迟加载功能
  • C get支持延迟加载,load不支持延迟加
  • D hibernate使用Java反射机制,而不是字节码增强程序来实现透明性

解析

显示答案/隐藏答案正确答案: C

Hibernate 中 get()和load() 的区别:

get是立即加载,load是延迟加载。
get()采用立即加载方式,当get()执行的时候会立即向数据库发出查询语句,如果没有对应的记录,返回null,而load()采用延迟加载,执行此方法的时候返回的是一个***,只有等真正使用该对象属性的时候,才会发出SQL语句进行查询,若没有,则出现异常ObjectNotFoundException

考点8:IO流支持Unicode的IO流

哪个类可用于处理Unicode?

  • A InputStreamReader
  • B BufferedReader
  • C Writer
  • D PipedInputStream

解析

显示答案/隐藏答案正确答案: A

InputStreamReader可以指定字符编码格式
InputStreamReader是转换流,将字节流转换成字符流。

BufferedReader只是起到了装饰的作用,就是不用每次都new一个数组了,增加了缓冲区,缓冲区有和没有都一样,只是读取的快慢不同,真正实现功能的是InputStreamReader

看API就知道了。
A、 InputStreanReader的构造函数:

方法 描述
InputStreamReader(InputStream in) Creates an InputStreamReader that uses the default charset.
InputStreamReader(InputStream in, String charsetName) Creates an InputStreamReader that uses the named charset.
InputStreamReader(InputStream in, Charset cs) Creates an InputStreamReader that uses the given charset.
InputStreamReader(InputStream in, CharsetDecoder dec) Creates an InputStreamReader that uses the given charset decoder.

B、BufferedReader的构造函数:

方法 描述
BufferedReader(Reader in) Creates a buffering character-input stream that uses a default-sized input buffer.
BufferedReader(Reader in, int sz) Creates a buffering character-input stream that uses an input buffer of the specified size.

D、PipedInputStream的构造函数:

方法 描述
PipedInputStream() Creates a PipedInputStream so that it is not yet connected.
PipedInputStream(int pipeSize) Creates a PipedInputStream so that it is not yet connected and uses the specified pipe size for the pipe’s buffer.
PipedInputStream(PipedOutputStream src) Creates a PipedInputStream so that it is connected to the piped output stream src.
PipedInputStream(PipedOutputStream src, int pipeSize) Creates a PipedInputStream so that it is connected to the piped output stream src and uses the specified pipe size for the pipe’s buffer.

考点9:

以下代码定义了一个变量,如何输出这个变量的值?
这里有一张图片

1
<bean:define id="stringBean" value="helloWorld"/>
  • A <% String myBean = (String)pageContext.getAttribute("stringBean",PageContext.PAGE_SCOPE); %> <%=myBean%>
  • B <bean:write name="helloworld"/>
  • C <bean:write name="stringBean"/>
  • D <%=stringBean%>

解析

显示答案/隐藏答案正确答案: ACD

—————看完秒懂—————————

  • A选项:
    • 通过 pageContext(PageContext类的实例,提供对JSP页面所有对象以及命名空间的访问) 获取stringBean 的值,赋给 String 类型的变量 myBean,然后通过 Jsp 表达式 处理该值。
  • bean:define
    • 题目中的 Struts 的bean:define 标签定义了一个字符串变量 stringBean ,它的值为 helloworld。
  • bean:write
    • bean:write相当于 <%=request.getAttribute("something")%> 其中 something 是属性的名字。所以 B 错,C对。
  • D选项:
    • 通过Jsp 表达式 获取变量 stringBean 的值

考点10:

下面有关值类型和引用类型描述正确的是()?

  • A 值类型的变量赋值只是进行数据复制,创建一个同值的新对象,而引用类型变量赋值,仅仅是把对象的引用的指针赋值给变量,使它们共用一个内存地址。
  • B 值类型数据是在栈上分配内存空间,它的变量直接包含变量的实例,使用效率相对较高。而引用类型数据是分配在堆上,引用类型的变量通常包含一个指向实例的指针,变量通过指针来引用实例。
  • C 引用类型一般都具有继承性,但是值类型一般都是封装的,因此值类型不能作为其他任何类型的基类。
  • D 值类型变量的作用域主要是在栈上分配内存空间内,而引用类型变量作用域主要在分配的堆上。

解析

显示答案/隐藏答案正确答案: ABC

我的理解(有错麻烦大家指正,谢谢!)

值类型:基本数据类型(int、double、boolean ...)
引用类型:reference类型,通过它可以直接或间接的查找到对象在java堆中数据存放的起始地址或索引(对象在java堆中的哪个位置)

先来两个例子,变量的赋值在内存中是怎么样的:
先上一张运行时数据区的网图
局部变量表、操作数栈在虚拟机栈中

一:基本变量的赋值

public void method() {
int a = 1;
int b = a;
}

该方法的字节码:
0 iconst_1 // 将 int 型 1 推送至操作数栈栈顶
1 istore_1 // 将操作数栈栈顶 int 型值存入第二个本地变量
2 iload_1 // 将第二个int型本地变量推送至操作数栈顶
3 istore_2 // 将操作数栈栈顶 int 型值存入第三个本地变量
4 return // 方法返回

图片说明

二:基本变量的赋值

public void method2() {
Object a = new Object();
Object b = a;
}

该方法的字节码:
0 new #15 <java/lang/Object> // 创建一个对象,并将其引用压入栈顶
3 dup // 复制栈顶引用类型数据并将其值压入栈顶
4 invokespecial #1 <java/lang/Object.<init>> // 执行对象构造方法(使用了栈顶引用类型)
7 astore_1 // 将操作数栈栈顶引用类型数据值存入第二个本地变量 a
8 aload_1 // 将第二个引用类型本地变量推送至栈顶
9 astore_2 // 将栈顶引用类型数值存入第三个本地变量b
10 return // 方法返回

图片说明

再看选项

  • A(✔)值类型的和引用类型的变量赋值就像上面一样,先把局部变量表中 a 的数值存入操作数栈,再取出来放入 b,不过区别在于:

    • 前者在局部变量表中存放的数值是真正意义上的 a 代表的数据,所以说赋值操作是“复制(iload_1、istore_2)”一份出来再给 b
    • 后者在局部变量表中存放的数值不是真正意义上 a 代表的数据,只是指向堆中对象的指针(指向 a 真正代表的数据)。赋值操作只是把 a 中数值即指针复制给 b ,堆中a代表正真的数据即对象(0x11)并没有被复制
  • B(✔)

    • "值类型数据是在栈(指虚拟机栈)上分配内存空间,它的变量直接包含变量的实例,使用效率相对较高。" :局部变量表(在虚拟机栈中)中存放数值的就是真正意义上的数据,不用访问堆,效率较高
    • “而引用类型数据是分配在上,引用类型的变量通常包含一个指向实例(指向堆中对象)的指针,变量通过指针来引用实例。” :局部变量表中存放的数值是指向中数据(对象)的指针
  • C(✔):类可以继承,基本数据类型不能继承

  • D(X):“值类型变量的作用域主要是在栈上分配内存空间内”:如果是跟上诉一致在方法内定义的基本变量,它的作用域就在栈中;如果是在类中定义的成员变量例如 Class A 中有成员变量 int val,这个类的实例在堆中,那么 val 作用域也在堆中


题外话:操作数栈深度在编译期就已经决定