Java总结(7)集合

来源:互联网 发布:tfidf java高效 编辑:程序博客网 时间:2024/05/20 16:40


集合框架简述

在JDK API 中专门设计了一组类,这组类的功能就是实现各种各样方式的数据存储,这样一组专门用来存储其它对象的类,一般被称为对象容器类,简称容器类,这组类和接口的设计结构也被统称为集合框架(Collection Framework)。
这组类和接口都包含在java.util 包中。
为了使整个集合框架中的类便于使用,在设计集合框架时大量的使用接口,实际实现的功能类实现对应的接口,这样可以保证各个集合类的使用方式保持统一。

在集合框架中两种存储方式:

①:按照索引值操作数据
在这种存储方式中,为每个存储的数据设定一个索引值,存储在容器中的第一个元素索引值是0,第二个索引值是1,依次类推。在操作数据时按照索引值操作对应的数据,实现这种方式的集合类都实现java.util.Collection 接口。
②:按照名称操作数据
在这种存储方式中,为每个存储的数据设定一个名称(任意非null 的对象都可以作为名称),以后按照该名称操作该数据,要求名称不能重复,每个名称对应唯一的一个值。这种存储数据的方式也称作名称-数值对,也就是名值对存储。实现这种方式的几个类都实现java.util.Map 接口。

特点:

1:对象封装数据,对象多了也需要存储。集合用于存储对象。
2:对象的个数确定可以使用数组,但是不确定怎么办?可以用集合。因为集合是可变长度的。

集合和数组的区别:

1:数组是固定长度的;集合可变长度的。
2:数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
3:数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。

数据结构:就是容器中存储数据的方式。

对于集合容器,有很多种。因为每一个容器的自身特点不同,其实原理在于每个容器的内部数据结构不同。
集合容器在不断向上抽取过程中。出现了集合体系。
在使用一个体系时,原则:参阅顶层内容。建立底层对象。



Collection接口

Collection:
|--List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引。元素可以重复。
|--Set:无序(存入和取出顺序有可能不一致),不可以存储重复元素。必须保证元素唯一性。
1,添加:
        add(object):添加一个元素
        addAll(Collection) :添加一个集合中的所有元素。
2,删除:
        clear():将集合中的元素全删除,清空集合。
        remove(obj) :删除集合中指定的对象。注意:删除成功,集合的长度会改变。
        removeAll(collection) :删除部分元素。部分元素和传入Collection一致。
3,判断:
        boolean contains(obj) :集合中是否包含指定元素 。
        boolean containsAll(Collection) :集合中是否包含指定的多个元素。    
        boolean isEmpty():集合中是否有元素。 
4,获取:
        int size():集合中有几个元素。
5,取交集:
        boolean  retainAll(Collection) :对当前集合中保留和指定集合中的相同的元素。如果两个集合元素相同,返回flase;如
        果retainAll修改了当前集合,返回true。
6,获取集合中所有元素:
        Iterator  iterator():迭代器
7,将集合变成数组:
        toArray();

Iterator接口:

迭代器:是一个接口。作用:用于取集合中的元素。
 boolean  hasNext()  如果仍有元素可以迭代,则返回 true。
 E  next()   返回迭代的下一个元素。
 void  remove()  从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
 每一个集合都有自己的数据结构,都有特定的取出自己内部元素的方式。为了便于操作所有的容器,取出元素。将容器内部的取出方式按照一个统一的规则向外提供,这个规则就是Iterator接口。
也就说,只要通过该接口就可以取出Collection集合中的元素,至于每一个具体的容器依据自己的数据结构,如何实现的具体取出细节,这个不用关心,这样就降低了取出元素和具体集合的耦合性。
Iterator it = coll.iterator();//获取容器中的迭代器对象,至于这个对象是是什么不重要。这对象肯定符合一个规则Iterator接口。

使用Iterator 遍历程序

public static void main(String[] args) {        Collection coll = new ArrayList();        coll.add("abc0");        coll.add("abc1");        coll.add("abc2");//--------------方式1----------------------        Iterator it = coll.iterator();        while(it.hasNext()){                System.out.println(it.next());        }//---------------方式2用此种----------------------        for(Iterator it = coll.iterator();it.hasNext(); ){                System.out.println(it.next());        }        }

List接口:

List本身是Collection接口的子接口,具备了Collection的所有方法。现在学习List体系特有的共性方法,查阅方法发现List的特有方法都有索引,这是该集合最大的特点。
List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引。元素可以重复。
|--ArrayList:底层的数据结构是数组,线程不同步,ArrayList替代了Vector,查询元素的速度非常快。
|--LinkedList:底层的数据结构是链表,线程不同步,增删元素的速度非常快。
|--Vector:底层的数据结构就是数组,线程同步的,Vector无论查询和增删都巨慢。
 1,添加:
        add(index,element) :在指定的索引位插入元素。
        addAll(index,collection) :在指定的索引位插入一堆元素。
2,删除:
        remove(index) :删除指定索引位的元素。 返回被删的元素。
3,获取:
        Object get(index) :通过索引获取指定元素。
        int indexOf(obj) :获取指定元素第一次出现的索引位,如果该元素不存在返回-1;
        所以,通过-1,可以判断一个元素是否存在。
        int lastIndexOf(Object o) :反向索引指定元素的位置。
        List subList(start,end) :获取子列表。
4,修改:
        Object set(index,element) :对指定索引位进行元素的修改。
5,获取所有元素:
        ListIterator listIterator():list集合特有的迭代器。
        List集合支持对元素的增、删、改、查。
        List集合因为角标有了自己的获取元素的方式: 遍历。
      for(int x=0; x<list.size(); x++){
            sop("get:"+list.get(x));
      }
在进行list列表元素迭代的时候,如果想要在迭代过程中,想要对元素进行操作的时候,比如满足条件添加新元素。会发生.ConcurrentModificationException并发修改异常。
导致的原因是:
集合引用和迭代器引用在同时操作元素,通过集合获取到对应的迭代器后,在迭代中,进行集合引用的元素添加,迭代器并不知道,所以会出现异常情况。
如何解决呢?
既然是在迭代中对元素进行操作,找迭代器的方法最为合适.可是Iterator中只有hasNext,next,remove方法.通过查阅的它的子接口,ListIterator,发现该列表迭代器接口具备了对元素的增、删、改、查的动作。
ListIterator是List集合特有的迭代器。
ListIterator it = list.listIterator;//取代Iterator it = list.iterator;

方法摘要

 void  add(E e) 将指定的元素插入列表(可选操作)。
 boolean  hasNext() 以正向遍历列表时,如果列表迭代器有多个元素,则返回 true(换句话说,如果 next 返回一个元素而不是抛出异常,则返回 true)。
 boolean  hasPrevious() 如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。
 E  next() 返回列表中的下一个元素。
 int  nextIndex() 返回对 next 的后续调用所返回元素的索引。
 E  previous() 返回列表中的前一个元素。
 int  previousIndex() 返回对 previous 的后续调用所返回元素的索引。
 void  remove() 从列表中移除由 next 或 previous 返回的最后一个元素(可选操作)。
 void  set(E e) 用指定元素替换 next 或 previous 返回的最后一个元素(可选操作)。
可变长度数组的原理:
当元素超出数组长度,会产生一个新数组,将原数组的数据复制到新数组中,再将新的元素添加到新数组中。
ArrayList:是按照原数组的50%延长。构造一个初始容量为 10 的空列表。
Vector:是按照原数组的100%延长。
注意:对于list集合,底层判断元素是否相同,其实用的是元素自身的equals方法完成的。所以建议元素都要复写equals方法,建立元素对象自己的比较相同的条件依据。
LinkedList:的特有方法。
addFirst();
addLast();
在jdk1.6以后。
offerFirst();
offerLast();
getFirst():获取链表中的第一个元素。如果链表为空,抛出NoSuchElementException;
getLast();
在jdk1.6以后。
peekFirst();获取链表中的第一个元素。如果链表为空,返回null。
peekLast();
removeFirst():获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,抛出NoSuchElementException
removeLast();
在jdk1.6以后。
pollFirst();获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,返回null。
pollLast();

Set接口:

Set接口中的方法和Collection中方法一致的。Set接口取出方式只有一种,迭代器。
|--HashSet:底层数据结构是哈希表,线程是不同步的。无序,高效;
HashSet集合保证元素唯一性:通过元素的hashCode方法,和equals方法完成的。
当元素的hashCode值相同时,才继续判断元素的equals是否为true。
如果为true,那么视为相同元素,不存。如果为false,那么存储。
如果hashCode值不同,那么不判断equals,从而提高对象比较的速度。
      |--LinkedHashSet:有序,hashset的子类。
|--TreeSet:对Set集合中的元素的进行指定顺序的排序。不同步。TreeSet底层的数据结构就是二叉树。

哈希表的原理:

1,对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值 称为哈希值。
2,哈希值就是这个元素的位置。
3,如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就
  存储,在原来对象的哈希值基础 +1顺延。
4,存储哈希值的结构,我们称为哈希表。
5,既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象的关键字是唯一的。
这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。
  对于ArrayList集合,判断元素是否存在,或者删元素底层依据都是equals方法。
  对于HashSet集合,判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法。

TreeSet:

用于对Set集合进行元素的指定顺序排序,排序需要依据元素自身具备的比较性。
如果元素不具备比较性,在运行时会发生ClassCastException异常。
所以需要元素实现Comparable接口,强制让元素具备比较性,复写compareTo方法。
依据compareTo方法的返回值,确定元素在TreeSet数据结构中的位置。
TreeSet方法保证元素唯一性的方式:就是参考比较方法的结果是否为0,如果return 0,视为两个对象重复,不存。
  注意:在进行比较时,如果判断元素不唯一,比如,同姓名,同年龄,才视为同一个人。
在判断时,需要分主要条件和次要条件,当主要条件相同时,再判断次要条件,按照次要条件排序。
TreeSet集合排序有两种方式,Comparable和Comparator区别:
1:让元素自身具备比较性,需要元素对象实现Comparable接口,覆盖compareTo方法。
2:让集合自身具备比较性,需要定义一个实现了Comparator接口的比较器,并覆盖compare方法,并将该类对象作为实际参数传递给TreeSet集合的构造函数。
第二种方式较为灵活。

Map集合:

|--Hashtable:底层是哈希表数据结构,是线程同步的。不可以存储null键,null值。
|--HashMap:底层是哈希表数据结构,是线程不同步的。可以存储null键,null值。替代了Hashtable.
|--TreeMap:底层是二叉树结构,可以对map集合中的键进行指定顺序的排序。
Map集合存储和Collection有着很大不同:
Collection一次存一个元素;Map一次存一对元素。
Collection是单列集合;Map是双列集合。
Map中的存储的一对元素:一个是键,一个是值,键与值之间有对应(映射)关系。
特点:要保证map集合中键的唯一性。
1,添加。
 put(key,value):当存储的键相同时,新的值会替换老的值,并将老值返回。如果键没有重复,返回null。
void putAll(Map);
2,删除。
void clear():清空
value remove(key) :删除指定键。
3,判断。
boolean isEmpty():
boolean containsKey(key):是否包含key
boolean containsValue(value) :是否包含value
4,取出。
int size():返回长度
value get(key) :通过指定键获取对应的值。如果返回null,可以判断该键不存在。当然有特殊情况,就是在hashmap集合中,是可以存储null键null值的。
Collection values():获取map集合中的所有的值。
5,想要获取map中的所有元素:
原理:map中是没有迭代器的,collection具备迭代器,只要将map集合转成Set集合,可以使用迭代器了。之所以转成set,是因为map集合具备着键的唯一性,其实set集合就来自于map,set集合底层其实用的就是map的方法。
把map集合转成set的方法:
Set keySet();
Set entrySet();//取的是键和值的映射关系。
   Entry就是Map接口中的内部接口;
   为什么要定义在map内部呢?entry是访问键值关系的入口,是map的入口,访问的是map中的键值对。

取出map集合中所有元素的方式一:keySet()方法。

可以将map集合中的键都取出存放到set集合中。对set集合进行迭代。迭代完成,再通过get方法对获取到的键进行值的获取。
Set keySet = map.keySet();Iterator it = keySet.iterator();while(it.hasNext()) {    Object key = it.next();    Object value = map.get(key);    System.out.println(key+":"+value);}

取出map集合中所有元素的方式二:entrySet()方法。

Set entrySet = map.entrySet();Iterator it = entrySet.iterator();while(it.hasNext()) {    Map.Entry  me = (Map.Entry)it.next();    System.out.println(me.getKey()+"::::"+me.getValue());}

使用集合的技巧:

看到Array就是数组结构,有角标,查询速度很快。
看到link就是链表结构:增删速度快,而且有特有方法。addFirst; addLast; removeFirst(); removeLast(); getFirst();getLast();
看到hash就是哈希表,就要想要哈希值,就要想到唯一性,就要想到存入到该结构的中的元素必须覆盖hashCode,equals方法。
看到tree就是二叉树,就要想到排序,就想要用到比较。
比较的两种方式:
一个是Comparable:覆盖compareTo方法;
一个是Comparator:覆盖compare方法。
LinkedHashSet,LinkedHashMap:这两个集合可以保证哈希表有存入顺序和取出顺序一致,保证哈希表有序。
集合什么时候用?
当存储的是一个元素时,就用Collection。当存储对象之间存在着映射关系时,就使用Map集合。
保证唯一,就用Set。不保证唯一,就用List。

接口的实现类

List 系列

List 系列的类均实现List 接口,大部分的类都以List 作为类名的后缀,也有部分该体系中的类命名比较特殊。
该系列中的类,比较常见的有ArrayList 和LinkedList 两个。其中ArrayList 是以数组为基础实现的List,而LinkedList 则是以链表为基础实现的List,ArrayList 拥有数组的优点,而LinkedList 拥有链表的优点。
由于该体系中的类均实现List 接口,所以在这些类的内部,相同的功能方法声明是保持一致的,下面进行一一介绍:
a、add 方法
boolean add(Object o)
该方法的作用是追加对象o 到已有容器的末尾。
另外一个add 方法:
void add(int index, Object element)
该方法的作用是将对象element 插入到容器中索引值为index 的位置,原来位于该位置的对象以及后续的内容将依次向后移动。
b、addAll 方法
boolean addAll(Collection c)
该方法的作用是将容器对象c 中的每个元素依次添加到当前容器的末尾。
另外一个addAll 方法:
boolean addAll(int index, Collection c)
该方法的作用是将容器对象c 中的第一个元素插入到当前容器中索引值为index的位置,第二个元素插入到当前容器中索引值为index+1 的位置,依次类推。而当前容器中原来位于index 以及index 索引值以后的元素则依次向后移动。
c、get 方法
Object get(int index)
该方法的作用是返回当前容器对象中索引值为index 的元素的内容。
d、indexOf 方法
int indexOf(Object o)
该方法的作用是查找当前容器中是否存在对象o,如果存在则返回该对象第一次出现位置的索引值,如果不存在则返回-1。另外一个方法lastIndexOf 则是从末尾向前查找,返回从末尾向前第一次出现位置的索引值,如果不存在则返回-1。
e、remove 方法
Object remove(int index)
该方法的作用是删除索引值为index 的对象的内容,如果删除成功则返回被删除对象的内容。
另外一个remove 方法:
boolean remove(Object o)
该方法的作用是删除对象内容为o 的元素,如果相同的对象有多个,则只删除索引值小的对象。如果删除成功则返回true,否则返回false。无论使用哪一个remove 方法,类内部都自动移动将被删除位置后续的所有元素向前移动,保证索引值的连续性。
f、set 方法
Object set(int index, Object element)
该方法的作用是修改索引值为index 的内容,将原来的内容修改成对象element的内容。
g、size 方法
int size()
该方法的作用是返回当前容器中已经存储的有效元素的个数。
h、toArray 方法
Object[] toArray()
该方法的作用是将当前容器中的元素按照顺序转换成一个Object 数组。下面是一个简单的以ArrayList 类为基础实现的List 系列中类基本使用的示例,代码如下:
import java.util.*;/*** 以ArrayList 类为基础演示List 系列类的基本使用*/public class ArrayListUse {        public static void main(String[] args) {                //容器对象的初始化                List list = new ArrayList();                //添加数据                list.add("1");                list.add("2");                list.add("3");                list.add("1");                list.add("1");                //插入数据                list.add(1,"12");                //修改数据                list.set(2, "a");                //删除数据                list.remove("1");                //遍历                int size = list.size(); //获得有效个数                //循环有效索引值                for(int i = 0;i < size;i++){                        System.out.println((String)list.get(i));                }        }}

该程序的运行结果为:
12
a
3
1
1
在List 系列中,还包含了Stack(栈)类和Vector(向量)类,Stack 类除了实现List 系列的功能以外,还实现了栈的结构,主要实现了出栈的pop 方法和入栈的push 方法。而Vector 类由于需要兼容老版本JDK 中缘故,所以在实现的方法中需要提供老版本Vector 类中对应的方法,这样导致Vector 类中相同或类似的功能方法一般是成对出现的。

Set 系列

Set 系列中的类都实现了Set 接口,该系列中的类均以Set 作为类名的后缀。该系列中的容器类,不允许存储重复的元素。也就是当容器中已经存储一个相同的元素时,无法实现添加一个完全相同的元素,也无法将已有的元素修改成和其它元素相同。
Set 系列中类的这些特点,使得在某些特殊场合的使用比较适合。
该系列中常见的类有:
1、CopyOnWriteArraySet
以数组为基础实现的Set 类。
2、HashSet
以哈希表为基础实现的Set 类。
3、LinkedHashSet
以链表为基础实现的Set 类。
4、TreeSet
以树为基础实现的Set 类。
以不同的数据结构类型实现的Set 类,拥有不同数据结构带来的特性,在实际使用时,根据逻辑的需要选择合适的Set 类进行使用。
Set 系列中的类的方法和List 系列中的类的方法要比List 系列中少很多,例如不支持插入和修改,而且对于Set 系列中元素的遍历也需要转换为专门的Iterator(迭代器)对象才可以进行遍历,遍历时顺序和Set 中存储的顺序会有所不同。
下面是以HashSet 类为基础实现的示例代码,代码如下:
import java.util.*;/*** 以HashSet 为基础演示Set 系列类的基本使用*/public class HashSetUse {        public static void main(String[] args) {                //容器对象的初始化                Set set = new HashSet();                //添加元素                set.add("1");                set.add("2");                set.add("3");                set.add("1");                set.add("1");                //删除数据                //set.remove("1");                //遍历                Iterator iterator = set.iterator();                while(iterator.hasNext()){                        System.out.println((String)iterator.next());                }        }}
该程序的运行结果为:
3
2
1

Map 系列

Map 系列中的类都实现了Map 接口,该系列中的部分类以Map 作为类名的后缀。该系列容器类存储元素的方式和以上两种完全不同。
Map 提供了一种使用“名称:值”这样的名称和数值对存储数据的方法,在该存储方式中,名称不可以重复,而不同的名称中可以存储相同的数值。具体这种存储的格式将在示例代码中进行实现。
在这种存储结构中,任何不为null 的对象都可以作为一个名称(key)来作为存储的值(value)的标识,使用这种形式更利于存储比较零散的数据,也方便数据的查找和获得。Map 类中存储的数据没有索引值,系统会以一定的形式索引存储的名称,从而提高读取数据时的速度。
该系列中常见的类有:
1、HashMap
以Hash(哈希表)为基础实现的Map 类。
2、LinkedHashMap
以链表和Hash(哈希表)为基础实现的Map 类。
3、TreeMap
以树为基础实现的Map 类。
和上面的结构类似,以不同的数据结构实现的Map 类,拥有不同数据结构的特点,在实际的项目中使用时,根据需要选择合适的即可。
该系列的类中常见的方法如下:
a、get 方法
Object get(Object key)
该方法的作用是获得当前容器中名称为key 的结构对应的值。
b、keySet 方法
Set keySet()
该方法的作用是返回当前容器中所有的名称,将所有的名称以Set 的形式返回。使用这个方法可以实现对于Map 中所有元素的遍历。
c、put 方法
Object put(Object key, Object value)
该方法的作用是将值value 以名称key 的形式存储到容器中。
d、putAll 方法
void putAll(Map t)
该方法的作用是将Map 对象t 中的所有数据按照原来的格式存储到当前容器类中,相当于合并两个Map 容器对象。
e、remove 方法
Object remove(Object key)
该方法的作用是删除容器中名称为key 的值。
f、size 方法
int size()
该方法的作用是返回当前日期中存储的名称:值数据的组数。
g、values 方法
Collection values()
该方法的作用是返回当前容器所有的值组成的集合,以Collection 对象的形式返回。
下面是一个简单的示例,在该示例中演示Map 系列类的基本使用,代码如下:
import java.util.*;/*** 以HashMap 为基础演示Map 系列中类的使用*/public class HashMapUse {        public static void main(String[] args) {                //容器对象的初始化                Map map = new HashMap();                //存储数据                map.put("苹果", "2.5");                map.put("桔子", "2.5");                map.put("香蕉", "3");                map.put("菠萝", "2");                //删除元素                map.remove("桔子");                //修改元素的值                map.put("菠萝", "5");                //获得元素个数                int size = map.size();                System.out.println("个数是:" + size);                //遍历Map                Set set = map.keySet();                Iterator iterator = set.iterator();                while(iterator.hasNext()){                        //获得名称                        String name = (String)iterator.next();                        //获得数值                        String value = (String)map.get(name);                        //显示到控制台                        System.out.println(name + ":" + value);                }        }}
该程序的运行结果为:
个数是:3
香蕉:3
菠萝:5
苹果:2.5

总结:

在本篇中,主要介绍了java.lang 包和java.util 包中比较常见的类的使用,熟悉了JDK API 的基本使用,掌握了文档的查阅以及方法调用等一些基本的技能,为以后的学习打下坚实的基础。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 pr导出视频后显示素材丢失怎么办 ps抠下来的图边缘发白怎么办 ps中抠出的图边缘虚不圆滑怎么办 ps的文字工具多了圆框怎么办 苹果6s屏幕锁忘了密码怎么办 网上下载的3d模型渲染很慢怎么办 cad下载完成后出现闪退怎么办 婴儿在肚子里被系带绑到怎么办 我想给外地的朋友送花怎么办 英雄联盟连接不上聊天服务器怎么办 用黄金换玫瑰金后悔了怎么办 劳力士日志系列玫瑰金和黄金怎么办 香菇代进地注水后长满绿毛怎么办 群主给你带了不满意的头衘怎么办 普兰德雪地靴洗变色了怎么办 书被水泡了皱了黏了怎么办 书被水泡了皱了没干怎么办 眼皮干燥起皮起皱怎么办能治好吗 手指头起小水泡指甲不平整怎么办 这几天我的内裤上带点血丝怎么办 一个月宝宝私处捂白了怎么办 工资算了字签了老板没把钱怎么办 百合种球叶子都变黄了怎么办 新买的富贵竹叶子发黄怎么办水养 朋友总是以隐私为借口欺骗我怎么办 三星手机版本低下载不了微信怎么办 选了动漫制作技术但不会画画怎么办 做主播高薪可是心累不愿做了怎么办 pr导出的avi无压缩太大怎么办 捡了个小米max被绑定了怎么办 二十岁时头发开始掉了怎么办 在酒店换衣服忘记关窗帘了怎么办 淘宝店铺装修更改图片要收费怎么办 惠阳市教育考试考证号忘记怎么办 高考完被被骗去读自考以后怎么办 孩子学习遇到瓶颈期了老师该怎么办 微信家长群有不好的言论出现怎么办 铃木汽车后备箱电动锁没有电怎么办 坐飞机没有连号座位带孩子怎么办 白沙的衣服洗衣服时染上颜色怎么办 网购商家少发了货怎么办