第一章 集合框架
集合框架是为表示和操作集合而规定的一种统一的标准系结构。集合框架都包含三个块内容对外的接口、接口的实现和集合运算的算法。
- 接口:表示集合的抽象数据类型,如Collection、List、Set、Map、Iterator。
- 实现:集合框架中接口的具体实现,如ArrayList、LinkedList、HashMap、HashSet。
- 算法:在一个实现了某个集合框架中的接口的对象身上完成某种有用的计算的方法,如查找、排序等。Java 提供了进行集合操作的工具类Collection(注意不是 Collection,类似于Arrays类),它提供了对集合进行排序等多种算法的实现。在使用Collection 的时候可以查阅JDK帮助文件。
可以清楚的看出Java集合框架中的两大类接口,Collection和Map,其中,Collection 又有两个子接口:List 和 Set。所以通常说Java集合框架共有三大类接口:List、Set 和 Map。它们的共同点:都是集合接口,都可以用来存储很多对象。区别如下。
- Collection 接口存储一组不唯一(允许重复)、无序对象。
- Set 接口继承Collection 接口,存储一组唯一(不予许重复)、无序的对象。
- List 接口继承 Collection 接口,存储一组不唯一(允许重复)、有序(以元素插入的次序来放置元素,不会重新排列)的对象。
- Map:接口存储一组成对的键——值对象,提供key(键)到value(值)的映射。Map 中key不要求有序,不允许重复。value同样不要求有序,但允许重复。
- Iterator:接口是负责定义访问和遍历元素的接口。
在集合框架中,List可以理解为前面讲过的数组,元素的内容可以重复并且有序。
Set可以理解为数学中的集合,里面数据不重复并且无序。
Map也可以理解为数学中的集合,只是其中每个元素都由key 和value 两个对象组成。
1、List 接口
实现List 接口的常用类有ArrayList 和 LinkedList 。它们都可以容纳所有类型的对象,包括null,允许重复,并且保证元素的存储顺序。
ArratList 对数组进行了封装,实现了长度可变的数组。ArrayList 存储数据的方式和数组相同,都是在内存中分配连续的空间,它的优点在于遍历元素和随机访问元素的效率比较高。
LinkedList 采用链表存储方式,优点在于插入、删除元素时效率比较高,它提供了额外的addFirst()、addLast()、removeFirst() 和 removeLast() 等方法,可以在LinkedList 的首部或尾部进行插入或删除操作。这些方法使得LinkedList 可被用做堆栈(stack)或者队列(queue)。
ArrayList 集合类
方法名称 | 说明 |
boolean add(Object o) | 在列表末尾顺序添加元素,起始索引位置从0开始 |
void add(int index, Object o) |
在指定的索引位置添加元素,原索引位置及其后面的元素依次后移, 注意:新添加元素的索引位置必须介于0和列表中元素的个数之间 |
int size() | 返回列表中的元素个数 |
Object get(int index) | 返回指定索引位置处的元素,注意:取出的元素是Object类型,使用前需要进行强制类型转换 |
boolean contains(Object o) | 判断列表中是否存在指定元素 |
boolean remove(Object o) | 从列表中删除元素 |
Object remove(int index) | 从列表中删除指定位置元素,起始索引位置从0开始 |
LinkedList 集合类
方法名称 | 说明 |
void addFirst(Object o) | 在列表的首部添加元素 |
void addLast(Object o) | 在列表的末尾添加元素 |
Object getFirst() | 返回列表中的第一个元素 |
Object getLast() | 返回列表中的最后一个元素 |
Object removeFirst() | 删除并返回列表中的第一个元素 |
Object removeLast() | 删除并返回列表中的最后一个元素 |
2、Set 接口
Set 接口是Collection 接口的另一个常用子接口。Set 接口描述的是一种比较简单的集合,集合中的对象并不按特定的方式排序,并且不能保存重复的对象,也就是说Set 接口可以存储一组唯一、无序的对象。
Set 接口常用的实现类有 HashSet。
使用HashSet 类动态存储数据
Java集合框架提供了一个查找效率高的集合类 HashSet ,HashSet 类实现了 Set 接口,是使用Set集合是最常用的一个实现类, HashSet 集合的特点如下:
- 集合内的元素是无序排列的。
- HashSet 类非线程安全的。
- 允许集合元素值为null。
方法 | 说明 |
boolean add(Object o) | 如果此Set 中尚未包含指定元素,则添加指定元素 |
void clear() | 从此Set中移除所有元素 |
int size() | 返回此Set中元素的数量(Set 的容量) |
boolean is Empty() | 如果此Set 不包含任何元素,则返回 true |
boolean contains(Object o) | 如果此Set包含指定元素,则返回true |
boolean remove(Object o) | 如果指定元素存在于此Set中,则将其移除 |
注意:使用HashSet类之前,需要导入相应的接口和类。
import java.util.Set;
import java.util.HashSet;
LIst接口可以使用For循环和增强for循环两种方式遍历。使用for循环遍历时,通过get()方法取出每个对象,但是HashSet类不存在get()方法,所以Set接口无法使用普通for循环遍历。其实遍历集合还有一种比较常用的方式,即使用Iterator接口。
3、Map 接口
Map接口存储一组成对的键——值对象,提供key(键)到 value(值)的映射。Map中的key不要求有序,不允许重复。value 同样不要求有序,但是允许重复。最常用的Map实现类是 HashMap,它的存储方式是哈希表。哈希表也称为散列表,是根据关键码值(key value)而直接进行访问的数据结构。也就是说,它通过把关键码映射到表中一个位置来访问记录,以加快查找速度。存放记录的数组为散列表。使用这种方式存储数据的优点是查询指定元素效率高。
HashMap 集合类
方法名称 | 说明 |
Object put(Object key, Object value) | 以“键-值对”的方式进行存储 注意:键必须是唯一的,值可以重复。如果试图添加重复的键,那么最后加入的“键-值对”将替换原先的“键-值对” |
Object get(Object key) | 根据键返回相关联的值,若不存在指定的键,则返回null |
Object remove(Object key) | 删除指定的键映射的“键-值对” |
int size() | 返回元素个数 |
Set keySet() | 返回键的集合 |
Collection values() | 返回值的集合 |
boolean containsKey(object key) | 若存在指定的键映射的“键-值对”,则返回true |
boolean isEmpty() | 若不存在键-值映射关系,则返回true |
void clear() | 从此映射中移除所有映射关系 |
对比:Hashtable 和HashMap 的异同
HashMap 类出现之前,JDK 中存在一个和它同样采用哈希表存储方式,同样实现键值映射的集合类 Hashtable。两者实现原理相同,功能相同,很多情况下可以互用。
Hashtable 和 HashMap 的主要区别如下。
Hashtable 继承自 Dictionary 类,而HashMap 实现了Map 接口。
Hashtable 是线程安全的, HashMap 重速度、轻安全,是线程非安全的,所以当允许到多线程环境中时,需要程序员自己管理线程的同步问题。
Hashtable 不允许null值(key 和 value 都不允许),HashMap 允许null值(key 和 value 都允许)。开发过程中,最好使用新版本的HashMap 。
4、迭代器 Iterator
所有集合接口和类都没有提供相应的遍历方法,而是把遍历交给迭代器Iterator 完成。Iterator 为集合而生,专门实现集合的遍历。它隐藏了各种集合实现类的内部细节,提供了遍历集合的统一遍历接口。
Collection 接口的Iterator() 方法返回一个Iterator,然后通过Iterator 接口的两个方法即可方便地实现遍历。
- boolean hasNext():判断是否存在另一个可访问的元素。
- Object next():返回要访问的下一个元素。
下面是通过Iterator 来实现遍历。
// 创建Map 集合对象并把多个键值对放入map中 Map map = new HashMap(); map.put("a","aaaa"); map.put("b","bbbb"); map.put("c","cccc"); // 通过迭代器依次输出集合中所有信息 Set keys = map.keySet(); //取出所有key的集合 iterator it = keys.iterator(); // 获取 Iterator 对象 while(it.hasNext()){ String key = (String)it.next(); // 取出key String value = keys.get(key); //根据key取出对应的值 System.out.println(key + " " + value); }
5、泛型集合
Collection 的 add(Object obj) 方法的参数是Object类型,无论把什么对象放入Collection 及其子接口或实现类中,都认为只是Object类型,在通过get(int index) 方法取出集合中元素时必须进行强制类型转换,不仅烦琐而且容易出现ClassCastException 异常。Map中使用put(Object key, Object value) 和get(Object key) 方法存取对象,使用Iterator 的next()方法获取元素时也存在同样的问题。
JDK1.5 中通过引入泛型(Generic)有效的解决了这个问题。在JDK1.5中已经改写了集合框架中的所有接口和类,增加了对泛型的支持。
使用泛型集合在创建集合对象时指定集合中元素的类型,从集合中取出元素时无须进行类型强制转换,并且如果把非指定类型对象放入集合,会出现编译错误。
List<String> list = new ArrayList<String>();
本章总结
- 集合弥补了数组的缺陷,它比数组更灵活、更实用,可大大提高软件的开发效率,而且不同的集合可适用于不同场合。
- 集合框架是为表示和操作集合而规定的一种统一的标准体系结构。集合框架包含三大块内容:对外的接口,接口的实现和对集合运算的算法。
- 通常说Java 的集合框架中有两大类。即Collection 和 Map。其中Collection 有两个子接口,即List 和 Set 。各接口区别如下。
- Collection 接口存储一组不唯一,无序的对象。
- Set 接口继承 Collection 接口,存储一组唯一、无序的对象。
- List 接口继承Collection 接口,存储一组不唯一、有序的对象。
- Map 接口存储一组成对的键——值对象,提供key 到 value 的映射。key 不要求有序,不允许重复。value同样不要求有序,但允许重复。
- ArrayList 和数组采用相同的存储方式,它的优点在于遍历元素和随机访问元素的效率比较高。LinkedList 采用链表存储方式,优点在于插入,删除元素时效率比较高。
- HashMap 是最常见的Map 实现类,它的存储方式是哈希表,优点是查询指定元素效率高。
- Iterator 是为集合而生,专门实现集合的遍历。它隐藏了各种集合实现类的内部细节,提供了遍历集合的统一编程接口。
- 使用泛型集合在创建集合对象时指定集合元素的类型,在从集合中取出元素时无须进行类型强制转换,避免了ClassCatException 异常。
第二章 实用类
Java API (Java Application Programming Interface)即Java 应用程序编程接口,它是运行库的集合,预先定义了一些接口和类。
1、枚举
枚举是指由一组固定的常量组成的类型,使用关键字 enum 定义,语法如下。
访问修饰符 enum 枚举名 {
常量1, 常量2;
}
例如:
public enum Week(){
MON,TUE,WED,THU,FRI,SAT,SUN;
}
程序中使用枚举的好处。
- 枚举可以使代码更易于维护,有助于确保为变量指定合法的、期望的值。
- 枚举更易于输入,使用枚举赋值,只需要输入枚举名,然后输入一个点(.),就能将所有的值显示出来。
- 枚举使代码更清晰,允许用描述性的名称表示数据,使用时直观方便。
2、包装类
Java语言是面向对象,但是Java中基本数据类型却不是面向对象的,这在实际开发中,存在很多的不便,为了解决这个不足,在设计类时为了每一基本数据类型设计了一个对应的类,称为包装类。
基本数据类型 | 包装类 |
byte | Byte |
boolean | Boolean |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
包装类的用途主要有两个:
- 包装类作为和基本数据类型对应的类类型存在,方法对象的操作。
- 包装类包含每种基本数据类型的相关属性,如最大值、最小值等,以及相关的操作方法。
2.1、包装类和基本数据类型的转换
在Java 中,基于基本数据类型数据创建包装对象通常可以采用如下两种方式。
1) 使用包装类的构造方法
包装类的构造方法有如下两种形式
- public Type(type value)。
- public Type(String value)。
其中,Type表示包装类,参数type为基本数据类型。
针对每一个包装类,都可以使用关键字new 将一个数据类型值包装为一个对象。例如,要创建一个 Integer 类型的包装类对象,可以这样写:
Integer intValue = new Integer(21); 或 Integer intValue = new Integer("21");
注意:不能使用第二种形式的构造方法创建Character 类型的包装对象,只能是 Character charValue = new Character('x');
2) 使用包装类的valueOf() 方式
包装类中一般包含静态的、重载的 valueOf() 方式,它也可以接收基本数据类型数据和字符串作为参数并返回包装类的对象。以Integer 包装类为例,valueOf() 方法定义如下。
方法 | 说明 |
integer valueOf(int i) | 返回一个表示指定的int值的Integer 对象 |
Integer valueOf(String s) | 返回保存指定的String 值的Integer 对象 |
Integer valueOf(String s, int radix) | 返回一个Integer 对象,该对象中保存了用第二个参数提供的技术进行解析时从指定的Dtring中提取的值 |
3) 包装类转换成基本数据类型
包装类转换成基本数据类型通常采用如下的方法:public type typeValue();。其中,type指的是基本数据类型,如byteValue()、cahrValue()等,相应的返回值则为byte、char。
具体用法如下代码所示:
Integer integerId = new Integer(25);
int intId = integerId.intValue();
Boolean bl = Boolean,ValueOf(true);
boolean bool = bl.booleanValue();
4) 基本类型和包装类的自动转换
在JDK1,.5 版本之后程序员不需要编码实现基本数据类型和包装类之间的转换,编译器会自动完成。
例如:
Integer intObject = 5; // 基本数据类型转换成包装类
int intValue = intObject; // 包装类转换成基本数据类型
注意:包装类对象只能在数据类型需要用对象表示时才使用,包装类并不是用来取代基本数据类型的。
3、使用Math 类生成随机数
java.lang.Math 类提供了一些基本数学运算和几何运算的方法。此类中的所有方法都是静态的。这个类的final类,因此没有子类,Math 类常见的方法如下。
- static double abs(double a); 返回double 值的绝对值。例如,Math.abs(-3.5);返回3.5。
- static double max(double a, double b); 返回两个double 值中较大的一个。例如,Math.max(2.5, 90.5); 返回90.5。
- static double random(); 返回一个double 值,该值大于等于0.0 且小于1.0。
产生随机数(0——9中任意整数)的方法:
int random = (int) (Math.random()*10);
4、使用String 类操作字符串
在Java中,字符串被作为String 类型的对象来处理。String 类位于 java.lang 包中,默认情况下,该包被自动导入所有的程序。
4.1、String 类常用方法
1)求字符串长度length()
语法: 字符串.length();
2) 字符串比较(大小写也在检查范围内)
语法:字符串1.equals(字符串2)
注意:在java中,双等号(==)和 equals()方法应用于两个字符串,所判断的内容是有差别的。
“==” 判断的是两个字符串对象在内存中的地址,就是判断是否是同一个字符串对象,而 equals()判断的是两个字符串对象的值。
在使用 equals()方法比较两个字符串时,对于字符的大小写,也在检查范围之内。
使用equalslgnoreCase()方法。这个方法在比较字符串时忽略字符的大小写。
3) 字符串比较事忽略大小写
语法:字符串1.equalslgnoreCase(字符串1)
4)改变字符串中的字符的大小写
toLowerCase():转换字符串中的英文字符为小写。
toUpperCase():转换字符串中的英文字符为大写。
5)字符串的连接
语法:字符串1.concat(字符串2);
字符串2 被连接到字符串1 的后面,返回连接后的新字符串。同时连接字符串还经常使用 “+” 运算符。
6)字符串提取和查询
方法 | 说明 |
public int indexOf(int ch) | 搜索第一个出现的字符ch(或字符串value) |
public int indexOf(String value) | |
public int lastIndexOf(int ch) | 搜索最后一个出现的字符ch(或字符串value) |
public int lastIndexOf(String value) | |
public String substring(int index) | 提取从位置索引开始的字符串部分 |
public String substring(int beginindex, int endindex) | 提取beginindex 和endindex 之间的字符串部分 |
public String trim() | 返回一个前后不含任何空格的调用字符串的副本 |
字符串是一个字符序列,每一个字符都有自己的位置。字符串事实上也是一个字符数组,因此它的索引位置从0开始到(字符串长度-1)结束。
判断邮箱格式:
String email = "1234@qq.com"; //第一种方式 if(email.contains("@")&&email.contains(".")) { if(email.lastIndexOf(".")>email.lastIndexOf("@")) { System.out.println("格式正确"); } }else { System.out.println("格式错误"); } //第二种方式 if(email.indexOf("@")!= -1 && email.indexOf(".") > email.indexOf("@")){ // 检验邮箱是否包含“@”、“.”,并且“.” 的位置在 “@” 后面 System.out.println("格式正确"); } //校验“.” 的位置在 “@” 后面 if(email.indexOf(".") > email.indexOf("@")){ System.out.println("格式正确"); }else { System.out.println("格式错误); }
7)字符串拆分
语法:字符串名.split(separator, limit);
- separator为可选项,标志拆分字符串时使用的一个或多个字符。如果不选择该项,则返回包含该字符串所有单个字符的元素数组。
- limit为可选项,该值用来限制返回数组中的元素个数。
5、StringBuffer 类和 StringBuilder 类
5.1、使用StringBuffer 类处理字符串
除了使用String类存储字符串之外,还可以使用StringBuffer 类来存储字符串。StringBuffer 类也是Java提供的用于处理字符串的一个类,而且它是比String 类更高效地存储字符串的一种引用数据类型。特别是对字符串进行连接操作时,使用StringBuffer 类可以大大提高程序的执行效率。
1)如何使用StringBuffer 类
StringBuffer类位于java.util包中,是String 类的增强类,StringBuffer 类提供了很多方法以供使用。声明StringBuffer 对象并初始化的方法如下:
StringBuffer sb2 = new StringBuffer("青春无悔");
2)常用的StringBuffer 类方法
toString()方法
语法:字符串1.toString();
toString() 方法可实现将StringBuffer 类型的字符串1 转换为 String 类型的对象并返回。
String s1 = sb2 .toString(); //转换为String类
append() 方法
追加字符串的语法:
字符串.append(参数);
append() 方法可实现将参数连接到原字符串后并返回。
注意:该方法和String类的concat()方法一样,都是把一个字符串追加到另一个字符串后面。所不同的是String类中只能将String类型的字符串追加到一个字符串后,而StringBuffer 类可以将任何类型的值追加到字符串之后。例如:int类型的也可以追加到字符串后面。
3)insert()方法
插入字符串的语法:
字符串.insert(位置,参数);
insert()方法可实现将参数插入到字符串的指定位置并返回。参数可以是包含String的任何类型。
5.2、使用StringBuilder 类处理字符串
java.lang.StringBuilder 是JDK1.5版本新增的类,它是一个可变的字符序列。此类提供一个与StringBuffer 兼容的API,被设计用做StringBuffer的一个简易替换,在大多数实现中,它比StringBuffer要快。使用StringBuilder 类处理字符串的方法与StringBuffer 类基本一样。
String 类、StringBuffer 类 及 StringBuilder 类对比
String 、StringBuffer 和 StringBuilder 这3个类在处理字符串时有各自的特点和适用场合,具体如下。
1)String:字符串常量
String 是不可变的对象,在每次对 String 类型进行改变的时候其实都等同生成了一个新的String 对象,然后指向新的String对象。所以经常改变内容的字符串最好不要用String类型,因为每次生成对象都会对系统性能产生影响。
2)StringBuffer :字符串变量
StringBuffer 是可变的字符串,在每次对StringBuffer 对象进行改变时,是对StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以,在字符串对象经常改变的情况下推荐使用StringBuffer 类。
字符串连接操作中,StringBuffer 类的效率要比String 类高,例如:
String str = new string("welcome to");
str+ = "here";
以上这两句代码是使用String类型操作字符串,但其处理步骤实际上是通过建立一个StringBuffer(或 StringBuilder),让它调用append()方法,最后在转化成String。这样,String的连接操作比StringBuffer多出了一些附加操作,当然效率要低。并且由于String 对象的不可变性也会影响性能。
3)StringBuilder :字符串变量
JDK1.5版本以后提供了StringBuilder 类,它和StringBuffer类等价,区别在于StringBuffer 类是线程安全,StringBuilder 类是单线程的,不提供同步,理论上效率更高。
String 类方法比较多,需要多做练习,灵活运用,同时要理解StringBuffer 类及StringBuilder 类与String类的不同之处。
6、日期时间类
java.util包中提供的和日期、时间相关的类有Date类、Calendar类和SimpleDateFormat类等。
Date类对象用来表示日期和时间,该类提供了一系列操作日期和时间各组成部分的方法。Date类使用最多的是获取系统当前的日期和时间,如Date date = new Date(); 这句代码是使用系统当前时间创建日期对象。
Calendar类也是用来操作日期和时间的类,它可以看做是Date类的一个增强版。Calendar 类提供了一组方法,允许把一个以毫秒为单位的时间转换成年、月、日、小时、分、秒。可以把Calendar类当做万年历,默认显示的是当前的时间,当然也可以查看其它时间。
Calendar 类是抽象类,可以通过静态方法getInstance()获得Calendar的对象,其实这个获得的对象是它的子类的对象。
Calendar类提供一些方法和静态字段来操作日历,例如:
- int get(int field):返回给定日历字段的值。
- YEAR:指示年。
- MONTH:指示月。
- DAY_OF_MONTH:指示一个月中的某天。
- DAY_OF_WEEK:指示一个星期中的某天。
另外,常用的还有格式化日期时间类——DateFormat类,它在java.text包下,是一个抽象类,提供了多种格式化和解析时间的方法。格式化是指日期转换成文本格式,解析时指文本转换成日期格式。使用比较多的是它的子类 SimpleDateFormat。SimpleDateFormat类是一个以与语言环境有关的方式来格式化和解析日期的具体类,如 “yyyy-MM-dd HH:mm:ss” 就是指定的一种日期和时间模式。
7、Random 类
Random 类用于生成随机数,每当需要以任意或非系统方式生成数字时,即使用此类。之前学习过的Math 类的random()方法也可以产生随机数,其实,Math 类的random()方法的底层就是使用Random 类实现的。
构造方法 | 说明 |
Random() | 创建一个新的随机数生成器 |
Random(long seed) | 使用单个long种子创建一个新的随机数生成器 |
int nextInt();
返回下一个伪随机数,它是此随机数生成器的序列中均匀分布的int值。
int nextInt(int n);
返回下一个伪随机数,它是取自此随机数生成器序列的、在0 (包括)和指定值(不包括)之间均匀分布的 int值。
注意:如果哦用同样一个种子值来初始化两个 Random 对象,然后用每个对象调用相同的方法,那么得到的随机数也是相同的。
本章总结:
- 枚举可以使代码更易于维护,有助于确保给变量指定合法的、期望的值。
- 包装类均位于 java.lang 包中,每个基本数据类型对应着一个包装类。
- java.lang.Math 类 提供了常用的数学运算方法。
- 定义一个字符串时可以使用 String 类、StringBuffer 类和 StringBuilder 类。
- String 类提供了大量的操作字符串的方法,常用的方法有:
- 获取字符串的长度:equals()
- 比较字符串:
更新中。。。。