Integer
1、Integer a= 127,Integer b = 127;Integer c= 128,Integer d = 128;相等吗?
答案是a和b相等,c和d不相等。
- 对于基本数据类型==比较的值
- 对于引用数据类型==比较的是地址
Integer a= 127这种赋值,是用到了Integer自动装箱的机制。自动装箱的时候会去缓存池里取Integer对象,没有取到才会创建新的对象。
如果整型字面量的值在-128到127之间,那么自动装箱时不会new新的Integer对象,而是直接引用缓存池中的Integer对象,超过范围 a1==b1的结果是false。
public static void main(String[] args) { Integer a = 127; Integer b = 127; Integer b1 = new Integer(127); System.out.println(a == b); //true System.out.println(b==b1); //false Integer c = 128; Integer d = 128; System.out.println(c == d); //false }
什么是Integer缓存?
因为根据实践发现大部分的数据操作都集中在值比较小的范围,因此 Integer 搞了个缓存池,默认范围是 -128 到 127,可以根据通过设置JVM-XX:AutoBoxCacheMax=
来修改缓存的最大值,最小值改不了。
实现的原理是int 在自动装箱的时候会调用Integer.valueOf
,进而用到了 IntegerCache
。
public static Integer valueof(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
很简单,就是判断下值是否在缓存范围之内,如果是的话去 IntegerCache 中取,不是的话就创建一个新的Integer对象。
IntegerCache是一个静态内部类, 在静态块中会初始化好缓存值。
private static class IntegerCache { …… static { //创建Integer对象存储 for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); …… } }
2、String转Integer的方法有哪些?
String
转成Integer
,主要有两个方法:
- 使用Integer类的静态方法parseInt()。该方法接受一个字符串参数,并返回该字符串表示的整数。例如:
String str = "123"; int i = Integer.parseInt(str);
- 使用Integer类的静态方法valueOf()。该方法接受一个字符串参数,并返回该字符串表示的整数的Integer包装类对象。例如:
String str = "123"; Integer i = Integer.valueOf(str);
不管哪一种,最终还是会调用Integer类内中的parseInt(String s, int radix)
方法。
核心代码:
public static int parseInt(String s, int radix) throws NumberFormatException{ int result = 0; //是否是负数 boolean negative = false; //char字符数组下标和长度 int i = 0, len = s.length(); …… int digit; //判断字符长度是否大于0,否则抛出异常 if (len > 0) { …… while (i < len) { // Accumulating negatively avoids surprises near MAX_VALUE //返回指定基数中字符表示的数值。(此处是十进制数值) digit = Character.digit(s.charAt(i++),radix); //进制位乘以数值 result *= radix; result -= digit; } } //根据上面得到的是否负数,返回相应的值 return negative ? result : -result; }
注意:
- 该方法不能将空字符串转换为整数,否则会抛出NumberFormatException异常。
- 该方法不能将非数字字符串转换为整数,否则会抛出NumberFormatException异常。
Object
1、Object 类有哪些方法? ⚡
Object 类是一个特殊的类,是所有类的父类,也就是说所有类都可以调用它的方法。它主要提供了以下 11 个方法,大概可以分为六类:
对象比较:
public native int hashCode()
:native
方法,用于返回对象的哈希码,主要使用在哈希表中,比如JDK中的HashMap。public boolean equals(Object obj)
:用于比较2个对象的内存地址是否相等,String类对该方法进行了重写用户比较字符串的值是否相等。
对象拷贝:
protected native Object clone() throws CloneNotSupportedException
:naitive
方法,用于创建并返回当前对象的一份拷贝。一般情况下,对于任何对象 x,表达式x.clone() != x
为true,x.clone().getClass() == x.getClass()
为true。Object
本身没有实现Cloneable
接口,所以不重写clone
方法并且进行调用的话会发生CloneNotSupportedException
异常。
对象转字符串:
public String toString()
:返回类的名字@实例的哈希码的16进制的字符串。建议Object所有的子类都重写这个方法。
多线程调度:
public final native void notify()
:native方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。public final native void notifyAll()
:native方法,并且不能重写。跟notify一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。public final native void wait(long timeout) throws InterruptedException
:native方法,并且不能重写。暂停线程的执行。注意:sleep方法没有释放锁,而wait方法释放了锁 。timeout是等待时间。public final void wait(long timeout, int nanos) throws InterruptedException
:多了nanos参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。所以超时的时间还需要加上nanos毫秒。public final void wait() throws InterruptedException
:跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
反射:
public final native Class getClass()
:native方法,用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写。
垃圾回收:
protected void finalize() throws Throwable
:通知垃圾收集器回收对象。
异常处理
1、异常有哪些分类?
所有异常都是 Throwable 的子类,分为 Error 和 Exception。
- Error是系统内部错误,比如虚拟机异常,是程序无法处理的。
- Exception的子类为RuntimeException异常和RuntimeException以外的异常(例如IOException)。
因此异常主要分为Error,RuntimeException异常和RuntimeException以外的异常。(错误、运行时异常和编译时异常)
常见异常: NullPointerException、ClassNotFoundException、arrayindexoutofboundsexception、ClassCastException(类型强制转换)
2、异常的处理方式?
针对异常的处理主要有两种方式:
- 遇到异常不进行具体处理,而是继续抛给调用者 (throw,throws)
- 抛出异常有三种形式,一是 throw,一个 throws,还有一种系统自动抛异常。
- throws 用在方法上,后面跟的是异常类,可以跟多个;而 throw 用在方法内,后面跟的是异常对象。
- try catch 捕获异常
- 在catch语句块中捕获发生的异常,并进行处理。
- try-catch捕获异常的时候还可以选择加上finally语句块,finally语句块不管程序是否正常执行,最终它都会必然执行。
3、三道经典异常处理代码题
题目1
public class TryDemo { public static void main(String[] args) { System.out.println(test()); } public static int test() { try { return 1; } catch (Exception e) { return 2; } finally { System.out.print("3"); } } }
执行结果:31。
try、catch。finally 的基础用法,在 return 前会先执行 finally 语句块,所以是先输出 finally 里的 3,再输出 return 的 1。
题目2
public class TryDemo { public static void main(String[] args) { System.out.println(test1()); } public static int test1() { try { return 2; } finally { return 3; } } }
执行结果:3。
try 返回前先执行 finally,结果 finally 里不按套路出牌,直接 return 了,自然也就走不到 try 里面的 return 了。
题目3
public class TryDemo { public static void main(String[] args) { System.out.println(test1()); } public static int test1() { int i = 0; try { i = 2; return i; } finally { i = 3; } } }
执行结果:2。
大家可能会以为结果应该是 3,因为在 return 前会执行 finally,而 i 在 finally 中被修改为 3 了,那最终返回 i 不是应该为 3 吗?
但其实,在执行 finally 之前,JVM 会先将 i 的结果暂存起来,然后 finally 执行完毕后,会返回之前暂存的结果,而不是返回 i,所以即使 i 已经被修改为 3,最终返回的还是之前暂存起来的结果 2。