常用类——基础


- String

1.String类的不可变性

String是指向常量池里的数据,对这个数据我们不能进行任何修改,要修改都是要新造一个数据。

 

2.String,StringBuffer,StringBuilder

底层都是char数组

  • String:不可变的字符序列,对内存消耗较大,关键字final

  • StringBuffer:可变的字符序列,效率高于String,低于StringBuilder,线程安全,涉及到安全问题

  • StringBuilder:线程不安全,适合用在多线程或者非共享数据上

 

3.String常用方法

length()、charAt()、equals()、compareTo()、startsWith()、endsWith()、contains()、indexOf()、getBytes()、toCharArray()、valueOf()

 

 

- Date

1.SimpleDateFormat:JDK8之前

 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
 //解析:将字符串转化为日期
 java.util.Date date = sdf.parse("2018-08-16")

2.DateTimeFormatter:JDK8

 DateTimeFormatter dtf = DateTimeFormatte.ofPattern("yyyy-MM-dd");
 //解析:将字符串转化为日期
 Date date = dtf.parse("2018-08-16")

 

编码:字符串-》字节数据

解码:字节-》字符串

格式化:日期-》字符串 format

解析:字符串-》日期 parse

 

 

- 自然排序和定制排序

  • Comparable 自然排序 ,实体类实现Comparable接口,可以去重写compareTo()方法,解决实际排序问题。 把元素放进去,就会自动的调用CompareTo方法

  • Compartor第三方的比较器接口, 用法:实现这个接口,重写compare()方法。

 

 

- Collection

1.集合框架的概述

集合、数组都是对多个数据进行存储操作的结构,简称java容器。(此时的存储主要指的是内存层面的存储,不涉及持久化存储

 

2.数组存储

2.1 数组在存储多个数据方面的特点
  • 一旦初始化以后,长度就确定了

  • 数组一旦定义好,元素的类型就确定了

2.2 数组在存储多个数据方面的缺点
  • 一旦初始化后,长度不可修改

  • 数组中提供的方法非常有限,对于增删插入数据等操作非常不便,执行效率不高

  • 获取数组中实际元素的个数的需求,没有现成的属性或方法可用

  • 数组存储数据的特点:有序可重复,对于无序不可重复的需求无法满足

 

3.集合框架

Collection接口:单列集合,用来存储一个一个的对象

  • List接口:存储有序的,可重复的数据 -->“动态”数组

    • ArrayList、LinkedList、Vector

  • Set接口:存储无序的、不可重复的数组

    • HashSet、LinkedHashSet、TreeSet

 

Map接口:双列集合、用来存储键值对数据

  • HashMap、LinkedHashMap、TreeMap、Hashtable、Properties

 

4.Collection和Collections的区别

Collection是集合类的上级接口,继承与他的接口主要有Set 和List. Collections是操作集合和map的工具类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。

 

- Collection子接口一:List接口

1.List的实现类的结构

Collection接口:单列集合、用来存储一个一个的对象

  • List接口:存储有序的、可重复的数据 -->”动态“数组

    • ArrayList:作为List接口的主要实现类:线程不安全的、效率高,底层使用Object[] elementData存储

    • LinkedList:对于频繁的插入删除操作,使用此类效率比ArrayList高,底层使用双向链表存储

    • Vector:作为List接口的古老实现类:线程安全的、效率低,底层使用Object[] elementData存储

  • Set接口

 

2. ArrayList的底层实现原理

2.1 jdk7情况下

ArrayList list = new ArrayList();//底层创建了长度是10的Object[]数组elementData

list.add(123);//elementData[0] = new Integer(123);

...

list.add(11);//如果此次的添加导致底层数组容量不够,则扩容。默认扩容1.5倍,同时将原有数组复制到新数组中。

结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity);

2.2 jdk8中的变化

只有第一次调用add()时,底层才创建了长度为10的数组,并将数据添加到数组中,节省了内存。

 

3.LinkedList的底层实现原理

LinkedList list = new LinkedList();//内部声明了Node类型的first和last属性,默认值为null

list.add(123);//将123封装到Node中,创建了Node对象

 

4.Vector的底层实现原理

jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组,在扩容时,默认扩容为原来的数组长度的2倍。

 

 

- 集合——Map接口

1.Map的实现类的结构

Map:双列数据,存储key-value对的数据

  • HashMap:作为Map的主要实现类;线程不安全,效率高,可以存储null的key和value。底层:数组+链表(jdk7及之前);数组+链表+红黑树(jdk8)

    • LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历,原因:在原有的HashMap底层结构基础上,添加了一对指针,只想前一个和后一个元素。对于频繁的遍历操作,执行效率高于HashMap。

  • TreeMap:保证按照添加的key-value对进行排序,实现排序遍历,此时考虑key的自然排序或定制排序。底层使用红黑树

  • Hashtable:作为古老的实现类,线程是安全的,效率低,不能存储null的key和value

    • Properties:常用来处理配置文件,key和value都是String类型

 

2.Map结构的理解

Map中的key:无序的、不可重复的,使用Set存储所有的key -> key所在的类要重写equals()和HashCode()方法(以HashMap为例)

Map中的value:无序的、可重复的、使用Collection存储所有的value -> value所在的类要重写equals()

一个键值对:key-value构成了一个Entry对象

Map中的Entry:无序的、不可重复的,使用Set存储所有的Entry

 

3.HashMap的底层实现原理(jdk7)

1.HashMap map = new HashMap();

  在实例化以后,底层创建了长度是16的一维数组,类型为Entry[]名字为table。

2.map.put(key1,value1);

首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算之后,得到在Entry数组中的存放位置。

  如果此位置上数据为空,此时添加成功。-------情况1

  如果此位置上的数据不为空(意味着此位置上存在一个或多个数据<以链表形式存在>),比较key1和已经存在的一个或多个数据的哈希值:

    如果都不相同,此时添加成功。--------情况2

    如果和某一个已经存在的数据(key2,value2)的哈希值相同,继续比较:调用key1所在类的equals(key2)方法,比较:

      如果返回false:添加成功。 --------情况3

      如果返回true:使用value1替换value2。

补充:关于情况2和情况3,此时key1-value1和原来的数据以链表的形式存储。

3.在不断的添加过程中,会涉及到扩容问题,当超出临界值且存放的位置非空时进行扩容,默认的扩容方式,扩容为原来的2倍,并将原有的数据复制过来。

jdk8相较jdk7的不同:

1.new HashMap():底层没有创建一个长度为16的数组,首次调用put()时才创建

2.jdk8底层的数组是Node[]而不是Entry[]

3.jdk8中的底层结构:数组+链表+红黑树

当数组的某一个索引位置上的的元素以链表形式存在的数据个数>8且当前数组的长度>64时,此时索引位置上的所有数据改为用红黑树存储,提高比较时的效率

 

 

枚举类:类中的对象个数是确定的,有限个

枚举类的对象声明的修饰符:public static final

元注解:对现有的注解进行解释说明的注解

Retention:指明所修饰注解的生命周期

  • SOURCE:注解仅存在于源码中,在class字节码文件中不包含

  • CLASS:默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得

  • RUNTIME运行时:注解会在class字节码文件中存在,解释运行后将类的结构加载到内存中,在运行时可以通过反射获取到

Target:指明注解修饰的对象范围,Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)

throw和throws的区别:

  • throw:手动生成一个异常对象并抛出,使用在方法内部

  • throws:处理异常的方式,使用在方法声明处的末尾

 

4.map的遍历

  • 在增强for循环中使用entries实现Map遍历

     for(Map.Entry<String, String> entry : map.entrySet()){
         String mapKey = entry.getKey();
         String mapValue = entry.getValue();
         System.out.println(mapKey+":"+mapValue);
     }
  • 在增强for循环中遍历key或value

     //key
     for(String key : map.keySet()){
         System.out.println(key);
     }
     //value
     for(String value : map.values()){
         System.out.println(value);
     }
  • 通过Iterator遍历

     Iterator<Entry<String, String>> entries = map.entrySet().iterator();
     while(entries.hasNext()){
         Entry<String, String> entry = entries.next();
         String key = entry.getKey();
         String value = entry.getValue();
         System.out.println(key+":"+value);
     }
  • 通过键找值遍历

     for(String key : map.keySet()){
         String value = map.get(key);
         System.out.println(key+":"+value);
     }