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

时间:2023-02-26 10:35:12

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());
	}
}

结果:
    [generticity.Demo1@6486b4d5, 今天周四, 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);