java|学习记录(JAVA 基础知识错题记录①)

【java|学习记录(JAVA 基础知识错题记录①)】若文章内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系博主删除。
本博客旨在记录错题,方便个人在线阅览,巩固 JAVA 基础知识
解析部分来自牛客网评论区、相关编程书籍、相关博客

牛客网.专项练习.编程语言.JAVA:https://www.nowcoder.com/exam/intelligent

目录
  • 题一:Interger 和 int
  • 题二:str.split()
  • 题三:内存回收
  • 题四:Java 标识符
  • 题五:interface
  • 题六:抽象类
  • 题七:线程的启动
  • 题八:JVM 基础知识
  • 题九:多线程和多进程
  • 题十:深堆和浅堆的问题
  • 题十一:静态分派问题
  • 题十二:Collection 接口
  • 题十三:Math.floor()
  • 知识补充

题一:Interger 和 int
Integer a = 1; Integer b = 1; Integer c = 500; Integer d = 500; System.out.print(a == b); System.out.print(c == d);

上述代码返回结果为:truefalse
https://www.nowcoder.com/questionTerminal/9aa8adae3a4e47ce819a5a34b9ec8bfe
https://blog.csdn.net/xingmengnihaoa/article/details/123995802
  1. Integer是 int 的包装类,int 则是 java 的一种基本数据类型
  2. Integer 变量必须实例化才能使用,int 变量不需要实例化
  3. Integer 的默认值是 null,而 int 的默认值是 0
  4. Integer 实际是一个对象的引用
    • 当 new 一个 Integer 对象时,实际是生成一个指针指向该对象;
    • 而 int 是基本数据类型,直接存储数值
  5. 在使用 Integer 时,对于 -128 到 127 之间的数,会进行缓存。
    • 例如:Integer i1 = 127 时,会将 127 进行缓存
    • 下次再写 Integer i2 = 127 时,就会直接从缓存中取,不会新 new 一个 Integer
    • 所以 i1i2== 进行比较时,会为 true。
  6. 自动拆箱和装箱(java 提供了自动拆装箱)
    • 装箱:把基本数据类型装换为对应的包装类类型
    • 拆箱:把包装类类型装换为对应的基本数据类型
    • 注意:在使用包装类数据时,如果做操作,最好先判断是否为 null
    • 推荐:只要是对象,在使用前就必须进行不为 null 的判断
题二:str.split()
String str = ""; System.out.print(str.split(",").length);

输出结果是 1
https://www.nowcoder.com/questionTerminal/29498beafbcc440f972644ddf1c1f9ed
  • str.split();
  • split() 方法根据分割符将输入的字符串断开成字符串对象数组
  • 若 str 字符串中找不到分隔符,则把整个 str 字符串放入字符串数组的第一个元素。
  • 因此 str.split(",").length = 1
题三:内存回收 下列哪些语句关于内存回收的说明是正确的? ( )
  • A.程序员必须创建一个线程来释放内存
  • B.内存回收程序负责释放无用内存
  • C.内存回收程序允许程序员直接释放内存
  • D.内存回收程序可以在指定的时间释放内存对象
答案是 B
https://www.nowcoder.com/questionTerminal/c8435ed863a14f84afc3f32d8f1e28bf
  • JVM 一旦启动,就会创建一个守护线程来监测是否需要有对象内存被释放
  • 程序员无法释放内存,程序员最多是使用 System.gc()Runtime.getRuntime().gc() 通知系统释放内存,但不能保证一定释放
  • 系统释放内存时间是不确定的,会根据当前程序的内存使用情况而定。
java|学习记录(JAVA 基础知识错题记录①)
文章图片

题四:Java 标识符 此处就不贴题了
https://www.nowcoder.com/questionTerminal/e8898ef5492d461d8fa881a93ed2fabb
  • 标识符由 26 个英文字符大小写(a ~ z,A ~ Z)、数字(0~9)、下划线(_)和美元符号($)组成;
  • 不能以数字开头,不能是关键字;
  • 严格区分大小写;
  • 标识符的可以为任意长度
题五:interface 以下哪个接口的定义是正确的?( )
  • A.interface B { void print() { } ; }
  • B.interface B { static void print() ; }
  • C.abstract interface B extends A1, A2 { abstract void print(){ }; } // A1、A2为已定义的接口
  • D.interface B { void print(); }
答案是 D
https://www.nowcoder.com/questionTerminal/abc2b6ccafa24be6ae3450880f4ede2b
  • A 选项:接口中方法默认被 public abstract 修饰,抽象方法不可以有方法体。A 错误。
  • B 选项:JDK8 中,接口中的方法可以被 defaultstatic 修饰,但被修饰的方法必须有方法体。B 错误。
  • C 选项:接口的确是可以继承的,但 C 选项错误的原因和继承没关系。它错在抽象方法不可以有方法体。
  • 接口中的方法默认为前面带有 public abstract 修饰,属性默认为前面带有 public static final 修饰
题六:抽象类 选项中哪一行代码可以替换 //add code here 而不产生编译错误
public abstract class MyClass { public int constInt = 5; //add code here public void method() { } }

  • A.public abstract void method(int a);
  • B.consInt = constInt+5;
  • C.public int method();
  • D.public abstract void anotherMethod(){}
答案是 A
https://www.nowcoder.com/questionTerminal/95c39a3154b64c9db3c2a43805a731d3
  • A 是抽象方法,抽象类可以包含抽象方法,也可以不包含,实现重载。(√)
  • B 在类中定义成员和方法,不能直接进行运算,可以写在代码块 {} 或者静态代码块中 static{} 中(×)
  • C 与第四行想要构成重载,二者区别是返回类型,但是返回类型不能作为重载的依据(×)
  • D 有方法体的不能作为抽象函数(×)
题七:线程的启动 下列程序的运行结果
public static void main(String args[]) { Thread t = new Thread() { public void run() { pong(); } }; t.run(); System.out.print("ping"); }static void pong() { System.out.print("pong"); }

输出结果:pongping
https://www.nowcoder.com/questionTerminal/912ae73df15d436dae99d1c61d408d01
  • 这里需要注意 Threadstartrun 方法
  • start 方法才能真正启动线程,此时线程会处于就绪状态,一旦得到时间片,则会调用线程的 run 方法进入运行状态。
  • run 方法只是普通方法,如果直接调用 run 方法,程序只会按照顺序执行主线程这一个线程。
  • 如果第 7 行换成 t.start() 方法,输出结果就不确定了
  • 因为 t.start() 后,线程变为就绪状态,什么时候开始执行时不确定的,可能是主程序先继续执行,也可能是新线程先执行。
  • 不过该主方法中就一条简单的语句:System.out.print("ping"); ,出现 pongping 的概率是极低的
  • 在主方法中使用 sleep() 方法,就有希望得到 pingpong 的结果
题八:JVM 基础知识 下列 Java 代码中的变量 a、b、c 分别在内存的____存储区存放。
class A { private String a = “aa”; public boolean methodB() { String b = “bb”; final String c = “cc”; } }

答案:堆区、栈区、栈区
https://www.nowcoder.com/questionTerminal/51123ddacab84a158e121bc5fe3917eb
  • a 是类中的成员变量,存放在堆区
  • b、c 都是方法中的局部变量,存放在栈区
  • 常量池:未经 new 的常量
  • 堆区:成员变量的引用,new 出来的变量
  • 栈区:局部变量的引用
  • 成员变量的引用在堆区,是因为成员变量的所属对象在堆区,所以它也在堆区。
  • 局部变量的引用在栈区,是因为局部变量不属于某一个对象,在被调用时才被加载,所以在栈区。
  • a 为成员变量的引用,b 为局部变量的引用,c 为局部变量的引用
题九:多线程和多进程 关于多线程和多进程,下面描述正确的是()
  • A.多进程里,子进程可获得父进程的所有堆和栈的数据;而线程会与同进程的其他线程共享数据,拥有自己的栈空间。
  • B.线程因为有自己的独立栈空间且共享数据,所有执行的开销相对较大,同时不利于资源管理和保护。
  • C.线程的通信速度更快,切换更快,因为他们在同一地址空间内。
  • D.一个线程可以属于多个进程。
答案是 A C
https://www.nowcoder.com/questionTerminal/fbe0cb97dcff4df5bf849d15cbe29e64
  • A.子进程得到的是除了代码段是与父进程共享以外,其他所有的都是得到父进程的一个副本
    • 子进程的所有资源都继承父进程,得到父进程资源的副本
    • 子进程可获得父进程的所有堆和栈的数据,但二者并不共享地址空间。
    • 两个是单独的进程,继承了以后二者就没有什么关联了,子进程单独运行
    • 进程的线程之间共享由进程获得的资源,但线程拥有属于自己的一小部分资源,就是栈空间,保存其运行状态和局部自动变量的。
  • B.线程之间共享进程获得的数据资源,所以开销小,但不利于资源的管理和保护;而进程执行开销大,但是能够很好的进行资源管理和保护。
  • C.线程的通信速度更快,切换更快,因为他们共享同一进程的地址空间。
  • D.一个进程可以有多个线程,线程是进程的一个实体,是CPU调度的基本单位。
题十:深堆和浅堆的问题 下面哪些描述是正确的( )
public class Test { public static class A { private B ref; public void setB(B b) { ref = b; } } public static Class B { private A ref; public void setA(A a) { ref = a; } } public static void main(String args[]) { … start(); … } public static void start() { A a = new A(); B b = new B(); a.setB(b); b = null; // a = null; … } }

  • A.b = null 执行后 b 可以被垃圾回收
  • B.a = null 执行后 b 可以被垃圾回收
  • C.a = null 执行后 a 可以被垃圾回收
  • D.a,b 必须在整个程序结束后才能被垃圾回收
  • E.类 A 和类 B 在设计上有循环引用,会导致内存泄露
  • F.a, b 必须在 start 方法执行完毕才能被垃圾回收
答案:B C
https://www.nowcoder.com/questionTerminal/b6bdeb342f1745f38e067ba7f78b6696
  • b = null 时,B 对象还被A对象引用着,不能别回收。
  • a = null 时,b 在之前已经为空,A 对象可以被回收。此时,B 对象不被引用了也可以被回收了
java|学习记录(JAVA 基础知识错题记录①)
文章图片

题十一:静态分派问题
import java.util.*; public class Test_2 {public static void main(String[] args) { Collection[] collections = {new HashSet(), new ArrayList(), new HashMap().values()}; Super subToSuper = new Sub(); for (Collection collection : collections) { System.out.println(subToSuper.getType(collection)); } }abstract static class Super { public static String getType(Collection collection) { return "Super: collection"; }public static String getType(List list) { return "Super:list"; }public String getType(ArrayList list) { return "Super:arrayList"; }public static String getType(Set set) { return "Super:set"; }public String getType(HashSet set) { return "Super:hashSet"; } }static class Sub extends Super { public static String getType(Collection collection) { return "Sub"; } } }

输出结果
Super: collection Super: collection Super: collection

https://www.nowcoder.com/questionTerminal/5dbdf7b89d9a4c27908a8c5c1e88c2fe
  • 考察点1:重载静态多分派——根据传入重载方法的参数类型,选择更加合适的一个重载方法
  • 考察点2:static 方法不能被子类覆写
    • 在子类中定义了和父类完全相同的 static 方法,则父类的 static 方法被隐藏
    • Son.staticmethod()new >Son().staticmethod() 都是调用的子类的 static方法
    • 如果是 Father.staticmethod() 或者 Father f = new Son(); f.staticmethod() 调用的都是父类的 static 方法。
  • 考察点3:此题如果都不是 static 方法,则最终会调用子类的 getType,输出 Sub Sub Sub
题十二:Collection 接口 此处就不贴题了
https://www.nowcoder.com/questionTerminal/03162f63b91545a6ac4cbd9c51cfadee
java|学习记录(JAVA 基础知识错题记录①)
文章图片

题十三:Math.floor() 问题:Math.floor(-8.5) 的值是?
答案是:(double)-9.0
https://www.nowcoder.com/questionTerminal/6a7a47502af94cb98d4e005ddaf35f33
  • Math.floor():表示向下取整,返回 double 类型 (floor—地板)
  • Math.ceil() :表示向上取整,返回 double 类型 (ceil—天花板)
  • Math.round():四舍五入。如果传入的是 double 类型,则返回 long;如果是 float 类型,则返回 int
知识补充 题目没错,但也不确定的知识
https://www.nowcoder.com/questionTerminal/00c765fa0b4744e3b5ba67634c50e154
Serializable 接口是专门提供给类实现序列化用的。要实现序列化对象必须要实现 Serializable 接口
https://www.nowcoder.com/questionTerminal/68c6c63ad0d444f481552a81fd769f2b
CopyOnWriteArrayList
  • 适用于写少读多的并发场景
ReadWriteLock
  • 即为读写锁,他要求写与写之间互斥,读与写之间互斥,读与读之间可以并发执行。在读多写少的情况下可以提高效率
ConcurrentHashMap
  • 是同步的 HashMap,读写都加锁
volatile
  • 只保证多线程操作的可见性,不保证原子性
https://www.nowcoder.com/questionTerminal/76696627939c46018092e56f7bf38293
方法的重写(override)两同两小一大原则
  • 方法名相同,参数类型相同
  • 子类返回类型小于等于父类方法返回类型,
  • 子类抛出异常小于等于父类方法抛出异常,
  • 子类访问权限大于等于父类方法访问权限。
https://www.nowcoder.com/questionTerminal/d9f28e29630e421cb954c13dfef34696
byte[] String.getBytes(String charsetName);
  • 得到的是以 charsetName 编码得到的 byte 数组;
String 的构造函数有:String (byte[] bytes, String charsetName);
https://www.nowcoder.com/questionTerminal/48db39d722894c08907a8f613858672e
  1. 堆区(heap):用于存放所有对象,是线程共享的(注:数组也属于对象)
  2. 栈区(stack):用于存放基本数据类型的数据和对象的引用,是线程私有的(分为:虚拟机栈和本地方法栈)
  3. 方法区(method):用于存放类信息、常量、静态变量、编译后的字节码等,是线程共享的(也被称为非堆,即 None-Heap
方法调用时,会创建栈帧在栈中,调用完是程序自动出栈释放,而不是 gc 释放
Java 的垃圾回收器(GC)主要针对堆区
https://www.nowcoder.com/questionTerminal/7c4934c90ab94c3c9f415815c491b40a
执行顺序,静态代码块先于主方法执行,静态代码块之间遵从代码顺序执行。
https://www.nowcoder.com/questionTerminal/38678bdcb70043cdbf9fbb987e713d3d
接口体现的是一种规范和实现分离的设计哲学
  • 代码编写过程中充分利用接口可以很大程度的降低程序各个模块之间的耦合
  • 从而提高系统的可扩展性和可维护性。
  • 基于这一原则,很多软件架构更提倡面向接口编程而不是实现类编程。
接口和抽象类都可以被声明使用(抽象类需要子类继承使用,接口需要被实现类继承使用)
接口没有构造方法,不能被实例化。
抽象类到底能不能被实例化是初学者很容易犯的错误
  • 抽象类确实有构造方法,但这个构造方法是用来被子类调用的,是用来初始化的
  • 因为任何子类都必须调用从 Object 开始的所有父亲的构造方法,才算完成初始化工作。
  • 如果抽象类被实例化,就会报错,编译无法通过。
  • 而接口里不包含构造器,自然无法被实例化。
https://www.nowcoder.com/questionTerminal/6047ef1f4cd345279a363580e6940547
  1. throws 出现在方法头,throw 出现在方法体
  2. throws 表示出现异常的一种可能性,并不一定会发生异常;throw 则是抛出了异常,执行 throw 则一定抛出了某种异常。
  3. 两者都是消极的异常处理方式,只是抛出或者可能抛出异常,是不会由函数处理,真正的处理异常由它的上层调用处理。

    推荐阅读