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 | /** |
深拷贝和浅拷贝
引用拷贝:只是复制引用地址
浅拷贝:将object对象在堆上复制一份对象,但是里面如果有引用对象的话,也只会复制地址
深拷贝:将object对象全部复制,包括内部对象。
String
Java 9 为何要将 String
的底层实现由 char[]
改成了 byte[]
?
我们建议更改类的内部表示 从 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:
- JIT无法对其进行优化,因为他不知道你要干什么
- 所有的创建和invoke操作需要去搜索
- Arguments need to be dressed up via boxing/unboxing, packing into arrays,
Exceptions
wrapped inInvocationTargetException
s and re-thrown etc. - 参数需要通过开箱/装箱打包到数组当中,异常需要通过InvocationTargetException包装异常
- 还需要进行特殊处理,(如判断变量和函数访问性,检查是否有无参构造函数等)
performance - Java Reflection: Why is it so slow? - Stack Overflow
静态代理
JDK 动态代理和 CGLIB 动态代理对比
- JDK 动态代理只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代理未实现任何接口的类。 另外, CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为 final 类型的类和方法。
- 就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显。
著作权归所有 原文链接:https://javaguide.cn/java/basis/proxy.html
静态代理和动态代理的对比
- 灵活性 :动态代理更加灵活,不需要必须实现接口,可以直接代理实现类,并且可以不需要针对每个目标类都创建一个代理类。另外,静态代理中,接口一旦新增加方法,目标对象和代理对象都要进行修改,这是非常麻烦的!
- 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相等的时候必须相等。