List接口及实现类——ArrayList
- 1、Lits是元素有序并且可以重复的集合,被称为序列
- 2、List可以精确的控制每个元素的插入位置,或删除某个位置的元素
- 3、ArrayList——数组序列,是List的一个重要实现类
- 4、ArrayList底层是由数组实现的
模拟学生选课功能-演示list基本操作
- 选择课程(往集合中添加课程)
1.ArrayList.add(object),将指定的元素添加到此列表的尾部。
2.ArrayList.add(index,object),将指定的元素插入此列表中的指定位置,原来在该位置,以及在后面的元素都向后移动一位。
3.ArrayList.addAll(collection),按照指定 collection 的迭代器所返回的元素顺序,将该 collection 中的所有元素添加到此列表的尾部。
4.ArrayList.add(index,collection),在数组index位置起添加一个collection
示例代码:
public void testAdd() {
//创建一个课程对象,并通过调用add方法,添加到备选课程List中
Course cr1 = new Course("1" , "数据结构");
coursesToSelect.add(cr1);
//从list中取出元素可以调用get(index)方法,index对应数组下标
//List中存放的数据都是无视元素类型的,一律视为object
//所以取出时也是一个object对象,需要强制转换
Course temp = (Course) coursesToSelect.get(0);
System.out.println("添加了课程:" + temp.id + ":" + temp.name);
//ArrayList.add(index,object)用于在指定位置添加元素
Course cr2 = new Course("2", "C语言");
coursesToSelect.add(0, cr2);
Course temp2 = (Course) coursesToSelect.get(0);
System.out.println("添加了课程:" + temp2.id + ":" + temp2.name);
//以下方法会抛出数组下标越界异常
// Course cr3 = new Course("3", "test");
// coursesToSelect.add(4, cr3);
// 1、可以通过addAll()方法将某类的对象数组(实例数组)添加到List中
// 2、由于addAll()的参数为Collection类型,因此需要将对象数组(作为参数)
// 转换成List类型,可以通过Arrays.asList()方法将数组转换成List。
// 3、无论是add()方法还是addAll()方法,都可以在List指定位置插入新元素或新数组
Course[] course = {new Course("3", "离散数学"), new Course("4", "汇编语言")};
coursesToSelect.addAll(Arrays.asList(course));
Course temp3 = (Course) coursesToSelect.get(2);
Course temp4 = (Course) coursesToSelect.get(3);
System.out.println("添加了两门课程:" + temp3.id + ":" +
temp3.name + ";" + temp4.id + ":" + temp4.name);
//在指定位置添加数组,原来位置的元素向后移动若干位
Course[] course2 = {new Course("5", "高等数学"), new Course("6", "大学英语")};
coursesToSelect.addAll(2, Arrays.asList(course2));
Course temp5 = (Course) coursesToSelect.get(2);
Course temp6 = (Course) coursesToSelect.get(3);
System.out.println("添加了两门课程:" + temp5.id + ":" +
temp5.name + ";" + temp6.id + ":" + temp6.name);
}
- 查看所选课程(获取数组元素)
1.ArrayList.get(index)方法,index对应数组下标
2.通过集合的iterator方法,通过迭代器来遍历List
示例代码;
/**
* 取得List中的元素的方法
* @param args
*/
public void testGet() {
int size = coursesToSelect.size();
System.out.println("有如下课程待选:");
for(int i= 0 ; i < size; i++) {
Course cr = (Course) coursesToSelect.get(i);
System.out.println("课程:" + cr.id + ":" + cr.name);
}
}
/**
* 通过迭代器来遍历List
* @param args
*/
public void testIterator() {
//通过集合的iterator方法,取得迭代器的实例
Iterator<Course> it = coursesToSelect.iterator();
System.out.println("有如下课程待选(通过迭代器访问):");
while(it.hasNext()) {
Course cr = it.next();
System.out.println("课程:" + cr.id + ":" + cr.name);
}
}
/**
* 通过for each方法访问集合元素
* @param args
*/
public void testForEach() {
System.out.println("有如下课程待选(通过for each访问):");
for (Object obj : coursesToSelect) {
Course cr = (Course) obj;
System.out.println("课程:" + cr.id + ":" + cr.name);
}
}
- 修改所选课程(替换数组上的元素)
使用list接口的set方法
代码示例:
/**
* 修改List中的元素
* @param args
*/
public void testModify() {
coursesToSelect.set(4, new Course("7", "毛概"));
}
- 删除所选的某门课程(删除集合中的元素)
数组的删除方法:
- remove(int index)移除此列表中指定位置上的元素。
- remove(object o)移除此列表中首次出现的指定元素(如果存在)。
- removeRange(int fromIdex,in toIndex)移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素。
- removeAll(collection),将集合中的所有元素删除
示例代码:
/**
* 删除List中的元素
* @param args
*/
public void testRemove() {
// Course cr = (Course) coursesToSelect.get(4);
System.out.println("即将删除4位置和5位置上的课程!");
Course[] courses = {(Course) coursesToSelect.get(4), (Course) coursesToSelect.get(5)};
coursesToSelect.removeAll(Arrays.asList(courses));
// coursesToSelect.remove(4);
System.out.println("成功删除课程!");
testForEach();
}
应用泛型管理集合
- 集合中的元素,可以是任意类型的对象(实质上是对象的引用,指向某个具体对象)
1)因此,把某个对象放入集合时,则会忽略他的类型,而把他当做Object处理
2)同样,当从集合中取出对象时,也把他当做Object处理,因此需要强制类型转换
- 泛型,规定了某个集合只可以存放特定类型的对象
1)在编译期间进行类型检查,而非运行时抛出异常
2)获取元素时,可以直接按指定类型获取,不需要进行强制类型转换
泛型定义:public/private List<Listtype> ListName
应用了泛型之后,调用foreach进行遍历时可直接使用对应类型的类型名定义循环变量的类型不必写成foreach(Object obj:ListName)
这样,可直接写成foreach(ListType lt:ListName)
示例代码:
/**
* 测试添加
*/
public void testAdd() {
Course cr1 = new Course("1","大学语文");
courses.add(cr1);
//泛型集合中,不能添加泛型规定的类型及其子类型以外的对象,否则会报错!
// courses.add("能否添加一些奇怪的东西呢??");
Course cr2 = new Course("2","Java基础");
courses.add(cr2);
}
** 此外集合泛型还有几个需要注意的点:**
1、泛型集合中可以添加泛型对象实例,也可以添加泛型子类型的对象实例
2、泛型不能是基本类型的(如:int long boolean),必须是引用类型
3、如果必须使用基本类型,则需要通过使用包装类实现(如:Integer)
/**
* 泛型结合可以添加泛型的子类型的对象实例
*/
public void testChild() {
ChildCourse ccr = new ChildCourse();
ccr.id = "3";
ccr.name = "我是子类型的课程对象实例~~";
courses.add(ccr);
}
/**
* 泛型不能使用基本类型
*/
public void testBasicType() {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
System.out.println("基本类型必须使用包装类作为泛型!" + list.get(0));
}
Set接口及其实现类-HashSet
- Set是元素无序并且不可以重复的集合,被称为集
- HashSet-哈希集,是Set的一个重要实现类
- Set中添加某个对象,无论添加多少次,最终只会保留一个该对象(的引用),并且保留的是第一次添加的那个Set中的元素可以添加null
List的contains和containsAll 方法:
list中的contains实现原理是,将list中的元素与比较对象调用equals逐一比对,若equals返回true则contains返回true。
对于类对象 equals方法比较的是 栈的地址 ,所以达不到比较contains方法想要达到的比较内容的目的,所以必须改写equals方法。对于类对象 equals 与 == 如果不该写几乎是等价的。改写程序中 首先判断两者栈地址是否相同,如果相同既为同一对象 肯定相同。其次如输入对象为 空 ,则返回-1;由于定义比较对象时 由于构造方法的存在, 不可能为空,所以不存在空跟空的比较。
正在对象类中重写equals方法,来达到比较内容的目的
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Course))
return false;
Course other = (Course) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
测试代码:
public class TestEquals {
ArrayList<Course> coursesList=new ArrayList<Course>();
public void testAdd() {
//创建一个课程对象,并通过调用add方法,添加到备选课程List中
Course cr1 = new Course("1" , "数据结构");
coursesList.add(cr1);
Course cr2 = new Course("2", "C语言");
coursesList.add(cr2);
Course[] course = {new Course("3", "离散数学"), new Course("4", "汇编语言")};
coursesList.addAll(Arrays.asList(course));
Course[] course2 = {new Course("5", "高等数学"), new Course("6", "大学英语")};
coursesList.addAll(Arrays.asList(course2));
}
public void testGet() {
int size = coursesList.size();
System.out.println("有如下课程待选:");
for(int i= 0 ; i < size; i++) {
Course cr = (Course) coursesList.get(i);
System.out.println("课程:" + cr.id + ":" + cr.name);
}
}
public void testContains(){
Scanner scanner=new Scanner(System.in);
System.out.println("请输入课程id");
String id=scanner.next();
System.out.println("请输入课程name");
String name=scanner.next();
Course course3=new Course(id,name);
if(coursesList.contains(course3)){
System.out.println("课程list中含有"+course3.name+"课程");
System.out.println("测试成功");
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
TestEquals testEquals=new TestEquals();
testEquals.testAdd();
testEquals.testGet();
testEquals.testContains();
}
}
输出结果:
List的index方法
index从零开始从头到尾逐个调用equals比对
lastIndex从尾到头逐个比对
![Upload Paste_Image.png failed. Please try again.]
- list可以通过indexOf方法来取得某元素的索引位置如果有重复元素,只返回第一次出现该元素的位置的值
- List还提供了lastIndexOf()方法,不同于IndexOf()方法,lastIndexOf()方法时从队尾到队头遍历,返回某个重复元素最后一次出现的索引位置
- 无论是indexOf()方法还是lastIndexOf()方法,如果参数对象在序列中都没有出现的话,则返回值都为-1
Set的contains方法
在判断set的contains方法时首先会调用 hashcode()方法判断哈希码是否相等,然后再调用equals方法判断,都通过的话返回true。
在需要判断的目标类Mycourse中,编辑界面右击选择源代码,可以自动
重写hashcode 和equals方法,使hashcode()计算的哈希值与我们需要比对的元素相关
通过重写这两个方法即可,使用元素为目标类的哈希集并自定义contain方法
得到我们想要的结果
运用collections.sort()方法对list进行排序:
sort
- 根据元素的自然顺序 对指定列表按升序进行排序。列表中的所有元素都必须实现 Comparable 接口.此外,列表中的所有元素都必须是可相互比较的(也就是说,对于列表中的任何 e1 和 e2 元素,e1.compareTo(e2) 不得抛出 ClassCastException)。
此排序方法具有稳定性:不会因调用 sort 方法而对相等的元素进行重新排序。 - 指定列表必须是可修改的,但不必是大小可调整的。
- 该排序算法是一个经过修改的合并排序算法(其中,如果低子列表中的最高元素小于高子列表中的最低元素,则忽略合并)。此算法提供可保证的 n log(n) 性能。 此实现将指定列表转储到一个数组中,并对数组进行排序,在重置数组中相应位置处每个元素的列表上进行迭代。这避免了由于试图原地对链接列表进行排序而产生的 n2 log(n) 性能。
扩展:
1、Arrays类,java.util.Arrays,提供了操作数组的各种静态方法
2、Collections工具类,java.util.Collection,提供了操作集合对象的各种静态方法
3、Collection类是java集合框架的成员,和Map,Collection是同一级别的
示例代码:
public class TestSort {
public ArrayList<Integer> list=new ArrayList<>();
//初整数始化数组,给数组随机添加10个元素
//字符串也能排序
public TestSort() {
Random random=new Random();
Integer k;
for(int i=0;i<10;i++){
do{
k=random.nextInt(100);
list.add(k);
}while(!list.contains(k));
}
}
//循环打印数组
void printList(){
for(Integer i:list){
System.out.print(i+" ");
}
System.out.println();
}
//调用collections类的sort方法对list进行排序
public void sortList(){
Collections.sort(list);
}
public static void main(String[] args) {
TestSort testSort=new TestSort();
System.out.println("排序前:~~~~");
testSort.printList();
testSort.sortList();
System.out.println("排序后:~~~~");
testSort.printList();
}
}
comparable&comparator
以上代码可以实现对整数列表或者字符串列表的排序,那么能否对自定义的的类的实例进行排序呢?答案是肯定可以的,但必须实现comparable或者comparator接口
其中:
comparable接口-
1、实现该接口表示:这个类的实例可以比较大小,可以进行自然排序
2、定义了默认的比较规则
3、其实现类需实现compareTo()方法
4、compareTo()方法返回正数表示大,负数表示小,0表示相等.
comparator接口-比较工具接口
1、用于定义临时的比较规则,而不是默认比较规则
使用:conllections.sort(list,comparator)
2、其实现类需要实现compare()方法
3、comparator和comparable都是java集合框架的集合
comparable示例代码:
public class Student implements Comparable<Student>{
String name;
String id;
public Student(String name, String id) {
super();
this.name = name;
this.id = id;
}
@Override
public int compareTo(Student o) {
return this.id.compareTo(o.id);
}
}
public class MyComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
public class TestStudent {
ArrayList<Student>sList=new ArrayList<>();
//初始化数组
public TestStudent() {
Student student1=new Student("Bop", "3");
Student student2=new Student("susan", "2");
Student student3=new Student("windy", "1");
sList.add(student1);
sList.add(student2);
sList.add(student3);
}
//循环打印数组
void printList(){
for(Student student:sList){
System.out.println("学生名字:"+student.name+" id:"+student.id);
}
System.out.println("------------------------------");
}
public static void main(String[] args) {
TestStudent testStudent=new TestStudent();
System.out.println("排序前:");
testStudent.printList();
Collections.sort(testStudent.sList);
System.out.println("排序后:");
testStudent.printList();
MyComparator myComparator=new MyComparator();
Collections.sort(testStudent.sList,myComparator);
System.out.println("使用comparator排序后:");
testStudent.printList();
}
}
输出结果: