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.方式1:
class Test1<T> implements A<T> {
public void testA(T t) {
实现方法
}
}
更加* 在创建类对象时,才对泛型进行约束。
2.方式2:
class 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);