学习笔记——Java基础(三)

学习笔记——Java基础(三)

1、Java中的Exception和Error有什么区别?

答:Exception和Error的主要区别:

  • Exception是程序正常运行中预料到可能会出现的错误,并且应该被捕获并进行相应的处理,是一种异常现象。eg:空指针异常、数组越界、指定的类找不到、方法传递参数错误、数据类型转换错误。
  • Error是正常情况下不可能发生的错误,Error会导致JVM处于一种不可恢复的状态,一般指虚拟机相关问题,不需要捕获处理,比如OutOfMemoryError。eg:系统崩溃,虚拟机错误,内存空间不足。

追问:NoClassDefFoundError 和 ClassNotFoundException 有什么区别?

答: ClassNotFoundException一般都是类名字传入有误导致的异常

NoClassDefFoundError要查找的类在编译时是存在的,运行的时候却找不到了。一般由于打包的时候漏掉了部分类或者Jar包被篡改已经损坏的错误。

追问: throw和throws的区别?

**throw:**在方法体内部,表示抛出异常,由方法内部的语句处理;

**throws:**在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理。

追问: 主线程可以捕获到子线程的异常?

答:正常情况下主线程是不能捕获到子线程的异常。但是我们可以用Thread的静态方法去进行处理。

Thread.setDefalutUncaughtExceptionHandler(new MyUncaughtExceptionHandle());

2、JIT编译器有了解吗?

答:JIT全名叫Just In Time Compile也就是即时编译器,把经常运行的代码作为热点代码编译成与本地平台相关的机器码,并进行各种层次的优化。JIT编译除了具有缓存的功能外,还会对代码做各种优化,包括逃逸分析、锁消除、锁膨胀、方法内联、空值检查消除、类型检测消除以及公共子表达式消除等。

追问: 那什么是逃逸分析?

逃逸分析的基本行为就是分析对象动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其它方法中,称为方法逃逸。JIT编译器的优化包括如下:

  • **同布省略:**也就是锁消除,当JIT编译器不会产生并发问题,那么会将同步synchronized去掉
  • 标量替换: 如果经过逃逸分析,发现一个对象不会被外界访问的话,那么经过JIT优化,就会把这个对象拆解成若干个其中包含的若干个成员变量来代替。这个过程就是标量替换。标量替换的好处就是对象可以不在堆内存进行分配,为栈上分配提供了良好的基础。

**追问: ** 什么是标量和聚合量?

  • **标量(Scalar)**是指一个无法再分解成更小的数据的数据。Java中的原始数据类型就是标量。
  • **聚合量(Aggregate)**是还可以分解的数据。Java中的对象就是聚合量,因为他可以分解成其他聚合量和标量。

追问: 那么逃逸分析技术存在哪些缺点呢?

答:技术不是特别成熟,分析的过程也很耗时,如果没有一个对象是不逃逸的,那么就得不偿失。

3、Java中的值传递和引用传递可以解释下吗?

答:

  • **值传递:**意味着传递了对象的一个副本,即时副本被改变,也不会影响源对象。
  • **引用传递:**意味着传递的并不是实际对象,而是对象的引用。因此,外部对引用对象的改变会反映到所有对象上。

4、StringBuffer与StringBuilder的区别?

  1. String:用于字符串操作,属于不可变类;【String不是基本数据类型,是引用类型,底层用char数组实现的】

  2. StringBuffer:也用于字符串操作,不同之处是StringBuffer属于可变类,对方法加了同步所,线程安全

    **注意:**StringBuffer中并不是所有方法都使用了Synchronized修饰来实现同步:

    insert方法通过调用超类AbstractStringBuilder中的方法,将s转换为String。

  3. StringBuilder:与StrigBuffer类似,都是字符串缓冲区,但线程不安全

执行效率:StringBuilder>StringBuffer>String

追问: String字符串修改实现的原理?

答:当用String类型来对字符串进行修改时,其实现方法是首先创建一个StringBuffer,其次调用StringBuffer的append()方法,最后调用StringBuffer的toString()方法把结果返回。

追问: String与基本数据类型直接的转换?

  • 字符串转基本数据类型:调用基本数据类型对应的包装类中的方法**parseXX(String)或者valueOf(String)**即可返回相应的基本数据类型;
  • 基本类型转字符串:
    • 将基本数据类型与空字符串(“ ”)连接(+)即可获得其对应的字符串;
    • 调用String类中的valueOf()方法返回相应字符串。

追问: 如何将字符串反转?

答:调用StringBuffer或者StringBuilder的reverse()方法。

5、==和equals的区别?

==:如果比较的对象是基本数据类型,则比较的是数值是否相等;如果比较的是引用数据类型,则比较的是对象的地址是否相等

equals:用来比较两个对象的内容是否相等;【equals不能用于比较基本数据类型的变量。】如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址。很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等)

追问: 为什么equals不能用于比较基本数据类型的变量?

答:对于基本数据类型,它们是作为常量在方法区中的常量池里面以HashSet策略存储起来的,在常量池中,一个常量只会对应一个地址,因此不管再多的123,这样的数据都只会存储一个地址,所以所有他们的引用都是指向同一块地址,当没有重写equals方法时,它就无法比较,因为它比较的是引用类型的变量所指向的对象的地址。

追问: 两个对象的 hashCode() 相同,则 equals() 也一定为true 吗?

答:不一定,因为在散列表中,hashCode()相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。【散列冲突】

6、为什么重写 equals() 就一定要重写 hashCode() 方法?

用不到哈希表的话,其实仅仅重写 equals() 方法也可以。而工作中的场景是常常用到 Java 集合,所以 Java 官方建议重写 equals() 就一定要重写 hashCode() 方法。

对于对象集合的判重,如果一个集合含有 10000 个对象实例,仅仅使用 equals() 方法的话,那么对于一个对象判重就需要比较 10000 次,随着集合规模的增大,时间开销是很大的。但是同时使用哈希表的话,就能快速定位到对象的大概存储位置,并且在定位到大概存储位置后,后续比较过程中,如果两个对象的 hashCode 不相同,也不再需要调用equals() 方法,从而大大减少了 equals() 比较次数。所以从程序实现原理上来讲的话,既需要 equals() 方法,也需要 hashCode() 方法。那么既然重写了 equals(),那么也要重写 hashCode() 方法,以保证两者之间的配合关系。

hashCode()与equals()的相关规定:
1、如果两个对象相等,则 hashCode 一定也是相同的
2、两个对象相等,对两个对象分别调用 equals 方法都返回 true;
3、两个对象有相同的 hashCode 值,它们也不一定是相等的
4、因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖;
5、hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则
该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

7、&和&&的区别?

&&: 有短路功能,当第一个表达式的值为 false 的时候,则不再计算第二个表达式;
&: 不管第一个表达式结果是否为 true,第二个都会执行。除此之外,& 还可以用作位运
算符:当 & 两边的表达式不是 Boolean 类型的时候,& 表示按位操作。

8、Java的泛型是如何工作的?

泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在
**运行时不存在任何类型相关的信息。**例如:List 在运行时仅用一个 List 来表示。
这样做的目的,是确保能和 Java 5 之前的版本开发二进制类库进行兼容。

追问: 什么是类型擦除?

泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如 则会被转译成普通的 Object 类型,如果指定了上限如 则类型参数就被替换成类型上限。

**注意:**Array 不支持泛型,要用 List 代替 Array,因为 List 可以提供编译器的类型安全保证,而 Array却不能。

9、什么是Java的序列化,如何实现Java的序列化?

对象序列化是一个用于将对象状态转换为字节流的过程,可以将其保存到磁盘文件中或通过网络发送到任何其他程序。从字节流创建对象的相反的过程称为反序列化。而创建的字节流是与平台无关的,在一个平台上序列化的对象可以在不同的平台上反序列化。序列化是为了解决在对象流进行读写操作时所引发的问题。

追问:序列化如何实现?

将需要被序列化的类实现 Serializable 接口,该接口没有需要实现的方法,只是用于标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个 ObjectOutputStream 对象,接着使用ObjectOutputStream 对象的 writeObject(Object obj) 方法可以将参数为 obj 的对象写出,要恢复的话则使用输入流。

追问:什么情况下需要序列化?

  • 要把内存中的对象状态保存到一个文件中或者数据库中的时候;
  • 要用套接字在网络上传送对象的时候;
  • 要通过RMI传输对象的时候。

注意:

关于套接字:https://blog.csdn.net/luzhensmart/article/details/81838193

关于RMI:https://blog.csdn.net/a19881029/article/details/9465663

10、Java和C++的区别

  1. Java是解释型语言,所谓的解释型语言,就是源码会先经过一次编译,成为中间码,中间码再被解释器解释成机器码。对于Java而言,中间码就是字节码(.class),而解释器在JVM中内置了。
  2. C++是编译型语言,所谓编译型语言,就是源码一次编译,直接在编译的过程中链接了,形成了机器码。
  3. C++比Java执行速度快,但是Java可以利用JVM跨平台
  4. Java是纯面向对象的语言,所有代码(包括函数、变量)都必须在类中定义。而C++中还有面向过程的东西,比如是全局变量和全局函数。
  5. C++中有指针,Java中没有,但是有引用。
  6. C++支持多继承Java中类都是单继承的。但是继承都有传递性,同时Java中的接口是多继承,类对接口的实现也是多实现。
  7. C++中,开发需要自己去管理内存,但是Java中JVM有自己的GC机制,虽然有自己的GC机制,但是也会出现OOM和内存泄漏的问题。C++中有析构函数,Java中Object的finalize方法。
    中还有面向过程的东西**,比如是全局变量和全局函数。
  8. C++中有指针,Java中没有,但是有引用。
  9. C++支持多继承Java中类都是单继承的。但是继承都有传递性,同时Java中的接口是多继承,类对接口的实现也是多实现。
  10. C++中,开发需要自己去管理内存,但是Java中JVM有自己的GC机制,虽然有自己的GC机制,但是也会出现OOM和内存泄漏的问题。C++中有析构函数,Java中Object的finalize方法。
  11. C++运算符可以重载,但是Java中不可以。同时C++中支持强制自动转型,Java中不行,会出现ClassCastException(类型不匹配)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值