章六、集合(1)—— Set 接口及实现类、集合迭代、Map 接口、Collections类

一、 Set 接口及实现类


Set接口不能存储重复元素

        Set接口继承了Collection接口。Set中所存储的元素是不重复的,但是是无序的, Set中的元素是没有索引的

Set接口有两个实现类:

        ● HashSet :HashSet类中的元素不能重复

        ● TreeSet :可以给Set集合中的元素进行指定方式的排序。存储的对象必须实现Comparable接口。

  HashSet

import java.util.HashSet;public class HashSetDemo {public static void main(String[] args) {/*Set:元素不重复HashSet:元素是无序的*/HashSet<String> set = new HashSet<>();set.add("a");set.add("b");set.add("c");set.add("a");set.add("d");System.out.println(set);//set.clear();set.contains("a");set.isEmpty();set.remove("a");//没有索引,故而不能用for循环,只能用增强for和迭代器set.size();set.iterator();}
}

HashSet在添加元素时,是如何判断元素重复的:

        当我们向集合中添加一个元素时,如果每次都使用equals()比较内容是否相等,效率会很低
在底层会调用hashCode()方法
-- 在Object中的hashCode()返回的是地址,不能用
-- 而是调用String类中重写的hashCode()方法,返回的是根据内容计算的哈希值

遍历时,会先比较内容的哈希值是否相等,会提高比较的效率,
        但是Hash值会可能存在问题:内容不同,哈希相同(例如“通话”和“种地”的哈希值相同)此种情况下再调用 equals()内容

import javax.xml.transform.Source;
import java.sql.SQLOutput;
import java.util.HashSet;public class HashSetDemo2 {/*HashSet在添加元素时,是如何判断元素重复的:当我们向集合中添加一个元素时,如果每次都使用equals()比较内容是否相等,效率会很低在底层会调用hashCode()方法-- 在Object中的hashCode()返回的是地址,不能用-- 而是调用String类中重写的hashCode()方法,返回的是根据内容计算的哈希值遍历时,会用哈希值先比较是否相等,会提高比较的效率,但是Hash值会可能存在问题,内容不同,哈希相同(例如“通话”和“种地”的哈希值相同)此种情况下再调用 equals()内容*/public static void main(String[] args) {HashSet<String> set = new HashSet<>();set.add("a");set.add("b");set.add("c");set.add("a");set.add("d");System.out.println(set);for (String s : set){System.out.println(s);}}
}

  TreeSet

        可以给Set集合中的元素进行指定方式的排序。由于这些自定义的类型的数据没有实现Comparable接口,因此无法直接在TreeSet集合中进行排序操作

解决方案:

        要求TreeSet集合中存储的元素所在的类必须实现Comparable接口,并重写comoareTo()方法,然后TreeSet集合就会对该类型使用compareTo()方法进行比较,并默认进行升序排序

public class Student implements Comparable<Student>{private int num;private String name;public Student() {}public Student(int num, String name) {this.num = num;this.name = name;}public int getNum() {return num;}public void setNum(int num) {this.num = num;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic int compareTo(Student o) {int temp = this.num - o.num;return temp == 0 ? this.name.compareTo(o.name) : temp;}}
import java.util.Iterator;
import java.util.TreeSet;/*
放入学生信息
要给自定义数据要实现compareTo接口*/
public class TreeSetDemo2 {public static void main(String[] args) {Student s1 = new Student(20,"张三1");Student s2 = new Student(21,"张三2");Student s3 = new Student(20,"张三3");Student s4 = new Student(23,"张三4");Student s5 = new Student(20,"张三1");TreeSet<Student> treeSet = new TreeSet<>();treeSet.add(s4);treeSet.add(s2);treeSet.add(s3);treeSet.add(s1);treeSet.add(s5);System.out.println(treeSet);}
}

  Set 接口集合迭代

        • 增强for循环

import java.util.Iterator;
import java.util.TreeSet;/*
放入学生信息
要给自定义数据要实现compareTo接口*/
public class TreeSetDemo2 {public static void main(String[] args) {Student s1 = new Student(20,"张三1");Student s2 = new Student(21,"张三2");Student s3 = new Student(20,"张三3");Student s4 = new Student(23,"张三4");Student s5 = new Student(20,"张三1");TreeSet<Student> treeSet = new TreeSet<>();treeSet.add(s4);treeSet.add(s2);treeSet.add(s3);treeSet.add(s1);treeSet.add(s5);System.out.println(treeSet);Iterator<Student> iterator = treeSet.iterator();for(Student a : treeSet){System.out.println(a.getNum()+a.getName());}}
}

        • 迭代器遍历

二、 Map 接口 


将键映射到值的对象

Map接口的特性
数据存储是以 (键,值) 的形式存储
键不能重复,值可以重复
一个键只能映射到一个值

一个映射不能包含重复的键,每个键最多只能映射到一个值,即 值 -> 键 是 一对多 的形式

  Map 接口常用方法

V put(K key,V value)        //一次向Map里放入一个键值对

V remove(Object key)        //通过键删除

void clear()        //清空 map

boolean containsKey(Object key)

boolean containsValue(Object value)

boolean isEmpty()

int size()

V get(Object key)

Collection<V> values()

Set<K> keySet()

Set<Map.Entry<K,V>> entrySet()

  HashMap ※

HashMap中元素的key值不能重复, 排列顺序是不固定的,可以存储一个为null的键。

其在存储时到底是什么结构?

首先用到 Hash数组(查询快,定位快),长度默认为16,创建Hash数组主要是用来定位

        然后通过输入的 key 来计算出一个 int类型 的 hash值(hash%数组长度),然后在该 hash值 的索引处创建一个 Next = NULL 的链表

 

 当下一个 key 计算出来的hash值与存在的相同时(即hash冲突),比较该位置的值,如果不相同,则向下链接新节点(拉链法),即将后来的元素添加到之前元素的Next节点;如果相同,则用后来的键的值覆盖原来的值

当某一hash节点处的链表过长( >=8 )时(会影响速度),且哈希数组长度 >=64时,链表会自动转为红黑树

 当哈希表的负载因子为0.75时,会自动扩容为原来数组长度的2倍

         • HashMap方法

import java.util.Collection;
import java.util.HashMap;public class HashMapDemo {public static void main(String[] args) {/*Map接口的特性数据存储是 (键,值)的形式存储键不能重复,值可以重复一个键只能映射到一个值*/HashMap<String,String> map = new HashMap<>();map.put("a","aa"); //(键,值)map.put("b","bb");map.put("w","ww");map.put("c","cc");map.put("d","bb"); //值可以重复map.put("a","aaa"); //用第二次加进的值覆盖了第一次键的值System.out.println(map);//删除指定的键并返回对应的值System.out.println(map.remove("a"));System.out.println(map);//清除 map/*map.clear();System.out.println(map);*///判断map中键值对的个数是否为空System.out.println(map.isEmpty());//判断是否有输入的键System.out.println(map.containsKey("b"));//判断是否有输入的值System.out.println(map.containsValue("bb"));//获得 键的值System.out.println(map.get("b"));//返回map的所有值System.out.println(map.values());}
}

  TreeMap

TreeMap中所有的元素都保持着某种固定的顺序,如果需要得到一个有序的Map就应该使用TreeMap,key值所在类必须实现Comparable接口。

import java.util.TreeMap;
/*
TreeMap
键可以排序
键元素必须实现 Comparable接口,重写compareTo()*/
public class TreeMapDemo1 {public static void main(String[] args) {TreeMap<Integer,String> treeMap  = new TreeMap<>();treeMap.put(2,"aa");treeMap.put(1,"bb");treeMap.put(3,"aa");treeMap.put(5,"cc");treeMap.put(4,"ee");treeMap.put(2,"bb");System.out.println(treeMap);}
}

 

●  HashTable

/*
        在HashMap中可以存储一个 键 或者 值 为null的对象
        但Hashtable不能存储,会直接报错
*/

 

三、 Map集合遍历


●  根据键找值

获取所有键的集合

遍历键的集合,获取到每一个键

根据键找值

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;public class Traverse1 {public static void main(String[] args) {/*方法一:先拿到所有的键,遍历键,根据键找值*///        Collection<String> values = Map.values();
//        System.out.println(values);HashMap<String,String> map = new HashMap<>();map.put("a","aa");map.put("b","bb");map.put("w","ww");map.put("c","cc");System.out.println(map);//第一种遍历方式Set<String> keyset = map.keySet();for(String key : keyset){System.out.println(key+":"+map.get(key));}}
}

●  根据键值对对象找键和值

获取所有键值对对象的集合

遍历键值对对象的集合,获取到每一个键值对对象

根据键值对对象找键和值

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;public class Traverse1 {public static void main(String[] args) {//        Collection<String> values = Map.values();
//        System.out.println(values);HashMap<String,String> map = new HashMap<>();map.put("a","aa");map.put("b","bb");map.put("w","ww");map.put("c","cc");System.out.println(map);//推荐的遍历方式Set<Map.Entry<String,String>> entries = map.entrySet();for(Map.Entry entry : entries){System.out.println(entry.getKey()+":"+entry.getValue());}}
}

四、 Collections


Collections是集合类的工具类,与数组的工具类Arrays类似

addAll(Collection<? super T> c , T ... elements);        //向集合中添加一个可变长度的数组

binarySearch(List<? extends Comparable<? super T >> list, T key)

sort(List<T> list)        //根据元素的自然顺序 对指定列表按升序进行排序

sort(List<T> list, Comparator<? super T> c)        //根据指定比较器产生的顺序对指定列表进行排序。

swap(List<?> list, int i , int j)        //在指定List的指定位置 i , j 处交换元素

copy(List<? super T> dest , List<? extends T> src) ;        //将集合复制

// 注意 dest size >= src.size

fill(List<? super T> list, T obj)        //覆盖

max(Collection<? extends T> coll)        //最大值

min(Collection<? extends T> coll)        //最小值

replaceAl l(List<T> list , T oldVal , T newVal)        //用 newVal 覆盖 list 中的 oldVal

reverse(List<?> list)        //反转列表中元素的顺序

shuffle(List<?> list)        //对List集合元素进行随机排序

copy(dest , src)        //集合复制

 addAll():向集合中添加一个可变长度的数组

import java.util.*;public class CollectionsDemo1 {public static void main(String[] args) {HashMap<String,String> map = new HashMap<>();map.put("a","aaa");map.put("b","bbb");map.put("c","ccc");map.put("d","ddd");map.put("e","eee");/*addAll(Collection < ? super T > c, T... elements);父类对象(可以传进Collection接口的所有对象)T ... elements :可变长度的 T类型的参数作用:向集合中添加元素*/ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);Collections.addAll(list,3,4,5,6);System.out.println(list);//test(1,2,3,4);}/*int ... a 可变长度的参数,本质是一个数组一个参数列表中只能有一个可变长度参数且必须放在参数列表最后*/
//    public static void test(int ... a){
//        System.out.println(Arrays.toString(a));
//    }}

sort():排序,需要根据元素重写

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;public class CollectionsDemo2 {public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);Collections.addAll(list,3,5,2,4);System.out.println(list);//排序---自定义排序规则//创建了一个实现Comparator接口的匿名内部类对象,就是省去创建一个类,简化了语法Collections.sort(list, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2.intValue()-o1.intValue();}});Collections.sort(list);System.out.println(list);}
}

copy():将原集合的值复制到目标集合

注:目标集合必须非空,且目标集合的size>=原集合

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;public class CollectionsDemo3 {public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);list.add(4);System.out.println(list);//交换指定位置上的元素Collections.swap(list,0,1);System.out.println(list);System.out.println();//将一个集合的元素复制到另一个集合去ArrayList<Integer> list1 = new ArrayList<>();//如果目标集合的为空,那copy事会报错list1.add(5);list1.add(6);list1.add(7);//且目标集合的 size >= 原集合的 size,否则报错list1.add(8);Collections.copy(list1,list);System.out.println(list);System.out.println(list1);}
}

其他:

import java.util.ArrayList;
import java.util.Collections;public class CollectionsDemo4 {public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);list.add(4);System.out.println(list);//最大值System.out.println(Collections.max(list));//最小值System.out.println(Collections.min(list));//用newVal覆盖oldValCollections.replaceAll(list,3,5);System.out.println(list);Collections.replaceAll(list,5,3);//翻转集合元素顺序Collections.reverse(list);System.out.println(list);//对集合元素随机排序Collections.shuffle(list);System.out.println(list);}
}

 

五、 泛型


        早期的Object类型可以接收任意的对象类型,但是在实际的使用中,会有类型转换的问题。也就存在这隐患,所以Java提供了泛型来解决这个安全问题。

●  什么是泛型

泛型,即“参数化类型” 。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。

参数化类型,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式,然后在使用/调用时传入具体的类型。

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,泛型的好处就是在编译的时候能够检查类型安全。

●  泛型类

泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口

public class Demo<T>{

/ /T可以为任意标识符,常见的如T、E、K、V等形式的参数常用于表示泛型

        private T key; / /key这个成员变量的类型为T,T的类型由外部指定

        public Demo(T key) {

        / /泛型构造方法形参key的类型也为T,T的类型由外部指定

                this.key = key;

        }

        public T getKey(){ / /泛型方法getKey的返回值类型为T,T的类型由外部指定

                return key;

        }

}

传入的实参类型需与泛型的类型参数类型相同,即为Integer.

1.泛型的类型参数只能是类类型

2.泛型的类型参数可以有多个

3.如果没有定义具体类型,默认为Object

●  从泛型类派生子类

父类:

public class A<T> {T data;
}

子类也是泛型类,子类和父类的泛型类型要一致

class A<T> extends Demo<T>

/*
父类是泛型类
方法一:直接给子类也定义为泛型类
*/
public class B<T> extends A<T>{public static void main(String[] args) {B b = new B();b.data = "String类型";}
}

子类不是泛型类,父类要明确泛型的数据类型

class A extends Demo<String>

/*
父类是泛型类方法二:若子类不是泛型类,那就要在子类中明确指出父类中的泛型
//public class B extends A<String>{*/public class B extends A<String>{public static void main(String[] args) {B b = new B();b.data = "String类型";}
}

●  泛型接口

泛型接口与泛型类的定义及使用基本相同。

public interface Demo<T> { //定义一个泛型接口 }

子类也是泛型类,子类和父类的泛型类型要一致

class A<T> implements Demo<T>{ }

子类不是泛型类,父类要明确泛型的数据类型

public class A implements Demo<String> { }

●  类型擦除

        泛型是Java 1.5版本才引进的概念,在这之前是没有泛型的,但是,泛型代码能够很好地和之前版本的代码兼容。那是因为,泛到信息只存在于代码编译阶段,在进入JVM之前,与泛型相关的信息会被擦除掉,我们称之为一类型擦除。

泛型类被类型擦除后,相应的类型就被替换成 Object 类型或者上限类型。

案例:

public class Demo<T>{

        T name;

        public Demo(T name) {

                this.name= name;

         }

}

Demo是一个泛型类,我们查看它在运行时的状态信息可以通过反射。

Demo<String> demo= new Demo<String>("jim");

Field f = eclz.getField(“name”);

System.out.println(f.getName()+" type:"+f.getType());

name type:java.lang.Object

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/735096.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python(5)之处理数组

上次代码结果如下&#xff1a; 1、处理数组的缺失值 1、isnan&#xff08;&#xff09;函数 isnan&#xff08;&#xff09;函数是Numpy模块里的一个可以标记数组中缺失值的位置 代码示例如下&#xff1a; import numpy as np ac np.array([1,2,3,2,3,4,5,9,np.nan,1]) p…

系统分析与设计(一)

我们有这么多各式各样的工具,互联网给我们带来了这么多用户和数据,这是好事也有副作用。 世界上能访问用户数据,并根据数据做分析和改进的公司,大概Google是其中翘楚,这种 data-centric 的做法做过了头,也有悲剧发生: Douglas Bowman 曾经是Google 的视觉设计主管,2009年的一天…

设计模式:观察者模式 ⑧

一、思想 观察者模式是一种常见的设计模式&#xff0c;也称作发布-订阅模式。它主要解决了对象之间的通知依赖关系问题。在这种模式中&#xff0c;一个对象&#xff08;称作Subject&#xff09;维护着一个对象列表&#xff0c;这些对象&#xff08;称作Observers&#xff09;都…

Docker完整版(一)

Docker完整版&#xff08;一&#xff09; 一、Docker概述1.1、Docker简介1.2、Docker的用途1.3、容器与虚拟机的区别1.4、Docker系统架构1.5、Docker仓库 二、Docker引擎2.1、Docker引擎架构2.2、Docker引擎分类2.3、Docker引擎的安装2.4、Docker镜像加速器 三、Docker镜像3.1、…

线程-创建线程的方法、线程池

1.创建线程一共有哪几种方法&#xff1f; 继承Thread类创建线程 继承Thread类&#xff0c;重写run()方法&#xff0c;在main()函数中调用子类的strat()方法 实现Runnable接口创建线程 先创建实现Runnable接口的类&#xff0c;重写run()方法&#xff0c;创建类的实例对象&#…

kibana配置 dashbord,做可视化展示

一、环境介绍 这里我使用的kibana版本为7.17版本。 语言选择为中文。 需要已经有es&#xff0c;已经有kibana&#xff0c;并且都能正常访问。 二、背景介绍 kibana的可视化界面&#xff0c;可以配置很多监控统计界面。非常方便&#xff0c;做数据的可视化展示。 这篇文章&…

数据结构:顺序表的奥秘

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生&#x1f43b;‍❄个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE&#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&a…

C#,排列组合的堆生成法(Heap’s Algorithm for generating permutations)算法与源代码

1 排列组合的堆生成法 堆生成算法用于生成n个对象的所有组合。其思想是通过选择一对要交换的元素&#xff0c;在不干扰其他n-2元素的情况下&#xff0c;从先前的组合生成每个组合。 下面是生成n个给定数的所有组合的示例。 示例&#xff1a; 输入&#xff1a;1 2 3 输出&a…

ZigBee技术与实践教程(无线传感网技术第三天)

1.MAC层规范 在IEEE802系列标准中&#xff0c;OSI参考模型的数据链路层进一步划分为逻辑链路控制子层和介子访问子层两个子层。MAC子层使用物理层提供的服务实现设备之间的数据帧传输&#xff0c;而LLC在MAC 层的基础上&#xff0c;在设备之间提供面向连接和非连接的服务&…

智慧城市的新引擎:物联网技术引领城市创新与发展

目录 一、引言 二、物联网技术与智慧城市的融合 三、物联网技术在智慧城市中的应用 1、智慧交通管理 2、智慧能源管理 3、智慧环保管理 4、智慧公共服务 四、物联网技术引领城市创新与发展的价值 五、挑战与前景 六、结论 一、引言 随着科技的日新月异&#xff0c;物…

注意!!墙裂推荐几个好用的实用小工具!一定会用到的!

前言 在开发的世界里&#xff0c;面对各种挑战和问题时&#xff0c;拥有一套合适的工具箱至关重要。这不仅能提升我们的工作效率&#xff0c;还能让复杂的任务变得简单&#xff0c;甚至在解决棘手问题的同时&#xff0c;还能让我们的心情略微舒畅。众所周知&#xff0c;有用的…

STM32F103 CubeMX ADC 驱动 PS2游戏摇杆控制杆传感器模块

STM32F103 CubeMX ADC 驱动 PS2游戏摇杆控制杆传感器模块 1. 工程配置1.1 配置debug口1.2 配置时钟1.3 配置ADC1.4 配置串口1.5 配置时钟1.6 生成工程 2. 代码编写2.1 串口代码2.2 ADC读取数据的代码 1. 工程配置 1.1 配置debug口 1.2 配置时钟 1.3 配置ADC 1.4 配置串口 1.5 …

笔记本电脑使用时需要一直插电吗?笔记本正确的充电方式

随着科技的不断发展&#xff0c;笔记本电脑已经成为人们日常生活和工作中不可或缺的电子设备。而在使用笔记本电脑时&#xff0c;很多人会有一个疑问&#xff0c;那就是笔记本电脑使用时需要一直插电吗&#xff1f;本文将就此问题展开讨论。 不一定需要一直插电&#xff0c;如果…

开源组件安全风险及应对

在软件开发的过程中&#xff0c;为了提升开发效率、软件质量和稳定性&#xff0c;并降低开发成本&#xff0c;使用开源组件是开发人员的不二选择&#xff08;实际上&#xff0c;所有软件开发技术的演进都是为了能够更短时间、更低成本地构建软件&#xff09;。这里的开源组件指…

【Web开发】深度学习HTML(超详细,一篇就够了)

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录文章&#xff1a;【Web开发】深度学习html(超详细,一篇就够了) &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 HTML1. HTML基础1.1 什么是HTML1.2 认识HTML标签1.3 HTML文件基本…

【linux进程信号】信号的产生

【Linux进程信号】信号的产生 目录 【Linux进程信号】信号的产生信号概念生活中的信号技术应用角度的信号注意信号概念用kill -l命令可以察看系统定义的信号列表信号处理常见方式概览 产生信号通过终端按键产生信号调用系统函数向进程发信号由软件条件产生信号由硬件异常产生信…

Linux 理解进程

目录 一、基本概念 二、描述进程-PCB 1、task_struct-PCB的一种 2、task_ struct内容分类 三、组织进程 四、查看进程 1、ps指令 2、top命令 3、/proc文件系统 4、在/proc文件中查看指定进程 5、进程的工作目录 五、通过系统调用获取进程标示符 1、getpid()/get…

css--浮动

一. 浮动的简介 在最初&#xff0c;浮动是用来实现文字环绕图片效果的&#xff0c;现在浮动是主流的页面布局方式之一。 二. 元素浮动后的特点 &#x1f922;脱离文档流。&#x1f60a;不管浮动前是什么元素&#xff0c;浮动后&#xff1a;默认宽与高都是被内容撑开&#xff0…

Redis基础篇:初识Redis(认识NoSQL,单机安装Redis,配置Redis自启动,Redis客户端的基本使用)

目录 1.认识NoSQL2.认识Redis3.安装Redis1.单机安装Redis2.配置redis后台启动3.设置redis开机自启 4.Redis客户端1.Redis命令行客户端2.图形化桌面客户端 1.认识NoSQL NoSQL&#xff08;Not Only SQL&#xff09;数据库是一种非关系型数据库&#xff0c;它不使用传统的关系型数…

ORACLE Linux(OEL) - Primavera P6EPPM 安装及分享

引言 继上一期发布的CentOS版环境发布之后&#xff0c;近日我制作了基于ORACLE Linux的P6虚拟机环境&#xff0c;同样里面包含了全套P6 最新版应用服务 此虚拟机仅用于演示、培训和测试目的。如您在生产环境中使用此虚拟机&#xff0c;请先与Oracle Primavera销售代表取得联系…