集合与常用类
一、集合
一、Set
set继承了Collection接口,继承的都是Collection中的方法,没有提供额外方法。
set经常称为实现无序、不重复数据集合,指的就是HashSet
1. HashSet(散列集)
HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。
HashSet 允许有 null 值。
HashSet 是无序的,即不会记录插入的顺序。
HashSet 不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。 您必须在多线程访问时显式同步对 HashSet 的并发访问。
HashSet 实现了 Set 接口。
HashSet通过Hash算法排布集合内的元素,所谓的Hash算法就是把任意长度的输入(又叫做预映射),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射。对于不同类型的信息,其散列值公式亦不完全相同。
当我们使用HashSet存储自定义类时,需要在自定义类中重写equals和hashCode方法,主要原因是集合内不允许有重复的数据元素,在集合校验元素的有效性时(数据元素不可重复),需要调用equals和hashCode验证。
HashSet在判断数据元素是否重复时,有两个步骤,注意先后顺序:
- 先检查hashCode值是否与集合中已有相同。
- 如果hashCode相同再调用equals方法进一步检查。(equals返回真表示重复)
- 添加元素
HashSet 类提供了很多有用的方法,添加元素可以使用 add() 方法:
// 引入 HashSet 类
import java.util.HashSet;
public class Demo001 {
public static void main(String[] args) {
HashSet<String> sites = new HashSet<String>();
sites.add("Google");
sites.add("Zhifubao");
sites.add("Taobao");
sites.add("Zhihu");
sites.add("Baidu");
System.out.println(sites);
}
}
如果添加了两个相同的Taobao,但他只会输出一个,因为它是不允许有重复元素的集合,集合内的元素是唯一的。
- 判断元素是否存在
使用 contains() 方法来判断元素是否存在于集合当中:
// 引入 HashSet 类
import java.util.HashSet;
public class Demo001 {
public static void main(String[] args) {
HashSet<String> sites = new HashSet<String>();
sites.add("Google");
sites.add("Zhifubao");
sites.add("Taobao");
sites.add("Zhihu");
sites.add("Baidu");
System.out.println(sites.contains("Taobao"));
}
}
结果输出为:True
- 删除元素
使用 remove() 方法来删除集合中的元素:
// 引入 HashSet 类
import java.util.HashSet;
public class Demo001 {
public static void main(String[] args) {
HashSet<String> sites = new HashSet<String>();
sites.add("Google");
sites.add("Zhifubao");
sites.add("Taobao");
sites.add("Zhihu");
sites.add("Baidu");
sites.remove("Taobao"); // 删除元素,删除成功返回 true,否则为 false
//sites.clear(); 若要删除所有元素用clear
System.out.println(sites);
}
}
- 计算大小
如果要计算 HashSet 中的元素数量可以使用 size() 方法:
// 引入 HashSet 类
import java.util.HashSet;
public class Demo001 {
public static void main(String[] args) {
HashSet<String> sites = new HashSet<String>();
sites.add("Google");
sites.add("Zhifubao");
sites.add("Taobao");
sites.add("Zhihu");
sites.add("Baidu");
System.out.println(sites.size());
}
}
输出为:5,因为有五个元素
2. TreeSet
- TreeSet是一个有序集合,其元素按照升序排列,默认是按照自然顺序排列,也就是说TreeSet中的对象元素需要实现Comparable接口来实现自比较功能。TreeSet类中跟HashSet类一样也没有get()方法来获取指定位置的元素,所以也只能通过迭代器方法来获取。
- TreeSet虽然是有序的,但是并没有具体的索引,当插入一个新的数据元素的时候,TreeSet中原有的数据元素可能需要重新排序,所以TreeSet插入和删除数据元素的效率较低。
- 当我们使用TreeSet存储自定义类时,需要在自定义类实现Comparable接口并重写其compareTo方法,以提供比对形式,否在TreeSet不能对用户自定义的类型进行正确的树状排序。
public class TreeSetDemo01 {
public static void main(String[] args) {
//创建
TreeSet<Integer> ts = new TreeSet<Integer>();
ts.add(10);
ts.add(50);
ts.add(40);
ts.add(60);
ts.add(30);
//遍历
for (Integer a : ts){
System.out.println(a);
}
}
}
二、Map
1. HashMap
HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。
当发生哈希冲突并且size大于阈值的时候,需要进行数组扩容,扩容时,需要新建一个长度为之前数组2倍的新的数组,然后将当前的Entry数组中的元素全部传输过去,扩容后的新数组长度为之前的2倍,所以扩容相对来说是个耗资源的操作。
package chapter_thirteen;
import java.util.HashMap;
import java.util.Map;
/**
* 实例操作一:
* 为集合中增加和取出内容
*/
public class HashMapDemo01 {
public static void main(String[] args) {
Map<String,String> map = new HashMap<String, String>(); //通过HashMap类为Map接口进行实例化操作
map.put("deku","努力奋斗"); //为map集合添加键名和键值数据
map.put("Hello","World");
map.put("Searching","True Statement");
String mysoul = map.get("Searching"); //通过Map接口的get()方法通过键名获取对应的键值
System.out.println(mysoul); //打印输出获取对应键名的键值
}
}
2. TreeMap
在Map集合框架中,除了HashMap以外,TreeMap也是我们工作中常用到的集合对象之一。
与HashMap相比,TreeMap是一个能比较元素大小的Map集合,会对传入的key进行了大小排序。其中,可以使用元素的自然顺序,也可以使用集合中自定义的比较器来进行排序;
不同于HashMap的哈希映射,TreeMap底层实现了树形结构,至于具体形态,你可以简单的理解为一颗倒过来的树—根在上–叶在下。如果用计算机术语来说的话,TreeMap实现了红黑树的结构,形成了一颗二叉树。
- TreeMap 继承于AbstractMap,而AbstractMap实现了Map接口,并实现了Map接口中定义的方法,减少了其子类继承的复杂度;
- TreeMap 实现了Map接口,成为Map框架中的一员,可以包含着key–value形式的元素;
- TreeMap 实现了NavigableMap接口,意味着拥有了更强的元素搜索能力;
- TreeMap 实现了Cloneable接口,实现了clone()方法,可以被克隆;
- TreeMap 实现了Java.io.Serializable接口,支持序列化操作,可通过Hessian协议进行传输;
基本内容:
public class TreeMapTest {
public static void main(String[] agrs){
//创建TreeMap对象:
TreeMap<String,Integer> treeMap = new TreeMap<String,Integer>();
System.out.println("初始化后,TreeMap元素个数为:" + treeMap.size());
//新增元素:
treeMap.put("hello",1);
treeMap.put("world",2);
treeMap.put("my",3);
treeMap.put("name",4);
treeMap.put("is",5);
treeMap.put("jiaboyan",6);
treeMap.put("i",6);
treeMap.put("am",6);
treeMap.put("a",6);
treeMap.put("developer",6);
System.out.println("添加元素后,TreeMap元素个数为:" + treeMap.size());
//遍历元素:
Set<Map.Entry<String,Integer>> entrySet = treeMap.entrySet();
for(Map.Entry<String,Integer> entry : entrySet){
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println("TreeMap元素的key:"+key+",value:"+value);
}
//获取所有的key:
Set<String> keySet = treeMap.keySet();
for(String strKey:keySet){
System.out.println("TreeMap集合中的key:"+strKey);
}
//获取所有的value:
Collection<Integer> valueList = treeMap.values();
for(Integer intValue:valueList){
System.out.println("TreeMap集合中的value:" + intValue);
}
//获取元素:
Integer getValue = treeMap.get("jiaboyan");//获取集合内元素key为"jiaboyan"的值
String firstKey = treeMap.firstKey();//获取集合内第一个元素
String lastKey =treeMap.lastKey();//获取集合内最后一个元素
String lowerKey =treeMap.lowerKey("jiaboyan");//获取集合内的key小于"jiaboyan"的key
String ceilingKey =treeMap.ceilingKey("jiaboyan");//获取集合内的key大于等于"jiaboyan"的key
SortedMap<String,Integer> sortedMap =treeMap.subMap("a","my");//获取集合的key从"a"到"jiaboyan"的元素
//删除元素:
Integer removeValue = treeMap.remove("jiaboyan");//删除集合中key为"jiaboyan"的元素
treeMap.clear(); //清空集合元素:
//判断方法:
boolean isEmpty = treeMap.isEmpty();//判断集合是否为空
boolean isContain = treeMap.containsKey("jiaboyan");//判断集合的key中是否包含"jiaboyan"
}
}
三、List
1. ArrayList
ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。
ArrayList 继承了 AbstractList ,并实现了 List 接口。
可以看到ArrayList类实现了四个接口:
- List:支持List接口中提供的方法
- RandomAccess:支持快速随机访问
- Cloneable:支持对象克隆功能
- Serializable:支持序列化功能
1. 创建和添加
public class ArrayListDemo01 {
public static void main(String[] args) {
//创建一个空集合对象
//public ArrayList();
ArrayList<String> arrayList=new ArrayList<>();
System.out.println(arrayList);//输出为 []
//将指定元素添加到集合末尾
//public boolean add(E e);
arrayList.add("hello");
arrayList.add("world");
System.out.println(arrayList);//输出为 [hello, world]
//在指定位置插入元素
//public void add(int index,E element);
arrayList.add(1,"wao");
System.out.println(arrayList);//输出为 [hello, wao, world]
}
}
2. 删除
public static void main(String[] args) {
//创建
ArrayList<String> arrayList=new ArrayList<>();
//添值
arrayList.add("hello");
arrayList.add("world");
arrayList.add("wao");
arrayList.add("fine");
System.out.println(arrayList);//输出[hello, world, wao, fine]
//删除指定元素 public boolean remove(Object o);
arrayList.remove("wao");
System.out.println(arrayList);//输出[hello, world, fine]
//删除指定位置的元素 public E remove(int index);
arrayList.remove(1);
System.out.println(arrayList);//输出[hello, fine]
}
3. 修改
public class ArrayListDemo03 {
public static void main(String[] args) {
//创建
ArrayList<String> arrayList=new ArrayList<>();
//添值
arrayList.add("hello");
arrayList.add("world");
arrayList.add("wao");
arrayList.add("fine");
System.out.println(arrayList);//输出[hello, world, wao, fine]
//修改指定位置的元素 public E set(int index,E element);
arrayList.set(1,"java");
System.out.println(arrayList);//输出[hello, java, wao, fine]
}
}
4. 获取集合元素
public class ArrayListDemo04 {
public static void main(String[] args) {
//创建
ArrayList<String> arrayList=new ArrayList<>();
//添值
arrayList.add("hello");
arrayList.add("world");
arrayList.add("wao");
arrayList.add("fine");
System.out.println(arrayList);//输出[hello, world, wao, fine]
//获取指定元素 public E get(int index);
System.out.println(arrayList.get(0));//输出hello
System.out.println(arrayList.get(1));//输出world
System.out.println(arrayList.get(2));//输出wao
}
}
5. 获取集合元素个数
public class ArrayListDemo05 {
public static void main(String[] args) {
//创建
ArrayList<String> arrayList=new ArrayList<>();
//添值
arrayList.add("hello");
arrayList.add("world");
arrayList.add("wao");
arrayList.add("fine");
System.out.println(arrayList);//输出[hello, world, wao, fine]
//获取集合中元素的个数 public int size();
System.out.println(arrayList.size());//输出4
}
}
2. LinkedList
LinkedList 继承了 AbstractSequentialList 类。
LinkedList 实现了 Queue 接口,可作为队列使用。
LinkedList 实现了 List 接口,可进行列表的相关操作。
LinkedList 实现了 Deque 接口,可作为队列使用。
LinkedList 实现了 Cloneable 接口,可实现克隆。
LinkedList 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。
当你需要通过循环迭代来访问列表中的某些元素,或者需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作的时候,更适合用LinkedList而不是ArrayList。
1. 如何移除头尾元素
// 引入 LinkedList 类
import java.util.LinkedList;
public class Demo001 {
public static void main(String[] args) {
LinkedList<String> sites = new LinkedList<String>();
sites.add("Google");
sites.add("Baidu");
sites.add("Taobao");
sites.add("Weibo");
// 使用 removeFirst() 移除头部元素
sites.removeFirst();
// 使用 removeLast() 移除尾部元素
sites.removeLast();
System.out.println(sites);
}
}
2. 如何添加头尾元素
// 引入 LinkedList 类
import java.util.LinkedList;
public class Demo001 {
public static void main(String[] args) {
LinkedList<String> sites = new LinkedList<String>();
sites.add("Google");
sites.add("Baidu");
sites.add("Taobao");
// 使用 addFirst() 在头部添加元素
sites.addFirst("Bilibili");
// 使用 addLast() 在尾部添加元素
sites.addLast("Weibo");
System.out.println(sites);
}
}
二、常用类
一、Object
Object 是 Java 类库中的一个特殊类,也是所有类的父类。也就是说,Java 允许把任何类型的对象赋给 Object 类型的变量。当一个类被定义后,如果没有指定继承的父类,那么默认父类就是 Object 类。由于 Java 所有的类都是 Object 类的子类,所以任何 Java 对象都可以调用 Object 类的方法。
- toString() 方法
toString() 方法返回该对象的字符串,当程序输出一个对象或者把某个对象和字符串进行连接运算时,系统会自动调用该对象的 toString() 方法返回该对象的字符串表示
//定义类
public class Person {
String name;
int age;
//构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//重写object中的toString()方法
@Override
public String toString() {
return "姓名:"+this.name+" 年龄:"+this.age;
}
}
//主方法
public class Test {
public static void main(String[] args) {
//实例化
Person person = new Person("zhang",18);
System.out.println(person);//打印对象调用toString()方法
}
}
- equals()方法
两种比较方法,分别是‘ == ’运算符和equals()方法,‘ == ’是比较两个引用变量是否指向同一个实例,equals() 方法是比较两个对象的内容是否相等 - getClass()方法
getClass() 方法返回对象所属的类,是一个 Class 对象;通过 Class 对象可以获取该类的各种信息,包括类名、父类以及它所实现接口的名字等。
二、String
- 创建字符串最简单的方式如下:
String str = "Ztx";
在代码中遇到字符串常量时,这里的值是 “Ztx”,编译器会使用该值创建一个 String 对象。和其它对象一样,可以使用关键字和构造方法来创建 String 对象。
用构造函数创建字符串:
String str2=new String("Ztx");
String 创建的字符串存储在公共池中,而 new 创建的字符串对象在堆上:
String s1 = "Ztx"; // String 直接创建
String s2 = "Ztx"; // String 直接创建
String s3 = s1; // 相同引用
String s4 = new String("Ztx"); // String 对象创建
String s5 = new String("Ztx"); // String 对象创建
字符串长度:
用于获取有关对象的信息的方法称为访问器方法。
String 类的一个访问器方法是 length() 方法,它返回字符串对象包含的字符数:
public class Demo001 {
public static void main(String args[]) {
String site = "Ztx is a bad guy";
int len = site.length();
System.out.println( "对他的评价等级数为: " + len );
}
}
输出的结果为:
对他的评价等级为:16
- 连接字符串
String 类提供了连接两个字符串的方法:
string1.concat(string2);
更常用的是使用’+'操作符来连接字符串
"Hello," + "ZTX" + "!"
三、StringBuffer 和 StringBuilder
当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
1. StringBuilder
StringBuilder对象中的内容是可变的;它和 StringBuffer 之间的最大不同在StringBuilder 的方法不是线程安全的;但 StringBuilder 相较于 StringBuffer 有速度优势
public class Demo01{
public static void main(String args[]){
StringBuilder sb = new StringBuilder();
sb.append("Ztx..");
System.out.println(sb);
sb.append("!");
System.out.println(sb);
sb.insert(5, "bad");
System.out.println(sb);
sb.delete(0,1);
System.out.println(sb);
}
}
输出结果为:
Ztx…
Ztx…!
Ztx…bad!
tx…bad!
其中StringBuilder 类表示可变字符的字符串:
- Capacity属性:获取或设置可包含在当前实例所分配的内存中的最大字符数
- Length属性:获取或设置当前 StringBuilder 对象的长度
2. StringBuffer
StringBuffer 类的对象后可以随意修改字符串的内容;每个 StringBuffer 类的对象都能够存储指定容量的字符串,如果字符串的长度超过了 StringBuffer 类对象的容量,则该对象的容量会自动扩大
public class Test{
public static void main(String args[]){
StringBuffer s = new StringBuffer("CSDN的官网为:");
s.append("www");
s.append(".csdn");
s.append(".net");
System.out.println(s);
}
}
StringBuilder 与 StringBuffer 的构造方法会创建一个默认大小是 16 的字符数组。使用 append() 方法时,如果长度超过了字符串存储空间大小就需要进行扩容,它会重新分配内存,创建一个更大的数组,这个数组的容量是原来的 2 倍 + 2 的大小,并将原先的数组复制过来,再丢弃旧的数组。因此,在大多数情况下,可以在创建 StringBuilder 与 StringBuffer 的时候指定大小,这样可以避免在容量不够的时候自动增长,从而提高性能。
所以为了节省空间的浪费,最好在使用时指定初始化的大小
四、System
System 类位于 java.lang 包,代表当前 Java 程序的运行平台,系统级的很多属性和控制方法都放置在该类的内部。由于该类的构造方法是 private 的,所以无法创建该类的对象,也就是无法实例化该类。
1. System 类的成员变量
System 类提供了一些类变量和类方法,允许直接通过 System 类来调用这些类变量和类方法。System 类有 3 个静态成员变量,分别是 PrintStream out、InputStream in 和 PrintStream err。
- PrintStream out
标准输出流。此流已打开并准备接收输出数据。通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标。
例如,编写一行输出数据的典型方式是:
System.out.println(data);
其中,println 方法是属于流类 PrintStream 的方法,而不是 System 中的方法。
-
InputStream in
标准输入流。此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。 -
PrintStream err
标准的错误输出流。其语法与 System.out 类似,不需要提供参数就可输出错误信息。也可以用来输出用户指定的其他信息,包括变量的值。
2. System 类的成员方法
System 类中提供了一些系统级的操作方法,常用的方法有 arraycopy()、currentTimeMillis()、exit()、gc() 和 getProperty()
arraycopy() 方法
该方法的作用是数组复制,即从指定源数组中复制一个数组
public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
其中,src 表示源数组,srcPos 表示从源数组中复制的起始位置,dest 表示目标数组,destPos 表示要复制到的目标数组的起始位置,length 表示复制的个数
public class SystemArrayCopy {
public static void main(String[] args) {
char[] srcArray = {'A','B','C','D'};
char[] destArray = {'E','F','G','H'};
System.arraycopy(srcArray,1,destArray,1,2);
System.out.println("源数组:");
for(int i = 0;i < srcArray.length;i++) {
System.out.println(srcArray[i]);
}
System.out.println("目标数组:");
for(int j = 0;j < destArray.length;j++) {
System.out.println(destArray[j]);
}
}
currentTimeMillis() 方法
该方法的作用是返回当前的计算机时间
long m = System.currentTimeMillis();
exit() 方法
该方法的作用是终止当前正在运行的 Java 虚拟机
public static void exit(int status);
gc() 方法
该方法的作用是请求系统进行垃圾回收,完成内存中的垃圾清除
public static void gc();
getProperty() 方法
该方法的作用是获得系统中属性名为 key 的属性对应的值
public static String getProperty(String key);
五、Data
- Date类的概述:
java.util,Date 表示日期和时间的类
类 Date 表示特定的瞬间,精确到千分之一秒(毫秒)
实例引入:获取时间原点到当前系统时间经历了多少秒
public class DemoDate {
public static void main(String[] args) {
System.out.println(System.currentTimeMillis());
}
}
- Date类常用的构造方法和成员方法
成员方法:
getTime()方法。返回:时间原点以来,此Date对象表示的毫秒数
import java.util.Date;
public class DemoGetTime {
public static void main(String[] args) {
Date date = new Date();
long time = date.getTime();
// 输出:1578728202850
// 该方法类似于 System.currentTimeMillis()
System.out.println(time);
}
}
构造方法
Date类的无参构造方法。返回:当前系统的日期和时间
import java.util.Date;
public class DemoDate1 {
public static void main(String[] args) {
Date date = new Date();
// 输出:Sat Jan 11 15:40:50 CST 2020
System.out.println(date);
}
}
Date类的带参构造方法
Date(long date) 参数为一个毫秒值,把传入的毫秒值转换为Date日期。返回:传入参数(毫秒值)对应的的日期和时间
import java.util.Date;
public class DemoDate2 {
public static void main(String[] args) {
Date date = new Date(0L);
System.out.println(date);
}
}