当前位置:网站首页>集合(泛型 & List & Set & 自定义排序)

集合(泛型 & List & Set & 自定义排序)

2022-07-06 16:53:00 一个很懒的人

本文主要介绍了集合的指示,包括但不限于以下知识:

  1. 泛型
  2. 集合体系层级
  3. 集合体系中的接口及其实现类
  4. 集合自定义排序

1.泛型

(1)概念

数据类型 作为 参数 进行传递
(泛型在使用时,接收到的是什么数据类型,此泛型就是什么数据类型)

(2)定义

	1,<T>T 声明一个泛型,可以使用任何字母,代指泛型,eg:<T><X>

	2<T,X,...>:声明多个泛型,TX.....

(3)使用

注意:

  • 泛型必须:先定义,再使用
  • 泛型在使用时,接收到的是什么数据类型,此泛型就是什么数据类型
  • 泛型可以在数据类型处定义
  • 泛型在类中定义的只能在类中使用,在方法中定义的只能在方法中使用(泛型作用域范围)
  • 使用泛型的类,在 创建对象 时要指明 实际 的数据类型(只能用引用数据类型)
  • 使用泛型的接口,公共抽象方法可以用泛型(静态修饰的成员不能使用泛型)
  • 实现 使用泛型的接口的类,在类和接口后都需要加泛型,但是一般使用匿名内部类创建接口实例

eg01:在方法中使用

public class Test {
    
	public static void main(String[] args) {
    
		Integer i = test(1);
		String str = test("123");
		Test t = new Test();
		Test test = test(t);
	}
    
	/** * 要求,传入的参数类型就是返回值类型 * 泛型在使用时,接收到的是什么数据类型,此泛型就是什么数据类型 */
	public static <X> X test(X str) {
    
		return str;
	}
    
	/** * 可以传入任何一种类型 */
	public static <X,Y> void test01(X str,Y y,Y y2) {
    
		
	}
}

eg02:在类中使用

  • 类上定义泛型,必须在类名之后继承与实现之前,紧随类名
  • 泛型在使用时,接收到的是什么数据类型,此泛型就是什么数据类型
/** * 类上定义泛型,必须在类名之后继承与实现之前,紧随类名 */
class Person<K,Y,Z> extends Object {
    
	private K k;
	private Y y;
	private Z z;
	private String str;
	
	public Person() {
    
		super();
	}

	public Person(K k, Y y, Z z, String str) {
    
		super();
		this.k = k;
		this.y = y;
		this.z = z;
		this.str = str;
	}
    
public class Test02 {
    
	public static void main(String[] args) {
    
	//泛型在使用时,接收到的是什么数据类型,此泛型就是什么数据类型
		Person<Integer, String, Boolean> person = new Person<Integer, String, Boolean>();
		Person<String, Integer, Integer> person2 = new Person<String, Integer, Integer>();
	}
}

eg03:在接口中使用

public class Test03 {
    
	public static void main(String[] args) {
    
        //1.匿名内部类使用泛型
		MyInterfaceTest<String> test = new MyInterfaceTest<String>();
		new MyInterface<Integer>() {
    
			@Override
			public void test01(Integer k) {
    
				// TODO Auto-generated method stub 
			}
			@Override
			public Integer test02(Integer k) {
    
				// TODO Auto-generated method stub
				return null;
			}
		};
	}
}
interface MyInterface<K>{
    
	void test01(K k);
	K test02(K k);
}
//2.类实现泛型接口
/*接口和实现类后都需要增加泛型 */
class MyInterfaceTest<K> implements MyInterface<K>{
    

	@Override
	public void test01(K k) {
    
		// TODO Auto-generated method stub 
	}
	@Override
	public K test02(K k) {
    
		// TODO Auto-generated method stub
		return null;
	}
}

2.集合

(1)概念

存储一组数据类型相同的数据(引用数据类型),长度可变

(2)体系层级

接口体系层级图

(3)Collection:接口(集合一级父类)

Collection:接口
	特点:无序(存入顺序与取出顺序不一致),无下标
	方法:boolean add(E e):添加一个数据
			boolean addAll(Collection<? extends E> c):将子集合中数据添加到集合中
		
		删
			boolean remove(Object o);:删除一个数据
			boolean removeAll(Collection<?> c):将子集合中所有数据从集合中删除
			void clear():清空
		
		改
			无
		查
			int size():获取集合中元素的个数
			boolean contains(Object o):判断指定元素是否在集合中存在
			boolean containsAll(Collection<?> c):判断子集合中所有数据是否在集合中存在
			Iterator<E> iterator():迭代器
		
		其他
			boolean isEmpty():判断集合中是否存在元素
			Object[] toArray():将集合转换为数组

(4)List:子接口(集合二级父类)

List:子接口
		特点:有序,有下标
		子类特有方法(除去继承Collection的方法)
		增
			一次插入一个数据,1:插入的位置,2:插入的数据
			void add(int index, E element);
			
			一次插入一组数据,1:插入的位置,2:插入的数据
			boolean addAll(int index, Collection<? extends E> c);
		
		删
			按照下标删除指定位置的数据
			E remove(int index);
		改
			修改:1:下标,2:修改后的元素
			E set(int index, E element);
		查
			获取指定位置的元素,参数:下标
			E get(int index):

(5)Set:子接口(集合二级父类)

Set
	特点:无序(存入顺序与取出顺序不一致,但存储到其内部输出是有序的(由大到小或由小到大)),无下标,不能重复
	子类特有方法:(除去继承Collection方法,没有其他自己的方法)

(6)子接口实现类(集合)

List子接口实现类

	(1)ArrayList	jdk1.2,线程不安全
		数据结构:数组
		特点:查询速度快,增删速度慢

	(2)Vector		jdk1.0,线程安全的
		数据结构:数组
	
	(3)LinkedList	jdk1.2,线程不安全
		数据结构:链表
		特点:增删速度快,查询速度慢

Set子接口实现类

	(1)HashSet		jdk1.2,线程不安全
		数据结构:链表+红黑树(基于哈希表)
	
	(2)LinkedHashSet	jdk1.4,线程不安全
		数据结构:链表+红黑树(基于哈希表,jdk源码封装实现)+链表
		特点:有序
	
	(3)TreeSet
		数据结构:链表+红黑树(需要自己实现)
		方案1:
			数据自身拥有比较性
			步骤1:让存储的数据所属的类实现Comparable接口
			步骤2:重写compareTo方法
			
		方案2:
			提供比较器
			创建TreeSet对象时,传入比较器的对象Comparator接口实现类

(7)迭代遍历

  1. 获取到集合的迭代器
  2. hasNext() 方法判断其要迭代的位置是否含有元素
  3. iterator.next()获取到迭代器指示位置的元素,并将迭代器指示位置向下移一个位置
  4. 如此循环,直到迭代器中元素遍历完毕
//迭代遍历
		Iterator<Person> iterator=treeSet.iterator();
		
		while(iterator.hasNext()) {
    
			Person person=iterator.next();
			System.out.println(person);
		}
		

3.集合实现自定义排序

(1)Comparable接口

  • 在java的jdk中提供了Comparable接口,其提供了一个抽象方法compareTo(T o),其中T代表泛型,将其与集合使用可以实现自定义排序
  • java的8中基本数据类型均实现类Comparable接口,实现类其中的方法

1.以TreeSet为例,分析Comparable接口,进而实现自定义排序

  1. Person实现Comparable接口
  2. 重写compareTo(Person o)方法
  3. 其中方法中 this 代之集合中add(e)的值,将其依次与集合中原有的元素比较,确定其位置在存储数据的 数据结构 中的位置,进而插入数据结构中(使用某种数据结构实现数据值的按序存储)
  4. TreeSet其存储是红黑树,jdk中没有实现其排序方法,需要自己实现,使其存储的类实现Comparable接口是实现其排序的方法之一
public class Person implements Comparable<Person> {
    
	
	private String name;
	private String sex;
	private int age;
	private int height;
	public Person() {
    
		super();
	}
	public Person(String name, String sex, int age, int height) {
    
		super();
		this.name = name;
		this.sex = sex;
		this.age = age;
		this.height = height;
	}
/* ............省略了标准类的其他方法 */
	
	//自定义比较
	@Override
	public int compareTo(Person o) {
    
		// TODO Auto-generated method stub
		if (this.height!=o.height) {
    
			return this.height-o.height;
		}else if (this.age!=o.age) {
    
			return this.age-o.age;
		}
		else {
    
			return this.name.compareTo(o.name)+this.sex.compareTo(o.sex);
		}

	}

}

(2)Comparator接口

  • Comparator接口中提供了compare(T o1, T o2)抽象方法,其中T代表泛型,其可以配合集合使用,实现集合的自定义排序

2.以TreeSet为例,分析Comparator接口,进而实现自定义排序

  1. 其可以看作是自定义比较器,在操作中使用,不需要对其操作对象的类进行实现接口
  2. 在创建TreeSet集合时,传入比较器(Comparator接口的实现类),下面使用匿名内部类的方式创建传入
  3. compare(T o1, T o2)方法在使用时,其o1参数代表集合正在add(e)的对象,o2代表集合中原有的对象元素,将o1其依次与集合中原有的元素(o2)比较,确定其位置在存储数据的 数据结构 中的位置,进而插入数据结构中(使用某种数据结构实现数据值的按序存储)
  4. TreeSet其存储是红黑树,jdk中没有实现其排序方法,需要自己实现,在创建TreeSet对象时,传入自定义比较器(Comparator接口实现类)是实现其集合有序排序的方法之一
TreeSet<Person01> treeSet=new TreeSet<Person01>(new Comparator<Person01>() {
    

			//实现比较器
			@Override
			public int compare(Person01 o1, Person01 o2) {
    
				// TODO Auto-generated method stub
				if (o1.getHeight()!=o2.getHeight()) {
    
					return o1.getHeight()-o2.getHeight();
				}
				else if (o1.getAge()!=o2.getAge()) {
    
					return o1.getAge()-o2.getAge();
				}
				else {
    
					return o1.getName().compareTo(o2.getName())+o1.getSex().compareTo(o2.getSex());
				}
			}
		});

(3)Comparable接口与Comparator接口的区别

Comparable接口

  1. 可以将其看作是小学时由高到低排座位,其排序方式是自己与别人去比较,确定你的位置
  2. 抽象为代码中就是,add(e)的对象与集合中已经存在的对象进行比较,确定add(e)的对象在底层数据结构中存储的位置

Comparator接口

  1. 可以将其看作是小学时由高到低排座位,其排序方式是老师给你们两两比较,然后再确定你的位置
  2. 抽象为代码中就是,add(e)的对象与集合中已经存在的对象进行比较,其内部的compare(T o1, T o2)方法中,o1代表add(e)的对象,o2代表合中已经存在的对象,将其两两比较确定add(e)的对象在底层数据结构中存储的位置

(4)操作集合的工具类:Collections(实现自定义排序)

  • 常用方法
Collections.sort(list);//排序
Collections.reverse(list);//翻转
Integer max = Collections.max(list);//寻找最大值
Integer min = Collections.min(list);//寻找最小值
  • Collections中sort方法
public static <T extends Comparable<? super T>> void sort(List<T> list)
   
public static <T> void sort(List<T> list, Comparator<? super T> c)

以上两个方法是Collections提供的两个重载的sort方法,从其参数可以看出其实现集合排序的两种方式也是和Comparable和Comparator有关,即若想使用此工具类实现对集合的排序有两种方式:

  • 方案一:集合中存储的数据类型自身拥有比较性
    调用 Collections.sort(list) 对list集合进行排序时,要求list集合中村存储的数据类型的类实现了Comparable接口,并重写了其中的comparaTo方法

  • 方案二:提供自定义比较器
    调用 Collections.sort(list,new Comparator(compara的实现方法)) 对list集合进行排序时,1参代表要排序的集合,2参代表自己创建的比较器(提供实现了Comparator接口的实现类,要求其重写了compara接口)

使用工具类Collections实现对集合排序的代码,可以参考我的另一篇博客:
JAVA_自定义排序(Comparable、Comparator)详解


4.双列集合(Map)

(1)概念

概念: 存储一组数据类型相同的数据,长度可变
存储数据的要求: 键值对应

(2)体系层级

Map(接口)

  • HashMap(类)
    特点: 链表+红黑树(哈希表),线程不安全,1.2
    -------在其内部是以键值Key 由小到大排序的
  • HashTable(类)
    特点: 链表+红黑树(哈希表),线程安全,1.0
    -------在其内部是以键值Key 由小到大排序的
    Properties(类)
  • TreeMap(类)
    特点: 链表+红黑树(需要自己提供)
    -------在其内部没有进行默认的排序,需要存储数据自身具有比较性或提供比较器
    注意: TreeMap存储数据, 键(key) 要么拥有比较性,要么在创建TreeMap时传入比较器(类似TreeSet集合)

(3)Map的方法

V put(K key, V value);
		注意:如果字典中key不存在,则是添加,如果key存在,那么将修改key对应的value
	void putAll(Map<? extends K, ? extends V> m);V remove(Object key);
	void clear();V put(K key, V value);int size();
	boolean isEmpty();
	boolean containsKey(Object key);
	boolean containsValue(Object value);
	V get(Object key);
	Set<K> keySet();
	Collection<V> values();
	Set<Map.Entry<K, V>> entrySet();

其他:
	Entry
		getKey();
		getValue();

(4)Map的遍历

Set<Integer> keySet = hashMap.keySet();
		//遍历方式1
		for (Integer key : keySet) {
    
			String value=hashMap.get(key);
			System.out.println(key+","+value);
		}
		
		//遍历方式2
		Set<Entry<Integer,String>> entrySet = hashMap.entrySet();
		for (Entry<Integer, String> entry : entrySet) {
    
			int key=entry.getKey();
			String value=entry.getValue();
			System.out.println(key+","+value);
		}
		
原网站

版权声明
本文为[一个很懒的人]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_43715360/article/details/125546706