JAVA基础(六)
Arrays类:
-
toString 返回数组的字符串形式 Arrays.toString(arr)
-
sort排序 (自然排序和定制排序)
-
binarySearch 通过二分搜索法进行查找,要求必须排好序 int index =Arrays.binarySearch(arr,3);
-
copyOf 数组元素的复制
Integer [] newArr = Arrays.copyOf(arr,arr.length); //如果拷贝长度>arr.length就在新数组的后面增加Null //如果拷贝的长度<0 就抛出异常NegativeArraySizeException //该方法的底层使用的是System.arraycopy()
-
fill 数组元素的填充
-
equals 比较两个数组元素是否完全一致。
-
asList 将一组值,转换成list
List<Integer> asList = Arrays.List(2,4,5,6,9);
System类:
- exit(0)退出当前程序,0表示是正常状态
- arraycopy: 复制数组元素,比较适合底层调用,一般使用Arrays.copyOf完成复制数组。
- currentTimeMillens:返回当前时间距离1970- 1 -1 的毫秒数
- gc:运行垃圾回收机制 System.gc();
BigInteger和BigDecimal类
BigInteger 适合保存比较大的整型。常用方法 。add 加 subtract 减 multiply 乘 divide除
BigDecimal适合保存精度更高的浮点型(小数)
日期类:
- Date :精确到毫秒,代表特定的瞬间
- SimpleDateFormate:格式和解析日期的类SimpleDareDormat格式化和解析日期的具体类。它允许进行格式化(日期->文本)、解析(文本->日期)和规范化
Date d1 =new Date();//获取当前系统时间
Date d2 = new Date(92345);//通过指定毫秒数得到时间
System.out.println(d1.getTime());//获取某个时间对应的毫秒数
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
String format = sdf.format(d1);
System.out.println(format);
//1、可以把一个格式化的String转换成对应的Date
//2、得到Date仍然在输出时,还在按照国外形式,如果希望指定格式输出,需要转换
//3、在把Sting->Date。使用的sdf 格式需要和你给的String的格式一样,否则回抛出异常
String s= "1999年01月01日 10:20:30 星期一";
Date parse = sdf.parse(s);
System.out.println(sdf.format(parse));
Calendar()日历类:
//1、Calendar 是一个抽象类,并且构造器是private
//2、可以通过 getInstance()来获得实例
//3、提供大量方法和字段
//4、Calendar没有提供对应的格式化类,需要自己组合输出
//5、如果需要24小时进制来获取时间,Calendar.Hour==>改成=>Calender.Hour_oF_DAy
Calendar c = Calendar.getInstance();
// System.out.println(c);
System.out.println(c.get(Calendar.YEAR));
//Calender返回月的适合,按0开始编号的。
System.out.println(c.get(Calendar.MONDAY)+1);
System.out.println(c.get(Calendar.DAY_OF_MONTH));
System.out.println(c.get(Calendar.HOUR));
System.out.println(c.get(Calendar.MINUTE));
System.out.println(c.get(Calendar.SECOND));
Date和Calendar存在的问题:
- 可变性:像日期和时间这样的类应该是不可变的
- 偏移性:Date 中的年份是从1900开始的 ,而且月份都是从0开始
- 格式化:格式化对Date有用,Calendar则不行
- 此外,它们也不是线程安全的,不能处理闰秒等(每隔2天,多1s)
第三代日期类常用方法:
LocalDate(日期/年月日)、LocalTime(时间/时分秒)、LocalDateTime(日期时间/年月日时分秒)JDK8加入
LocalDateTime ldt =LocalDateTime.now();//LocalDae.now();//LocalTime.now();
//使用DateTimeFormatter 对象来进行格式化
//创建DateTimeFormatter对象
DateTimeFormatter date = DateTimeFormatter.ofPattern("yyyy年MM月dd日 hh:mm:ss");
String format = dateTimeFormatter.format(ldt);
//Instant 时间戳
//1.通过静态方法now()获取表示当前时间戳对象
Instant now = Instant.now();
System.out.println(now);
//2.通过from 可以把Instant转换成Date
Date date = Date.from(now);
//3.通过date的toInstant()可以把date转成Instant对象
Instant instant = date.toInstant();
//提供plus 和 minus 方法可以对当前时间进行加或减
数组:
1、长度开始时必须指定的,而且一旦指定,不能更改
2、保存的必须是同一类型的元素
3、使用数组进行增加/删除元素比较麻烦。
集合的好处:
- 可以动态保存任意多个对象。
- 提供了一系列方便的操作对象的方法:add、remove、set、get
- 使用集合添加,删除新元素
1、集合主要两组(单列集合,双列集合)
2、Collection 接口有两个重要的子接口List,Set ,他们的实现子类都
3、Map接口的实现子类,是双列集合,存放K-V
Collection接口和常用方法:
-
public interface Collection<E> extends Iterable <E> //collection实现子类可以存放多个元素,每个元素可以是Object //有些Collection的实现类,可以存放重复的元素,有些不可以,有些是有序的(List),有些不是有序的(set) //Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的。
Collection 接口遍历元素方式-使用Iterator(迭代器)
- Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。
- 所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
- Iterator仅用于遍历集合,Iterator本身不存放对象。
Iteraator iterator = coll.iterator();//得到一个集合的迭代器
//hasNext();判断是否还有下一个元素
while(iterator.hasNext()){
//next();1、指针下移 2、将下移以后集合位置上的元素返回
System.out.println(iterator.next());
}
增强for循环,可以替代iterator迭代器,特点:增强for就是简化版的iterator,本质一样。只用于遍历集合或数组。(底层就是迭代器)
基本语法:
for(元素类型 元素名称:集合名或数组名){
访问元素
}
List接口基本介绍:
List接口是Collection接口的子接口
- List 集合类中元素有序(即添加顺序和取出顺序一致)、且可重复。
- List集合中的每个元素都有其对应的顺序索引,即支持索引。(索引都是从0开始的)
- List容器中的元素对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
- 常用的实现类有:ArrayList、LinkedList、Vector。
ArrayList注意事项:
- permits all elements、including null、ArrayList 可以加入null,并且多个。
- ArrayList是由数组来实现数据存储的。
- ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高),多线程情况下,不建议使用ArrayList.
ArrayList的底层机制操作源码分析:
- ArrayList中维护了一个Object类型的数组elementData.transient Object[] elementData;//transient 表示瞬间、短暂的,表示该属性不会被序列化。
- 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0.第1次添加,则扩容elementData为10,如果需要再次扩容,则elementData为1.5倍。
- 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData1.5倍。
Vector的基本介绍:
public class Vector<E>
extends AbstractList<E>
implements List<E>,RundomAccess,Cloneable,Serializable
1、Vector底层也是一个对象数组 proected Object[] elementData;
2、Vector 是线程同步的,即线程安全,Vector类的操作方法带有synchronized
3、在开发中,需要线程同步安全时,考虑使用Vector。
Vector和ArrayList的比较:
底层结构 | 版本 | 线程安全(同步)效率 | 扩容倍数 | |
---|---|---|---|---|
ArrrayList | 可变数组 | jdk1.2 | 不安全、效率高 | 如果有参构造1.5倍,如果是无参,第一次10,从第二次开始按1.5倍扩 |
Vector | 可变数组Object[] | jdk1.0 | 安全、效率不高 | 如果是无参,默认10,满后,就按2倍扩容。如果指定大小,每次直接按2倍扩容 |
LinkedList的底层结构:
- LinkedList实现了双向链表和双端队列特征
- 可以添加任意元素(元素可以重复),包括null
- 线程不安全,没有实现同步。
LinkedList的底层操作机制:
- LinkedList底层维护了一个双向链表
- LinkedList中维护了两个属性first和last分别指向 首节点和尾节点
- 每个节点(Node对象),里面又维护prev、next、item三个属性,其中通过prev指向前一个节点,最终实现双向链表。
- 所以LinkedList元素的添加和删除,不是通过数组完成的,相对来说效率较高。
class Node {
public Object item;//真正存放数据
public Node next;//指向下一个结点
public Node pre;//指向上一个结点
public Node(Object name){
this.item = name ;
}
public String toString(){
return "Node name=" + item;
}
}
ArrayList和LinkedList的比较:
底层结构 | 增删效率 | 改查的效率 | |
---|---|---|---|
ArrayList | 可变数组 | 较低、数组扩容 | 较高 |
LinkedList | 双向链表 | 较高、通过链表追加 | 较低 |
如何选择ArrayList和LinkedList:
- 如果改查的操作多,选择ArrayList
- 如果删除的操作多,选择LinkedList
- 在项目中,根据业务灵活选择,一个模块可以使用ArrayList,另外一个模块是LinkedList
Set接口和常用方法:
- 无序(添加和取出的顺序不一致),没有索引
- 不允许重复元素,最多包含一个Null
- Set接口是Collection的子接口,可以使用迭代器,增强for循环,不能索引的方式来获取。
HashSet接口实现类:
-
HashSet实现了Set接口
-
HashSet实现了是HashMap
-
可以存放Null值,但是只能有一个null
-
HashSet不能保证元素是有序的,取决于hash后,再确定索引的结果,存储元素不能重复。
-
在执行add方法后,会返回一个boolean值,如果添加成功则返回true
-
可以通过remove指定删除哪个对象。
HashSet set = new HashSet(); set.add("lucy");//true set.add("lucy");//true set.add("new Dog()");//true set.add("new Dog()");//true class Dog{ private String name; } set.add("new String("hsp")");//true set.add("new String("hsp")");//false,加不了
HashSet底层机制说明:
分析HashSet底层是HashMap,HashMap底层是(数组+链表+红黑树)
- HashSet底层是HashMap,第一次添加时,table数组扩容到16,临界值(threshold)是 16*加载因子(loadFactor)是0.75=12;
- 如果table数组使用到了临界值12,就会扩容到16*2=32,新的临界值就是32*0.75=24,以此类推。
- 在Java8中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认是8)并且table的大小 >= MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树),否则仍然采用数组扩容机制。
Set接口实现类–LinkedHashSet
-
LinkedHashSet是HashSet 的子类。
-
LinkedHashSet 底层是一个LinkedHashMap,底层维护了一个数组+双链表
-
LinkedHashSet根据元素的hashCode值决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
-
LinkedHashSet不允许添加重复元素。
Map接口和常用方法:(JDK8 以后的Map接口)
-
Map与Collection并列存在,用于保存具有映射关系的数据:Key-Value(双列元素)
-
Map中的key和value可以是任何引用类型的数据,会封装到HashMao$Node对象中。
-
Map中的key不允许重复 ,原因和HashSet一样,Map中的值可以重复。
-
Map的key可以为null,value也可以为null,注key为null只能有一个,value为null,可以为多个。
-
常用String类作为Map的key。
-
Key和Value之间存在单向的一对一关系,即通过指定的Key总能找到对应的Value。
-
Map存放数据的key-value,一对k-v是存放在一个Node中的,因为Node实现了Entry接口,因此有时被称为一个Entry。
1、k-v最后是HashMap$Node node = newNode(hash,key,value,null)
2、k-v为了方便程序员的遍历,还会创建EntrySet,该集合存放的元素类型Entry,而一个Entry对象就有k, v,EntrySet<Entry<K,V>>即:transient Set<Map. Entry<K,V>>entrySet;
3、entrySet中,定义类型是Map.Entry,但是实际上存放的还是HashMap$Node
//这是因为static class Node<K,V> implements Map.Entry<K,V>
4、当把HashMap$Node 对象存放到 entrySet 就方便遍历,因为Map.Entry提供重要方法 //K getKey(); V getValue();
Map接口常用的方法: put //添加 、remove//根据建删除映射关系、get//根据键获取值、size//获取元素个数 、isEmpty //判断个数是否为0、clear //清除 、containsKey//查找键是否存在。
HashMap的遍历方式:
//一、通过Key取出对应的Value
Set keyset = map.keySet(); //1、先取出所有的Key
for (Object key : keyset) {//增强for
System.out.println(key+""+map.get(key));
}
//2、迭代器
Iterator iterator = keyset.iterator();
while (iterator.hasNext()) {
Object key = iterator.next();
System.out.println(key+""+map.get(key));
}
//二、通过使用所有的Collection使用遍历方法
//1、把所有的value取出
Collection values = map.values();
for (Object value : values) {
System.out.println(value);
}
//2、迭代器
Iterator iterator1 =values.iterator();
while (iterator1.hasNext()) {
Object value = iterator1.next();
System.out.println(value);
}
//三、通过EntrySet来获取 K - V
Set entrySet = map.entrySet();//EntrySet<Map.Entry<K,V>>
//1、增强For
for (Object emtry : entrySet) {
//将entry 转换成 Map.Entry
Map.Entry m = (Map.Entry) emtry;
System.out.println(m.getKey()+" -"+m.getValue());
}
//2、迭代器
Iterator iterator2 = entrySet.iterator();
while (iterator2.hasNext()) {
Object entry = iterator2.next();
System.out.println(entry.getClass());//HashMap$Node -实现-> Map.Entry(getKey,getValue)
//向下转型
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey()+" "+m.getValue());
}
HashMap小结:
- Map接口的常用实现类:HashMap、Hashtable 和Properties
- HashMap是Map 接口使用频率最高的实现类。
- HashMap是以key-val 对的方式来存储数据[Entry]
- key 不能重复,但是是值可以重复,允许使用null键和null值
- 如果添加相同的key,则会覆盖原来的key-val,等同于修改(key不会替换,val会替换)
- 与HashSet一样,不能保证映射的顺序,因此底层是以hash表的方式存储的。(jdk8的hashMap 底层 数组+链表+红黑树)
- HashMap没有实现同步,因此线程是不安全的。方法没有做同步互斥的操作,没有synchronized。
HashTable的基本介绍:
- 存放的元素是键值对:即 K-V
- hashtable的键和值都不能为null,否则会抛出NullPointerException
- hashTable使用方法基本与HashMap一样
- hashTable是线程安全的(synchronzied),hashMap是线程不安全的。
Hashtable的底层:
- 底层有数组Hashtable$Entry[] 初始化大小为11
- threshold 8 = 11 * 0.15
- 扩容:按照自己的扩容机制进行即可。当if(count >= threshold )满足时,就进行扩容 按照: int newCapacity = (oldCapacity <<1 )+ 1 ;的大小扩容。
线程安全 | 效率 | 允许null键null值 | |
---|---|---|---|
HashMap | 不安全 | 高 | 可以 |
Hashtable | 安全 | 低 | 不可以 |
Map接口实现类----Properties
- Properties类继承自Hashtable类并且实现Map接口,也是使用一种键值对的形式保存数据。使用特点和Hashtable类似
- Properties还可以用于从xxx.properties文件中,加载数据到Properties类对象,并进行读取和修改。
- xxx.properties 文件通常作为配置文件。
在开发中,选择什么集合实现类,主要取决于业务操作,然后根据集合实现类特性进行选择,分析如下:
-
先判断存储类型(一组对象[单例]或一组键值对[双列])
-
一组对象[单例]:Collection接口
允许重复:List
增删多: LinkedList[底层维护了一个双向链表]
改查多:ArrayList[底层维护Object类型的可变数组]
不允许重复:
无序:HashSet [底层时HashMap,维护了一个哈希表即(数组+链表+红黑树)]
排序:TreeSet
插入和取出顺序一致:LinkedHashSet,维护数组+双向链表
-
一组键值对[双链表]:Map
键无序: HashMap[底层是:哈希表 jdk7:数组+链表,jdk8:数组+链表+红黑树]
键排序:TreeMap
键插入和取出顺序一致:LinkedHashMap
读取文件: Properties
//当使用无参构造器,创建TreeSet时,仍然时无序的。
TreeSet treeSet =new TreeSet();
//使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)并致指定排序规则
TreeSet treeSet = new TreeSet(new Comparator(){
@Override
public int compare(Object o1 , Object o2){
//下面 调用String 的compareTo 方法进行字符串大小比较
return ((String)o1).compareTo((String)o2);
}
});
Collection工具类:
- Collection是一个操作Set、List和Map等集合的工具类。
- Collections中提供了一系列静态方法对集合元素进行排序、查询和修改等操作。
- reverse(List):反转List中元素 shuffle(List):对List元素随机排序 sort(List) :根据元素的自然顺序对指定的List集合元素按升序排序 sort(List,Comparator):根据指定的Comparator 产生的顺序对List集合进行排序
- swap(List,int,int)将指定list集合中的i处元素和 j 处元素进行交换。