黑马程序员—JAVA基础—集合类

------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
1、概念:集合类是一个容器,只用于存储对象。
2、与数组相比,集合用于存储对象,且长度可变。数组用于存储基本数据类型,长度不可变。
3、为什么出现集合类,java语言的编程思想是面向对象,对象就会很多,集合就是为了更好的管理对象。
4、集合框架:





List:元素是有序的,元素可以重复
         ArrayList:底层为数组结构,带有脚标。特点:查询快,增删慢,线程不同步。
         LinkedList:底层为链表数据结构,没有脚标。特点:查询慢,增删快,线程不同步。
         Vector:底层为数组结构,带有脚标。特点:查询、增删都慢,线程同步,因为效率低,jdk升级后被ArrayList代替。

Set:元素是无序的,元素不可以重复。

       Collection 接口中定义了集合框架中共性的功能:
        添加:
               add(E):添加一个元素
               addAll(Conllection):添加一个集合中所有元素
        删除:
               remove(Object):移除一个元素
               removeAll(Conllection):移除本集合中与传入集合相同的元素
               clear():清空集合
        判断:
               contains(Object):是否包含某个元素
               containsAll(Conllection):是否包含一个集合中的所有元素
               isEmpty():判断集合是否为空
        获取:
               iterator():迭代器
               size():获取集合的长度
        取交集:
retainAll(Conllection):保留本集合与传入集合相同的元素
       转成数组:
               toArray()

         List接口中的特有方法:
         添加:
add(int index, E element):根据脚标添加
                add(int index,Conllection)
         删除
                remove(int index):根据脚标移除元素
         修改:
                set(int index,E):替换指定脚标的元素
         查询:
                get(int index):获取指定脚标的元素
                listIterator():特有迭代器,在迭代过程中可以对数据进行添加、修改操作
                indexOf(Object):获取元素的脚标
                subList(int fromIndex, int toIndex):获取集合中某一段

LinkedList中特有的方法:
添加:
addFirst()
addLast()
获取:
getFirst()
getLast()
删除:
removeFirst()
removeLast()
上述两个方法同样可以获取元素,但是跟获取中两个方法比较,此方法会删除元素


在jdk1.6版本后
添加:
offerFirst()
offerLast()
获取:
peekFirst()
peekLast()
删除:
pollFirst()
pollLast()

           Vector中特有方法:
            枚举:相当于迭代器
代码示例:
import java.util.*;
class VectorDemo 
{
	public static void main(String[] args) 
	{
		Vector v = new Vector();
		v.add("person01");
		v.add("person02");
		v.add("person03");
		v.add("person04");

		//Vector枚举方法相当于迭代器
		Enumeration e = v.elements();
		while (e.hasMoreElements())
		{
			sop(e.nextElement());
		}
	}
	public static void sop(Object o)
	{
		System.out.println(o);
	}
}

练习1:模拟队列结构和堆栈结构
队列结构:先进先出,就像水管
堆栈结构:先进后出,就像水杯
import java.util.*;
class DuiLie
{
	private LinkedList link;
	DuiLie()
	{
		link = new LinkedList();
	}
	public void myAdd(Object o)
	{
		link.addFirst(o);
	}
	public Object myGet()
	{
		//return link.removeLast();
		return link.removeFirst();//要改为堆栈结构,只需修改取数据的动作,同时
		//也可以修改存储的动作
	}
	public boolean isNull()
	{
		return link.isEmpty();
	}
}
练习2:去除ArrayList中的重复元素
public static ArrayList removeSame(ArrayList al)
{
	/*
	定义一个新的容器,将要去除重复元素的容器进行迭代,
	新的容器对迭代出来的元素进行是否包含判断,如果包含
	就存储进新的容器
	*/
	ArrayList newAl = new ArrayList();
	Iterator it = al.iterator();
	while (it.hasNext())
	{
		Object o = it.next();
		if (!newAl.contains(o))
		{
			newAl.add(o);
		}
	}
	return newAl;
}
当要存储自定义对象时,在自定义对象类中呀重写Object类中的equals方法,因为集合的contains方法会调用对象的equals方法
比如要在集合中存储人对象,当人的姓名和年龄相同时,就视为同一个人,那么,人这个类中就可以这样描述
class Person
{
	private String name;
	private int age;
	Person(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	public String getName()
	{
		return name;
	}
	public int getAge()
	{
		return age;
	}
	//复写Object类中的equals方法
	public boolean equals(Object o)
	{
		if (!(o instanceof Person))
			return false;
		Person p = (Person)o;
		return this.name.equals(p.name) && this.age == p.age;
	}
}

HashSet:底层是哈希表结构,元素是无序的,在存储元素的时候,先判断元素的哈希值,再判断元素是否相同
练习3:往HashSet存储自定义对象的时候,要复写Object类中的hashCode和equals方法:
那么在定义对象的时候就可以这样定义
class Person
{
	private String name;
	private int age;
	Person(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	public String getName()
	{
		return name;
	}
	public int getAge()
	{
		return age;
	}
	public int hashCode()
	{
		//System.out.println(this.name+"----hashCode......");
		/*
		return 60;
		直接返回数值也可以,但是为了减少判断对象是否相同,也就是减少
		equals方法,要自定义返回值,而且要不一样
		*/
		return this.name.hashCode()+age*39;//乘39是为了避免返回的哈希值一样
	}
	//复写Object类中的equals方法
	public boolean equals(Object o)
	{
		if (!(o instanceof Person))
			return false;
		Person p = (Person)o;
		//System.out.println(this.name+"----equals....."+p.name);
		return this.name.equals(p.name) && this.age == p.age;
	}
}

TreeSet:底层为二叉树结构

以34位基准,比34小的往左边放,比34大的往右边放,,在插入过程中,会找一个中间数作为比较,永远都遵循小的在左边
大的在右边

用TreeSet存储自定义对象时,在运行时会发生java.lang.ClassCastException(类型转换异常)
解决办法:
第一:可以让自定义对象具有比较性,实现Comparable接口,覆盖compareTo方法,
在compareTo方法里面自定义比较内容
第二:可以自定义一个比较器,实现comparator接口,覆盖compare方法,里面自定义比较内容,
将比较器作为参数传给TreeSet对象
注意:当两者都存在时,以比较器为主
代码示例:当用TreeSet集合存储自定义人对象时,按年龄升序排序,但是遇到姓名不同,年龄相同时,不能存储,所以当年龄相同时,要比较姓名
第一:让对象具有比较性
class Person implements Comparable//让对象具有比较性
{
	private String name;
	private int age;
	Person(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	public String getName()
	{
		return name;
	}
	public int getAge()
	{
		return age;
	}
	public int compareTo(Object o)
	{
		if (!(o instanceof Person))
		{
			throw new RuntimeException("参数不匹配");
		}
		Person p = (Person)o;
		/*
		if (this.age>p.age)
		{
			return 1;
		}
		if (this.age==p.age)
		{
			return this.name.compareTo(p.name);
		}
		return -1; 
		*/
		//同样是先比较年龄,主要条件,再比较姓名这个次要条件
		int a = new Integer(this.age).compareTo(new Integer(p.age));//Integer自身具有默认的比较方法
		if (a==0)
		{
			return this.name.compareTo(p.name);
		}
		return a;	
	}
}
第二:自定义比较器方法:
class MyComparator implements Comparator//定义比较器,实现Comparator接口
{
	public int compare(Object o1,Object o2)
	{
		Person p1 = (Person)o1;
		Person p2 = (Person)o2;
		//比较主要条件,当年龄相同时,再比较次要条件,姓名
		int a = new Integer(p1.getAge()).compareTo(new Integer(p2.getAge()));
		if (a==0)
		{
			//次要条件
			return p1.getName().compareTo(p2.getName());
		}
		return a;
	}
}

练习1:按字符串的长度进行排序
/*
	自定义比较器,用于比较字符串长度,但是当用户存储的字符串长度一样,但是内容不一样时,
	没有存储进去,所以当长度一样时,要进行字符串的比较
*/
class MyComparator implements Comparator
{
	public int compare(Object o1,Object o2)
	{
		String s1 = (String)o1;
		String s2 = (String)o2;
		
		int a = new Integer(s1.length()).compareTo(new Integer(s2.length()));
		if (a==0)
		{
			return s1.compareTo(s2);
		}
		return a;
	}
}
练习2:"90 -7 0 18 2 45 4" 将字符串中的数值进行排序。使用TreeSet完成
/*
	分析:将字符串进行切割,将切割后的字符转成Integer存储进
		TreeSet集合,TreeSet本身具备比较功能
*/
import java.util.*;
class TreeSetTest2 
{
	public static void main(String[] args) 
	{
		String s= "90 -7 0 18 2 45 4";
		String[] str = s.split(" ");//按空格对字符串进行切割
		TreeSet t = new TreeSet();
		for (int x=0; x<str.length; x++)
		{
			t.add(Integer.parseInt(str[x]));//转成Integer依次存储进TreeSet集合中
		} 
		System.out.println(t);//打印集合
	}
}
5、泛型:是一个安全机制,提高代码安全性
在编写代码时用<>指定类型,在编译时,如果传入不是指定类型,就会编译失败
避免强转
泛型可以定义在类上
//泛型定义在类上,在整个类中有效
class Test<T>
{
	public void show(T t)
	{
		System.out.println("show----"+t);
	}
	//将泛型定义在接口上,不受类上泛型的影响
	public <W> void print(W w)
	{
		System.out.println("print----"+w);
	}
	//静态方法不能直接访问类上的泛型
	//如果静态方法操作的数据类型不确定,可以将泛型定义在方法上
	/*
	public static void print_2(T t)
	{
		System.out.println("show----"+t);
	}
	*/
}
泛型定义在接口上:
//泛型定义在接口中
interface Inter<E>
{
	public void show(E e);
}
//在实现接口时,指定类型,在使用的时候,只能操作指定的类型
class InterImpl implements Inter<String>
{
	public void show(String s)
	{
		System.out.println("show---"+s);
	}
}
//如果操作的类型不确定,也可以不指定类型,在类中继续使用泛型
class InterImpl_2<E> implements Inter<E>
{
	public void show(E e)
	{
		System.out.println("show---"+e);
	}
}
泛型限定
?通配符或者占位符
? extends E 可以接收E类型或者E的子类型  向上限定
? super E 可以接收E类型或者E的父类型   向下限定
代码示例:
class GenericTest4 
{
	public static void main(String[] args) 
	{
		TreeSet<Student> t = new TreeSet<Student>(new MyComparator());
		t.add(new Student("Student01",21));
		t.add(new Student("Student02",19));
		t.add(new Student("Student03",25));
		t.add(new Student("Student04",22));
		t.add(new Student("Student05",19));
		printColl(t);

	}
	//定义一个打印集合的方法,限定泛型为Person或者Person的子类
	public static void printColl(Collection<? extends Person> al)
	{
		Iterator<? extends Person> it = al.iterator();
		while (it.hasNext())
		{
			Person p = it.next();
			System.out.println("name:"+p.getName()+"-----age:"+p.getAge());
		}
	}
}
//定义一个比较器接收Person或者Person的子类
class MyComparator implements Comparator<Person>
{
	public int compare(Person p1,Person p2)
	{
		int a = new Integer(p1.getAge()).compareTo(new Integer(p2.getAge()));
		if (a==0)
		{
			return p1.getName().compareTo(p2.getName());
		}
		return a;
	}
}
class Person
{
	private String name;
	private int age;
	Person(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	public String getName()
	{
		return name;
	}
	public int getAge()
	{
		return age;
	}
}
class Student extends Person
{
	Student(String name,int age)
	{
		super(name,age);
	}
}
class Worker extends Person
{
	Worker(String name,int age)
	{
		super(name,age);
	}
}

Map集合:接口 Map<K,V>  该集合存储的是键值对,一个key对应一个value
|--Hashtable:底层是哈希表结构,key和value都不能为null,线程是同步的,效率低
|--HashMap:底层是哈希表结构,key和value可以为null,线程是不同步的,效率高
|--TreeMap:底层是二叉树结构,key和value不可以为空,线程是不同步的,可以给key进行排序

添加:
put(K key, V value)
putAll(Map<? extends K,? extends V> m)
删除:
remove(Object key):在移除元素的时候,可以获取value的值
clear():清空
判断:
contains(Object key)
contains(Object value)
isEmpty()
获取:
get(Object key)
size()
values()
ketSet:
将map中的key存储到Set集合中,通过迭代器,根据key的用get(Object key)方法获取值

entrySet:
将map集合中的映射关系存储到Set集合中,这种映射关系的类型是Map.Entry
entrySet是map中一个静态内部接口,因为先存在键值对,才有映射关系,并且要直接访问map的映射关系,所以定义在内部
练习1、往HashMap中存储学生对象和地址,学生类中有姓名和年龄,姓名和年龄一样视为同一个学生,保证学生唯一性
class MapTest 
{
	public static void main(String[] args) 
	{
		Map<Student,String> m = new HashMap<Student,String>();
		Student s1 = new Student("张三",18);
		Student s2 = new Student("李四",22);
		Student s3 = new Student("王五",25);
		Student s4 = new Student("赵六",20);
		Student s5 = new Student("赵六",20);

		m.put(s1,"广东省");
		m.put(s2,"湖南省");
		m.put(s3,"福建省");
		m.put(s4,"黑龙江省");
		m.put(s5,"北京市");

		//keySet方式取出数据
		Set<Student> keySet = m.keySet();
		Iterator<Student> it = keySet.iterator();
		while (it.hasNext())
		{
			Student s = it.next();
			System.out.println("姓名:"+s.getName()+"-年龄:"+s.getAge()+"-地址:"+m.get(s));
		}
		//entrySet方式取出数据
		Set<Map.Entry<Student,String>> entrySet = m.entrySet();
		Iterator<Map.Entry<Student,String>> it2 = entrySet.iterator();
		while (it2.hasNext())
		{
			Map.Entry<Student,String> me = it2.next();
			Student s = me.getKey();
			String address = me.getValue();
			System.out.println("姓名:"+s.getName()+"-年龄:"+s.getAge()+"-地址:"+address);
		}
	}
}
class Student implements Comparable<Student>
{
	private String name;
	private int age;
	Student(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public String getName()
	{
		return name;
	}
	public void setAge(int age)
	{
		this.age = age;
	}
	public int getAge()
	{
		return age;
	}
	//因为HashMap底层为哈希表结构,要保证唯一性,
	//就要复写Object类中的hashCode方法
	public int hashCode()
	{
		return name.hashCode()+age*39;
	}
	//并且要覆盖equals方法
	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;
	}
	//因为可能需要往TreeSet集合里面存储学生
	//所以实现Comparable接口覆盖compareTo方法
	public int compareTo(Student s)
	{
		int a = new Integer(this.age).compareTo(new Integer(s.age));
		if (a==0)
		{
			return this.name.compareTo(s.name);
		}
		return a;
	}
}

练习2:获取一段字符串中每个字母出现的次数,并以a(次数)b(次数)这样的形式打印
/*
分析:
	先将字符串转换成字符数组
	将字符作为键,次数作为值存入TreeSet集合中,因为TreeSet集合自身具有排序功能
	遍历字符数组,将每一个元素作为键去查找集合中是否有值
	如果没值,就将(字符,1)存入集合,如果有值,就将(字符,原来的次数加1)存入集合
	因为在map集合中,如果key一样,新的value会覆盖旧的value
*/
class MapTest2 
{
	public static void main(String[] args) 
	{
		String s = "abcabce2fgh}oll.eabb";
		s = getCharCount(s);
		System.out.println(s);
	}
	//定义一个获取出现次数的方法
	public static String getCharCount(String s)
	{
		char[] arr = s.toCharArray();//将字符串转换成字符数组
		TreeMap<Character,Integer> hm = new TreeMap<Character,Integer>();
		int count = 0;//定义计数器,记录次数
		for (int x=0; x<arr.length; x++)
		{
			//判断数组中的元素是否为字母
			if(!(arr[x]>'a' && arr[x]<'z' || arr[x]>'A' && arr[x]<'Z'))
				continue;
			Integer value = hm.get(arr[x]);//根据字符获取value
			if(value!=null)
				count = value;
			count ++;
			hm.put(arr[x],count);
			count = 0;//要循环获取每个字符,计数器要清零
		}
		Set<Map.Entry<Character,Integer>> entrySet = hm.entrySet();
		Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator();
		StringBuilder sb = new StringBuilder();//定义字符缓冲区对象
		while (it.hasNext())
		{
			Map.Entry<Character,Integer> me = it.next();
			Character ch = me.getKey();
			Integer i = me.getValue();
			sb.append(ch+"("+i+")");//将迭代出来的字符按照如下形式依次存入
		}
		return sb.toString();//将字符缓冲区转换为字符串,并返回
	}
}
Map集合拓展:Map集合中嵌套集合
代码示例:
class MapTest3 
{
	/*
	集合中嵌套集合
	一个公司中有多个部门,一个部门有多个员工
	将部门中的员工存储在List集合中,然后再将部门名称作为key,员工作为value
	存储Map集合中
	*/
	public static void main(String[] args) 
	{
		List<Employee> personnel = new ArrayList<Employee>();//人事部
		List<Employee> technology = new ArrayList<Employee>();//技术部
		HashMap<String,List<Employee>> compary = new HashMap<String,List<Employee>>();//公司
		compary.put("人事部",personnel);
		compary.put("技术部",technology);
		personnel.add(new Employee(01,"zhangsan"));
		personnel.add(new Employee(02,"lisi"));
		personnel.add(new Employee(03,"wangwu"));
		technology.add(new Employee(01,"张三"));
		technology.add(new Employee(02,"王五"));
		technology.add(new Employee(03,"李四"));
		
		//通过entrySet方法取出元素
		Set<Map.Entry<String,List<Employee>>> entrySet = compary.entrySet();
		Iterator<Map.Entry<String,List<Employee>>> it = entrySet.iterator();
		while (it.hasNext())
		{
			Map.Entry<String,List<Employee>> me = it.next();
			String department = me.getKey();
			List<Employee> al = me.getValue();
			System.out.println(department);
			printList(al);
		}
	}
	public static void printList(List<Employee> l)//打印list集合中的元素
	{
		Iterator<Employee> it = l.iterator();
		while (it.hasNext())
		{
			Employee e = it.next();
			System.out.println("id:"+e.getId()+"----name:"+e.getName());
		}
	}
}
class Employee//员工类
{
	private int id;
	private String name;
	Employee(int id,String name)
	{
		this.id = id;
		this.name = name;
	}
	public String getName()
	{
		return name;
	}
	public int getId()
	{
		return id;
	}
}
Collections:集合框架工具类,定义都是静态方法
          Collection和Collections的区别?
          Collection是集合框架中一个顶层接口,定义了集合中共性的方法。常用子类口有List和Set
          Collections是集合框架工具类,提供了各种操作集合的静态方法,比如二分法查找、排序、同步方法

常用方法:
        sort(List<T> list):对list集合进行自然排序
        sort(List<T> list, Comparator<? super T> c):用自定义比较器进行排序
        static void swap(List<?> list, int i, int j):交换元素
        reverse(List<?> list):反转指定list集合中的元素
        replaceAll(List<T> list,T oldVal,T newVal):替换list集合中某个值
        reverseOrder():逆转现有比较器的排序方式
        reverseOrder(Comparator<T> com):逆转自定义比较器的排序方式
        shuffle(List<?> list):对list集合中的元素随机产生不同的顺序

       注意:Collection中toArray方法:当需要限定对集合中的元素进行操作时,就把集合转成数组
                  定义转换后数组长度时,如果定义小于原集合的长度,该方法内部会新建一个数组,长度为原集合的长度
                  如果定义大于原集合长度,则不会新建一个数组,直接使用传递进来的集合,但是多余的部分将会是null值

Arrays:用于操作数组的工具类,定义的都是静态方法
        asList:将数组变为list集合
        注意:如果原数组存储的是对象,转换成集合时,数组中的元素就是集合中的元素
                   如果原数组存储的是基本数据类型,转换成集合时,那么会将数组对象作为集合中的元素。
                   将数组转换成集合后,不可以使用集合中增删方法,因为数组的长度是固定的。

可变参数:一定要将可变参数定义在参数列表的最后
代码示例:
class  ParamMethodDemo
{
	public static void main(String[] args) 
	{
		show("haha",2,3,4,5,6);
	}
	public static void show(String str,int... arr)
	{
		System.out.println(arr.length);
	}
}

静态导入:在导入包时,加上static关键字,导入的是类中静态方法,在调用时,可以省略类名.
       注意:当类重名时,要指定包名。
                  当方法重名时,要指定类名或者对象。
                  




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
**数字乡村解决方案摘要** **国家战略与乡村振兴** 中国正实施国家大数据战略,以加快数字中国的建设,整合数据资源,保障数据安全,并推动产业升级。2023年中央一号文件强调了乡村振兴战略,旨在通过产业兴旺、生态宜居、乡风文明、治理有效和生活富裕五大方面,实现农业农村现代化。 **数字乡村建设的重要性** 数字乡村建设是乡村振兴战略的重要组成部分,通过整合资源数据,推动物联网和遥感技术在农业中的应用,促进农业现代化。它被视为促进乡村转型发展的新方向,是数字化在农业农村经济社会发展中的应用。 **关键要素与效益** 数字乡村建设的关键要素包括数据资源整合、产业促进、农业发展规模化和标准化,以及改善乡村生活服务体系。预期效益包括提升国家治理能力,实现政府决策科学化和社会治理精准化,同时推动公共服务高效化。 **体系架构与数据融合** 数字乡村的体系架构包括乡村生态、基层治理、慧治、慧享、慧融、慧美、慧智和慧图等多个方面,实现城乡、政企、农户各级平台及服务的融合。数据融合是核心,整合乡村人口、产值、环境监测等多方面数据,为乡村治理和产业发展提供支撑。 **多业务协同与智慧治理** 数字乡村通过多业务协同应用平台,实现乡村物联网的布局和触达,涵盖农业生产、农资厂商、消费者等环节。区块链技术在农产品质量溯源中的应用,确保了产品全过程可追溯。乡村智慧治理通过村务管理、财务管理等方面提升治理效能,实现绿色发展理念。综合服务体系通过“互联网+服务”模式,提供便民服务和乡村经济发展支持,推动乡村全面振兴。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值