第一讲 集合
1) 集合的概述(个人理解):Java是一种面向对象语言,如果我们要针对多个对象进行操作,就必须对多个对象进行存储,而对多个元素进行存储,可以使用前面学习过数组,但是数组有弊端,长度固定。这样数组将不能满足变化的需求。所以,java就提供了集合来弥补数组的不足。
2)集合的特点:
1、只用于存储对象,集合长度可以发生改变
2、集合可以存储不同类型的对象,(一般存储的还是同一种)
3)集合和数组的区别:
1、长度问题:数组长度固定,集合可变。
2、存储元素问题:数组可以是基本类型,也可以是引用类型。而集合只能是引用类型。
3、是否同一类型:数组元素类型一致,集合元素类型可以不一致。
4)集合体系的由来:集合是存储多个元素的容器,但是,由于数据结构不同,java就提供了多种集合类。而这些集合类有共性的功能,所以通过不断的向上抽取,最终形成了集合体系结构。
个人觉得java中的数据结构其实就是容器中存储数据的方式。
下面是java中集合类的关系图:
第二讲 Collection接口
Collection:
|--List 有序(元素存入集合的顺序和取出的顺序一致),元素都有索引,而且元素可以重复。
|--ArrayList
|--Vector
|--LinkedList
|--Set 无序(存入和取出顺序有可能不一致),不可以存储重复元素。必须保证元素唯一性。
|--HashSet
|--TreeSet
Collection的功能:
A:添加功能
boolean add(Object obj):向集合中添加一个元素
boolean addAll(Collection c):向集合中添加一个集合的元素
B:删除功能
void clear():删除集合中的所有元素
boolean remove(Object obj):向集合中删除指定的元素
booleanremoveAll(Collection c):向集合中删除一个指定的集合元素
C:判断功能
boolean isEmpty():判断集合是否为空
boolean contains(Object obj):判断集合中是否存在指定的元素
boolean containsAll(Collection
c):判断集合中是否存在指定的元素
D:遍历功能
Iterator iterator():就是用来获取集合中每一个元素
E:长度功能
int size():获取集合中的元素个数
F:交集功能
boolean retainAll(Collection c):判断两个集合中是否有相同的元素
G:转换功能
Object[] toArray():把集合变成数组
小练习:遍历集合中的元素,判断是否存在元素“hello”。
/*
* 请遍历集合:也就是获取到集合中的每一个元素。
* 判断集合中是否存在"hello"这个元素.
* 注意:
* 在往集合中添加元素的时候,集合默认接收的是Object类型。
* 也就是说你开始存储字符串的时候,其实做了一个向上转型的操作。
*
* 在获取元素的时候,默认还是以Object类型的返回。
* 但是,你明明知道这应该是String类型。
* 所以,如果你想使用String类型的特殊功能,就必须做向下转型。
* 如果仅仅是为了看结果,就不用。因为通过多态的形式,最终输出语句调用的是String类的toString()
*/
public class CollectionDemo2 {
public static void main(String[] args) {
flag=true; //元素标记符,
Collection c = new ArrayList(); //创建集合对象
// 添加元素
c.add("hello"); // String -- Object
c.add("world");
c.add("java");
// 直接使用判断功能
// System.out.println("contains:"+c.contains("hello"));
// System.out.println("c:" + c);//若存在,则会输出true
// 遍历集合,获取到每一个元素,然后判断这个元素是否是hello
// Object[] toArray():把集合变成数组。
Object[] objs = c.toArray();
for (int x = 0; x < objs.length; x++) {
//将Object类型的数组强制转换为String类型
String s = (String) objs[x];
if(s.equals("hello")){
flag=true; //如果存在,就输出真,否则输出假
}else{
flag=false;
}
System.out.println(s + "***" + s.length()+"***"+flag);
}
}
}
第三讲 Iterator 接口 <java.util>
迭代器:是一个接口。 作用:用于取集合中的元素。
Iterator iterator():就是用来获取集合中每一个元素。
1)方法摘要:
1、 boolean hasNext() 判断迭代器中是否还有元素,如果仍有元素可以迭代,则返回true。
2、E next() 获取元素,并自动移动到下一个位置等待获取,返回迭代的下一个元素。
3、void remove() 从迭代器指向的collection中移除迭代器返回的最后一个元素(可选操作)。
2)迭代器的使用
A:使用步骤
a:通过集合对象获取迭代器对象。
b:通过迭代器对象判断。
c:通过迭代器对象获取。
B:迭代器原理
由于多种集合的数据结构不同,所以存储方式不同,进而取出方式也不同。这个时候,我们就把判断和获取功能定义在了一个接口中,将来遍历哪种集合的时候,只要该集合内部实现这个接口即可。
小练习:用迭代器遍历集合中的元素。
/*
* 成员方法:
* Object next():获取元素,并自动移动到下一个位置等待获取。
* boolean hasNext():判断迭代器中是否还有元素。
* NoSuchElementException:没有这样的元素异常。你已经获取到元素末尾了,你还要获取,已经没有元素了。所以报错了。
*/
public class IteratorDemo {
public static void main(String[] args) {
// 创建对象
Collection c = new ArrayList();
// 添加元素
c.add("hello");
c.add("world");
c.add("java");
// 方式1
// Object[] objs = c.toArray();
// for (int x = 0; x < objs.length; x++) {
// String s = (String) objs[x];
// System.out.println(s);
// }// 方式2
// Iterator iterator():就是用来获取集合中每一个元素。
// 通过集合对象获取迭代器对象
Iterator it = c.iterator();// 这是返回的是Iterator的子类对象,多态
while (it.hasNext()) {
// System.out.println(it.next());
String s = (String) it.next();
System.out.println(s);
} } }
到这儿,总结一下集合的常见使用步骤:
1、创建集合对象------>2、创建元素对象-------->3、把元素添加到集合中------>
4、遍历集合
a:通过集合对象获取迭代器对象
b:通过迭代器对象判断
c:通过迭代器对象获取
第四讲 list接口
List本身是Collection接口的子接口,具备Collection的所有方法。现在学习list体系特有的共性方法,查阅方法发现List的特有方法都有索引,这是该集合最大的特点。
1)List特有功能:
A:添加功能
void add(int index,Object obj):在指定位置添加元素
B:删除功能
Object remove(int index):根据指定索引删除元素,并把删除的元素返回
C:修改功能
Object set(int index,Object obj):把指定索引位置的元素修改为指定的值,返回修改前的值。
D:获取功能
Object get(int index):返回指定元素在集合中第一次出现的索引
int indexOf(Object obj):获取指定位置的元素,如果该元素不存在返回-1;所以,通过-1,可以判断一个元素是否存在 int
lastIndexOf(Object obj):反向索引指定元素的位置
List subList(start,end):获取子列表
ListIterator listIterator():列表迭代器(List集合特有的迭代器)
2)List的遍历方式
A:Iterator 迭代器
B:ListIterator迭代器(了解)
C:普通for(和list的get方法使用)
3)ListIterator迭代器
A:是Iterator的子接口。
B:有自己的特有功能,可以逆向遍历数据,但是需要先正向遍历。一般不用。
/*
* ListIterator listIterator():列表迭代器
*
* boolean hasNext()
* Object next()
*
* 特有功能:
* boolean hasPrevious()
* Object previous()
*
* 虽然,可以逆向遍历,但是,要求先正向遍历,然后才能逆向遍历。
*/
public class ListDemo5 {
public static void main(String[] args) {
// 创建集合对象
List list = new ArrayList();
// 添加元素
list.add("hello");
list.add("world");
list.add("java");
// 遍历
ListIterator lit = list.listIterator();
while (lit.hasNext()) {
String s = (String) lit.next();
System.out.println(s);
}
System.out.println("----------------");
// System.out.println(lit.previous());
// System.out.println(lit.previous());
// System.out.println(lit.previous());
// // NoSuchElementException
// System.out.println(lit.previous());
// 逆向遍历
while (lit.hasPrevious()) {
String s = (String) lit.previous();
System.out.println(s);
}
}
}
4)面试题:并发修改异常
A:并发修改异常的产生原因:用迭代器遍历集合,用集合去操作集合。
B:解决方案:a:使用集合操作。
b:使用列表迭代器操作。
代码如下:
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
/*
* ListIterator listIterator():列表迭代器
*
* public interface ListIterator extends Iterator
*
* 面试题:ConcurrentModificationException:并发修改异常。
* 这是个什么异常,怎么产生的,怎么解决的?
* 怎么产生:
* 当我们通过迭代器迭代元素的过程中,又通过集合去添加了元素。这种情况是不允许的。
* 因为迭代器是依赖于集合存在的,如果集合发生改变,迭代器也应该相应的发生改变。
* 而我们目前看到的确实,迭代器没变,集合变了。所以,报出了一个并发修改异常。
*
* 注意问题:通过迭代器遍历集合的时候,是不能通过集合去操作(添加,删除)。
* 那么,我们可不可以这样理解呢?
* A:全部通过迭代器操作:元素是添加到刚遍历的那个元素后面。
* 通过迭代器迭代的时候,可以通过迭代器对集合进行操作。
* B:全部通过集合操作:元素是添加到最后的。
* 通过集合普通for遍历的时候,可以通过集合去操作。
*/
public class ListDemo4 {
public static void main(String[] args) {
// 创建集合对象
List list = new ArrayList();
// 添加元素
list.add("hello");
list.add("world");
list.add("java");
// 迭代器
// Iterator it = list.iterator();
// while (it.hasNext()) {
// String s = (String) it.next();
// System.out.println(s);
// }
// System.out.println("-----------");
// 需求:请遍历集合,判断其中是否有"hello"这个元素,如果有,就再添加一个元素:"IOS"
// Iterator it = list.iterator();
// while (it.hasNext()) {
// String s = (String) it.next();
// if ("hello".equals(s)) {
// list.add("IOS");
// // it = list.iterator();//这样从原理是可以解决的,但是它会引起另外一个问题。
// }
// }
// System.out.println("list:" + list);
// System.out.println("-----------");
// 完全通过集合实现
// for (int x = 0; x < list.size(); x++) {
// String s = (String) list.get(x);
// if ("hello".equals(s)) {
// list.add("IOS");
// }
// }
// System.out.println("list:"+list);
// System.out.println("-----------");
// 遍历
ListIterator lit = list.listIterator();
while (lit.hasNext()) {
String s = (String) lit.next();
if ("hello".equals(s)) {
lit.add("IOS");
}
}
System.out.println("list:" + list);
}
}
5)List:
|--ArrayList:底层数据结构是数组,线程不安全(即不同步),它的出现替代了Vector,增删的效率很慢,但是查询的效率很高。
|--Vector:底层数据结构是数组,线程安全,无论增删还是查询都非常慢。
|--LinkedList:底层是链表,线程不安全,对元素的增删的操作效率很高,查询效率低。
ArrayList的小练习:
需求:我现在用ArrayList存储多个字符串元素。
比如说数据如下:hello,world,java,hello,.net,java,php,IOS,java,android
我要求你写程序,实现去除重复元素。也就是说结果是:hello,world,java,.net,php,IOS,android
import java.util.ArrayList;
import java.util.Iterator;
/*
* 需求:我现在用ArrayList存储多个字符串元素。
* 比如说数据如下:
* hello,world,java,hello,.net,java,php,IOS,java,android
* 我要求你写程序,实现去除重复元素。
* 也就是说结果是:
* hello,world,java,.net,php,IOS,android
*
* 思路:
* A:创建一个新的集合。
* B:在同一个集合上操作。
*/
public class ArrayListTest {
public static void main(String[] args) {
//创建旧集合,并添加元素
ArrayList array = new ArrayList();
array.add("hello");
array.add("world");
array.add("java");
array.add("hello");
array.add(".net");
array.add("java");
array.add("java");
array.add("java");
array.add("php");
array.add("IOS");
array.add("java");
array.add("android");
//创建新集合
ArrayList array2 = new ArrayList();
//遍历旧集合,获取到每一个元素
Iterator it = array.iterator();
while(it.hasNext()){
String s = (String)it.next();
//在新集合中判断,看是否存在这个元素
if(!array2.contains(s)){
//如果s不再array2中存在,就添加
array2.add(s);
}
}
//array2就是没有重复元素的集合。
//遍历array2
for(int x=0; x<array2.size(); x++){
String s = (String) array2.get(x);
System.out.println(s);
}
}
}
方法二:/*
* 在同一个集合上操作:双层循环实现
* 第一方式没有问题,第二种可能有问题。
* 但是,第二种的问题也是可以解决的?
* 怎么解决呢?
* 把每次删除掉元素的那个位置,在回来比较一次即可。
*/
public class ArrayListTest2 {
public static void main(String[] args) {
// 创建旧集合,并添加元素
ArrayList array = new ArrayList();
array.add("hello");
array.add("world");
array.add("java");
array.add("hello");
array.add(".net");
array.add("java");
array.add("java");
array.add("java");
array.add("php");
array.add("IOS");
array.add("java");
array.add("android");
// 这下面的代码和选择排序类似。理解即可。最好通过断点看过程。
for (int x = 0; x < array.size() - 1; x++) {
for (int y = x + 1; y < array.size(); y++) {
if (array.get(y).equals(array.get(x))) {
array.remove(y);
y--;
}
}
}
// 遍历
Iterator it = array.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}
}
}
下面是一个面试题:用ArrayList存储学生,如何去除重复的元素?
import java.util.ArrayList;
import java.util.Iterator;
/*
* ArrayList如果存储的是学生,那么,怎么去除重复元素呢?
* 问题:如何知道学生是重复的。
* 需求:如果学生的姓名和年龄相同,我就认为是同一个学生。即重复值。
*
* 通过简单分析,我们估计是判断那里出问题了。
* 怎么办呢?
* 看判断的方法。
* 而我们又知道,判断的方法是API提供的。不是自己的写的。
* 看源码,看底层到底怎么实现的。
* 通过看源码,我们发现,底层依赖的是equals()。
* 由于学生类中,我们并没有equals()方法,所以,默认用的是Object的方法。
* 而Object类的方法,默认比较的是地址值。
* 由于学生对象都是new出来的,地址值肯定不一样,所以从这个角度考虑结论是正确的。
* 但是不符合我们的需求。
* 肿么办?
* 重写equals(),让他按照我们的需要来比较。
*/
//标准学生类
public class Student {
//定义两个成员变量
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//重写equals方法
@Override
public boolean equals(Object obj) {
// 提高效率
if (this == obj) {
return true;
}
// 提高健壮性
if (!(obj instanceof Student)) {
return false;
}
// 向下转换
Student s = (Student) obj;
return this.name.equals(s.name) && this.age == s.age;
}
}
public class ArrayListTest3 {
public static void main(String[] args) {
ArrayList array = new ArrayList();
Student s1 = new Student("301宿舍--笨笨", 22);
Student s2 = new Student("301宿舍--姗姗", 23);
Student s3 = new Student("301宿舍--姗姗", 30);
Student s4 = new Student("301宿舍--红红", 20);
Student s5 = new Student("301宿舍--红红", 20);
Student s6 = new Student("301宿舍--蛋蛋", 24);
Student s7 = new Student("301宿舍--媛媛", 22);
Student s8 = new Student("301宿舍--歪歪", 23);
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);
array.add(s5);
array.add(s6);
// 创建新集合
ArrayList array2 = new ArrayList();
// 遍历旧集合,获取到每一个元素
Iterator it = array.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
// 在新集合中判断,看是否存在这个元素
if (!array2.contains(s)) {
// 如果s不再array2中存在,就添加
array2.add(s);
}
}
// array2就是没有重复元素的集合。
// 遍历array2
for (int x = 0; x < array2.size(); x++) {
Student s = (Student) array2.get(x);
System.out.println(s.getName() + "***" + s.getAge());
}
}
}
运行结果:
LinkedList的特有功能:
A:添加功能
void addFirst(Object e)
void addLast(Object e)
B:获取功能
Object getFirst()
Object getLast()
C:删除功能
Object removeFirst()
Object removeLast()
面试题:通过LinkedList 模拟栈数据结构。
/*
* 面试题:通过LinkedList模拟栈数据结构
* 要模拟的内容的特点:
* 先进后出。
*
* 通过LinkedList模拟栈数据结构:
* 它的意思是说,你有一个LinkedList可以用,但是,你需要自己定义一个栈集合。
* 对外提供获取和添加功能。
*
* 自定义栈集合。
*/
public class MyStack {
<span style="white-space:pre"> </span>private LinkedList link;
<span style="white-space:pre"> </span>public MyStack() {
<span style="white-space:pre"> </span>link = new LinkedList();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>public void add(Object obj) {
<span style="white-space:pre"> </span>link.addFirst(obj);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>public Object get(int index) {
<span style="white-space:pre"> </span>return link.get(index);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>public int size() {
<span style="white-space:pre"> </span>return link.size();
<span style="white-space:pre"> </span>}
}
public class LinkedListTest {
public static void main(String[] args) {
// 创建集合对象
MyStack ms = new MyStack();
// 创建并添加元素
ms.add("hello");
ms.add("world");
ms.add("java");
// 获取
// System.out.println(ms.get(0));
// System.out.println(ms.get(1));
// System.out.println(ms.get(2));
// System.out.println(ms.get(3));
for (int x = 0; x < ms.size(); x++) {
String s = (String) ms.get(x);
System.out.println(s);
}
}
}
第五讲 泛型
1)泛型:广泛的类型(直译)。是一种特殊的类型,它把指定类型的工作推迟代码声明并实例化类或方法的时候进行。
个人理解:泛型是一种把明确类型的工作放在了创建对象或者调用方法时候才去明确的特殊的类型。
2)泛型的表现形式:<数据类型>
3)好处:
A:解决了黄色警告线问题。
B:把运行期间的转换异常:ClassCastException 给提前到了编译期间。
C:优化了程序设计,避免了强制转换的麻烦。
4)泛型的前世今生
A:泛型类 B:泛型方法 C:泛型接口
5)泛型的使用: 看API中的类或者接口,其后是否跟有<>,如果有,就是泛型的应用。一般在集合中用。
附加:
泛型类:就是把泛型定义在类上。
泛型方法:把泛型定义在方法上。它是能够在调用方法的时候,才去明确类型。
泛型接口:把泛型定义在接口上。好处:在写实现类的时候,我已经知道接口上应该是什么类型了。
用集合存储字符串并遍历。标准代码:
/*
* 标准代码:
* 用泛型改进。
* 用集合存储字符串并遍历。
*/
public class ArrayListDemo2 {
public static void main(String[] args) {
// JDK7以后,new后面的集合的泛型指定可以只写<>,不写类型即可。
// 但是,建议永远加上。
ArrayList<String> array = new ArrayList<String>();
array.add("hello");
array.add("world");
array.add("java");
Iterator<String> it = array.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
System.out.println("----------------");
for (int x = 0; x < array.size(); x++) {
String s = array.get(x);
System.out.println(s);
}
}
}
第六讲 增强for
for(数组或者Collection集合中元素类型 变量名 : 数组或者Collection集合对象)
{
执行语句;(使用变量名即可)
}
作用:简化数组和Collection集合的变量。
注意:增强for是用来替代迭代器的。不能再用增强for的时候,用集合对象对集合进行改变。
public class ForDemo {
public static void main(String[] args) {
// 整型数组
int[] arr = { 1, 2, 3, 4, 5 };
// 普通for
for (int x = 0; x < arr.length; x++) {
System.out.println(arr[x]);
}
System.out.println("--------------");
// 增强for
for (int x : arr) {
System.out.println(x);
}
System.out.println("--------------");
// 字符串数组
String[] strArray = { "hello", "world", "java" };
// 增强for
for (String str : strArray) {
System.out.println(str);
}
System.out.println("--------------");
// 集合
ArrayList<String> array = new ArrayList<String>();
array.add("hello");
array.add("world");
array.add("java");
for (String str : array) {
System.out.println(str);
}
System.out.println("--------------");
// 增强for和迭代器我们一般只选一种。
// 增强for是来替代迭代器的。
// ArrayList<String> array2 = new ArrayList<String>();
// array2.add("hello");
// array2.add("world");
// array2.add("java");
// ConcurrentModificationException
ArrayList<String> array2 = null;
// NullPointerException
for (String str : array2) {
if (str.equals("world")) {
array2.add("EE");
}
}
}
}