复习集合
1. 迭代器
迭代器:接口
接口:定义标准
为什么迭代器使用接口?
通过迭代器接口,可以定义多个不同类型的迭代器,每个迭代器可以根据不同的数据结构进行实现(要迭代的数据结构不同),这样就可以在不同情况下使用不同类型的迭代器,而无需修改迭代器的代码。
default void remove() { throw new UnsupportedOperationException("remove");}
迭代器底层实现中的
remove()方法被设置为抛出UnsupportedOperationException异常的原因是为了保持迭代器的一致性和安全性。迭代器的主要目的是提供一种遍历集合元素的方式,并且允许在遍历过程中删除元素。然而,并非所有的集合都支持在遍历过程中进行元素的删除操作,因为删除操作可能会导致迭代器的状态不一致。
为了解决这个问题,Java的迭代器接口中提供了
remove()方法,该方法用于从底层集合中删除迭代器最后访问的元素。但是,并不是所有的集合都实现了remove()方法。如果集合不支持删除操作,调用remove()方法可能会导致不一致的状态。为了避免这种情况,迭代器接口的默认实现中将remove()方法设置为抛出UnsupportedOperationException异常。这样做的好处是,当使用不支持删除操作的迭代器时,如果尝试调用
remove()方法,会立即抛出异常,提醒开发者该集合不支持删除操作,避免产生不一致的状态。需要注意的是,如果需要在迭代过程中删除元素,应该确保使用的是支持删除操作的迭代器,如
ArrayList的迭代器,而不是不支持删除操作的迭代器,如Collections.unmodifiableList()返回的迭代器。默认方法:实现类去重写
2.迭代器底层
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
//外部操作数:记录添加数据、删除数据的次数(记录元素个数变化的次数)
protected transient int modCount = 0;//4
}public class ArrayList<E> extends AbstractList<E> implements List<E>{
//数据容器
transient Object[] elementData;//["aaa","bbb","ccc","ddd",null,null,...]
//元素个数/指针
private int size;//4
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
int cursor; // 游标 - 4
int lastRet = -1; // 遍历当前元素的下标 - 3
int expectedModCount = modCount;//内部操作数 - 4
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();//判断内外操作数是否一致,不一致就报错
//i = 3
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
//获取外部对象中的容器
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
//迭代器内部还是使用ArrayList的remove方法去做删除
ArrayList.this.remove(lastRet);
//把当前的元素下标赋值给游标
cursor = lastRet;
lastRet = -1;
//重新将外部操作数赋值给内部操作数,保证了内外部操作数是一致的
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
//外部操作数不等于内部操作数就报错
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
}找场景:
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
Iterator<String> it = list.iterator();
while(it.hasNext()){
String element = it.next();
System.out.println(element);
}线程
1. 线程的创建
进程 与 进程 的关系:独享内存空间和系统资源
线程 与 进程 的关系:有一个进程中至少包含一个线程
线程 与 线程 的关系:在同一个进程里,多个线程共享内存空间和系统资源
一个进程中包含多个线程,只有一个主线程
经典面试题:请问当我们编写一个单纯的main方法时,此时该程序是否为单线程的?为什么?
垃圾回收器是一个后台线程
1.线程类
创建MyThread类,继承Thread,重写run方法
//创建MyThread类
package com.wz.thread01;
//线程类
public class MyThread extends Thread{
//线程是进程中的一条执行路径(功能),线程里的功能就写在run方法中
//当前线程对象抢到CPU资源后才会调用run方法
@Override
public void run() {
System.out.println("MyThread的run方法被调用了");
}
}package com.wz.thread01;
public class Test01 {
/**
* 知识点:创建线程 -- 线程类
* 步骤:
* 1.创建线程类(MyThread),继承Thread
* 2.重写run方法
* 3.在测试类中创建线程类的对象 -- MyThread t = new MyThread();
* 4.启动子线程 -- t.start();
*/
public static void main(String[] args) {
//子线程的对象
MyThread t = new MyThread();
//启动子线程
t.start();
}
}2.任务类
创建Task类,实现Runnable接口中的run方法
package com.wz.thread02;
public class Task implements Runnable{
//当前线程抢到CPU资源后,才会调用任务类对象中的run方法
@Override
public void run() {
System.out.println("Task的run方法被调用");
}
}package com.wz.thread02;
public class test01 {
/**
* 知识点:创建线程 -- 任务类
*
* 步骤:
* 1.创建任务类(Task),实现Runnable
* 2.重写run方法
* 3.创建任务类对象 - Task task = new Task();
* 4.创建子线程对象,并将任务类对象传入到子线程中 - Thread t = new Thread(task);
* 5.启动子线程
*/
public static void main(String[] args) {
//任务对象
Task task = new Task();
//创建子线程对象
Thread t = new Thread(task);
t.start();
}
}3.带返回值的任务类
4.线程池
2. 感受线程之间资源争抢
需求:编写一个多线程的应用程序,主线程打印1-100之间的数字,子线程打印200-300之间的数字,观察其输出的结果,体会多线程互相争抢资源的场景
package com.wz.thread03;
public class test01 {
/**
* 需求:编写一个多线程的应用程序
* 主线程打印1-100之间的数字,子线程打印200-300之间的数字
* 观察其输出的结果,体会多线程互相争抢资源的场景
* @param args
*/
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
//主线程
for (int i = 1; i <= 100; i++) {
System.out.println("主线程--"+i);
}
}
}package com.wz.thread03;
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 200; i <= 300 ; i++) {
System.out.println("子线程--"+i);
}
}
}3. 线程的优先级别,setPriority
需求:在主线程中创3个子线程,并且设置不同优先级,观察其优先级对线程执行结果的”影响”。
package com.wz.thread04;
public class A extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("A线程---"+i);
}
}
}
package com.wz.thread04;
public class B extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("B线程---"+i);
}
}
}
package com.wz.thread04;
public class C extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("C线程---"+i);
}
}
}package com.wz.thread04;
public class test01 {
/**
* 知识点:线程的优先级别
*
* 需求:在主线程中创3个子线程,并且设置不同优先级,观察其优先级对线程执行结果的”影响”。
*/
public static void main(String[] args) {
//创建线程对象
A a = new A();
B b = new B();
C c = new C();
//设置线程的优先级别
a.setPriority(Thread.MAX_PRIORITY);
b.setPriority(Thread.NORM_PRIORITY);
c.setPriority(Thread.MIN_PRIORITY);
//启动子线程
a.start();
b.start();
c.start();
}
}线程的优先级别:1~10,数字越大,优先级别越高* 理解:优先级别越高,抢到资源的概率越大,但是结果不是绝对的,只是影响而已
4. 代码优化(给线程取名字)
- 自己写getThreadName/setThreadName
- 调用父类的一个参数的构造方法和getName
- Thread.currentThread().getName()
package com.wz.thread05;
public class MyThread extends Thread{
private String threadName;
public MyThread(String threadName) {
this.threadName = threadName;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(threadName+"----"+i);
}
}
}package com.wz.thread05;
public class test01 {
public static void main(String[] args) {
MyThread a = new MyThread("A");
MyThread b = new MyThread("B");
MyThread c = new MyThread("C");
//设置线程优先级别
a.setPriority(Thread.MAX_PRIORITY);
b.setPriority(Thread.NORM_PRIORITY);
c.setPriority(Thread.MIN_PRIORITY);
//启动线程
a.start();
b.start();
c.start();
}
}package com.qf.thread06;
public class MyThread extends Thread{
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
//获取当前线程对象
Thread currentThread = Thread.currentThread();
//获取当前线程对象的名字
String n = currentThread.getName();
System.out.println(n + ":" + i);
}
}
}
文章详细介绍了Java中迭代器的概念,包括为什么使用接口、默认方法`remove()`的异常处理以及ArrayList的迭代器实现。同时,文章还阐述了线程的创建,通过线程类和实现Runnable接口的方式,展示了线程间资源争抢的场景和线程优先级别的设定及其影响。

被折叠的 条评论
为什么被折叠?



