6.3集合框架
6.3.1简述
1、由来
对象用于封装特有数据,对象多了需要存储,且对象的个数不确定,于是 SUN公司专
门设计了一组类,这组类因内部的数据结构不同,不断向上抽取,就形成了各种不同的具体容器,即容器类,这些容器共同组成了集合框架(Collection Framework)。集合框架包含在java.util 包中。
任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。
2、 从体系上讲,集合框架可分为两种:
⑴、Collection 接口:
①、Set:集,无序性,无重复
②、List:以线性方式存储,只能在头或尾添加,或者在指定的位置后面插入新对象
⑵、Map 接口。
3、整个框架如下图:
4、特点
①、集合用于存储对象。
②、集合的长度是可变的
③、集合中不可以存储基本数据类型
5、集合与数组的区别
①、数组的长度是固定的;集合长度是可变的。
②、数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
③、数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。
6.3.2 Collection
java.util.collection接口是描述Set和List集合类型的根接口,
1、集合操作的常见方法,包括:
以代码的形式介绍:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
publicclass CollectionDemo {
publicstaticvoidmain(String[] args) {
Collection c1 = new ArrayList();
Collection c2 = new ArrayList();
// 1、添加元素(add)
c1.add("hufei1");
c1.add("hufei2");
Sop(c1);// 测试代码
c2.add("hufei3");
c2.add("hufei4");
c2.add("hufei1");
c1.addAll(c2);// 将c2中的元素添加到c1中
Sop(c1);// 测试代码
// 2、删除元素
c1.remove("hufei1");// 删除hufei1元素,同时改变了集合的长度
Sop(c1);// 测试代码
c1.clear();// 清空集合
Sop(c1);// 测试代码
c1.removeAll(c2);// 将俩个集合中的相同的元素从调用该的集合删除
Sop(c1);// 测试代码
// 3、判断元素
Sop(c1.contains("hufei2"));// 测试代码
Sop(c1.containsAll(c2));// 测试代码
Sop(c1.retainAll(c2));
//取交集,保留俩集合相同的元素,除此之外还有isEmpty(),containAll(collection c),
// 4、获取元素(Iterator)
// 下面的代码会详述
}
}
2、关于迭代器
⑴、定义:按次序一个一个的获取集合中的所有对象
⑵、使用迭代器的基本机制:
集合—>迭代器—>hasNext()测试—真—>连续调用next()方法—>对象
—假—>不再有对象有效
⑶、迭代器原理:在集合框架中,容器种类很多,每种容器的数据结构都有自己的特点,而要取出其中的元素,就必须依赖于具体容器来实现迭代器,从而创造自己独有的迭代器,这个迭代器必须做俩件事,判断有没有元素和取出元素,即hasNext()和next(),把这些容器的独有迭代器向外抽取就形成了Iterator接口。他是对所有的Collection容器进行元素取出的公共接口
接上的代码:
//与forEach相结合
Iteratorit = c1.iterator();
for(it.hasNext()){
//以上代码也可写成for(Iterator it = c1.Iterator();it.hasNext())
Sop(it.next());
}
//与while相结合
Iteratorit = c1.Iterator();
while(it.hasNext()){
Sop(it.next());
//它与for循环的区别在于在代码结束后,引用还留在内存中,所以是否用它视
//情况而定
}
6.3.3 List
1、常见方法
⑴、常见方法的特点:可以操作角标
⑵、以代码的形式介绍方法:
//1、添加元素(add)
list.add("hufei1");
list.add("hufei2");
list.add("hufei3");
Sop(list);
//2、删除元素
Sop(list.remove(0));//删除角标为2的元素,同时改变了集合的长度
//3、修改元素
Sop(list.set(1, "hufei4"));//
//4、获取元素
Sop(list.get(0));//测试代码
//5、获取子元素
Sop(list.subList(1, 2));
//返回指定的 角标1(包括 )和 角标2(不包括)之间的子元素
2、ListIterator接口
⑴、list获取元素的方法
//获取元素的方法一
Iterator it = list.Iterator();
for(it.hasNext()){
Sop(it.next());
}
//获取元素的方法二
for(int x= 0; x < List.size()); x++){
Sop(list.get(x));//list独有的方法
}
⑵、由来(利用代码解释)
import java.util.ListIterator
import java.util.ArrayList;
import java.util.List;
publicclass ListIterator {
publicstaticvoidmain(String[] args){
List list = new ArrayList ();
Iteratorit = list.iterator();
while(it.hasNext()){
Object obj = it.next();//返回Object的原因是add方法添加的就是Object对象
if(obj.equals("hufei2"))
list.add("hufei4");//这样做会发生ConcurrentModificationException异常,因为list与Iterator同时发生,
else
Sop(obj);
//以上代码容易出现异常,
}
}
}
由于在迭代器过程中,使用集合操作元素,容易出现异常,所以可以使用Iterator接口的子类接口ListIterator来完成在迭代中对元素进行更多的操作。
以上迭代器的代码可改为以下代码:
ListIterator it = list.listIterator();
while(it.hasNext()){
Object obj = it.next();
if(obj.equals("hufei2"))
it.add("hufei5");
Sop(obj);
3、ListIterator的常见方法
①、ListIterator可以在迭代过程中实现增删改查,而且只有List集合具备该迭代功能
②、hasNext();以正向遍历列表时,如果列表迭代器有多个元素,则返回 true
③、hasPrevious();如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。
④、nextIndex() 返回对 next 的后续调用所返回元素的索引。
4、List常用子类
①、Vector:内部是数组数据结构,是同步的,Vector只保存对象的引用,而不是实际对象
②、ArrayList:内部是数组数据结构,是不同步的,替代了Vector,由于空间连续,所以查询的速度快。
import java.util.ArrayList;
import java.util.Iterator;
publicclass ArrayListTest {
publicstaticvoid main(String[] args) {
ArrayList al = new ArrayList();//初始容量为 10 的空列表
al.add(new Person("zhangsan1",21));
al.add(new Person("zhangsan2",22));
al.add(new Person("zhangsan3",23));
al.add(new Person("zhangsan4",24));
al.add(5);//自动装箱,基本数据类型赋值给引用数据类型al.add(5)
//相当于al.add(new Integer(5))
Iterator it = al.iterator();
while(it.hasNext()){
//Sop(it.next().getName);失败的原因:在add的时候,已经自动将
Person提升为Object类型了,但Object中没有getName方法
//Sop(((Person)it.next()).getName()+"::"+((Person)it.next()).getAge());//在里面放俩个next,它会指向下一个数据,会输出zhangsan1::22 zhangsan 3 : :24,会出现问题,所以代码应该如下:
Person p = (Person) it.next();
//多次调用it.next()先给它取个名字
Sop(p.getName()+"::"+p.getAge());
}
}
}
将以下代码放置于另一个java文件中
publicclass Person{
privateString name;
privateintage;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
}
public String getName() {
returnname;
}
publicvoidsetName(String name) {
this.name = name;
}
publicintgetAge() {
returnage;
}
publicvoidsetAge(int age) {
this.age = age;
}
}
③、LinkedList:内部是链表数据结构,是不同步的。增删元素速度快
LinkedList常见方法 | ||||
| jdk1.6以前 | jdk1.6 | 共同点 | 区别 |
添加 | addFirst | offerFirst | 将指定元素插入此列表的开头 |
|
addLast | offerLast | 在此列表末尾插入指定的元素。 |
| |
获取 | getFirst | peekFirst | 获取元素,但不删除 | 如果链表为空,则抛出NoSuchElementException |
getLast | peekLast | 如果链表为空,返回null | ||
删除 | removeFirst | pollFirst | 获取元素并删除,还返回删除的元素 | 如果链表为空,则抛出NoSuchElementException |
removeLast | pollLast | 如果链表为空,返回null |
面试题
import java.util.Iterator;
import java.util.LinkedList;
class Queue{
privateLinkedList link;
Queue(){
link = new LinkedList();
}
publicvoid myAdd(Object obj){
link.add(obj);
}
publicObject myGet(){
returnlink.removeLast();// 队列:先进先出(FIFO)
//return link.removeFirst();//堆栈:先进后出(FILO)
}
publicboolean isNull(){
returnlink.isEmpty();
}
}
publicclass InterviewTest {
/*
* 请使用LinkedList来模拟一个堆栈或者队列数据结构容器,
* 即描述这样一个容器,给使用对象提供一个容器完成这俩种结构的一种
* 堆栈:先进后出(FILO)
* 队列:先进先出(FIFO)
*/
publicstaticvoidmain(String[] args) {
Queue q = new Queue();
q.myAdd("hufei1");
q.myAdd("hufei2");
q.myAdd("hufei3");
while(!q.isNull()){
Sop(q.myGet());
}
}
}
6.3.4 Set
1、其方法与collection一致
2、特点: 元素不可重复,无序。
3、HashSet:
⑴、哈希表:是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射方法叫做散列方法,存放记录的数组叫做散列表。
⑵、哈希方法的构造方法: 除留余数法:取关键字被某个不大于哈希表毕表长m的数p除后所得余数为哈希地址。
⑶、冲突:
①含义:对于不同的关键字可能得到同一哈希地址
②哈希表确定关键字是否相同的方法:先判断的是俩个元素的哈希值是否相同。如果相同,在判断俩个对象的内容是否相同。判断哈希值相同,就是判断对象的hashCode()方法,判断内容相同,用的是equals方法,当然,如果哈希值不同,是不需要判断equals的
③处理冲突的方法:链地址法
⑷、LinkedHashSet:哈希表与链表的实现
⑸、代码示例:
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
publicclass SetDemo {
publicstaticvoidmain(String[] args) {
HashSet<Person> hs = new HashSet<Person>();
/*
* HashSet集合数据结构是哈希表,所以存储的时候,使用的元素
* 的hashCode方法来确定位置,如果位置相同,在通过元素的
* equals确定是否相同。
*/
hs.add(new Person("hufei1",21));
hs.add(new Person("hufei2",22));
hs.add(new Person("hufei2",22));
/* 为什么打印的结果是22::hufei2 22::hufei2,HashSet的元
* 素不是不可以相同的吗?因为Person类继承的是Object类的
* 法,于是使用的元素的hashCode方法来确定位置,而位置相同,
* 再利用元素的equals来确定,可是在Object中equals方法比较
* 的是地址值,每new一个对象,其地址值就不一样,所以打印的
* 结果是这个样子的,所以要根据Person自己的特点,创建自己的
* hashCode和equals方法
*/
hs.add(new Person("hufei3",23));
hs.add(new Person("hufei4",24));
Sop(hs.remove(newPerson("hufei1",21)));
Iterator<Person> it =hs.iterator();
while(it.hasNext()){
Person p =(Person)it.next();
Sop(p.getAge()+"::"+p.getName());
}
Sop("以上为HashSet的代码示例的结果,以下为LinkedHashSet的代码示例的结果");
HashSet<Person>hs1 = new LinkedHashSet<Person>();
//即要保证有序,又要保证唯一就用LinkedHashSet
hs1.add(new Person("hufei1",21));
hs1.add(new Person("hufei2",22));
hs1.add(new Person("hufei3",23));
Iterator<Person> it1 =hs1.iterator();
while(it1.hasNext()){
Person p1 =(Person)it1.next();
Sop(p1.getAge()+"::"+p1.getName());
}
}
}
4、TreeSet
排序方法一:让元素自身具备比较功能,然后实现Comparable接口,覆盖compareTo方法。
publicclass TreeSetDemo {
publicstaticvoid main(String[] args) {
Demo_1();
//只是为了说明TreeSet可以对Set集合中的元素进行指定的排序
TreeSet<Person> ts = new TreeSet<Person>();
ts.add(new Person("zhangsan",28));
ts.add(new Person("wangwu",24));
ts.add(new Person("lisi",29));
ts.add(new Person("zhaoliu",30));
Iterator<Person> it =ts.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
Sop(p.getName()+":::"+p.getAge());
}
}
privatestaticvoidDemo_1() {
TreeSet<String> ts = new TreeSet<String>();
ts.add("yaner");
ts.add("hufei");
ts.add("meiqi");
ts.add("mama");
Iterator<String> it =ts.iterator();
while(it.hasNext()){
Sop(it.next());
}
}
}
排序方法二;如果不按照对象中的自然顺序进行排序,或者不具备自然顺序时,可以使用这种方式,即让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法,将该对象作为参数传递给TreeSet集合的构造方法。
publicclass ComparatorByName implements Comparator {
int compare(Object o1, Object o2) {
Personp1 = (Person)o1;
Person p2 = (Person)o2;
int temp = p1.getName().compareTo(p2.getName());
return temp==0?p1.getAge()-p2.getAge():temp;
}
}
}
以上代码的Person类的代码:
publicclass Person implements Comparable{
privateString name;
privateintage;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
publicint hashCode() {
returnname.hashCode()+age*45;//可以乘任意数值
}
@Override
publicboolean equals(Object obj) {
if(this==obj){
returntrue;
}
if(!(obj instanceof Person)){
Sop("类型不符");
}
Person p = (Person)obj;//类型强转
returnthis.name.equals(p.name);
}
publicPerson() {
super();
}
public String getName() {
returnname;
}
publicvoidsetName(String name) {
this.name = name;
}
publicintgetAge() {
returnage;
}
publicvoidsetAge(int age) {
this.age = age;
}
@Override
publicint compareTo(Object o) {
//返回的是int的原因:compareTo返回的正数、负数或零
Person p = (Person)o;
//------------以下为年龄排序----------------------
// if(this.age>p.age)
// return 1;
// if(this.age>p.age)
// return -1;
// return this.name.compareTo(p.name);
//------------以上代码太烂------------------------------
// int temp = this.age-p.age;
// return temp == 0 ? this.name.compareTo(p.name):temp;
//------------以姓名排序--------------------------
int temp = this.name.compareTo(p.name);
return temp == 0 ? this.age-p.age:temp;
}}
6.4Map
6.4.1 Map概述
1、Map的特点
⑴、Map:一次添加一对元素,Collection一次添加一个元素。
⑵、Map也称双列集合,Collection也称单列集合,在集合框架中并列存在
⑶、其实Map集合存储的就是键值对,Map集合中键必须保证唯一性。
⑷、Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素
⑸、Map存储元素使用put方法,Collection使用add方法。
2、常用方法:
⑴、添加
valueput(key,value);返回前一个和key关联的值,如果没有就返回null。
putAll(Map<? extends K,? extendsV> m)
⑵、删除
value clear();清空map集合。
valueremove();根据指定的key翻出这个键值对。
⑶、判断
booleancontainKey(key);
booleancontainValue(value);
booleanisEmpty();
⑷、获取
valueget(key):通过键获取值,如果没有该键返回null,当然也可以通过返回null,来判断是否包含指定键。
intsize():获取键值对的个数。
⑸、values方法
3、重点方法:获取所有的键值对的方式
⑴、Set<k> keySet
privatestaticvoidmethod_2(Map<Integer, String> map) {
Set<Integer>keySet = map.keySet();
Iterator<Integer>it = keySet.iterator();
while (it.hasNext()) {
Integer key = it.next();
Stringvalue = map.get(key);
Sop(key+ "=" + value);
}
}
⑵、Set<Map.Entry<k,v>>entrySet:提倡用这种方法
将map集合中的映射关系存入到了set集合中,而这个关系的数据类型就是:Map.Entry。Entry其实就是Map中的一个static内部接口。为什么要定义在内部呢?因为只有有了Map集合,有了键值对,才会有键值的映射关系。关系属于Map集合中的一个内部事物。而且该事物在直接访问Map集合中的元素。
privatestaticvoidmethod_3(Map<Integer, String> map) {
Set<Map.Entry<Integer,String>> entrySet = map.entrySet();
// public static interfaceMap.Entry<K,V>:Entry<K,V>是Map内部接口
Iterator<Entry<Integer,String>> it = entrySet.iterator();
while (it.hasNext()) {
Map.Entry<Integer,String> me = it.next();
Integerkey = me.getKey();
Stringvalue = me.getValue();
Sop(key+ "=" + value);
}
}
4、 map常用的子类:
Map皆空常用的实现类有Hashtable,HashMap和TreeMap,通常建议使用HashMap结合实现Map集合,因为HashMap类实现Map集合对于添加和删除映射效率更高.HashMap是给予哈希表的Map接口的实现,HashMap通过哈希吗对其内部的映射关系进行快速查找。
而TreeMap中的映射关系存在一定的顺序,如果希望Map集合中的对象存在一定的顺序,应该使用TreeMap类实现Map集合.Map和Set很像,Set底层就是使用了Map集合。
注意:面试时,问HashMap和Hashtable的区别:
HashMap:允许null作为键,null作为值
Hashtable:不允许null作为键,null作为值
⑴、Hashtable:内部结构是哈希表,是同步的,不允许null作为键,null作为值
Properties:用来存储键值对型的配置文件的信息,可以和IO技术结合
⑵、HashMap:内部结构是哈希表,不是同步的。允许null作为键,null作为值。
①、HashMap代码示例②
publicclass HashMapDemo {
// 需求:将学生对象和学生的归属地通过键与值存储到map集合中
publicstaticvoidmain(String[] args) {
HashMap<Student, String> hm = new HashMap<Student, String>();
hm.put(new Student("hufei", 23), "九江");
hm.put(new Student("zhouxia", 21), "宁波");
hm.put(new Student("hubing", 21), "宜春");
hm.put(new Student("wuxuan", 22), "上饶");
hm.put(new Student("zhouxia", 21), "浙江");
// Set<Student> keySet = hm.keySet();
// Iterator<Student> it = keySet.iterator();
Iterator<Student> it =hm.keySet().iterator();
while (it.hasNext()) {
Student key = it.next();
String value = hm.get(key);
Sop(key.getName() + ":" + key.getAge() + "--" + value);
}
// -----------------注---------意---------------------------
// hm.put(new Student("zhouxia", 21), "宁波")和hm.put(new Student ("zhouxia", //21), "浙江")的键相同但却没有被覆盖,原因是hash有自己的判断标准,所以我们要自定义//我们的判断规则,只需要在Person类中通过hashcode和equals方法建立规则就行
}
}
②、LindkedHashMap代码示例
publicclass LinkedHashMapDemo {
//HashMap是无序的,如何有序?有序是指怎么存入就怎么取出。要有序只需利LinkedHashMap
publicstaticvoidmain(String[] args) {
HashMap<Integer, String> hm = new LinkedHashMap<Integer, String>();
hm.put(1, "九江");
hm.put(78, "宁波");
hm.put(6, "宜春");
hm.put(22, "上饶");
Iterator<Map.Entry<Integer,String>> it = hm.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, String> me= it.next();
Integer key = me.getKey();
String value = me.getValue();
Sop(key + "=" + value);
}
}
}
⑶、TreeMap:内部结构是二叉树,不是同步的,可以对Map集合中的键值对进行排序
publicclass TreeMapDemo {
// 需求:将学生对象和学生的归属地通过键与值存储到map集合中
publicstaticvoid main(String[]args) {
TreeMap<Student, String> tm = new TreeMap<Student, String>(new CompareByName());
tm.put(new Student("hufei", 23), "九江");
tm.put(new Student("zhouxia", 21), "宁波");
tm.put(new Student("hubing", 22), "宜春");
tm.put(new Student("wuxuan", 22), "上饶");
tm.put(new Student("zhouxia", 21), "浙江");
Iterator<Map.Entry<Student,String>> it = tm.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Student, String> me =it.next();
Student key = me.getKey();
String value = me.getValue();
Sop(key.getName() + ":" + key.getAge() + "---"+ value);
}
}
}
6.4.2 工具类
1、Collections
collections是集合框架的工具类 里面的方法都是静态的方法
⑴、排序:用俩个mySort方法来写俩个sort()方法源码
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
publicclass CollectionsDemo {
publicstaticvoidmain(String[] args) {
List<String> list = new ArrayList<String>();
list.add("ad");
list.add("ter");
list.add("fae");
list.add("dsjfa");
Collections.sort(list);
mySort1(list);
Sop(list);
mySort2(list,new ComparatorByLength());
Collections.sort(list,new ComparatorByLength());
Sop(list);
}
privatestatic<T> void mySort2(List<T> list,Comparator<? super T> comp){
for (int i = 0; i < list.size() - 1; i++) {
for (int j = i + 1; j < list.size(); j++) {
if (comp.compare(list.get(i), list.get(j)) >0) {
Collections.swap(list,i, j);
}
}
}
}
privatestatic<T extends Comparable<? super T>> void mySort1(List<T> list){
for (int i = 0; i < list.size() - 1; i++) {
for (int j = i + 1; j < list.size(); j++) {
if (list.get(i).compareTo(list.get(j)) > 0){
// T temp = list.get(i);
// list.set(i, list.get(j));
// list.set(j, temp);
// -----以上的代码是以下代码的原码-----------------
Collections.swap(list,i, j);
}
}
}
}
}
⑵、折半
int index = Collections.binarySearch(list,"add");
Sop(index);// 其结果是:-2,什么意思?(-(插入点)-1)
⑶、最值
String max1 =Collections.max(list);
Stringmax2 = Collections.max(list, new ComparatorByLength());
Sop(max1);
Sop(max2);
⑷、逆序
①、逆序的源码
TreeSet<String>ts = new TreeSet<String>(new ComparatorByLength(){
public intcomparator(String s1, String s2) {
int temp = s2.length()-s1.length();
return temp == 0 ? s2.compareTo(s1) : temp;
}
});
②、逆序排序
TreeSet<String>ts = new TreeSet<String>(Collections.reverseOrder());
③、根据自己定义的比较器进行逆序排序
TreeSet<String>ts = new TreeSet<String>( Collections.reverseOrder(new ComparatorByLength()));
⑸、替换及其他方法
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
publicclass ReverseOrderDemo
publicstaticvoidmain(String[] args) {
List<String> ts = new ArrayList<String>();
ts.add("fafa");
ts.add("joi");
ts.add("eowru");
ts.add("weu");
Sop(ts);
// 原理:set(indexOf("fafa"),"hugei")
Collections.replaceAll(ts, "fafa", "hugei");
Sop(ts);
Collections.shuffle(ts);// 随机排序,可用于洗牌等。
Sop(ts);
Collections.fill(ts, "obj");// 将所有的元素换成obj。
Sop(ts);
}
}
⑹、自定义比较器
import java.util.Comparator;
publicclass ComparatorByLength implements Comparator<String> {
@Override
publicint compare(String o1, String o2) {
int temp = o1.length() - o2.length();
return temp == 0 ? o1.compareTo(o2) : temp;
}
}
⑺、Collections和Collection有什么区别?
①、Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。它有
两个常用的子接口,List:对元素都有定义索引。有的。可以重复元素。Set:不可以重复元素。
无序。
②、Collections是集合框架中的一个工具类。该类中的方法都是静态的
ⅰ、提供的方法中有可以对list集合进行排序,二分查找等方法。
ⅱ、通常常用的集合都是线程不安全的。因为要提高效率。
ⅲ、如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,
转换成安全的。
2、Arrays
⑴、二分查找
binarySearch
(XX[] a, XX key)
:使用二分搜索法来搜索指定的XX型数组,以获得指定的值。
binarySearch
(XX[]a, int fromIndex, int toIndex, XX key)
使用二分搜索法来搜索指定的XX型数组的范围,以获得指定的值。
XX
可以是byte、char、double、float、int、long、short等。
⑵、复制指定的数组
copyOf
(XX[] original, int newLength)
复制指定的数组,截取或用false或0填充(如有必要),以使副本具有指定的长度。
copyOfRange
(XX[]original, int from, int to)
XX
可以是byte、char、double、float、int、long、short、boolean等
⑶、数组比较
equals
(XX[] a, XX[] a2)
如果两个指定的XX型数组彼此相等,则返回true。
⑷、排序
sort
(XX[] a)
对指定的 XX型数组按数字升序进行排序。
sort
(XX[] a, intfromIndex, int toIndex)
对指定 XX 型数组的指定范围按数字升序进行排序。
XX
可以是byte、char、double、float、int、long、short、Object等。
sort
(T[] a, Comparator<? superT> c)
根据指定比较器产生的顺序对指定对象数组进行排序。
sort
(T[] a, intfromIndex, int toIndex, Comparator<? superT> c)
根据指定比较器产生的顺序对指定对象数组的指定范围进行排序。
⑸、toString()
publicclass ArraysDemo {
publicstaticvoidmain(String[] args) {
int[] arr = { 4, 2, 5, 3, 1 };
Sop(Arrays.toString(arr));
String str = MyToString(arr);
Sop(str);
}
// toString的经典实现,toString的原代码
privatestatic String MyToString(int[] arr) {
if (arr == null)
return"null";
int iMax = arr.length - 1;
if (iMax == -1)
return"[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0;; i++) {// 中间省略了条件判断,提高了效率
b.append(arr[i]);
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
}
⑹、集合与数组互相转换的方法
①将数组转成集合:asList方法
好处:这样可以用集合的方法操作数组中的元素
注意:ⅰ、数组的长度是固定的,所以对数组的增删方法是会出现异常的
{
List<int[]> list = Arrays.asList(arr);
boolean b = list.contains(1);
// list.add(4);这样添加会出现UnsupportedOperationException
Sop(b);
}
ⅱ、 如果数组中的元素是对象,那么转成集合时,直接将数组的元素作为集合中的元素进行集合存储;如果数组中的元素是基本数据类型,那么会将该数组作为集合中的元素进行存储
List<int[]> list = Arrays.asList(arr);
Sop(list);
//打印结果是:[[I@bb0d0d],即list中只有一个元素。
②数组转集合toArray()
toString方法需要传入一个指定类型的数组。该方法返回值有两种形式:一种是Object类型,一
种是
返回的是<T> T[]
,而我们一般应该选择后一种。
长度该如何决定?如果长度小于集合的size,那么该方法会创建一个同类型并和集合相同size的数组如果长度大于集合的size,那么该方法会使用指定的数组,存储集合中的元素,其他位置并默认为null 所以建议,长度指定为集合的size
好处:可以对集合中的元素的操作方法进行限定,不允许进行增删。
privatestaticvoidtoArrayDemo(){
List<String> list = new ArrayList<String>();
list.add("abc1");
list.add("abc2");
list.add("abc3");
String[] arr = list.toArray(new String[list.size()]);
Sop(Arrays.toString(arr));
}
3、方法可变参数
⑴、其实就是一个数组,但是接收的是数组的元素。自动将这些元素封装成数组,简化了调用者的书写。
⑵、注意:方法可变参数,必须定义在参数的结尾处,只能有一个。
⑶、应用:asList
(T... a)
方法就用了
⑷、代码
publicclass ParamterDemo {
publicstaticvoidmain(String[] args) {
// int sum = add(4,5);
// Sop(sum);
// int sum1 = add(4,5,4);
// }
// private static int add(int i, int j, intk) {
// return i+j+k;
// }
// private static int add(int i, int j) {
// return i+j;
// }
// ---------从可以看出,假如数据量很大,我们可以利用数组------
int[] arr = { 3, 4, 12, 43, 5 };
int sum = add(arr);
Sop(sum);
// ------但上面的方法依然很怂,我们可以利用jdk1.5新特性 方法可变参数-----
int newSum = newAdd(arr);
Sop(sum);
}
privatestaticint newAdd(int... arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
privatestaticintadd(int[] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
}
4、静态导入
其实导入的就是类中的静态成员。
6.4.3 结合总结
1、需要唯一吗 ?
需要:set
需要制定顺序;
需要:TreeSet
不需要:HashSet
但是想要一个和存储一致的顺序:LinkedHashSet
不需要:List
需要频繁增删吗
需要:LinkedList
不需要ArrayList
2,如何记录每一个容器的结构和所属体系呢?
看名字:
List
|--LinkedList
|--ArrayList
Set
|--TreeSet
|--HashSet
后缀名就是该集合所属体系,前缀名就该集合所属结构。
看到Array:就要想到数组,想到查询快,有角标
看到link:就要想到链表表,想到增删快,要想到add,get remove+first last方法
看到hash:就要想到哈希表,想到唯一性,想到元素需要覆盖;hashcode方法和equals方法
看到tree:就要想到二叉树,想到排序,想到俩个接口Comparator和comparable
而且通常这想法常用的集合都不同步。
3、给非同步的集合加锁
List list = new ArrayList();//非同步的
listMyCollections.synList(list)//返回一个同步的
class MyCollections{
public List synList(list){
return new MyList(list);
}
}
private class MyListimplements List{
private List list;
private static final Object lock = newObject();
MyList(List list){
this.list = list;
}
public boolean add(Object obj){
synchronized(lock){
return list.add(obj);
}
}
public boolean remove(Object obj){
synchronized(lock){
return list.remove(obj);
}
}
对于非同步的集合,在框架中,提供了一个方法将其变成同步。他是synchronizedXxx(xxx<T> c)
6.5 其他对象
6.5.1 System类
publicclass SystemDemo {
privatestaticfinalString LINE_SEPARATOR = System.getProperty("line.separator");
/*
*System类中的方法和属性都是静态的
*常见方法currentTimeMillis():返回当前时间与协调世界时1970年1月1 日午夜之间
*的时间差
*/
publicstaticvoidmain(String[] args) {
long l1 = 1372734194222l;// System.currentTimeMillis();
Sop(l1 / 1000 / 60 / 60 / 24 + LINE_SEPARATOR);
long l2 = System.currentTimeMillis();
Sop(l2 - l1);
// 给系统设置一些属性信息,其他程序都可以用
System.setProperty("hufei", "yaner");
Dome_1();
}
privatestaticvoidDome_1() {
/*
*获取系统的属性信息,这些信息是全局的,其他程序都是可以使用的。
*properties集合中存储的都是String类型的键和值,最好使用它自己的 存储和取出的
*方法来完成元素的操作。
*/
Properties prop = System.getProperties();// 获取当前的系统属性
Set<String> nameSet =prop.stringPropertyNames();
// stringPropertyNames()返回此属性列表中的键集,其中该键及其对应值是字符串
for (String name : nameSet) {
String value =prop.getProperty(name);//获取指定键指示的系统属性
Sop(name + "::" + value);
}
}
}
6.5.2 Runtime类
publicclass RuntimeDemo {
/*
*Runtime:没有构造方法,说明该类不可以创建对象又发现还有静态方法,说明该类应该提
* 供静态的返回该类对象的方法而且只有一个,说明Runtime类使用了单例设计模式。
*/
publicstaticvoidmain(String[] args) throws IOException,
InterruptedException {
Runtime r = Runtime.getRuntime();
Process p = r.exec("notepad.exeC:\\RuntimeDemo.java");
// 会抛出异常,因为有可能没有该执行文件,即exe文件
Thread.sleep(5000);
p.destroy();
}
}
6.5.3 Math类
publicclass MathDemo {
/*
*Math:提供了操作数学运算的方法,都是静态方法
* 常用的方法
* ceil:返回大于参数的最小整数
* floor:返回小于参数的最大整数
*round返回四舍五入的整数
* pow(a,b):a的b次方。
*/
publicstaticvoidmain(String[] args) {
for (int i = 0; i < 10; i++) {
int d = (int) (Math.random() * 10 + 1);
Sop(d);
}
Random r = new Random();
for (int i = 0; i < 10; i++) {
int d= r.nextInt(10) + 1;
Sop(d);
}
//上面两方法功能一样
double d1 = Math.ceil(12.46);
double d2 = Math.floor(12.46);
double d3 = Math.round(12.46);
double d4 = Math.pow(10, 5);
Sop(d1);
Sop(d2);
Sop(d3);
Sop(d4);
}
}
6.5.4 Data类
1、日期对象和毫秒值之间的转换。
⑴、毫秒值转成日期对象
①、通过Data对象的构造方法:new Data(timeMillis)
②、可以通过setTime设置
为什么要转?因为可以通过Data对象的方法对该日期中的各个字段进行操作
⑵、日期对象转成毫秒值
①、通过getTime设置
为什么要转?因为可以通过具体的数值进行运算。
2、常见方法 日期的比较: after、before、compareTo的方法
publicclass DataDemo {
publicstaticvoidmain(String[] args) throws ParseException {
long time = System.currentTimeMillis();
Sop(time);// 1372749625346
Date d = new Date();// 将当前日期和时间封装成对象
Sop(d);// Tue Jul 02 15:21:49 CST 2013
Date d2 = new Date(1372749625346l);// 将指定的毫秒值封装成Data对象
Sop(d2);
}
3、日期对象与日期字符串之间的转换
⑴、 日期对象转成日期字符串:对日期对象进行格式化, 将日期对象转换成日期字符串,使用的是DataFormat类中的format方法
publicclass DataToString {
publicstaticvoidmain(String[] args) {
Date d = new Date();
// 获取日期格式对象,具有着默认的风格。FULL LONG等
DateFormat dateFormat1 = DateFormat.getDateInstance(DateFormat.FULL);
DateFormat dateFormat2 = DateFormat.getDateTimeInstance(
DateFormat.FULL, DateFormat.FULL);
// 如何自定义日期格式风格
dateFormat2 = new SimpleDateFormat("yyyy--MM--dd");
String str_data1 =dateFormat1.format(d);
String str_data2 =dateFormat2.format(d);
Sop(str_data1);
Sop(str_data2);
}
⑵、日期字符串转成日期对象:将日期字符串转换成日期对象,使用的是DataFormat类中的
publicclass StringToData {
publicstaticvoidmain(String[] args) throws ParseException {
String str_date = "2013-07-02";
DateFormat dateFormat = DateFormat.getDateInstance();
dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = dateFormat.parse(str_date);
Sop(date);
}
4、练习 “2012-3-17”到“2012-4-6”中间有多少天
思路:两个日期相减就O了,必须要有两个可以进行相减运算的数。能减的可以是毫秒值,如何获取?通过Data对象,如何获取data对象?可以将字符串转成data对象。
publicclassDataDemo {
publicstaticvoid main(String[] args) throws ParseException {
String str_date1 = "2012-3-17";
String str_date2 = "2012-4-6";
DateFormat dateFormat = DateFormat.getDateInstance();
Date date1 = dateFormat.parse(str_date1);
Date date2 = dateFormat.parse(str_date2);
longtime1 = date1.getTime();
longtime2 = date2.getTime();
longtime = Math.abs(time1 - time2);
intday = getDay(time);
Sop(day);
}
privatestaticintgetDay(long time) {
intday = (int) (time / 1000 / 60 / 60 / 24);
returnday;
}
}
6.5.5 Calendar类
publicclass CalendarDemo {
publicstaticvoidmain(String[] args) {
Calendar c = Calendar.getInstance();
c.set(1990, 03, 12);
c.add(Calendar.YEAR, 23);
c.add(Calendar.MONTH, 3);
c.add(Calendar.DAY_OF_MONTH, -10);
String[] months = { "1月", "2月", "3月", "4月",
"5月", "6月", "7月", "8月",
"9月", "10月", "11月", "12月" };
String[] weeks = { "星期一", "星期二", "星期三", "星期四",
"星期五", "星期六", "星期日" };
int index = c.get(Calendar.MONTH);
int index1 = c.get(Calendar.DAY_OF_WEEK);
sop(c.get(Calendar.YEAR) + "年");
sop(months[index]);
sop(c.get(Calendar.DAY_OF_MONTH) + "日");
sop(weeks[index1]);
}
}