知识点总结第五篇
1.泛型类就是带有参数类型的类,其类中也有属性和方法 数据类型可以实已有的类型,也可以是"类型参数"的类型。
2.泛型的好处
1.强制类型检查,在编译的时候就能得到类型错误的消息
2.避免显是强制转换
3.方便实现通用算法
3.泛型的使用规则
1.泛型的类型参数只能是类类型,而不能是简单类型eg可以使用Interger但是不能用int
2.泛型的类型参数可以有多个,比如public class Pair<T,V>{……}
3.静态字段的类型可以有很多个,如public class Box<T> {private static T object}
4.不能直接创建类型参数变量的数组,只能通过反射创建
5.泛型的参数类型还可以使用extends
和super
关键词,eg:<T extends superclass>
6.泛型的参数类型还可以是通配符类型
4.泛型还能解决类型参数不固定的问题eg:
static <T> void print(T...k) {
for(int i = 0;i <k.length; ++i) {
System.out.println(k[i]);
}
}
5.List集合常用的类有ArrayList、LinkedList、Vector和Stack
List常用的方法:
1.boolean add(E e)
将元素加到链表的末尾
2.void add(int index,E e)
将元素加到指定的位置,其他元素往后移
3.boolean equls(Object o)
比较对象o是否与列表中的元素是同一元素
4.void set(int index,E e)
将e代替链表的位置的元素
5.int indexOf(object o)
获得元素o在列表中第一次出现的位置,不存在则返回-1
6.Iterator<E> iterator()
获得列表的迭代器
7.E remove(int index)
删除列表中第index位置的元素
8.int size()
获得列表中元素的个数
6.ArrayList是线程不安全的,Vector是线程安全的,但是两者的实现原理都一样都是动态数组,而LinkedList采用的是双链表实现数据存储
7.Set集合能解决元素重复的问题,并且TreeSet能自动排序
Treeset常用的方法
1.E first()
返回集合的第一个元素
2.E last()
返回集合的第二个元素
3.void add()
往集合里添加元素
4.void addAll(Collection c)
得到两个集合的并集,结果保存在当前集合里面
4.void retainAll(Collection c)
得到两个集合的交集,结果保存在当前集合里面
4.void removeAll(Collection c)
得到两个集合的差集,结果保存在当前集合里面
8.Map集合通过键值存储信息,能在O(1)的时间内返回对应的信息
Map常用的方法
1.void clear()
删除集合中的所有元素
2.boolean containKey()
查询集合中是否有key的键
3.V get(Object key)
返回该键上对应的值
4.boolean isEmpty()
查询集合是否为空
5.V put(K key , V value)
添加一个键值,如果已经有那么将对应的键值改为当前添加的键值
6.V remove(Object key)
删除该键对应的键值对
7.int size()
返回集合中键值对应的个数
9.HashMap采用的是哈希表实现Map的,而TreeMap则是采用的红黑树实现的。
10.当我们想遍历集合的时候,可以使用迭代器Iterator进行遍历,并且也可以通过迭代器删除当前迭代器指向的位置的元素.remove()
11.线程是进程的一个执行单元,进程至少有一个线程
12.线程是处理器调度的基本单位,但进程不是
13.要实现自己的线程我们可以通过继承Thread类,或者实现Runnable接口,其实Thread类本身就是实现了Runnable接口的,只不过继承Thread要写构造方法,但是注意两者都需要重写run方法
eg:
class myThread extends Thread{
public myThread(String name) {
super(name);
}
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 运行" + i);
}
}
}
class myThread extends Thread{
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 运行" + i);
}
}
}
14.用Callable和FutureTask定义线程也可以只不过线程体call()要返回值(感觉不会考,所以不讲解了)
15.线程的状态
1.新建状态
2.就绪状态
3.运行状态
4.阻塞状态
5.死亡状态
16.关于线程的跳读,线程有十个优先级,通过.getPriority()
可以获取线程的优先级,通过.setPriority()
可以设置线程的优先级,线程默认的优先级是5
17.注意的是,优先级高的线程将优先的到且比优先级第的线程得到更多的CPU执行时间,但并不是优先级高的线程会抢占优先级低的线程,抢占的意义在于获得更多的时间而不是独占
18.线程让步表示的是先让当前的线程从运行状态转到可运行状态,而不是阻塞状态,一般通过.yield()
方法实现线程让步
19.线程联合表示的是线程与线程之间可能在执行顺序上会有关联,我们可以通过.join()
的方法实现线程联合
20.线程分为用户线程和守护线程,守护线程是为了用户线程服务的,通过.setDaemon(true)
的方法可以设置一个守护线程,当然记得该方法的调用必须在.start()
方法之前调用
eg:
Thread t = new Thread(new deThread(),"后台线程");
t.serDaemon(true);
t.start();
21.当所有的用户线程停止之后,后台线程也会停止
22.线程中断可以使用.interrupt()
方法但是interrupt方法本身不能终止程序的执行,需要借助异常机制,比如join()方法、sleep()方法、wait()方法抛出异常InterruptedException,借此达到中断的目的
23.线程同步和锁机制
(长话短说)通过synchronized修饰方法或者代码块(主要是方法)即可实现同步锁机制,通过synchronized修饰的方法可以保证在某个线程访问期间,其他线程不可访问,从而保证数据的准确性
synchronized public void run () {//通过synchronized修饰的线程同步的run方法
while (true) {
loc.lock();
try {
if (cnt > 0) {
System.out.println(Thread.currentThread().getName() + " 抢到了票" + cnt--);
}
else
return;
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
23.volatile关键字多用于多线程的同步变量
eg:
private volatile int i;//表面声明了一个私有的线程同步的整数形的i
24.线程死锁
两个线程被堵塞,并且双方都在等待另一个线程
线程死锁的条件:
1.线程使用的资源必须至少是一个不能共享的
2.至少有一个线程必须持有一个资源并且正在等待获取一个当前被其他线程占有的资源
3.分配资源不能从相应的线程中被强制剥夺
4.第一个线程等待其他的线程,后一个线程等待第一个线程
25.每个对象只有一个锁,当同步的时候应该清楚在哪个对象上同步
26.如果线程拥有同步方法和非同步方法,则非同步方法可以被多个线程访问,且不受锁的限制
27.线程睡眠的时候,它所持有的任何锁都不会释放
28.使用start()方法可以使一个线程成为可运行的,但是它不一定立即开始运行
29.线程是一个程序的单个执行流,而多线程是指一个程序的多个执行流,线程是程序的一部分,而不是程序本身
30.等待阻塞状态下的线程被notify()唤醒不能使线程从等待阻塞状态进入对象阻塞状态
31.wait()方法可以使线程从运行状态进入其他阻塞状态
32.新建的线程调用start()方法不一定立即进入运行状态,可能会被堵塞