1. List集合简单使用
//学习Collection子类List的一些特有方法的使用
//1.创建,还是采用父类引用指向子类对象,开发中一般直接用子类
List lt = new ArrayList();
//2. void add(int index, E element):在指定位置添加元素
lt.add("a");
lt.add("b");
lt.add("d");
//在指定位置添加元素
lt.add(2,"c");//index可以小于等于size()并且大于等于0;
System.out.println(lt);
//3. E remove(int index):移除指定位置的元素,返回被删除的那个元素
lt.remove(2);
System.out.println(lt);
//这里我们举个例子有问题的情况
List lt1 = new ArrayList();
lt1.add(11);
lt1.add(23);
lt1.add(45);//我们将这几个整数加入到集合中
//来用哈删除方法
//Object ob3 = lt1.remove(11);//这样写运行就会报错,我们的本意
//也许就是想删除我们加入到集合中的11元素,但是在加入集合时,有自动装箱
//而在这里传值进来却没有自动装箱,所以系统会将这个11当成索引使用,那么就会越界报错
//4. E get(int index):获取指定位置的元素
Object ob = lt.get(2);//这个方法可以用来做遍历,这是List集合中特有的遍历方式
System.out.println(ob);
//5. E set(int index, E element):给集合中指定位置的元素赋值,并返回改变之前这个位置的元素值
Object ob1 = lt.set(2,"jj");
System.out.println(ob1);
System.out.println(lt);
2. 并发修改异常产生的原因和处理
//1.需求:我有一个集合,请问我想判断里面有没有"world"元素,有就向集合里面添加一个"javaEE"元素
List lt = new ArrayList();
lt.add("a");
lt.add("b");
lt.add("d");
lt.add("world");
lt.add("f");
//迭代器遍历
//Iterator it = lt.iterator();
//用专门操作List集合的迭代器
ListIterator lir = lt.listIterator();
while (lir.hasNext()){
//用String来记录这个it.next()
String str = (String)lir.next();
//判断是否有world元素
if (str.equals("world")){
//有,就向集合中添加一个元素
// lt.add("javaEE");
//出错原因解释:我们的集合中原来就5个元素,拿给迭代器去负责展示,但是
//在迭代器展示元素的过程中,我们又去给集合增加了一个元素,这样就造成了并发修改
lir.add("javaEE");
}
}
System.out.println(lt);
//错误显示:java.util.ConcurrentModificationException:并发修改异常:当方法检测到对象的并发修改,
//但不允许这种修改时,抛出此异常
//解决问题:我们可以利用迭代器自己有的方法来帮助我们修改集合中的元素
3. 简单学习ListIterator(了解反向遍历)
//ListIterator简单操作
List lt = new ArrayList();
lt.add("a");
lt.add("b");
lt.add("d");
lt.add("world");
lt.add("f");
//用专门操作List集合的迭代器
ListIterator lir = lt.listIterator();
while (lir.hasNext()){
System.out.println(lir.next());//获取元素,并将指针向后移动
}
System.out.println("-------------------");
while (lir.hasPrevious()){//判断是否有前一个
System.out.println(lir.previous());//获取元素,并将指针向前移动--相当于反向遍历
}
//会出现的问题:如果我们把正向遍历的代码注释掉的话,会发现调用反向遍历的代码也没有作用。
//这是因为没有正向遍历的话,集合指针是指向0这个索引的,我们来向前遍历的话,就会到-1,那就没有元素,所以直接没有返回了
4. 数组和链表
1.数组:查询快,修改快,但是增和删操作慢(ArrayList)
2.链表:查询,修改满, 增删快(LinkedList)
3.List的三个子类的特点:
ArrayList:
底层数据结构是数组,查询快,增删慢
线程不安全,效率高
Vector:
底层数据结构是数组,查询快,增删慢
线程安全,效率低
Vector相对ArrayList查询慢(线程安全)
Vector相对LinkedList增删慢(数据结构)
LinkedList:
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
Vector和ArrayList的区别:
Vector是线程安全的,效率低
ArrayList是线程不安全的,效率高
ArrayList和LinkedList的区别:
ArrayList底层数据结构,查询和修改快
LinkedList底层是链表结构的,增和删比较快,查询和修改比较慢
//我们如何使用List的三个子类呢?
查询多用:ArrayList
增删多用:LinkedList
都多用:ArrayList
5. 去除ArrayList中的重复元素
//去除ArrayList中的重复元素的方式
//思路:创建新集合的方式
ArrayList lt = new ArrayList();
lt.add("a");
lt.add("b");
lt.add("j");
lt.add("world");
lt.add("f");
lt.add("b");
lt.add("b");
lt.add("j");
lt.add("j");
lt.add("world");
ArrayList newList = getSingleArr(lt);
System.out.println(newList);
}
//单独抽取一个方法
public static ArrayList getSingleArr(ArrayList arrl){
//创建一个新集合
ArrayList newList = new ArrayList();
//获取老集合的迭代器
Iterator it = arrl.iterator();
//遍历这个老集合
while (it.hasNext()){
Object ob = it.next();
if (!newList.contains(ob)){
newList.add(ob);
}
}
return newList;
}
6. 对于自定义对象在ArrayList中的去重
首先定义一个自定义类
public class Student {
//两个私有成员变量
private String name;
private int age;
//空参构造
public Student() {
super();
}
//有参构造
public Student(String name, int age) {
super();
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;
}
//重写toString方法
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public boolean equals(Object obj){
//比较字面值,不比较地址
Student s = (Student)obj;
if (this.name.equals(s.name) && this.age == s.age){
return true;
}else{
return false;
}
}
}
//在实现中:
public static void main (String[] args){
//去除ArrayList中自定义重复对象
ArrayList lt = new ArrayList();
lt.add(new Student("tmac",18));
lt.add(new Student("tmac",18));
lt.add(new Student("kobe",18));
lt.add(new Student("tmac",18));
lt.add(new Student("kobe",18));
lt.add(new Student("tmac",18));
ArrayList newList = getSingleArr(lt);
Iterator it = newList.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//我们传入的是自定义对象,但是同样执行我们去除重复元素的方法,打印发现并没有去除掉
//我们仔细分析,没有去除掉应该是!newList.contains(ob)这个判断都是真。造成这个的原因是
//我们看底层contains的实现,发现是用equals方法作比较的,而equals方法比较的是对象的地址值
//而我们上面创建的对象,地址值都不一样,所以无法去除,解决办法就是重写Student对象的equals方法
//顺带做到这里了,我们也来举个列子,我们先将Student中的重写equals方法注释掉
//我们来删除这个newList中的对象
newList.remove(new Student("tmac",18));
System.out.println("****");
System.out.println(newList);
//你会发现这样也删不掉,那是因为remove的方法,底层一样依赖的是equals方法
}
//单独抽取一个方法
public static ArrayList getSingleArr(ArrayList arrl){
//创建一个新集合
ArrayList newList = new ArrayList();
//获取老集合的迭代器
Iterator it = arrl.iterator();
//遍历这个老集合
while (it.hasNext()){
Object ob = it.next();
if (!newList.contains(ob)){
newList.add(ob);
}
}
return newList;
}
}
7. LinkedList的特有功能
//LinkedList的特有功能
/*
* public void addFirst(E e)及addLast(E e)
* public E getFirst()及getLast()
* public E removeFirst()及public E removeLast()
* public E get(int index):
* */
//1.public void addFirst(E e)及addLast(E e):
LinkedList list = new LinkedList();
list.addFirst("a");
list.addFirst("b");
list.addFirst("c");
list.addFirst("d");
//我们看这个我们每个元素都是放到第一位的,对于链表来说,就成了先进在后了
System.out.println(list);
list.addLast("e");
list.addLast("f");//addLast:就是先进在前了
System.out.println(list);
//2. public E getFirst()及getLast()
Object ob = list.getFirst();
Object ob1 = list.getLast();
System.out.println(ob);
System.out.println(ob1);
//3. public E removeFirst()及public E removeLast():删除头尾
//4. public E get(int index):根据索引查找元素
Object ob2 = list.get(2);
//我们看这个get(int index):的源码,就知道为什么这个链表的查找更慢了
System.out.println(ob2);
8. 栈和队列数据结构
栈: 先进后出
队列: 先进先出
LinkedList模拟栈的数据结构:
单独封装一个Stack(栈类):
public class Stack {
//我们自己创建一个栈类,然后内部用LinkedList来实现进栈和弹栈
//创建LinkedList的成员变量
private LinkedList list = new LinkedList();
//模拟进栈方法
public void inStack(Object obj){
list.addLast(obj);
}
//模拟出栈
public Object outStack(){
return list.removeLast();
}
//模拟栈结构是否为空
public boolean isEmpty(){
return list.isEmpty();
}
//重写Object的toString方法
public String toString(){
String str = new String();
Iterator it = list.iterator();
while (it.hasNext()){
Object ob = it.next();
str = str + ob + ",";
}
return str;
}
}
//使用:
//直接调用我们封装的Stack类
Stack s = new Stack();
s.inStack("a”);//这里最先加进去的元素其实是a,因为最先调用这个加入a元素的方法
s.inStack("b");
s.inStack("c”);//理解一下先进后出
System.out.println(s);
while (!s.isEmpty()){
System.out.println(s.outStack());
}
9. 泛型简介
//泛型
/*
* 泛型好处:
* 提高安全性(将运行期的错误转换到编译器)
* 免去强转的麻烦
* 泛型基本作用:
* <>号中放的必须是引用数据类型
* 泛型使用注意事项:
* 前后的泛型必须一致,或者后面的泛型可以省略不写(1.7版本的新特性)
* */
//泛型举例说明:
ArrayList<Student> list = new ArrayList<Student>();
// list.add(110);
// list.add(true);
list.add(new Student("tmac",18));
list.add(new Student("李四",24));
//我们给集合添加了三个不同类型的值,我们来遍历一下
Iterator<Student> it = list.iterator();
while (it.hasNext()){
//System.out.println(it.next());
//我们这样直接遍历是没有问题的,但是如果我们想要获得Student对象中的名字,年龄,
//就要单独调用Student中的getName和getAge方法,如果我们直接将it.next()获得的元素
//直接强转为Student对象,就会出错
// Student s = (Student)it.next();
//System.out.println(s.getName() + " " + s.getAge());
//报错:java.lang.ClassCastException:类型转换异常
//解决加泛型--其实和iOS里面的泛型是一个道理哈
Student s= it.next();
//最好不要直接打印it.next(),因为it.next()方法只能调用一次,调用多次会将指针向后移动
System.out.println(s.getName() + " 、、 " + s.getAge());
}
10.方法泛型的区别
//泛型
//普通方法
Tool tool = new Tool();
tool.show("我爱你");
//静态方法
Tool.print("我是谁”);
public class Tool<T> {
private T t;
public T getObj(){
return t;
}
public void setObj(T t){
this.t = t;
}
public void show(T t){
System.out.println(t);//方法泛型最好和类的泛型一致
//如果不一致,需要在方法前声明该泛型
}
//对于T而言,在创建Tool的对象,给其赋值的时候,是什么类型的,T就是什么类型的
//对于静态方法--必须要声明自己的泛型
//这是因为,T是跟随Tool对象时,创建而创建,而静态方法是跟随Tool类的创建而创建的
//如果我们将静态方法的泛型和类的泛型相同的话,很可能Tool对象还没有创建,而Tool创建了
//这样我们静态方法的泛型就会出问题
public static<X> void print(X x){
System.out.println(x);
}
//这个一致,不是说命名相同,如果我只是在静态方法的方法名后接泛型名和类相同,是不行的
//但是这样写是可以的:public static<T> void print(T t){}是可以的
网友评论