欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【JAVA学习笔记】18 泛型genericity Map集合

程序员文章站 2022-07-14 23:33:57
...

2018.4.19

泛型

泛型简述。

[问题]

1.发现ArrayList可以放入任意类型的数据,但是实际操作中发现数据类型
 	不一致会导致更多的错误。
 	2.就是知道取出的数据是一个String类型,但是还是要通过【强转】才能真正拿到想要的
 	String类型数据,这个操作很麻烦。

【期望】

集合中的数据类型能够统一。
 	数据类型一致化问题。

【解决问题】

泛型
 	java jdk1.5之后的新特征。

public class Demo1 {
	public static void main(String[] args) {
		ArrayList<Object> list = new ArrayList<Object>();
		
		list.add(new Demo1());//自定义类对象
		list.add("今天周四");
		list.add(3);
		
		
		System.out.println(list);
	
		Object object = list.get(1);
		
		String string = (String) object;
		System.out.println(string.length());
		System.out.println(string);
		
		Object[] arr = list.toArray();
		
		//Arrays.sort(arr);
		
		System.out.println(arr.toString());
	}
}

结果:
    [[email protected], 今天周四, 3]
    4
    今天周四
    [Ljava.lang.Object;@47ca3f82

泛型实例

使用泛型来解决之前遇到的问题
 		1.解决集合中数据类型一致化问题,要求保存什么数据就保存什么数据,添加其他数据的话报错。
 		异常提前。
 		2.从集合中取出数据,保存的是什么类型,拿出来的就是什么类型,不需要无意义的【强制类型转换】。
 		
 标准格式:
 		ArrayList<String> list = new ArrayList<String>();  <E>占位符。无意义
 以下情况也允许:
 	1.ArrayList list = new ArrayList<String>();
 	2.ArrayList<String> list = new ArrayList();
 	为了照顾不同的版本和不同IDE工具。
 	
【 但是以下情况不允许】
	ArrayList<Object> list = new ArrayList<String>();
	ArrayList<String> list = new ArrayList<Object>();


public class Demo2 {
	public static void main(String[] args) {
		//<String>这是泛型,要求这个ArrayList集合中有且只能保存String类型的数据
		ArrayList<String>list = new ArrayList<String>();
		
		list.add("今天阿根廷被灌了6个球。");
		list.add("西班牙真牛逼");
		list.add("梅西提前离场了");
		
		
		//这里无法保存除string类型之外的任意其他类型。
		//list.add(new Demo2());
		//list.add(1);
		
		String str = list.get(2);
		System.out.println(str);
	}
}

结果:

梅西提前离场了

泛型的运用

需求:
	定义一个方法,可以接受任意数据类型,而且要求返回的数据类型,就是你传入的数据类型。
	例如:
		传入String返回String
		传入Demo3类型返回Demo3类型
		
泛型的使用需要:
	占位符!<一个大写字母>,只是一个占位符,没有实际含义,而且不同地方定义的占位符没有联系。
	
	
泛型在函数中使用的格式:
	修饰符<声明的自定义泛型占位符> 返回值类型(可以使用自定义泛型) 函数名(形式参数列表“也可以使用泛型”) {
		函数体
		在函数体中,所有用到自定义泛型的地方,都可以被替换 
	} 
	
包装类:
	JAVA是完全面向对象的语言,在JAVA中万物皆对象,如果是要保存类对象,那么八大基本数据类型就无法使用,
	所以JAVA提供了一个包装机制,包装基本数据类型,让他们成为类对象,自动封箱。
	Integer --> int
	Byte --> byte
	Long --> long
	Short --> short
	
	Double --> double
	Float --> float
	
	Boolean --> boolean
	
	Character -> char
	
	如果使用包装类直接赋值给普通的基本数据类型,这个操作称之为拆箱。

public class Demo3 {
	public static void main(String[] args) {
		String string = getType("String");
		Demo3 demo3 = getType(new Demo3());
		
		int num = getType(5);//integer int的包装类。
		
	}

自定义泛型的占位符<E>

<E>是自定义泛型的占位符,表示在该函数中可以使用占位符E,而E的具体数据类型,由传入参数控制
 这样操作可以让函数多样化,多元化,代码更加简单。


public static <E> E getType(E e) {
	
	return e;
}

}

类内使用泛型。

在类内使用泛型。

格式:

	class 类名<自定义泛型的占位符> {
		//在这里所用的泛型和用户创建对象时声明的一致。
	}
	
注意事项:
	1.一个类声明的自定义泛型,如果在创建类对象时定了泛型的具,确体数据类型,那么在整个类内所有用到
	该泛型占位符的非静态成员方法,使用的数据类型都是创建时创建的类型。
	
	2.如果创建使用了自定义泛型的类对象,但是没有确定泛型的具体类型,那么编译器会把这个
	泛型认为是Object类型。
	
	3.类中声明的自定义泛型,不能在内的静态方法使用,如果想让静态方法使用泛型,自己声明自己使用
	类似于方法中使用泛型。
	
	4.建议:如果在代码中出现了多个使用泛型的地方,请使用多个名字。 T E

class InvalidArrayException extends Exception {

	public InvalidArrayException(String message) {
		super(message);
	}
}

class invalidComparatoraException extends Exception {
	public invalidComparatoraException(String message) {
		super(message);
	}
}

class ArrayTools<A> {
	/**
	 * 利用泛型来满足不同数据类型的排序算法,可以在创建类对象时约束!!
	 * @param array A类型,泛型的数组,可以是任意类型
	 * @param com	<? super A>是A类型的比较器或者其父类的比较器
	 * @throws InvalidArrayException	数组无效异常
	 * @throws invalidComparatoraException	比较器无效异常
	 */
	public void selectSortUsingCompare(A[] array,Comparator<? super A> com) throws InvalidArrayException, invalidComparatoraException {//?在A之上。
		//参数合法性判断
		if(null == array || array.length == 0) {
			throw new InvalidArrayException("数组无效");
		}else if(null == com) {
			throw new invalidComparatoraException("比较器无效");
			
		}
		for (int i = 0; i < array.length - 1; i++) {
			int index = i;
			
			for(int j = i + 1;j <array.length;j++) {
				if(com.compare(array[index], array[j]) > 0) {
					index = j;
				}
			}
			if (index != i) {
				A tempA = array[index];
				array[index] = array[i];
				array[i] = tempA;
			}
		}
	}
	
	public void printArray(A[] array) {
		for (A a : array) {
			System.out.println(a);
		}
	}
  • 静态成员方法加载的比类早,所以类声明的泛型是在创建类的时候需求,是不能约束静态方法的,是无关的,,可以在静态方法中自己声明泛型
public static <T> void test(T a) {
		System.out.println(a);
	}
	
}
public class Demo4 {
	public static void main(String[] args) 
			throws InvalidArrayException, invalidComparatoraException {
		Integer[] array = {1,3,5,6,7,8,2,4};
		
		ArrayTools<Integer> tools = new ArrayTools<Integer>();//
		
		//匿名内部类的匿名对象。  心脏是成员变量描述合适还是成员方法描述合适? 发动机对于汽车? 都不是,属于成员内部类。
		tools.selectSortUsingCompare(array, new Comparator<Integer>() {

			@Override
			public int compare(Integer o1, Integer o2) {
				
				return o1 - o2;
			}			
		});
		
		tools.printArray(array);
		
	}
}

结果:

1
2
3
4
5
6
7
8

HashMap

---| Collection

------| List(接口)

---------| ArrayList(实现类)

---------| LinkedList(实现类)

------| Set(接口)

---------| HashSet(实现类)

---------| TreeSet(实现类)

比较器:
		Comparable接口 实现 compareTo方法
		Comparator接口 实现 compare方法
				
生活中,有关系的数据更多一点
	账号 密码
	钥匙 锁
	英文 解释
	
	NSDictionary Objective-C Next Step公司。
	
	---| Map<K,V> 双列集合,这是一个接口 Key值不能重复
	------| HashMap 实现类
	------| TreeMap 实现类
	
	K:key 键! 是一个不允许重复的唯一值。
	V: Value 值 一个键(key)对应一个值(value) 可以重复的
	
	在Map<K,V> 双列集合中,保存的只能是一个键(key)值(value)对。
	
	
	Map中要学习的方法:
		增
			put(K key, V value);//添加一个键(K)值(value)对
			putAll(Map<? extends K,? extends V> map);//添加一个符合数据类型的Map双列集合
		删
			remove(Object key);//根据key删除对应的键值对。
			clear();//清空所有键值对。
		改
			put(K key,V value);//当键key存在的时候,这个操作时重新修改值。size();//获取键值对个数
			get(Object key);//通过键获取对应的值value。
			containsKey(Object key);//查看这个key是否在Map中存在。
			containsValue(Object value);//查看这个value是否在map中存在
			
			keySet();//返回所有键(key)的set的集合
			values();//返回所有值(value)的Collection集合

public class Demo1 {
	public static void main(String[] args) {
		Map<String, String>map = new HashMap<String,String>();
		
		//使用put(k,v)添加元素
		map.put("薛之谦", "高磊鑫");
		map.put("鹿晗", "关晓彤");
		map.put("宋仲基", "宋慧乔");
		map.put("余文乐", "王棠云");
		map.put("王宝强", "马蓉");
		
		System.out.println(map);
		
		Map<String,String> map2 = new HashMap<String,String>();
		
		map2.put("科比", "瓦妮莎");
		
		//添加另一个Map
		map.putAll(map2);
		System.out.println(map);
		
		//清空当前map双列集合
		map2.clear();
		System.out.println(map2.isEmpty());
		System.out.println(map2);
		
		//根据Key删除对应的键值对
		map.remove("科比");
		System.out.println(map);
		
		//当key值存在时,这个操作是修改对应的value
		map.put("王宝强", null);
		System.out.println(map);
		
		System.out.println(map.size());
		
		System.out.println(map.containsKey("谢霆锋"));
		System.out.println(map.containsKey("薛之谦"));
		
		System.out.println(map.containsValue("高磊鑫"));
		System.out.println(map.containsValue("王菲"));
		
		System.out.println(map.get("科比"));
		System.out.println(map.get("鹿晗"));
		
		Set<String> set = map.keySet();
	
		for (String string : set) {
			System.out.println(string);
		}
		System.out.println("........................");
		Collection<String> c = map.values();
		for (String string : c) {
			System.out.println(string);
		}
		System.out.println(c.toString());
	}
}

MAP集合遍历

public class Demo1 {
	public static void main(String[] args) {
		HashMap<String, Integer> map = new HashMap<String,Integer>();
		
		map.put("macpro",28888);
		map.put("iphoneX", 8300);
		map.put("ipad pro",5190);
		
		System.out.println(map);
		
		//第一种遍历方式,借助于keySet
		
		Set<String> set = map.keySet();
		
		//使用Set集合的Iterator迭代器
		Iterator<String> it = set.iterator();
		while(it.hasNext()) {
			String key = it.next();//获取每一个map中key值
			int value = map.get(key);
			
			System.out.println(key+"="+value);
			
		}
		//以上方法,其实不太合适,获取的是key值,再借助于Map里面的get方法,获取相应的value
		//并没有获取到完整的键值对。
		
		//第二种方式,借助于values
		Collection<Integer> c = map.values();
		
		for (Integer i : c) {
			System.out.println(i);
		}
		
		//以上方法不合适,只能拿到value,不能获得Key
		
		//在java中,万物皆对象。[]
		
		/*
		 这里把键值对认为是一个对象组成一个类,称之为Entry。 
		 
		 class Entry<k,v> {
		 	K key;
		 	V value;
		 }
		 
		 //这里可以认为在map集合中,保存的每一个键值对都是一个entry对象,把这些entry对象获取出来,
		   作成一个集合,进行遍历。
		   entrySet();
		   map.Entry
		 */
		Set<Entry<String,Integer>> entrySet = map.entrySet();
		
		Iterator<Entry<String,Integer>> it2 = entrySet.iterator();
		
		while (it2.hasNext()) {
			System.out.println(it2.next());
		}
	}
}

泛型复习--------错误提前

为了解决数据类型一致化的问题
避免没有意义的强制类型转换。

自定义泛型使用的格式
	<大写字母> 一般用T E。
占位符 没有任何含义。

泛型在函数中的使用
		格式:
		权限修饰符<自定义泛型> 返回值类型(可以使用泛型) 函数名(形式参数列表“自定义泛型”) {
				同样可以使用泛型
		}

泛型在类中使用
		格式:
		class 类名<自定义泛型> {
			非静态的成员变量或者方法都可以使用类中定义的<自定义泛型>
			
			静态方法不能使用类中自定义泛型,但是可以方法中自己定义泛型
		}
		
		Array.sort(T[] t,Comparator<? super T> c)
		
泛型在接口中的使用
		格式:
		interface 接口名<自定义泛型> {
				//成员变量 缺省属性: public static final 必须初始化因为final不可变
				//成员方法 缺省属性: abstract
		}
		一个类遵从带有自定义泛型的有两种方式:
			例如:
				interface A<T> {
					public void testA(T t);
				}
				
			1.方式1class Test1<T> implements A<T> {
					public void testA(T t) {
					
					实现方法
					}
				}
			更加* 在创建类对象时,才对泛型进行约束。	
			
			2.方式2class Test implements A<String> {
					public void testA(String t) {
							//实现方法
						}
				}
			遵从接口时,接口直接确定了泛型的具体类型。
			
	
	泛型的上下限:
		<? super T>
			表示数据类型是T对象或者是其父类对象
		<? extends T>
				表示数据类型是T对象或者其子类对象
				
##Map
	Map<K,V> K不可重复,V可重复 1,1对应。
	---| HashMap
	---| TreeMap
	
	put(K key, V value);
	putAll(map<? extends k,? extends v> map);
	
	clear();
	remove(Object k);
	
	size();
	containsKey(object Key);
	containsValue(Object value);
	
	keySet();
	values();
	
	get(Object l);