集合老大哥-Collection
集合,是java提供的一种容器,可以用来存储多个数据,数组同样是容器,但是两者有区别:
- 数组的长度是固定的,而集合的长度是可变的
- 集合中存储的元素必须是引用类型的数据
学会使用集合:能够使用集合来存储对象,能够遍历集合取出对象,能够掌握不同集合的特点,如List集合(有序可重复)Set集合(无序不可重复)等
集合的使用(两个例子)
例一:集合存储Person类对象
package 集合;
//Person类
public class Person {
private String name;
private int age;
public Person(String name,int age) {
this.name = name;
this.age = age;
}
}
package 集合;
import java.util.ArrayList;
public class Collection_Demo {
public static void main(String[] args) {
ArrayList<Person> list = new ArrayList<Person>();
list.add(new Person("张三",20));
list.add(new Person("李四",22));
list.add(new Person("王五",18));
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
}
输出如下:
集合.Person@1540e19d
集合.Person@677327b6
集合.Person@14ae5a5
这是因为list中存储的是Person类的对象,get()方法打印的是对象,在java中打印对象会调用该类的toString()方法,若未重写该方法,打印的是对象在内存中的地址
重写Person类的toString()方法
package 集合;
public class Person {
private String name;
private int age;
public Person(String name,int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
再次打印,观察输出,打印对象确实是调用toString()方法
Person{name='张三', age=20}
Person{name='李四', age=22}
Person{name='王五', age=18}
例二:集合存储基本类型(数值)
package 集合;
import java.util.ArrayList;
public class Collection_Demo {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(123);
list.add(456);
list.add(789);
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
}
输出如下:
123
456
789
集合本身只能存储引用类型的数据(对象),但是java的自动装箱可以将基本类型转换为封装后的引用类型,如int -> Integer(int类型的数据封装为Integer的对象)
查看ArrayList类发现它继承了抽象类AbstractList,同时实现了接口List
public class ArrayList extends AbstractList implements List{}
而List接口又继承了Collection接口
interface List extends Collection {}
同理Set接口也继承了Collection接口
interface Set extends Collection {}
在集合框架中,Collection是爸爸,有俩出名的儿子List和Set
即Collecton接口常用的子接口有:List接口、Set接口
List和Set又都有比较出息的儿子们
List接口常用的子类有:ArrayList类、LinkedList类(有序可重复)
Set接口常用的子类有:HashSet类、LinkedHashSet类(无序不可重复)
通关集合,必须先搞定大BOSS:Collection
Collection接口中的方法,是集合中所有实现类必须拥有的方法,下面是Collection接口中经常使用的几个方法:
- add(E e)
- clear()
- contains(Object o)
- remove(Object o)
- toArray()
package 集合;
import java.util.ArrayList;
import java.util.Collection;
public class Collection_Demo {
public static void main(String[] args) {
function();
}
private static void function() {
//接口多态的方式调用
Collection<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
System.out.println(list);
list.clear();
System.out.println(list);
}
}
//输出
//[one, two, three]
//[]
clear()方法:清空集合中的所有元素,但是集合本身依然存在,还可以继续添加元素,就像水杯倒水一样,水没了,但是杯子还在
package 集合;
import java.util.ArrayList;
import java.util.Collection;
public class Collection_Demo {
public static void main(String[] args) {
function();
}
private static void function() {
//接口多态的方式调用
Collection<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
boolean judge = list.contains("two");
System.out.println(judge);
}
}
//输出
//true
contains()方法:如果集合包含指定元素则返回true,否则返回false
package 集合;
import java.util.ArrayList;
import java.util.Collection;
public class Collection_Demo {
public static void main(String[] args) {
function();
}
private static void function() {
//接口多态的方式调用
Collection<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("two");
System.out.println(list);
boolean judge = list.remove("two");//删除的是第一个two
System.out.println(judge);
System.out.println(list);
}
}
//输出
//[one, two, three, two]
//true
//[one, three, two]
remove()方法:从这个集合中移除指定元素
package 集合;
import java.util.ArrayList;
import java.util.Collection;
public class Collection_Demo {
public static void main(String[] args) {
function();
}
private static void function() {
//接口多态的方式调用
Collection<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
//数组的长度不可变,但是集合的长度可以变
Object[] objs = list.toArray();
//java中长度的三种表现形式:数组.length属性,字符串.length()方法,集合.size()方法
for(int i=0;i<objs.length;i++){
System.out.println(objs[i]);
}
}
}
//输出
//one
//two
//three
toArray()方法:返回一个包含此集合中所有元素的数组,数组存储的数据类型是Object,因为集合可以存储任意类型对象
集合遍历-迭代器
java中提供了很多种集合,每种集合的底层的数据结构不同,例如ArrayList的底层是数组,LinkedList的底层是链表,虽然在存储时采用的存储方式不同,但是我们却不需要针对不同的存储方式来设计相应的遍历方法,因为无论使用哪种集合,我们都会有判断是否有元素以及取出里面的元素的动作,所以能够通过一种通用的方式来遍历集合:那就是迭代
迭代过程:在取元素之前先要判断集合中是否有元素,如果有,就把这个元素取出来,继续判断,如果还有,就再取出来,一直把集合中的所有元素全部取出
代码实现
package 集合;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Collection_Demo {
public static void main(String[] args) {
function();
}
private static void function() {
//接口多态的方式调用
Collection<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
//调用集合的iterator()方法,获取Iterator接口的实现类对象
Iterator<String> it = list.iterator();
//接口的实现类对象,调用hasNext()方法判断集合中是否有元素
//boolean b= it.hasNext();
//接口的实现类对象调用next()方法取出集合中的元素
//String str = it.next();
//System.out.println(str);//one
//迭代是反复内容,推荐使用while循环实现,循环结束的条件, hasNext()返回了false
while(it.hasNext()){
System.out.println(it.next());
}
}
}
//输出
//one
//two
//three
Tips:
- 集合中存储的其实都是对象的地址,在jdk1.5版本以后可以存储基本类型了,因为出现了基本类型包装类,提供了自动装箱操作(基本类型 对象),集合中的元素就变成了基本类型的包装类对象
- 集合不指定存储的数据类型时,则什么元素都可以存,参数是Object类型,存储时提升到Object,取出时要使用元素的特有内容,必须向下转型
Collection list = new ArrayList();
list.add("one");
list.add("two");
list.add("three");
Iterator it = list.iterator();
while(it.hasNext()){
//需要打印每个字符串的长度,就要把迭代出来的对象转成String类型
String str = (String)it.next();//String str=(String)obj;
System.out.println(str.length());
}
- 当使用Iterator控制元素类型后,就不需要强制转换了,因为获取到的元素直接就是String类型
Iterator<String> it = list.iterator();
增强for循环遍历
JDK1.5版本后,出现新的接口java.lang.Iterable
老大哥Collection继承Iterable
Iterable的作用:实现增强for循环
格式:
for(数据类型 变量名 : 数组或者集合){
sop(变量);
}
- 增强for循环遍历数组
String[] strs = {"one","two","three"};
for(String str : strs){
System.out.println(str);
}
- 增强for循环遍历集合
ArrayList<Person> list = new ArrayList<Person>();
list.add(new Person("张三",20));
list.add(new Person("李四",22));
list.add(new Person("王五",18));
for(Person p : list){
System.out.println(p);
}
增强for循环的优缺点:
优点: 代码少了,方便对容器遍历
缺点: 没有索引,不能改变容器里面的元素
泛型
jdk1.5 出现了新的安全机制,引入了泛型来保证程序的安全性
泛型:指明了集合中存储数据的类型<数据类型>
public class GenericDemo {
public static void main(String[] args) {
List list = new ArrayList();
list.add("one");
list.add("two");
list.add(3);//由于集合没有做任何限定,任何类型都可以存放,相当于 Object obj=new Integer(3);
Iterator it = list.iterator();
while(it.hasNext()){
//需要打印每个字符串的长度,就要把迭代出来的对象转成String类型
String str = (String) it.next();//String str=(String)obj;
//编译时期仅检查语法错误,String是Object的儿子可以向下转型
//运行时期String str=(String)(new Integer(5))
//String与Integer没有父子关系所以转换失败
//程序在运行时发生了问题java.lang.ClassCastException
System.out.println(str.length());
}
}
}
使用泛型可以将运行时期的ClassCastException类型转换异常转移到编译时期,使编译失败,同时还可以避免类型的强制转换,如下
//使用泛型
public class GenericDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
//list.add(3);//当集合明确类型后,存放类型不一致就会编译报错
//当使用Iterator<String>控制元素类型后,就不需要强制转换了,获取到的元素就是String类型
Iterator<String> it = list.iterator();
while(it.hasNext()){
String str = it.next();
System.out.println(str.length());
}
}
}
泛型的通配符:泛型的通配,匹配所有的数据类型 ?
public class GenericDemo {
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<String>();
HashSet<Integer> set = new HashSet<Integer>();
array.add("one");
array.add("two");
set.add(3);
set.add(4);
iterator(array);
iterator(set);
}
/*
* 定义方法,可以同时迭代集合array和set
* 方法参数: 共同继承的父类或者共同实现的接口,不能写ArrayList,也不能写HashSet,要写两者共同实现的接口Collection,接口的参数要写?
* 迭代器参数: 不能写String,也不能写Integer,要写?
*/
public static void iterator(Collection<?> coll){
Iterator<?> it = coll.iterator();
while(it.hasNext()){
//it.next()获取的对象不确定是什么类型
System.out.println(it.next());
}
}
}