------Java培训、Android培训、iOS培训、.Net培训、期待与您交流!
一、集合概述
集合框架图:
这就是Java中集合框架的体系,在以后的使用中参考顶层接口,创建底层对象。
一、为什么出现集合类?
面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
二、数组和集合类同是容器,有何不同?
数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。
三、为什么有这么多集合?集合的特点又是什么?
集合就是一个容器,存储的是对象的引用(地址),因为每一个容器对数据的存储方式都有所不同,这个存储方式称为:数据结构。集合只用于存储对象,集合的长度是可变的,可以存储不同类型的对象。
二、Collection
Collection是集合框架中的常用接口。我们经常使用的是它的两个子接口(List、Set)的子类。Collection
|----List:元素是有序的,元素可以重复。因为该集合体系有索引。
|-----Set:元素是无序的,元素不可以重复。
Collection共性方法:
1.添加
boolean add(Object obj) 传入的参数类型是Object类型,以便接收任意类型对象。
2.删除
boolean remove(Object obj)
boolean removeAll(另一集合) 只保留另一集合中没有的元素。
void clear() 清空集合
3.判断
contains(Object obj);//判断集合中是否存在指定元素
isEmpty();//判断集合是否为空
4、获取集合的长度
int size();
5、取交集
boolean retainAll(另一集合)//调用者只保留和被调用者中相同的元素,被调用的集合不变,若无交集,调用者变成空。
下面用代码进行演示://创建集合迭代:
Collection coll=new ArrayList();
//添加元素
coll.add("java01");
coll.add("java02");
coll.add("java03");
//获取集合的长度
coll.size();
//删除元素
coll.remove("java02");
//判断元素是否存在于集合中
boolean b= coll.contains("java03");
//清空集合
coll.clear();
迭代是取出集合中元素的一种方式。对于集合的元素取出这个动作:不足以用一个函数来描述,需要用多个功能来体现,所以就将取出这个动作封装成一个对象来描述。就把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内部的元素,那么取出方式就被定义成了内部类。每一个容器的数据结构不同,所以取出的动作细节也不同,但是都有共性内容:判断和取出。那么就将共性抽取。抽取出来的规则就是Iterator(迭代器),通过一个对外提供的方法:iterator(),来获取集合中的迭代器。Collection的子类集合对象中都有迭代器。
下面通过一段代码,介绍迭代器的获取和具体方法的使用。如下:
//创建集合迭代器在Collection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。迭代器的next方法是自动向下取出元素,要避免出现NoSuchElementException。迭代器中的next方法返回值类型是Object,要记得类型转换。
Collection coll=new ArrayList();
//添加元素
coll.add("java01");
coll.add("java02");
coll.add("java03");
coll.add("java03");
//通过iterator方法,获取迭代器
Iterator it=coll.iterator();
//hasNext()方法 :判断是否还有下一个元素,有则返回true。
while(it.hasNext()){
//next()方法:取出下一个元素
String s=(String)it.next();
System.out.println(s);
if("java01".equals(s))
//迭代器中在迭代过程中可以通过remove方法移除指定元素
it.remove();
}
//在迭代循环过程中,next调用一次,就用hasNext()判断一次。
三、List
List:元素是有序的,元素可以重复。因为该集合体系有索引。
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
|--LinkedList:底层使用的是链表数据结构。特点:增删速度很快,查询稍慢。
|--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。
List的特有方法:List的方法都是可以操作脚标的方法。例如:
1、增加
void add(index,element);//指定位置添加元素
boolean addAll(index,Collection);//在指定位置增加给定集合中的所有元素,若省略位置参数,则在当前集合的后面依次添加元素
2、删除
remove(index);//删除指定位置的元素,返回被删除的元素
3、修改
set(index,element);//修改指定位置的元素。返回被修改的元素
4、获取
get(index);//通过脚标获取元素
subList(from,to);//获取部分对象元素
5、其他
listIterator();//List特有的迭代器
indexOf(obj);//获取元素第一次出现的位置,如果没有则返回-1
List集合判断元素是否相同,移除等操作,依据的是元素的equals方法。
ListIterator:
ListIterator是List集合特有的迭代器,是Iterator的子接口。在迭代时,ListIterator除了可以对元素进行判断、取出、删除外,还具备添加元素,修改元素的功能。通过List集合的listIterator方法获取。下面一段代码对其进行演示:
List list=new ArrayList();LinkedList:底层是链表结构。特有方法如下:
//添加元素
list.add("java01");
list.add("java02");
list.add("java03");
list.add("java03");
//通过listIterator方法,获取迭代器
ListIterator it=list.listIterator();
while(it.hasNext()){
String s=(String)it.next();
System.out.println(s);
if("java01".equals(s))
//迭代器中在迭代过程中修改指定元素
it.set("haha");
//添加元素,
it.add("no");
}
1.增加:addFirst();addLast();
2.获取:getFirst();getLast();
获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException
3.删除:removeFirst();removeLast();
获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException
JDK1.6出现了替代方法:
1.增加:offerFirst();offerLast();
2.获取:peekFirst();peekLast();
获取元素,但不删除元素。如果集合中没有元素,会返回null。
3.删除:pollFirst();pollLast();
获取元素,但是元素被删除。如果集合中没有元素,会返回null。
下面是利用LinkedList的一段程序,如下:
/**
需求:使用LinkedList模拟一个队列数据结构。
队列:先进先出 First in First out FIFO 如同一个水管。
*/
class DuiLie
{
//定义一个LinkedList引用,成员方法可以使用其方法
private LinkedList link;
DuiLie()
{
link = new LinkedList();
}
//定义添加方法
public void myAdd(Object obj)
{
link.addFirst(obj);
}
//定义获取方法
public Object myGet()
{
return link.removeLast();
}
//判断是否为空
public boolean isNull()
{
return link.isEmpty();
}
}
class LinkedListTest
{
public static void main(String[] args)
{
//建立队列对象
DuiLie dl = new DuiLie();
//添加元素
dl.myAdd("java01");
dl.myAdd("java02");
dl.myAdd("java03");
dl.myAdd("java04");
//取出元素
while(!dl.isNull())
System.out.println(dl.myGet());
}
}
四、Set
Set:元素是无序的(存入和取出的顺序不一定一致),元素不可以重复
|——HashSet:底层结构是哈希表,线程不同步,保证元素唯一性的原理:判断元素的hashCode值是否相同,如果相同,还会继续判断元素的equals方法,返回值是否为true。
|——TreeSet: 底层是二叉树结构,可以对Set集合中的元素进行排序,默认按照字母的自然顺序,保证元素唯一性的一句:compareTo方法,返回值是否为0。
Set集合的操作方法和Collection是一致的。
1.HashSet:
线程不安全,存取速度块。可以通过元素的两个方法hashCode和equals来保证元素的唯一性。如果hashCode值相同,才判断equals方法的返回值是否为true;如果hashCode不同,不调用equals方法。HashSet中判断元素是否存在,以及删除等操作,依据的都是元素的hashCode和equals方法下面通过一段代码,对HashSet的使用进行学习。如下:
/**
需求:往hashSet集合中存入自定义对象
姓名和年龄相同为同一个人,重复元素。
*/
class HashSetDemo
{
public static void main(String[] args)
{
//建立HashSet集合
HashSet hs = new HashSet();
//添加元素
hs.add(new Student("小明",11));
hs.add(new Student("大明",12));
hs.add(new Student("阿亮",13));
hs.add(new Student("小明",12));
hs.add(new Student("老罗",14));
//对元素进行迭代
Iterator it = hs.iterator();
while(it.hasNext())
{
Student s= (Student)it.next();
System.out.println(s.getName()+"::"+s.getAge());
}
}
}
//定义学生类
class Student
{
//定义学生的姓名和年龄属性
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
//复写hashCode方法,自定义对象的hashCode算法
public int hashCode()
{
return name.hashCode()+age*37;
}
//复写equals方法。
public boolean equals(Object obj)
{
//判断传入对象是否是本类型
if(!(obj instanceof Student))
return false;
//向下转换
Student s = (Student)obj;
//姓名和年龄都相同时,返回true,为相同的对象。
return this.name.equals(p.name) && this.age == p.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
2.TreeSet
可以对Set集合中的元素进行排序。
特点:
1.底层的数据结构是二叉树结构。
2.可读Set集合中的元素进行排序,是因为TreeSet类实现了Comparable接口,该接口强制对增加到集合的对象进行了比较,需要复写comparrTo方法,才能让对象满足需求(如:比较人的年龄大小)继续排序,加入集合。Java中的很多类都具备比较性其实就是实现了Comparable。当排序时的主要条件相同时,会按次要条件排序。
3.保证数据的唯一性的一句:通过compareTo方法的返回值,返回值为正整数、负整数和0,为0时元素为相同对象不存入集合。
TreeSet有两种对添加元素进行比较的方法:自然排序和比较器排序。
(1)自然排序:让元素自身具备比较性,元素需要实现Comparable接口,覆盖compareTo方法,这种放称为元素的自然排序,或者加默认排序。下面通过代码进行演示:
/**使用这种方法对元素进行排序,要求元素自身必须具备比较性。
需求:往TreeSet集合中存入自定对象
姓名和年龄相同为同一个人,重复元素。
并按年龄的大小排序。
年龄相同 ,按姓名首字母的自然顺序排序。
*/
class TreeSetDemo
{
public static void main(String[] args)
{
//建立TreeSet集合
TreeSet ts = new TreeSet();
//添加元素
ts.add(new Student("小明",11));
ts.add(new Student("大明",12));
ts.add(new Student("阿亮",13));
ts.add(new Student("小明",12));
ts.add(new Student("老罗",14));
//对元素进行迭代
Iterator it = ts.iterator();
while(it.hasNext())
{
Student s= (Student)it.next();
System.out.println(s.getName()+"::"+s.getAge());
}
}
}
//定义学生类,实现Comparable接口
class Student implements Comparable
{
//定义学生的姓名和年龄属性
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
//复写compareTo方法,按年龄大小进行比较,年龄相同,比较姓名
public int compareTo(Object obj)
{ if(!(obj instanceof Student))
throw new ClassCastException("该对象不是学生类型");
Student s=(Student)obj;
if(this.age==s.age)
return this.name.compareTo(s.name);
return this.age-s.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
(2)比较器:当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时就让集合自身具备比较性。当集合初始化时,就有了比较方式。定义一个比较器,将比较器对象作为参数传给TreeSet集合的构造函数。
比较器构造方式:定义一个类,实现Comparator接口,需要覆盖compare方法。注意当两种排序方式都存在时,以比较器为主。如下面的程序:
/**
需求:往TreeSet集合中存入自定对象
姓名和年龄相同为同一个人,重复元素。
以姓名的长短排序,姓名的长度相同时,以年龄大小排序
使用比较器。
*/
class ReflectTest1
{
public static void main(String[] args)
{
//建立TreeSet集合,传入比较器对象
TreeSet ts = new TreeSet(new MyComparator());
//添加元素
ts.add(new Student("小明",11));
ts.add(new Student("王大明",12));
ts.add(new Student("李阿亮",13));
ts.add(new Student("欧阳小明",12));
ts.add(new Student("老罗",14));
//对元素进行迭代
Iterator it = ts.iterator();
while(it.hasNext())
{
Student s= (Student)it.next();
System.out.println(s.getName()+"::"+s.getAge());
}
}
}
//定义一个比较器,实现Comparator接口
class MyComparator implements Comparator
{
//复写compare方法,定义以姓名长短的比较方法。长短相同时比较年龄大小
public int compare(Object o1,Object o2)
{
if(!(o1 instanceof Student )&&!(o2 instanceof Student))
throw new ClassCastException("对象不是学生类型");
Student s1=(Student)o1;
Student s2=(Student)o2;
int num=0;
if((num=s1.getName().length()-s2.getName().length())==0)
return s1.getAge()-s2.getAge();
return num;
}
}
//定义学生类
class Student implements Comparable
{
//定义学生的姓名和年龄属性
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
//复写compareTo方法,按年龄大小进行比较
public int compareTo(Object obj)
{ if(!(obj instanceof Student))
throw new ClassCastException("该对象不是学生类型");
Student s=(Student)obj;
if(this.age==s.age)
return this.name.compareTo(s.name);
return this.age-s.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
五、Map
Map<k、v>集合是一个接口,和List集合以及Set集合不同的是,它是双列集合,并且可以给对象加上名字,即键(Key).该集合存储键值对,一对一往里存。存入元素时要保证键的唯一性。
Map
|-----HashTable :底层是哈希表结构,不可以存入null键,null值,线程同步,JDK1.0出现,效率低。
|-----HashMap : 底层是哈希表结构,可以存入null键,null值,线程不同步,JDK1.2出现。效率高。
|-----TreeMap: 底层是二叉树结构。线程不同步,可以用于给Map集合中的键排序。
Map和Set很像,其实Set底层就是使用了Map集合。
Map的常用方法:
1.添加
V put(K key,V value);添加元素,如果添加元素时,出现相同的键,后添加的值会覆盖原有键对应的值,并返回被覆盖的值。
void putAll(Map<? extends K,? extends V> m);添加一个集合。
2.删除
V remove(Object key)删除指定映射关系,返回被删除的映射关系中的值。
void clear() 清空集合
3.判断
containsKey(Object key) 判断是否含有指定键
containsValue(Object Value) 判断是否含有指定值
isEmpty() 集合是否为空
4.获取
V get(Object key) 获取指定键对应的值,HashMap集合中可以通过get()方法的返回值判断一个键是否存在。返回null不 存在
size() 获取集合的长度
values();返回集合中的所有值。
下面通过代码对Map中的方法进行演示,如下:
Map<String,String> map = new HashMap<String,String>();
//添加元素,如果添加时,出现相同的键。那么后添加的值会覆盖原有键对应值。
map.put("01","张三");
map.put("01","李四");
map.put("02","王五");
map.put("03","陈六");
//删除键值对
map.remove("01");
//获取指定键的对应值
map.get("02");
//获取集合的长度
map.size();
//获取map集合中所有的值。
Collection<String> coll = map.values();
将Map集合转换成Set集合,再通过迭代器取出。具体方法有以下两种:
1.Set<k> keySet():将Map中的所有的键存到Set集合中,因为Set具备迭代器。所以通过迭代方式取出所有的键,再通过get方法获取每个键对应的值。
2.Set<Map.Entry<K、V>> entry():将Map集合中的映射关系存放到Set集合中,而这个关系的数据类型是:Map.Entry。Entry是一个接口,它是Map接口中的一个内部接口,可以通过它具有的getKey()和getValue()方法获得对应的键和值。
这里还要对Map.Entry做一个介绍:Map.Entry之所以定义在内部,是因为Map集合中存在的是映射关系的两个数据,是先有Map集合,才可以有映射关系的存在,而且此类关系是集合的内部事务,这个映射关系可以直接访问Map集合中的成员,所以定义在集合内部。
下面通过一段程序,分别表示Map取出元素的两种方式:
<pre name="code" class="java"> //创建Map集合,这里用到了泛型。
Map<String,String> map = new HashMap<String,String>();
//添加元素,如果添加时,出现相同的键。那么后添加的值会覆盖原有键对应值。
map.put("01","张三");
map.put("01","李四");
map.put("02","王五");
map.put("03","陈六");
//第一种:将Map中所有的键存到Set集合中
Set<String> keyset=map.keySet();
//对set集合进行迭代
Iterator<String> it=keyset.iterator();
while(it.hasNext()){
//获取键
String key=it.next();
//通过map的get方法,获取对应值
String value=map.get(key);
System.out.println(key+"..."+value);
}
//第二种:将Map中的所有映射关系存放到Set中
Set<Map.Entry<String, String>> entryset=map.entrySet();
Iterator<Map.Entry<String, String>> it1=entryset.iterator();
while(it1.hasNext()){
Map.Entry<String, String> me=it1.next();
//通过Map.Entry的方法,获取键和对应的值
String key=me.getKey();
String value=me.getValue();
System.out.println(key+"..."+value);
}
}
下面是一段Map集合使用的练习,当要存储的数据之间存在映射关系时,就会用到map集合,如下:
/**在操作,有时数据是一对多的映射,这时就需要在Map集合中嵌套一个集合。如下面的程序:
每一个学生都有对应的归属地。
学生Student,地址String。
学生属性:姓名,年龄。
注意:姓名和年龄相同的视为同一个学生。
保证学生的唯一性。
*/
//定义学生类,具备比较性
class Student implements Comparable<Student>
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
//复写compareTo方法,以年龄大小为比较的主要条件
public int compareTo(Student s)
{
int num = this.age-s.age;
if(num==0)
return this.name.compareTo(s.name);
return num;
}
//复写hashCode方法
public int hashCode()
{
return name.hashCode()+age*34;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Student))
throw new ClassCastException("类型不匹配");
Student s = (Student)obj;
return this.name.equals(s.name) && this.age==s.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public String toString()
{
return name+":"+age;
}
}
class MapTest
{
public static void main(String[] args)
{
HashMap<Student,String> hm = new HashMap<Student,String>();
//添加元素
hm.put(new Student("lisi1",21),"beijing");
hm.put(new Student("lisi1",21),"tianjin");
hm.put(new Student("lisi2",22),"shanghai");
hm.put(new Student("lisi3",23),"nanjing");
hm.put(new Student("lisi4",24),"wuhan");
//第一种取出方式 keySet
Set<Student> keySet = hm.keySet();
Iterator<Student> it = keySet.iterator();
while(it.hasNext())
{
Student stu = it.next();
String addr = hm.get(stu);
System.out.println(stu+".."+addr);
}
//第二种取出方式 entrySet
Set<Map.Entry<Student,String>> entrySet = hm.entrySet();
Iterator<Map.Entry<Student,String>> iter = entrySet.iterator();
while(iter.hasNext())
{
Map.Entry<Student,String> me = iter.next();
Student stu = me.getKey();
String addr = me.getValue();
System.out.println(stu+"........."+addr);
}
}
}
/**
一个学校中每个教室名对应一个教室,而在每一个教室中每一个学号对应一个学生名,如:
"yureban" "01" "zhangsan";
"yureban" "02" "lisi";
"jiuyeban" "01" "wangwu";
"jiuyeban" "02" "zhaoliu";
*/
class ReflectTest1
{
public static void main(String[] args)
{
//创建预热班集合
HashMap<String,String> yureban=new HashMap<String,String>();
//创建就业班集合
HashMap<String,String> jiuyeban=new HashMap<String,String>();
//学校集合
HashMap<String,HashMap<String,String>> czbk=new HashMap<String,HashMap<String,String>>();
//存入教室名和对应的教室。
czbk.put("yureban",yureban);
czbk.put("jiuyueban",jiuyeban);
//预热班级中存入学号和对应的学生名。
yureban.put("01","zhangsan");
yureban.put("02","lisi");
//预热班级中存入学号和对应的学生名。
jiuyeban.put("01","wangwu");
jiuyeban.put("02","zhouqi");
//获取每个学生信息
for (Iterator<String> it=czbk.keySet().iterator();it.hasNext();)
{ //教室名称
String roomName= it.next();
System.out.println(roomName+":");
//获取到每个教室
HashMap<String,String> stu=czbk.get(roomName);
//获取每个教室中的学生信息
for (Iterator<String> it1=stu.keySet().iterator();it1.hasNext();)
{ //学号、姓名
String id=it1.next();
String name=stu.get(id);
System.out.println(id+"..."+name);
}
}
}
}
Collections是集合框架的一个工具类,它里面的方法都是静态的,不需要创建对象,并没封装特有数据。在Collections中大部分方法是用来对List集合进行操作的,如比较、二分查找、随机排序等。
常见操作:
1、排序
sort(List<T>list)按自然顺序排序
sort(List<T>list,Comparator<? super T> c) 根据比较器排序
2.查找
T max(Collection<? extends T> coll) 根据集合的自然顺序,获取最大值
T max(Collection<? extends T> coll,Comparator<? super T>c) 根据比较器,获取最大值
int binarySearch(List<? extends Comparable<? super T> c>list,T key) 二分法查找
3.替换
void fill(List<? super T>list, T obj) 集合中的元素全部替换成指定指定元素
boolean replaceAll(List<T>list,T oldVal,T newVal) 替换指定元素
void swap(List list,int i,int j)位置置换
void shuffle(List<T>list)随机置换
4、反转
void reverse(List<?>list)
reverseOrder() 强行逆转Comparable接口
reverseOrder(Comparator<T>comp)强行逆转一个比较器,返回一个比较器。
5.同步
LIST<T> synchronizedList(List<T> list) 返回支持的同步List集合。
Map<K、V> synchronizedMap(Map<K、V>m) 返回支持的同步map集合。
下面通过代码,看一下Collections的使用,如下:
List<String> list=new ArrayList<String>();Collections和Collection的区别:
list.add("abc");
list.add("abd");
list.add("cbd");
list.add("a");
//给集合中的元素排序
Collections.sort(list);
//取最大值
String s=Collections.max(list);
//替换指定元素
Collections.replaceAll(list, "abc", "ff");
//全部替换
Collections.fill(list,"kkk");
//反转
Collections.reverse(list);
Collection是集合框架的一个顶层接口,里面定义了单列集合的共性方法,常用的子接口是List和Set;Collections是集合框架中的一个工具类,该类中的方法都是静态的,提供的方法可以对List集合进行排序、二分查找等方法。集合通常都是线程不安全的,因为要提高效率,如果多线程操作这些集合时,可以通过Collections的同步方法,将不安全的集合变成安全的。
七、Arrays
Arrays是用于操作数组的工具类,方法都是静态的,不需要创建对象。
常见方法:
1.List<T> asList(T....a) 将数组变为集合
把数组变成集合后,可以使用集合的方法操作数组中的元素。但要注意:.转变后,不可以使用集合的增删方法,因为数组的长度是固定的,如果进行增删操作,则产生UnsupportedOperationException异常。数组中的元素如果都是对象,则这些元素转变后直接变成数组中的元素;如果数组中的元素都是基本数据类型,则将数组变为集合中的一个元素存在。
2.binarySearch、fill、sort等
特点:可对数组进行对应操作,可以接收boolean型之外的基本数据类型及有序的应用类型数组的参数,且还可以对指定的元素的范围,并对指定的范围进行操作。如:sort(T[ ] a,int fromIndex,int toIndex);
3.toString(T[]t )可以将各种类型的数组转换为字符串。
如下:
String[]str={"dbc","adef","bgh"};
//对数组进行排序
Arrays.sort(str);
//查找数值,若不存在,返回-1
int a= Arrays.binarySearch(str, "abc");
System.out.println(a);
//将数组变为字符串
System.out.println(Arrays.toString(str));
//将数组变为集合。
List list= Arrays.asList(str);
System.out.println(list.get(1));
注意:数组可以变成集合,集合也可以变成数组,通过Collections接口中的toArray方法。格式:<T>T[] toArray(T[]a)。集合转成数组时,当指定数组的长度小于集合的长度时,该方法内部会创建一个新的数组,长度是集合的size;相反如果大于集合的长度,则方法中直接使用传递进来的数组。我们在使用此方法时,一般设定数组的长度为集合的长度。为了限定对元素的操作,无法再进行增删操作了。使用该方法如下:
ArrayList<String> al = new ArrayList<String>();
al.add("abc1");
al.add("abc2");
al.add("abc3");
//将集合转变为数组
String[] arr = al.toArray(new String[al.size()]);
//再将数组变成字符串
System.out.println(Arrays.toString(arr));
-------------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------