Java问题收集

理解原码、反码、补码、移码

  • 符号位:0位正数,1为负数

  • 原码不能进行运算

  • 正数的原码和反码一样,负数的反码是在原码的基础上,符号位不变,其余取反

  • 正数的补码和反码一样,负数的补码是在反码的基础上进行+1操作

  • 移码是在补码的基础上,把符号位取反

1 -1 1+(-1) 结果
原码 0000 0001 1000 0001 1000 0010 -2
反码 0000 0001 1111 1110 1111 1111 -0
补码 0000 0001 1111 1111 0000 0000 +0
移码 1000 0001 0111 1111 1000 0000 0

取值范围

整数 n=8
原码 -(2^(n-1)-1)~2^(n-1)-1 -127~127
反码 -(2^(n-1)-1)~2^(n-1)-1 -127~127
补码 -2^(n-1)~2^(n-1)-1 -128~127

Object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* native 方法,用于返回当前运行时对象的 Class 对象,使用了 final 关键字修饰,故不允许子类重写。
*/
public final native Class<?> getClass()
/**
* native 方法,用于返回对象的哈希码,主要使用在哈希表中,比如 JDK 中的HashMap。
*/
public native int hashCode()
/**
* 用于比较 2 个对象的内存地址是否相等,String 类对该方法进行了重写以用于比较字符串的值是否相等。
*/
public boolean equals(Object obj)
/**
* native 方法,用于创建并返回当前对象的一份拷贝。
*/
protected native Object clone() throws CloneNotSupportedException
/**
* 返回类的名字实例的哈希码的 16 进制的字符串。建议 Object 所有的子类都重写这个方法。
*/
public String toString()
/**
* native 方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
*/
public final native void notify()
/**
* native 方法,并且不能重写。跟 notify 一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
*/
public final native void notifyAll()
/**
* native方法,并且不能重写。暂停线程的执行。注意:sleep 方法没有释放锁,而 wait 方法释放了锁 ,timeout 是等待时间。
*/
public final native void wait(long timeout) throws InterruptedException
/**
* 多了 nanos 参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上 nanos 毫秒。。
*/
public final void wait(long timeout, int nanos) throws InterruptedException
/**
* 跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
*/
public final void wait() throws InterruptedException
/**
* 实例被垃圾回收器回收的时候触发的操作
*/
protected void finalize() throws Throwable { }

深拷贝和浅拷贝

引用拷贝:只是复制引用地址

浅拷贝:将object对象在堆上复制一份对象,但是里面如果有引用对象的话,也只会复制地址

深拷贝:将object对象全部复制,包括内部对象。

String

Java 9 为何要将 String 的底层实现由 char[] 改成了 byte[] ?

JEP 254: 紧凑字符串 (openjdk.org)

我们建议更改类的内部表示 从 UTF-16 数组到数组加上编码标志字段。 新类将存储编码为 ISO-8859-1/Latin-1(每个字符一个字节),或 UTF-16(每个字符两个字节) 字符)

字符串拼接用“+” 还是 StringBuilder?

可以从字节码里看出

字符串对象通过“+”的字符串拼接方式,实际上是通过 StringBuilder 调用 append() 方法实现的,拼接完成之后调用 toString() 得到一个 String 对象 。

不过,在循环内使用“+”进行字符串的拼接的话,存在比较明显的缺陷:编译器不会创建单个 StringBuilder 以复用,会导致创建过多的 StringBuilder 对象


著作权归所有 原文链接:https://javaguide.cn/java/basis/java-basic-questions-02.html

Java代理

反射优缺点

优点 : 可以让咱们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利

缺点 :让我们在运行时有了分析操作类的能力,这同样也增加了安全问题。比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。另外,反射的性能也要稍差点,不过,对于框架来说实际是影响不大的。


著作权归所有 原文链接:https://javaguide.cn/java/basis/reflection.html

反射为什么慢

Reflection is slow for a few obvious reasons:

  1. JIT无法对其进行优化,因为他不知道你要干什么
  2. 所有的创建和invoke操作需要去搜索
  3. Arguments need to be dressed up via boxing/unboxing, packing into arrays, Exceptions wrapped in InvocationTargetExceptions and re-thrown etc.
  4. 参数需要通过开箱/装箱打包到数组当中,异常需要通过InvocationTargetException包装异常
  5. 还需要进行特殊处理,(如判断变量和函数访问性,检查是否有无参构造函数等)

performance - Java Reflection: Why is it so slow? - Stack Overflow

静态代理

JDK 动态代理和 CGLIB 动态代理对比

  1. JDK 动态代理只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代理未实现任何接口的类。 另外, CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为 final 类型的类和方法。
  2. 就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显。

著作权归所有 原文链接:https://javaguide.cn/java/basis/proxy.html

静态代理和动态代理的对比

  1. 灵活性 :动态代理更加灵活,不需要必须实现接口,可以直接代理实现类,并且可以不需要针对每个目标类都创建一个代理类。另外,静态代理中,接口一旦新增加方法,目标对象和代理对象都要进行修改,这是非常麻烦的!
  2. JVM 层面 :静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 class 文件。而动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。

著作权归所有 原文链接:https://javaguide.cn/java/basis/proxy.html

BigDecimal

浮点数之间的等值判断,基本数据类型不能用 == 来比较,包装数据类型不能用 equals 来判断,给定误差范围

我们在使用 BigDecimal 时,为了防止精度丢失,推荐使用它的BigDecimal(String val)构造方法或者 BigDecimal.valueOf(double val) 静态方法来创建对象。

大小比较使用 a.compareTo(b), equals() 方法不仅仅会比较值的大小(value)还会比较精度(scale),而 compareTo() 方法比较的时候会忽略精度。


著作权归所有 原文链接:https://javaguide.cn/java/basis/bigdecimal.html

equals和hashcode

equals==true 说明两个对象相等。

hashcode相等,说明两个对象哈希码相等,并不代表对象相等,hashcode用于确定在哈希表中的位置。

如果hashcode相等equals不相等,说明两个对象不相等。

如果equals相等,hashcode不相等,那么在hashMap中如果两个对象被分在两个不同的哈希桶中,那么hashMap就无法进行新值覆盖,Hashset就无法进行去重。

所以重写的hashcode()在equals相等的时候必须相等。

作者

leon Yan

发布于

2023-02-20

更新于

2023-09-21

许可协议


评论