java易错题锦集四

effective java

不要再构造方法中启动任何线程

g = new GameServer();
g.start();
  • 构造器无返回值,但是不能void修饰

字符串

String是包装类型吗?

答案: 不是
对应的基本类型和包装类如下表: 基本数据类型 包装类 byte Byte boolean Boolean short Short char Character int Integer long Long float Float double Double

statement

Statement 每次执行sql语句,数据库都要执行sql语句的编译 ,最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement.

PreparedStatement是预编译的,使用PreparedStatement有几个好处

a. 在执行可变参数的一条SQL时,PreparedStatement比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率要高。

b. 安全性好,有效防止Sql注入等问题。

c. 对于多次重复执行的语句,使用PreparedStament效率会更高一点,并且在这种情况下也比较适合使用batch;

d. 代码的可读性和可维护性。

CallableStatement接口扩展 PreparedStatement,用来调用存储过程,它提供了对输出和输入/输出参数的支持。CallableStatement 接口还具有对 PreparedStatement 接口提供的输入参数的支持。

Statement 对象用于将 SQL 语句发送到数据库中。
实际上有三种 Statement 对象,它们都作为在给定连接上执行 SQL语句的包容器:
Statement、
PreparedStatement(它从 Statement 继承而来)和
CallableStatement(它从 PreparedStatement 继承而来)。
它们都专用于发送特定类型的 SQL 语句:
Statement 对象用于执行不带参数的简单 SQL 语句;
PreparedStatement 对象用于执行带或不带 IN参数的预编译 SQL 语句;
CallableStatement 对象用于执行对数据库已存储过程的调用。
Statement 接口提供了执行语句和获取结果的基本方法。
PreparedStatement 接口添加了处理 IN 参数的方法;
而CallableStatement 添加了处理 OUT 参数的方法。

类之间关系

类之间存在以下几种常见的关系:
A。“USES-A”关系
B。“HAS-A”关系
C。“IS-A”关系

题2

2.
关于继承和实现说法正确的 是 ? (    )

A。类可以实现多个接口,接口可以继承(或扩展)多个接口
B。类可以实现多个接口,接口不能继承(或扩展)多个接口
C。类和接口都可以实现多个接口
D。类和接口都不可以实现多个接口

答案: A
接口中都不允许有实现 ,怎么实现接口

字符串

public class StringDemo{
    
    
  private static final String MESSAGE="taobao";
  public static void main(String [] args) {
    
    
    String a ="tao"+"bao";
    String b="tao";
    String c="bao";
    System.out.println(a==MESSAGE);
    System.out.println((b+c)==MESSAGE);
  }
}

解析:

答案:true false

基本数据类型

对于java类型变量char c,short s,float f,double d,表达式c*s+f+d的结果类型为()
A、float
B、char
C、short
D、double

解析:

答案:d
自动类型转换遵循下面的规则:
1.若参与运算的数据类型不同,则先转换成同一类型,然后进行运算。
2.转换按数据长度增加的方向进行,以保证精度不降低。例如int型和long型运算时,先把int量转成long型后再进行运算。
3.所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算。
4.char型和short型参与运算时,必须先转换成int型。
5.在赋值运算中,赋值号两边的数据类型不同时,需要把右边表达式的类型将转换为左边变量的类型。如果右边表达式的数据类型长度比左边长时,将丢失一部分数据,这样会降低精度。
下图表示了类型自动转换的规则:

低级向高级是隐式类型转换,高级向低级必须强制类型转换,byte<char<short<int<long<float<double

值传递

下面代码输出什么

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
可以改变参数指向对象的值,但是不会改变参数指向的对象。

因为second(v, i);是将v指向的地址传递给方法内的临时变量v,使其指向传递外部的那个对象,因此,在v = val;中只是将改变此方法中临时变量的指向,不会影响外部的v。而v.i = 20;则是修改指向的对象的变量的值。
原因就是因为second中的v和first中的v是存在栈中的,而栈是私有的,当线程执行一个方法的时候会有一个栈帧入栈,简单说second中的v在1号栈帧中,first中的v在2号栈帧中,在second方法执行v = val;这一步骤之前,这两个栈帧中的v都执行堆中的同一个对象,但是v = val;执行后仅仅是修改了2号栈帧中v的引用

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

这样更容易理解

方法头

非抽象类实现接口后,必须实现接口中的所有抽象方法,除了abstract外,方法头必须完全一致.

方法头指:修饰符+返回类型 +方法名(形参列表)
接口的访问权限:public,abstract
两同两小一大原则
返回值和参数列表相同
返回值类型小于等于父类的返回值类型
异常小于等于父类抛出异常
访问权限大于等于父类

下面哪个关键字可以用于Java的构造方法上?
Afinal
Bstatic
Csynchronized
Dnative
ENone of these.

解析:

构造方法不能被子类继承,所以用final修饰没有意义。构造方法用于创建一个新的对象,不能作为类的静态方法,所以用static修饰没有意义。此外,Java语言不支持native或synchronized的构造方法。
答案:E

java线程运行状态

在Java线程状态转换时,下列转换不可能发生的有()?

A。初始态->运行态
B。就绪态->运行态
C。阻塞态->运行态
D。运行态->就绪态

.wait()、sleep()、yield()的理解
1)wait()是Object的实例方法,在synchronized同步环境使用,作用当前对象,会释放对象锁,需要被唤醒。
2)sleep()是Thread的静态方法,不用在同步环境使用,作用当前线程,不释放锁。
3)yield()是Thread的静态方法,作用当前线程,释放当前线程持有的CPU资源,将CPU让给优先级不低于自己的线程用,调用后进入就绪状态。
参考链接:

简版图

简版扩展

完整版图片

java集合类


jvm

先来一道热身

下面哪种情况会导致持久区jvm堆内存溢出?
A 循环上万次的字符串处理
B 在一段代码内申请上百M甚至上G的内存
C 使用CGLib技术直接操作字节码运行,生成大量的动态类
D 不断创建对象

解析:
Java中堆内存分为两部分,分别是permantspace和heap space。permantspace(持久区)主要存放的是Java类定义信息,与垃圾收集器要收集的Java对象关系不大。持久代溢出通常由于持久代设置过小,动态加载了大量Java类,因此C选项正确。

heap space分为年轻代和年老代, 年老代常见的内存溢出原因有循环上万次的字符串处理、在一段代码内申请上百M甚至上G的内存和创建成千上万的对象,也就是题目中的ABD选项。

finallize

finalize在被JVM回收时会进行判断:1、如果此对象finalize未被执行过,则执行,并放置此对象到F-Queue中,此时,若在下次GC之前,重新与GC ROOTS建立引用连接,则对象"复活",下次GC时如果此对象又被GC,则直接进行回收,因为finalize只执行一次。2、如果此对象finalize已经执行过一次,则在GC时不执行finalize,直接回收
JVM将重写了finalize方法的对象放置于F-Queue队列,由一个优先级很低的Finalizer线程执行,为了防止对象的finalize方法执行缓慢,或者发生死循环。jvm不保证Finalizer线程执行完成。

判定一个对象 objA 是否可回收,至少要经历两次标记过程:

  1. 如果对象 objA 到 GC Roots 没有引用链,则进行第一次标记。
  2. 进行筛选,判断此对象是否有必要执行 finalize()方法:
    ① 如果对象 objA 没有重写 finalize()方法,或者 finalize() 方法已经被虚拟机调用过,则虚拟机视为 “没有必要执行”,objA 被判定为不可触及的。
    ② 如果对象 objA 重写了 finalize() 方法,且还未执行过,那么 objA 会被插入到 F-Queue 队列中,由一个虚拟机自动创建的、低优先级的Finalizer线程触发其 finalize() 方法执行。
    ③ finalize() 方法时对象逃脱的最后机会,稍后GC会对F-Queue队列中的对象进行第二次标记。如果objA在 finalize()方法中与引用链上的任何一个对象建立了联系,那么第二次标记时,objA会被移出 “即将回收” 集合。之后,对象会再次出现没有引用存在的情况。这个情况下,finalize 方法不会被再次调用,对象会直接编程不可触及的状态,也就是说,一个对象的 finalize 方法只会被调用一次。

再来一道热身

关于Java内存区域下列说法不正确的有哪些
A 程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的信号指示器,每个线程都需要一个独立的程序计数器.
B Java虚拟机栈描述的是java方法执行的内存模型,每个方法被执行的时候都会创建一个栈帧,用于存储局部变量表、类信息、动态链接等信息
C Java堆是java虚拟机所管理的内存中最大的一块,每个线程都拥有一块内存区域,所有的对象实例以及数组都在这里分配内存。
D 方法区是各个线程共享的内存区域,它用于存储已经被虚拟机加载的常量、即时编译器编译后的代码、静态变量等数据。

解析:

答案在下面的解析中

jvm虚拟机


A.程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的信号指示器(偏移地址),Java编译过程中产生的字节码有点类似编译原理的指令,程序计数器的内存空间存储的是当前执行的字节码的偏移地址,每一个线程都有一个独立的程序计数器(程序计数器的内存空间是线程私有的),因为当执行语句时,改变的是程序计数器的内存空间,因此它不会发生内存溢出 ,并且程序计数器是jvm虚拟机规范中唯一一个没有规定 OutOfMemoryError 异常 的区域;

B.java虚拟机栈:线程私有,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会床创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。 没有类信息,类信息是在方法区中

C.java堆:对于绝大多数应用来说,这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例和数组

D.方法区:属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

反射

反射

猜你喜欢

转载自blog.csdn.net/weixin_44154094/article/details/129089270