1、Java集合类简介:
集合大致分为Set、List、Queue、Map四种
Set:无序、不可重复的集合
List:有序、可重复集合
Map:映射关系的集合
Queue:队列集合
1、数组:保存定长的数据,集合可以保存数量不确定的数据,数组元素可以是基本类型的值也可以是对象,集合只能保存对象。
2、Java集合主要有两个接口Collection和Map派生出。
3、Collection是Set、Queue、List的父接口
4、Map的子类:SortedMap、WeakHashMap、EnumMap、HashMap、HashTable
5、Iterator接口经常被称作迭代器,它是Collection接口的父接口,它包含hasNext()如果仍有元素,则返回true
next()返回迭代的下一个元素。比如:
public class IteratorExample{
public static void main(String[ ] args ){
List<MyObject> list =new ArrayList<>();
for ( int i=0; i<10; i++){
list.add(new MyObject(i));
}
System.out.println(list.toString());
Iterator<MyObject> iterator =list.iterator();
while(iterator.hasNext()){
MyObject next = iterator.next();
next.num = 99;
}
System.out.println(list.toString());
}
static class MyObject{
int num;
MyObject(int num){
this.num=num;
}
@override
public String toString(){
return String.valueOf(num);
}
}
}
6、Collection接口的三个子接口:Set 、List、Queue
Set集合与Collection集合基本相同,不同点Set不允许包含重复元素,比如通过add()方法添加重复元素,会返回false
List集合:有序、可重复,它里边每个元素都有对应索引
Java8中为List接口添加两个默认方法:
void replaceAll(UnaryOperator operator)
void sort( Comparator c) : 根据Comparator参数对List集合的元素排序。
Queue:队列,先进先出 FIFO,队列的头部元素在队列中存放时间最长的元素,队列的尾部存放时间最短的元素,新元素插入(offer)到队列的尾部,访问元素(poll)操作会返回队列头部的元素,通常,不允许随机访问队列中的元素。
队列的基本方法如下:
element():获取,但不移除此队列的头。
offer(E e):boolean 类型,插入元素到队列中
peek():获取但不移除次队列的头,如果此队列为空,则返回null
poll():获取并移除此队列的头, 如果此队列为空,则返回null
7、Map用户保存具有映射关系的数据,因此Map集合里保存者两组数,分别是Key和Value,一一对应关系,通过key可以找到对应value。key中的值不能重复,value可以重复
8、Map包含了一个KeySet()方法,用来返回Map里所有key组成的Set集合
Map包含entrySet()返回映射中包含映射的关系的Set视图Set<Map.Entry<K,V>>
Map<String,Day> m =new HashMap<String,Day>();
m.put("第一个",day1);
m.put("第二个",day2);
map.containsKey(“第一个”);//true
map.containsValue(day);//true
Set<String> keySet = map.keySet();
for(String key : keySet){
System.out.println(map.get(key));
}
1、ArrayList分配连续的内存空间,如果超过集合大小会自动扩容,增加的大小为原来集合大小的0.5倍,比如初始化自动定义集合大小为10,则会自动增加5个大小,集合总大小变为15个。
ArrayList<String> a =new ArrayList<String>();
2、LinkedList是基于链表实现的,按下标访问元素,如果下标i>数组大小的一半,会从末尾移起。时间复杂度为O(n/2);
LinkedList<String> l =new LinkedList<String>();
list.add("语文");
list.add(“数学”);
list.add("英语");
private class Node{
public String title;
public Node pre;//当前节点的上一个节点元素
public Node next;//当前节点的下一个节点元素
public Node(String title){
this.title = title;
}
}
HashMap:
遍历:通过map.keySet()可以获取HashMap的key集合、通过map.entrySet()获取KV的映射集合,然后再循环获取:
HashMap<String , Integer> map =new HashMap<>();
map.put("语文",1);
map.put("数学",2);
map.put("英语",3);
map.put("音乐",4);
for(Entry<String, Integer> entry : map.entrySet()){
String key = entry.getKey();
Integer i =entry.getValue();
}
1、HashMap基于Map接口实现,允许null键/值、非同步、不保证有序、也不保证顺序不随时间变化。
2、容量(Capacity)、负载因子(Load factor)
如果当前集合已经大于capacity*load factor时,需要调整bucket的大小为当前的2倍。
3、HashMap主要包含put和get方法,put方法的思路:
1)、对Key的hashCode()做hash,然后计算出index
2)、如果没碰撞直接放到bucket里
3)、如果碰撞了,以链表形式存在buckets后
4)、如果碰撞导致链表过长(>=TREEIFY_THRESHOLD),就把链表转换成红黑树
5)、如果节点已经存在就替换old value(保证key的唯一性)
6)、如果bucket满了(>load factor * current capacity),就resize
4、HashMap的get方法思路如下:
1)、bucket里的第一个节点,直接命中
2)、如果有冲突、则通过key.equals(k)去查找对应的entry,若为树则在树中通过key.equals(k)查找,O(logn);
若为链表,则通过key.equals(k)查找,O(n)
5、对象o的HashCode如何进行hash操作的
1)、获取o的HashCode叫做h,比如值为:1111 1111 1111 1111 1111 0000 1110 1010
2)、对o的HashCode进行向右移动16位,即:h>>>16
移动后为h1:0000 0000 0000 0000 1111 1111 1111 1111
3)、hash值即为h与h1的异或运算,即:hash = h^h1,值为:1111 1111 1111 1111 0000 1111 0001 0101
4)、下标值即为:(n-1)& hash的结果。
n为bucket的数量,默认为16,16-1=15换算为二进制为
0000 0000 0000 0000 0000 0000 0000 1111
& ==>0101 =5
1111 1111 1111 1111 0000 1111 0001 0101
使用Java方法实现即为:
static final int hash( Object key) {
int h;
return (key == null )?0:(h = key.hashCode())^(h>>>16);
}
5)RESIZE的实现:HashMap的扩容因子为0.75,扩容则直接把bucket大小变为原来的2倍,之后重新计算index,把节点再放到新的bucket中
6、计算Key对应的hash值:hash=(h = k.hashCode() ^ (h>>>16)),计算key在集合中的index,则(n-1)& hash。
-------------------------------------------优雅的分割线-----------------------------------------
HashMap不保证数据的有序,LinkedHashMap保证数据可以保持插入顺序,如果希望Map可以保持Key的大小顺序,可以利用TreeMap。
TreeMap<Integer,String> tMap = new TreeMap<>();
tMap.put(1,"语文");
tMap.put(3,"英语");
tMap.put(2,"数学");
for(Entry<Integer , String> entry : tMap.entrySet()){
System.out.println( entry.getKey() + ":" + entry.getValue());
}
使用红黑树的好处可以使树具有不错的平衡性,操作速度可以达到log(n)
TreeMap的迭代输出相当于树的中序遍历(LDR)
-------------------------------------------优雅的分割线-----------------------------------------
LinkedHashMap迭代输出保持了插入的顺序,它是Hash表和链表的实现,并且依靠着双向链表保证了迭代顺序,也就是插入的顺序。
LinkedHashMap<String , Integer> lMap =new LinkedHashMap<String , Integer>();
lMap.put(" 语文" ,1);
lMap.put(" 数学" ,2);
lMap.put(" 英语" ,3);
lMap.put(" 音乐" ,4);
for (EntrySet<String , Integer> entry : lMap.entrySet()){
String key =entry.getKey();
Integer value =entry.getValue();
}
---------------------------------------------优雅的分割线-------------------------------------
泛型、变长参数、条件编译、自动拆箱装箱、内部类
List list =new ArrayList();//这个时候list添加的是Objct类型
List<String> list =new ArrayList<String>();//泛型,list添加的是String类型
泛型:对Java语言类型系统的一种扩展。
泛型好处:
1、类型安全,类型错误在编译的时候就被发现,而不是运行是出现ClassCastException。
2、消除代码强制类型转换,增强了代码可读性。
3、为较大优化带来可能性。
第一:定义接口时指定了一个类型形参,该形参名为E
第二:定义类型时指定了一个类型形参,该形参为E
比如:
public class Container< K , V>{
private K key;
private V value;
public Container( K k , V v){
key = k;
value = v;
}
public K getKey(){
return key;
}
public V getValue(){
return value;
}
public void setKey(){
this.key = key ;
}
public void setValue(){
this.value = value;
}
}
在使用Container类时,只要指定K 、 V的具体类型即可
Container<String , String > c1 =new Container<String , String >("name" , "hello");
Container<String , Integer> c2 =new Container<String , Integer>("age" , 22);
public class A extends Container<Integer , String>{} 也可以
public class A extends Container{ }
所谓泛型方法:声明方法时定义一个或多个类型形参,比如:
public static <T> void out(T t) {
System.out.println(t);
}
out("hello");
out(123);
格式: 修饰符<T , S> 返回值类型 方法名 (形参列表){
方法体
}
泛型构造器如下:
public class Person {
public <T> Person( T t) {
System.out.println(t);
}
}
Throwable:Java语言中所有错误或异常的超类,他包含Error和Exception两个子类
接口:对动作的抽象
比如:人吃东西,狗吃东西,这个”吃东西“动作可以定义为一个接口
抽象类:对根源的抽象
比如:男人,女人,这个"人"可以抽象为一个类
-------------------------------------------优雅的分割线-----------------------------------------
Java反射机制:在运行状态中,对于任意一个类都能够知道这个类中的所有属性和方法,对于任意一个对象,都能够调用他的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法功能称作Java语言反射机制。
在Java程序中获取Class对象通常有如下三种方式:
1、Class类的forName( String clazzName) 该字符串参数的值是某个类的全线定名(必须添加完整包名)。
2、调用某个类的class属性来获取该类对应的Class对象
3、调用莫个对象的getClass()方法。
class1 = Class.forName("com.lvr.reflection.Person");
class1 = Person.class;
Person person =new person();
Class<?> class1 = person.getClass();
Field[ ] allFields = class1.getDeclaredFields( );//获取class对象的所有属性
Field[ ] publicFields = class1.getFields( );//获取class对象的public属性
Field ageField = class1.getDeclaredField("age");//获取class指定属性
Field desField = class1.getField("des");//获取class指定的public属性
-------------------------------------------优雅的分割线-----------------------------------------
静态代理:
1、代理对象和目标对象实现同一个行为接口。
2、代理类和目标类分别具体实现接口逻辑。
3、在代理类的构造函数中实例化一个目标对象。
4、在代理类中调用目标对象的行为接口。
5、客户端想要调用目标对象的行为接口,只能通过代理类来操作。
public class ProxyDemo {
public static void main(String[ ] args[ ] ){
RealSubject subject =new RealSubject();
Proxy p = new Proxy(subject);
p.request();
}
}
interface A(){
void request();
}
public class RealSubject implements A {
public void request(){
System.out.println("request");
}
}
public class proxy implements Subject {
private Subject subject;
public Proxy( Subject subject){
this.subject = subject;
}
public void request(){
System.out.println(" proxy print-----");
subject.request();
System.out.println(" proxy print-----");
}
}
-------------------------------------------优雅的分割线-----------------------------------------
动态代理:运行时动态生成代理类,和静态代理不同点是目标类以及类的属性和方法在运行的时候反射获取。
IO流:字符流、字节流
序列化,一个对象只要实现了Serilizable接口,这个对象就可以被序列化,这个类所有属性和方法都会自动序列化,
如果莫个属性只想内存声明周期存在内存,不想序列化到磁盘,可以增加transient修饰,比如:
private transient String password;
transient关键字只能修饰变量,不能修饰方法和类,一个静态变量不管是否被transient修饰,局不能序列化
ConcurrentHashMp 线程安全
创建线程方式:
1、集成Thread类创建线程类
2、通过Runnable接口创建线程类
3、通过Callable和Future创建线程
线程池:
1、降低系统资源消耗
2、提高系统响应速度
3、方便便新城并发数的管控,统一分配、调优、提供资源使用率
4、功能强大,是用简单
ThreadPoolExecutor 用来创建线程池
ExecutorService service = new THreadPoolExecutor(....);
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit ,
BlockingQueue<Runable> workQueue , ThreadFactory threadFactory , RejectedExecutionHandler handler)
corePoolSize:核心线程数,默认情况,核心线程一直存活在线程池中,当allowCoreThreadTimeOut属性设置为true,当超过keepAliveTime闲置的核心线程将会被终止。
2、maximumPoolSize:线程池中所容纳的最大线程数,当线程达到这个数值后,后续新任务将被阻塞
3、keepAliveTime:非核心线程闲置时的超时时长,对于非核心线程闲置时间超过这个时间,非核心线程就会被回收,只有对ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true时,这个超时时间才会对核心线程产生效果。
4、unit:置顶keepAliveTime参数的时间单位
5、workQueue:线程池中保存等待执行的任务的阻塞队列,主要阻塞队列包括:
ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、PriorityBlockingQueue
6、threadFactory:线程工厂,它是一个接口,里面只有一个newThread方法
Java中四种线程池类,他们都是直接或间接配置ThreadPoolExecutor来实现各自的功能,他们分别是:
newFixedThreadPool:线程数量固定,只存在核心线程,响应速度快
ExecutorService service = Executors.newFixedThreadPool(4);
newCachedThreadPool:无核心线程数,非核心线程数量为Integer.MAX_VALUE
newScheduledThreadPool:核心线程数固定,非核心线程几乎没有限制的
newSigleThreadExecutor:只有一个核心线程
一共有两种锁来实现线程同步问题,分别是:synchronized 和 ReentrantLock
synchronized实现同步基础,当线程试图访问同步代码时,必须先获得对象锁,退出或抛出异常时必须释放锁
synchronzied可以实现:代码块同步和方法同步
网友评论