《学习笔记Day15》泛型超详细学习笔记;Set(HashSet,LinkedHashSet)详细介绍附加代码学习

1、泛型就是广泛的类型,在定义类的时候,某些方法的参数列表或者返回值类型不确定,就使用一个符号,来表示那些尚未确定的类型,这个符号就是泛型。
2、使用:对于具有泛型的类型,在类型后面加上<>,<>中写上泛型的确定类型
3、

泛型必须书写成引用数据类型,不能写基本数据类型
泛型是写的时候,必须保持前后一致
左必写,右可选择不写

public class Dome {
		public static void main(String[] args) {
			
			ArrayList<String> list = new ArrayList<>();//创建一个数组并且泛型定义为String
			
			list.add("abc");
			list.add("def");
			list.add("ghi");
			list.add("jkl");
			
			list.add("mno");
			list.add("pqr");
			
			
			Iterator<String> it = list.iterator();//迭代器也必须是String
			
			while(it.hasNext()) {
				String str = it.next();
				System.out.println(str.length());
			}
			
			}
		}

泛型类的定义

1、格式:class 类名<泛型1,泛型2,泛型3…>{ }
2、说明:
(1)类后面跟着的泛型类型,是泛型的声明,一旦泛型声明出来,就相当于这个类未来会有一个已知类型,这个类型就可以在类中去使用了
(2)泛型类型的声明:只要是一个合法的标识符即可,一般使用单个的大写字母表示:T(Type)、E(Element)、K(Key)、V(Value)
(3)泛型确定的时机:将来使用这个类创建对象的时候,对象的泛型必须确定为具体的类型,对象的泛型确定为什么类型,类的泛型就跟着变成什么类型

public class Dome {
		public static void main(String[] args) {
			Student<String> s = new Student<String>();
			
			s.show("123");
			s.test(null);
	}
}

class Student<T>{
	
	public void show(T t) {
		System.out.println(t);
	}
	public T test(T t) {
		return null;
	}
}

模拟栈

package ceshi01;
import java.util.LinkedList;

public class Dome {
		public static void main(String[] args) {
			
			MyStack<String> ms = new MyStack<>();
			ms.show("aaa");
			ms.show("bbb");
			ms.show("ccc");
			ms.show("ddd");
			ms.show("eee");
			
			System.out.println(ms);
			while(ms.cap() > 0) {
				System.out.println(ms.test());
			}
	}
}

class MyStack<T>{
		//创建一个栈对象使用链表,因为双链表模拟进栈弹栈
	 LinkedList<T> l = new LinkedList<>();
	
	public void show(T t) {//进栈方法
		 l.addFirst(t);
	}
	public T test() {//弹栈方法,弹出的内容作为返回值
		return l.removeFirst();
	}
	public int cap() {//计算集合的长度
		return l.size();
	}
}

		

泛型方法的定义

格式
权限修饰符<泛型1,泛型2,…> 返回值类型 方法名称(参数列表){方法体 }
3、说明:
(1)在方法上声明泛型,可以在整个方法中作为已知类型来使用
(2)如果【非静态】方法没有声明任何泛型,可以直接使用类的泛型,此时泛型就会和类泛型确定时机一样,随着对象泛型的确定而确定;
如果【非静态】方法上自己定义了泛型,泛型就会随着参数的类型进行变化
(3)【静态】方法,不能使用类的泛型,如果想要使用泛型,必须自己在方法声明上定义泛型。因为类泛型随对象确定,静态优先于对象存在,静态方法使用泛型的时候,对象很可能还未创建,泛型极有可能还不确定。

package ceshi01;
import java.util.LinkedList;

public class Dome {
		public static void main(String[] args) {
			
			Person<String> p = new Person<>();
			p.show3("qwe");
			
			Person<Integer> p1 = new Person<>();
			p1.show3("qwe");
			System.out.println(p1.show4(123));
		}
	}
	//1.方法使用类的泛型
	//2.方法自己定义泛型
		//1.非静态方法
		//2.静态方法
	class Person<T> {
		
		//1.方法使用类的泛型
		
		public void show1(T t) {
			System.out.println(t);
		}
		
		public T show2() {
			return null;
		}
		
		//----------------
		
		//2.方法自己定义泛型
		//2.1 非静态方法自己定义泛型
		public <E> void show3(E e) {//Object
			System.out.println(e);
		}
		
		public <E> E show4(E e) {//Object
			return e;
		}
		
		public <E> void show5(E e, T t) {
			
		}	
		//2.2 静态泛型方法
		//类泛型随着对象的泛型确定而确定,静态方法随着类的加载而加载优先于对象存在
		//如果静态方法使用类的泛型,对象就极有可能不存在,泛型也就确定不下来
		//所以静态方法要想使用泛型,只能自己定义
		public static <E> void show6(E e) {
			System.out.println(e);
		}
	}
		

交换

package ceshi01;
import java.util.Arrays;

public class Dome {
		public static void main(String[] args) {
			
			String[] arr = {"aaa", "bbb", "ccc", "ddd"};
			//Integer[] arr = {111, 222, 333, 444};
			
			System.out.println(Arrays.toString(arr));
			
			swap(arr, 0, 3);
			
			System.out.println(Arrays.toString(arr));
		}
		
		/**
		 * 交换数组两元素的位置
		 * 
		 * @param arr 待交换元素位置的数组
		 * @param index1 要交换位置的元素索引
		 * @param index2 要交换位置的元素索引
		 */
		public static <T> void swap(T[] arr, int index1, int index2) {
			T temp = arr[index1];
			arr[index1] = arr[index2];
			arr[index2] = temp;
		}
	}


泛型接口的定义和使用

格式:
interface 接口名<泛型1, 泛型2, 泛型3…>{ }
3、说明:
(1)在接口声明上,定义好泛型,整个接口中都可以将接口的泛型拿来使用
(2)泛型接口被其他类实现:
1)类实现接口的时候,泛型确定为了具体类型:
class 类名 implements 接口名<具体类型> {
实现接口的方法,方法使用了泛型,也都成了具体类型
}
2)类实现接口的时候,泛型依然不确定:
class 类名<泛型1, 泛型2…> implements 接口名<泛型1, 泛型2…> {
实现接口的方法,方法使用的泛型依然不确定
}
注意事项:类后面和接口后面的泛型符号要保持一致,表示同一个泛型;类实 现接口的时候,和原接口的泛型符号可以不一样

泛型的通配符

1、符号:?
2、使用泛型的时候,没有使用具体的泛型声明【T】,而是使用了和T有关的类型,如果要表示和T有关的类型,就需要使用到泛型通配符【?】

3、第一种形式:使用?来表示可以使任意类型
在Collection中,removeAll(Collection<?> c)方法的参数,就表示可以接受任意类型泛型的集合,参数集合的泛型可以和调用者集合的泛型没有任何关系

package com.offcn.demos;

import java.util.ArrayList;
import java.util.Collection;

public class Demo07 {
	
	public static void main(String[] args) {
		//removeAll(Collection<?> c) 
		
		Collection<String> list = new ArrayList<>();
		Collection<Integer> list1 = new ArrayList<>();
		
		//假设调用者集合的泛型是A类型,参数集合的泛型可以是任意类型,此时?的作用就是通配
		list.removeAll(list1);
	}
}

3、第二种格式:? extends E
在Collection集合中,方法addAll(Collection<? extends E> c)泛型所表示的就是:确定泛型的上边界。即:参数泛型是调用者泛型的本类或者子类,不能是父类,更不能是无关类

package com.offcn.demos;

import java.util.ArrayList;
import java.util.Collection;

public class Demo07 {
	
	public static void main(String[] args) {
		//addAll(Collection<? extends E> c) 
		
		Collection<String> list = new ArrayList<>();
		Collection<Integer> list1 = new ArrayList<>();
		Collection<Object> list2 = new ArrayList<>();
		Collection<String> list3 = new ArrayList<>();
		
		//list.addAll(list1);//String和Integer是无关类
		
		list.addAll(list2);//参数的泛型是调用者的泛型的父类
		
		list2.addAll(list1);//参数泛型是调用者泛型的子类
		list2.addAll(list);
		list.addAll(list3);//参数泛型和调用者泛型是同类
	}

	public static void test1() {
		//removeAll(Collection<?> c) 
		
		Collection<String> list = new ArrayList<>();
		Collection<Integer> list1 = new ArrayList<>();
		
		//假设调用者集合的泛型是A类型,参数集合的泛型可以是任意类型,此时?的作用就是通配
		list.removeAll(list1);
	}
}

4、第三种情况:? super E
确定泛型的下边界:表示泛型是E的父类或者是E本身,不能是E的子类,更不能是无关类。

Set

1、Set是Collection的子接口
2、特点:无序,不可重复
3、实现类:

1、HashSet,底层是哈希表
2、LinkedHashSet,底层是链表加哈希表

4、存储特点:存取顺序不一致,不可重复

package ceshi01;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

public class Dome {
		public static void main(String[] args) {
		//创建对象的时候,创建的是实现类的对象
			Set s1 = new HashSet();
			Set s2 = new LinkedHashSet();
			
			s1.add("a");
			s2.add("b");

			syso
		}
	}

Set集合的遍历

1、没有自己特有的方法,使用Collectino中的方法
2、第一种:toArray()转数组,遍历数组
3、第二种:T[ ] toArray(T[ ] a) 转数组,遍历

(1)当数组的长度等于元素个数时,就是用提供的数组
(2)当数组的长度小于元素个数时,底层创建新的数组存储集合元素
(3)当数组长度大于元素个数时,依然使用提供的数组,但是数组剩余的部分就按照默认值填充

4、迭代器
5、增强for循环

for(元素的数据类型 元素名称: 要遍历的集合或者数组) {
使用元素名称操作元素
}
(2)说明:增强for循环的底层是迭代器,如果增强for循环遍历几个的过程中,使用了集合对象修改集合,会出现并发修改异常

package ceshi01;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

public class Dome {
		public static void main(String[] args) {
		Set<Integer> set = new HashSet<>();
			
			set.add(0);
			set.add(0);
			set.add(324);
			set.add(324);
			set.add(11);
			set.add(11);
			set.add(-97);
			
			firstWay();//第一种:toArray()转数组,遍历数组
			secondWay(set);//第二种:T[ ] toArray(T[ ] a) 转数组,遍历
			thirdWay(set);//迭代器
			
		
			public static void firstWay() {
			Set<Integer> set = new HashSet<>();
			
			set.add(0);
			set.add(0);
			set.add(324);
			set.add(324);
			set.add(11);
			set.add(11);
			set.add(-97);
		
			
			//1.调用toArray()方法,将集合转为数组
			Object[] arr = set.toArray();
			
			//2.遍历数组
			for (int i = 0; i < arr.length; i++) {
				System.out.print(arr[i] + " ");
			}
		}


			public static void secondWay(Set<Integer> set) {
			/*
			 * 1.当数组的长度等于元素个数时,就是用提供的数组
			 * 2.当数组的长度小于元素个数时,底层创建新的数组存储集合元素
			 * 3.当数组长度大于元素个数时,依然使用提供的数组,但是数组剩余的部分就按照默认值填充
			 * 
			 * */
			
			//1.准备数组
			//Integer[] arr = new Integer[set.size()];
			//Integer[] arr = new Integer[3];
			Integer[] arr = new Integer[10];
			
			//2.调用toArray(T[] arr)
			Integer[] arr1 = set.toArray(arr);
			
			//3.遍历数组
			for (int i = 0; i < arr1.length; i++) {
				System.out.print(arr1[i] + " ");
			}
			
			System.out.println(arr);
			System.out.println(arr1);
		}


			public static void thirdWay(Set<Integer> set) {
			//1.获取集合中的迭代器对象
			Iterator<Integer> it = set.iterator();
			
			//2.迭代器遍历集合
			while(it.hasNext()) {
				System.out.println(it.next());
			}
		}
		}

LinkedHashSet

1、是HashSet的一个子类,和HashSet保证元素唯一性的原理相同
2、和HashSet的不同之处在于:存取顺序一致
3、特点:有序,不可重复
4、应用:既要保证顺序,又要去重的时候,可以考虑使用

LinkedHashSet<String> set = new LinkedHashSet<>();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
黑马是一个非常受欢迎的IT培训机构,他们提供了很多优质的编程课程,包括TypeScript。以下是一些关于TypeScript学习笔记,希望对你有所帮助: 1. TypeScript是一种由微软开发的开源编程语言,它是JavaScript的一个集,意味着所有的JavaScript代码都是合法的TypeScript代码。 2. TypeScript引入了静态类型系统,这意味着你可以在编写代码时指定变量的类型,并在编译时进行类型检查。这有助于减少错误,并提供更好的代码提示和自动完成。 3. 使用TypeScript可以提高代码的可维护性和可读性。通过明确指定类型,你可以更好地理解代码的意图,并且在与其他开发人员协作时更容易理解和调试代码。 4. TypeScript支持面向对象编程的特性,如类、继承、接口和模块。这使得你可以更好地组织和结构化你的代码,并实现更高级的设计模式。 5. TypeScript还具有一些高级特性,如泛型、装饰器和枚举。这些特性可以帮助你编写更灵活和可复用的代码。 6. 学习TypeScript时,你可以使用官方文档和教程作为学习资源。此外,还有很多在线课程和视频教程可供参考。 7. 练习是学习的关键。尝试编写一些简单的TypeScript程序,并逐渐增复杂性。通过实践,你将更熟悉语言的语法和概念。 希望这些笔记对你的TypeScript学习有所帮助!如果你有任何其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿福真的不想掉头发

大爷?赏点?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值