一.String类
1.String不可变的原理
String类里面的value是final修饰的
2.StringBuffer和StringBuilder
StringBuffer和StringBuilder非常类似,均代表可变的字符序列。 这两个类都是抽象类AbstractStringBuilder的子类,方法几乎一模一样。
不可变和可变字符序列使用陷阱
String一经初始化后,就不会再改变其内容了。对String字符串的操作实际上是对其副本(原始拷贝)的操作,原来的字符串一点都没有改变。比如:
String s =”a”; 创建了一个字符串
s = s+”b”; 实际上原来的”a”字符串对象已经丢弃了,现在又产生了另一个字符串s+”b”(也就是”ab”)。 如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的时间和空间性能,甚至会造成服务器的崩溃。
相反,StringBuilder和StringBuffer类是对原字符串本身操作的,可以对字符串进行修改而不产生副本拷贝或者产生少量的副本。因此可以在循环中使用。
3.Arrays工具类的使用
JDK提供的java.util.Arrays类,包含了常用的数组操作,方便我们日常开发。Arrays类包含了:排序、查找、填充、打印内容等常见的操作。
打印数组
1 | import java.util.Arrays; |
此处的Arrays.toString()方法是Arrays类的静态方法,不是前面讲的Object的toString()方法。 探究:
1 | /** |
> 注意新名词:协变返回
数组元素的排序
1 | import java.util.Arrays; |
数组元素是引用类型的排序(Comparable接口的应用)
1 | import java.util.Arrays; |
二分法查找
1 | import java.util.Arrays; |
二.冒泡排序,优化
1 | /** |
1. 外层循环控制总循环次数
2. 内层循环控制两两比较的次数
3. 内层循环之前写错过,来看看,里面有个 j<values.length-1-i (这个i是外层循环的控制变量),为什么要减i呢?
因为你每次两两比较完之后最后一个元素就是最大的,这个元素就不再比较了
1 | for(int i = 0;i<values.length;i++){ |
## 三.折半查找
1 | /** |
## 四.包装类
Java是面向对象的语言,但并不是“纯面向对象”的,因为我们经常用到的基本数据类型就不是对象。但是我们在实际应用中经常需要将基本数据转化成对象,以便于操作。比如:将基本数据类型存储到Object[]数组或集合中的操作等等。
为了解决这个不足,Java在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。
包装类均位于java.lang包,八种包装类和基本数据类型的对应关系如下
在这八个类名中,除了Integer和Character类以外,其它六个类的类名和基本数据类型一致,只是类名的第一个字母大写而已。
在这八个类中,除了Character和Boolean以外,其他的都是“数字型”,“数字型”都是java.lang.Number的子类。Number类是抽象类,因此它的抽象方法,所有子类都需要提供实现。Number类提供了抽象方法:intValue()、longValue()、floatValue()、doubleValue(),意味着所有的“数字型”包装类都可以互相转型。
4.1 包装类的用途
- 作为和基本数据类型对应的类型存在,方便涉及到对象的操作,如Object[]、集合等的操作
- 包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法(这些操作方法的作用是在基本数据类型、包装类对象、字符串之间提供相互之间的转化!)。
4.2 包装类的使用
1 | public class Test { |
4.3 包装类的的缓存问题
整型、char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓存处理,其目的是提高效率。
缓存处理的原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱过程发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。
Integer类相关源码如下:
1 | public static Integer getInteger(String nm, int val) { |
这段代码中我们需要解释下面几个问题:
- IntegerCache类为Integer类的一个静态内部类,仅供Integer类使用。
- 一般情况下 IntegerCache.low为-128,IntegerCache.high为127,IntegerCache.cache为内部类的一个静态属性
IntegerCache类相关源码如下:
1 | private static class IntegerCache { |
由上面的源码我们可以看到,静态代码块的目的就是初始化数组cache的,这个过程会在类加载时完成。
测试代码
1 | public class Test3 { |
五.自动装箱和拆箱
其实呢,所谓的自动都是骗人的,只不过是编译器在运行的时候帮我做了,看起来是自动的一样,其实是骗人的
1 | /** |
注意:
1 | Integer c = null; -----> Integer c = Integer.valueof(null); |
上面这两句代码会产生异常,空指针异常
因为我们在调用 int d = c.intValue(); 来进行自动拆箱时c是一个null值,所以报了空指针异常
控制箱异常是怎么报的呢?就是当前你这个对象是null,你还用这个null去调用它的方法,这个时候就会包空指针异常