Java 集合 一
集合 只能装载引用类型的对象 对于基本类型byte shor int long float double char boolean 都只能自动装箱后存储
Collection接口 的方法
add( e) 尝试向集合添加元素 ,若成功则返回true
remove( e) 尝试删除集合中的元素 ,若成功则返回true
clear( ) 清空集合中的元素
contains(e ) 元素是否在集合中
size( ) 集合大小
toArray( ) 集合元素转为数组元素 返回得到数组 Object[ ] array
被List接口 Set接口 继承
被ArrayList LinkedList HashSet LInkedHashSet 具体实现
ArrayList LinkedList的三种遍历方式
1.迭代器遍历
import java.util.ArrayList; import java.util.Iterator; ArrayList<String> arr = new ArrayList<String> (); arr.add("abc");//只能添加String类型的对象 arr.add("it"); arr.add("it"); Iterator<String> it = arr.iterator(); while(it.hasNext()){ System.out.println(it.next()); }
/* for循环写法
for(Iterator<String> it2 = arr.iterator(); it2.hasNext();){
System.out.println(it.next());
}
*/
//不管是while循环 还是for循环 都是用同一个迭代器对象去集合中取元素 (it和it2变量名指向的是同一个对象)
//因此一旦while循环 迭代器对象已经对集合遍历了一遍 那么再用for循环中的同一迭代器再去取元素 就会报错 java.util.NoSuchElementException 因为 迭代器只能取一遍!
2. for循环
3.增强型 for循环 (foreach Java 1.5版本引入 这是因为 1.5引入了 Iterable接口 该接口成为了 Collection List Set接口的 父接口 Iterable的作用就是增强for循环! )
增强型for
好处 :代码简化 方便对容器进行遍历
弊端: 没有索引 无法对容器中的指定元素进行操作
迭代器 Java1.2版本引入 成为了 Collection的父类接口
该接口中抽象方法 hasNext( ) next( ) 是由具体的ArrayList LinkedList HashSet LInkedHashSet 类来实现的
该接口的对象(接口没有对象 这里指的是实现类的对象)例如ArrayList这个实现类中 重写了方法 iterator( ) 该方法可以返回实现类对象 即 Iterator<String> it = new ArrayList<String> ().iterator( )
迭代器 是集合通用的 获取其元素的方式——取元素前先判断是否有元素存在,有则取出,直到全部取出(一旦开始取就只能向下取,只能从头到尾取一遍,且在取的过程中 集合长度不能发生变化)
由于集合是存储任意类型的对象,因此集合中什么都可存 即存Object类型的对象
对集合中元素迭代获取时,得到的也是Object obj = it.next( ), 这种父类对象没办法使用其子类对象的特有方法 为了使用这些方法 必须向下转型 从Object类型 -> 子类类型 例如 String s =(String)it.next() 对象s才能使用 s.length()方法
为防止 向下转型时出现异常 我们可以对集合使用泛型,从而约束了集合中对象元素的类型统一, 这样就避免了迭代器取值后的类型强制转换
类型强制转换后 运行时发生 ClassCastException异常
import java.util.ArrayList; import java.util.Iterator; ArrayList arr = new ArrayList(); arr.add("abc");//只能添加String类型的对象 arr.add("it"); arr.add("it");// String类型 arr.add(5);// int类型 自动封箱为 Integer类型 Iterator it = arr.iterator(); while(it.hasNext()){ String str = (String)it.next();//强制类型转换! System.out.println(str.length()); }
泛型 只是编译时对类型的约束,编译后运行时 并不存在泛型,因此 java的泛型是一种伪泛型 不同于C++中的真泛型
ArrayList<String> arr
arr.add(" ") 如果添加的不是String类型 则编译失败,只有添加对象的类型正确 才能编译通过 编译后的.class文件中没有泛型 因此对于java的反编译文件 你是看不到泛型存在的 ┭┮﹏┭┮
ArrayList<String> list = new ArrayList<String>();//ArrayList类 就是一个带泛型的类 String[] arr = new String[list.size()];//String类型的数组 数组长度=集合的长度 String[] result = list.toArray(arr);//将集合元素存储到指定数据类型的数组中 这个是一个带泛型的方法 public <T> T[] toArray(T[] a){ } //带有泛型的接口 public interface List <E>{ abstract boolean add(E e); } //对于这种接口的实现 //1.先实现接口,不理会泛型 由调用者在创建 实现类 对象时 指定泛型中的数据类型 public class ArrayList<E> implements List<E>{ } //2.在实现接口的同时,就指定好泛型中的数据类型 public class Xxx implements List<String>{ }
使用泛型的好处
将运行时的异常 转移到编译时期的编译失败
避免强制转型的麻烦
泛型的通配符 ? extends 类型的类名 传参的类型 必须都继承自 已限定的父类 上限被限制
泛型的通配符 ?super 类型的类名 传参的类型 必须是限定子类的父类或超类 下限被限制