Java高级API(上)

API文档

什么是JDK的API

  1. JDK中包含大量的API类库,所谓API(Application Programming Interface,应用程序编程接口),就是一些已经写好,可以直接调用的功能.(在Java语言中,这些功能以类的形式封装)

  2. JDK API包含类库功能强大,经常使用的有:
    字符串操作,
    集合操作,
    文件操作,
    输入输出操作,
    网络编程,
    多线程,
    等待.

  3. JDK包结构
    为了便于使用和维护,JDK类库按照包结构划分,不同功能的类,划分在不同的包中;

经常使用的包如下所示:

功能
java.langJava程序的基础包,如字符串,多线程等,该包中的类使用频率非常高,不需要import,可以直接使用
java.util常用工具类,如集合,随机数产生器,日历,时钟等
java.io文件操作,输入\输出操作
java.net网络操作
java.math数学运算相关操作
java.security安全相关操作
java.sql数据库访问
java.text处理文件,日期数字,信息的格式

文档注释规范

  • 以 /** 开始,以 */ 结束
  • 加在类和方法的开头,用于说明作者,时间,版本,要实现功能的详细描述等信息;
  • 通过javadoc工具,可以轻松的将此注释转换为HTML文档说明,学习者和程序员主要通过文档了解到API功能
  • 文档注释不同于普通注释( // 或者 / * * / ),普通注释写在程序之中,用于程序员进行代码维护和交流,无法通过工具生成文档,而文档注释(/** */)写在类和方法的开头,专门用于生成供API使用者进行参考的文档资料
    在这里插入图片描述

String及其常用API

  • String是不可变对象
  • java.lang.String被final修饰,不能被继承
  • 字符串底层封装了字符数组及针对了字符数组的操作算法
  • 字符串一旦创建,对象就永远无法改变,但字符串引用可以重新赋值
  • Java字符串在内存中采用Unicode编码方式,任何一个字符对应两个字节的定长编码

String a = “123”
a 引用变量 指向 “123”
a = “1234”
创建一个新的"1234",然后a指向它
"123"等待回收

  • 字符串本质是转换成char[]
  • char一个占据两字节,使用Unicode编码格式

String常量池

  • Java为了提高性能,使静态字符串(字面量(直接量)/常量/常量连接的结果)在常量池中创建,尽量使用同一个对象,复用静态字符串
  • 对于重复出现的字符串字面量,JVM首先会在常量池中查找,如果存在即返回该对象
String a = "1234";
String b = "12"+"34";
//像这样的字符串会在常量池中创建
//这个时候不会在内存中去创建b,而是将a引用的值赋给b
//此时a和b都指向一个对象

== 和equals的区别?

  1. == 比较基本类型/原生类是比较值,强类型/引用类型是比较引用
  2. 基本类型只能用==,没有equals方法
  3. 强类型的equals方法默认是继承自Object类的,该方法默认和==一样,比较引用,如果重写,按照重写后的比较
  4. Java规定如果重写equals方法,那么也推荐一并重写hashcode方法,保证对象相等的情况下,hashcode也要相等

    如果hashcode相等但equals不一定相等,会有hash冲突的情况,会造成使用HashMap,HashSet对象的时候出现错误

内存编码及长度

String在内存中采用Unicode编码,每个字符占用两个字节,任何一个字节(无论是中文还是英文)都算是一个字符长度,占用两个字节

String a = "123 中国 abc";
//同等于
char[] a = {'1','2','3','中','国','a','b','c'}
String str1 = "Hello";
System.out.println(str1.length());//5
Stirng str2 = "你好,String";
System.out.println(str2.length());//9

使用indexOf实现检索

  • indexOf方法用于实现字符串中检索另外一个字符串
  • String提供几个重载的indexOf方法
    1. int indexOf(String str) 在字符串中检索str返回其第一次出现的位置如果找不到就返回-1
    2. int indexOf(Stirng str, int fromIndex) 从字符串的fromIndex位置开始检索
  • String还定义了lastIndexOf()方法
    int lastIndexOf(String str, int from) str 在字符串中多次出现时将返回最后一个出现位置
String str  = "I can because i think i can";
int index = str.indexOf("can");
System.out.println(index);//2index = str.lastIndexOf("can");
System.out.println(index);//24index = str.indexOf("can",6);
System.out.println(index);//24index = str.indexOf("Can");
System.out.println(index);//-1

使用substring获取子串

  • substring方法用于返回一个字符串的子类字符串
  • substring常用重载方法定义如下:
    1. String substring(int beginIndex, int endIndex)
      返回字符串中从beginIndex(包括)开始到endIndex(不包括)结束的子字符串
    2. String substring(int beginIndex)
      返回字符串中从下标beginIndex(包括)到字符串结尾的子字符串
public void testSubstring(){String str = "http://www.baidu.com";Stirng subStr = str.substring(11,17);System.out.println(subStr);//baidu.subStr = str.substring(7);System.out.print(subStr);//www.baidu.com
}

trim

去掉一个字符串的前导和后继空字符串

public void testTrim(){String userName = "   good man   ";userName = userName.trim();System.out.println(userName);//good manSystem.out.println(userName.length());//8
}

charAt

String中定义有charAt()方法
char charAt(int index)方法 charAt()用于返回字符串指定位置的字符,参数index表示指定的位置

public void testCharAt(){String name = "Whatisjava";for(int i= 0 ; i < name.length();i++){char c = name.charAt(i);System.out.print(c+" ")}//W h a t i s j a v a
}

startsWith和endsWith

检查一个字符串是否以指定字符串开头或结尾

public void testStartsWithAndEndsWith(){String str = "Think in Java";System.out.println(str.startsWith("Java"));//falseSystem.out.println(str.endsWith("Java"));//trueSystem.out.println(str.endsWith("a"));//true
}

大小写转换

public void testToUpperCaseAndToLowerCase(){String str = "我喜欢java";str = str.toUpperCase();System.out.println(str);//我喜欢JAVAstr = str.toLowerCase();System.out.println(str);//我喜欢java
}

valueOf

将其他类型转换为字符串类型

public void testValueOf(){double pi = 3.1415926;int value = 123;boolean flag = true;char[] charArr ={'a','b','c','d','e','f'};String str = String.valueOf(pi);System.out.println(str.length());//9str = String.valueOf(value);System.out.println(str.length());//3str = String.valueOf(flag);System.out.println(str.length());//4str = String.valueOf(charArr);System.out.println(str);//abcdefSystem.out.println(str.length());//6
}

toString 和 valueOf的区别

  1. toString是属于对象的方法
  2. valueOf是属于类的方法
  3. 使用toString需要先构建要转换成字符串类型的对象,而使用valueOf则直接使用String点出即可

split方法

  • String的split方法可以将字符串按照特定的分隔符拆分成字符串数组
  • String[] split(String regexp)参数regexp为正则表达式或字符串,以regexp所表示的字符串为分隔符,将字符串拆分成字符串数组
	String str2 = "3,sicheng,3,sicheng@qq.com,33";//拆分:["3","sicheng","3","sicheng@qq.com","33"];String[] strArr = str2.split(",\\s*");for(int i = 0; i < strArr.length;i++){System.out.print(strArr[i]);}
	String line = "100+200-150=150";//将数字内容单独提出来组成一个数组String[] strArr = line.split("\\+\\-\\=");//\\+等同于文本+System.out.println(Arrays.toString(strArr));

replaceAll方法

  • String提供了用于字符串替换的方法
  • String replaceAll(String regexp,String replacement)将字符串中匹配正则表达式regexp的字符串替换为replacement
	public void testReplaceableAll(){String str = "abc123asd456ghj789456";//将str中的数字替换为"数字"二字//str = str.replaceAll("[0-9]","数字");str = str.replaceAll("\\d+","数字");System.out.println(str);//abc数字asd数字ghj数字}

StringBuilder及其API

StringBuilder封装可变的字符串,对象创建之后可以通过调用方法改变其封装的字符序列

  • StringBuilder有如下常用构造方法:
    1. public StringBuilder();
    2. public StringBuilder(String str);

StringBuilder常用方法

方法名功能
append(String str)追加字符串
insert(int detOffset,String str)插入字符串
delete(int start,int end)删除字符串
replace(int start,int end,String str)替换字符串
reverse()字符串反转

StringBuilder

  • StringBuilder的很多方法的返回值均为StringBuilder类型,这些方法的返回语句均为return this

    new append(String str).append(return this;)

  • 由于改变封装字符串序列后又返回了该对象的引用,可以按照如下简介的方式书写代码

    public void testStringBuilder(){//StringBuilder对象的值改变前后地址不变StringBuilder buf = new StringBuilder("seecen");System.out.print(buf.hashCode());System.out.println(buf.append("牛逼").hashCode());buf.append("大神").insert(8,"爱装逼").replace(6,8,"学生");System.out.println(buf);//seecen学生爱装逼
    }
    

StringBuilder总结

  • StringBuilder是可变字符串,字符串的内容计算,建议采用StringBuilder实现,这样性能会好一些
  • Java的字符串连接过程是利用StringBuilder实现的
    String s = "AB";
    String s1 = s + "DE" + 1;
    //等同于
    String s2 = new StringBuilder(s).append("DE").append("1").toString();
    

StringBuilder和StringBuffer

  1. StringBuilder是非线程安全的,并发处理,性能稍快
  2. StringBuffer是线程安全的,同步处理,性能稍慢

正则表达式

基本正则表达式

正则表达简介

  • 实际开发中,经常需要对字符串数据进行一些复杂的匹配,查找,替换等操作.通过"正则表达式",就可以方便实现字符串的复杂操作

  • 正则表达式是一串特定字符(字符串数据类型),组成一个"规则字符串",这个"规则字符串"是描述文本规则的工具,正则表达式就是记录文本规则的代码

字符集合

正则表达式说明
[abc]a,b,c中任意一个字符
[^abc]除了abc以外的任意字符
[a-z]表示a-z中任意一个字符
[a-zA-Z0-9]表示a-z,A-Z,0-9中任何一个字符
[a-z&&[^bc]]a-z中除了b,c以外的任意一个字符,其中&&表示"与"关系

预定义字符集合

正则表达式说明
.任意一个字符
\d任意一个数字字符,相当于[0-9]
\w单词字符,相当于[a-zA-Z0-9_]
\s空白字符(并不是只有空格才会产生空白字符)
\D非数字字符
\W非单词字符
\S非空白字符

数量词

正则表达式说明
X?表示0个或1个X
X*表示1个或者任意多个X
X+表示1个到多个X(大于等于1)
X{n}表示n个X
X{n,}表示n个到任意多个X(大于等于n)
X{n,m}表示n个到m个X

练习
检索邮政编码
规则为6位数字
例如:330006
要求:写出匹配邮政编码的正则表达式

  1. [0-9][0-9][0-9][0-9][0-9][0-9]
  2. \d\d\d\d\d\d
  3. \d{6}

分组"()"

  • 分组():圆括号表示分组,可以将一系列正则表达式看做一个"整体",分组是可以使用"|"表示"或"关系

录入:匹配手机号码前面的区号:
+0086 12345678911
^(+86|0086)?(\s)*([0-9]{11})$

String 正则API

matches方法

matches(正则表达式)方法:将一个字符串与正则表达式进行匹配如果匹配成功则返回true,否则返回false
	String phone = "+86    12345678911";String phoneRegExp = "\\+86?\\s*\\d{11}";System.out.println(phone.matches(phoneRegExp));

“^“和”$”

  • 边界匹配
  • "^"代表字符串开始
  • "$"表示字符串结束
	public void testLimit(){//匹配用户名规则-从头到尾连续8~10个单词字符//String reg = "\\w{8,10}";String test = "abcd1234_abcd";//此时test是可以验证通过的,只要字符串存在连续8~10长度的单词字符即可通过验证String reg1 = "^\\w{8,10}$";//此时无法验证通过,要求字符串从头到尾必须符合正则表达式,对字符串整体存在限定boolean flag = test.matches(reg1);System.out.println(flag);//false}

Object

  • 在Java类继承结构中java.lang.Object类位于顶端
  • 如果定义一个Java类时没有使用extends关键字声明父类,则其父类默认为java.lang.Object
  • Object类型的引用可以指定任何类型的对象

    Object s1 = new 任意类型对象();

重写toString()方法

  • Object类中的重要方法,用于返回对象的值的字符串表示,原则上建议重写
    形式如下所示:
    public String toString(){return "Cell{"+"row="+ this.row+",col="+ this.col +"}";
    }
    
  • Java语言中很多地方会默认调用对象的toStirng方法
  • 字符串+对象,自动调用对象的toStirng方法
  • System.out.println(任意对象),直接调用toString()方法
  • 如果不重写toString方法将使用Object的toString方法,其逻辑:类的全称@散列码
  • toString方法是非常有用的调试工具
  • JDK中的标准类库中,许多类都定义了toString方法,方便用户获得有关对象状态的必要信息
  • String重写toString方法就是将自身返回
    public String toString(){return this;
    }
    

equals方法

  • Object中方法,作用在于检测一个对象是否对于另外一个对象
  • 在Object类中,这个方法判断两个对象是否具有相同的引用,即是否为相同的对象
  • 在实际中,一般需要重写该方法,通过比较对象的成员属性,使该方法更加有意义
  • 没有重写的equals方法等同于==

重写equals

public boolean equals(Object obj){if(obj==null){return false;}if(this == obj){return true;}if(obj instanceof Cell){Cell cell = (Cell)obj;return cell.row == this.row && cell.col == this.col;}else{retuen false;}
}

包装类

包装类概述

  • 在进行类型转换的范畴内,有一种特殊的转换,需要将int这样的基本类型转换为对象
  • 所以所有基本类型都有一个与之对应的类,即包装列类
  • 包装类是不可变的,在构造了包装类对象后,不允许更改包装在其中的值
  • 包装类是final的,不能定义他们的子类
基本类型包装类父类
intjava.lang.Integerjava.lang.Number
longjava.lang.Longjava.lang.Number
doublejava.lang.Doublejava.lang.Number
shortjava.lang.Shortjava.lang.Number
floatjava.lang.Floatjava.lang.Number
bytejava.lang.Bytejava.lang.Number
charjava.lang.Characterjava.lang.Object
booleanjava.lang.Booleanjava.lang.Object

Number及其主要方法

  • 抽象类Number 是Byte,Short,Integer,Long,Float,Double的父类

  • Number的子类必须要提供将表示的数值转换为byte,short,int,long,float,double的方法 ,例如:

      doubleValue()以double形式返回指定的数值intValue()以int形式返回指定的数组floatValue()以float形式返回指向的数组
    

包装类可以通过对应的方法将自己表示的值转换为6种基本类型

自动装箱和自动拆箱

  • 从Java5.0版本以后加入autoboxing功能
  • 自动"装箱"和"拆箱"是依靠JDK5的编译器在编译时的"预处理"工作
  • 例如下列代码写法均为正确形式:
    	Integer a = 100;//装箱Integer b = 200;//装箱Integer c = a+b;//先拆箱后装箱double d = c;//拆箱```
    

ps:一个基本类型可以转换为任意包装类型,但是可能会造成精度损失和溢出

Number d = 123.45;
Number n = 123;
//输出d和n对象所属类型
System.out.println(d.getClass().getName());//java.lang.Double
System.out.println(n.getClass().getName());//java.lang.Integer
int intValue = d.intValue();
double doubleValue = n.doubleValue();
//可以将基本类型包装成不同的类
double c = 123.45;
Double c1 = Double.valueOf(c);
Integer c2 = Integer.valueOf((int)c);
Long c3 = Long.valueOf((long)c);
  • 装箱和拆箱是"编译器"认可的,而不是虚拟机,编译器在生成字节码时插入必要的方法调用
  • 在进行自动装箱和拆箱的过程中,Integer的变量自动调用intValue,Double类型自动调用doubleValue,以此类推
  • 基本类型到包装类要遵循基本类型之间的转换关系
Integer.valueOf(12.12);//这要会报错
Double.valueOf(12);//这样可以

Integer常用功能

  • 该类提供了多个方法,能在int类型和String类型之间相互转换,还提供一些常量,例如:

static int MAX_VALUE // 值为2的31次方-1,表示int类型的最大值
static int MIN_VALUE // 值为-2的31次方,表示int类型的最小值

//Integer 的静态方法parseInt用于将字符串转换为int
String str = "123";
int value = Integer.parseInt(str);
System.out.println(value);
//转换的前提是str是一个数值类型字符串
str = "一二三四";//NumberFromatException;数据格式转换异常
value = Integer.parseInt(str);
System.out.print(value);
int
Integer
String

Double常用功能

在Double类的对象中包装一个基本类型double值
//构造方法
Double(double value)
Double(String str)

方法

  • double doubleValue() 返回此Double对象的double值
  • static double parseDouble (String str)返回一个新的double值,该值被初始化为用指令的String表示的值
String str = "12345.0000";
double value = Double.parseDouble(str);
System.out.println(value);//12345.0str = "12345.00";
value = Double.parseDouble(str);
//获取Double类型的对象
Double a = Double.valueOf(12.6);
//等价
Double b = new Double(12.6);
//等价
Double c = new Double("12.6");//将会自动将"12.6"转换为double类型的12.6
//其他包装类同理

包装类到基本类型

  • 包装类可以转换为6种基本类型,但需要显示的调用,否则也要遵循基本类型之间的转换关系
Integer a = 100;
//int b = a;
//double b = a.doubleValue();
double b = a.intValue();Double a1 = 100.0;
//double b1 = a1;
//int b1 = a1.intValue();
int b1 = a1.doubleValue();
int b1 = (int)a1.doubleValue();

在这里插入图片描述

SimpleDateFormat简介

  • java.text.SimpleDateFormat是一个与语言环境有关的方式来格式化和解析日期的具体类
  • 它允许进行格式(日期–>文本),解析(文本–>日期)和规范

构造方法

SimpleDateFormat()
SimpleDateFormat(String parrtern)用给定的模式和默认语言环境的日期格式符号构造SimpleDateFormat

方法

  • final String format(Date date) Date ⇒ String
  • Date parse (String sourse) throws ParseException String ⇒ Date

日期模式匹配字符

字符含义示例
yyyyy年------2013年;yy----13年
MMM月-----01月;M月—1月
ddd日–06日;d日----6日
aam或pm标识a—下午(PM)
H小时(24小时制)H时---- 13时
h小时(12小时制度)a h时----下午 12时
m分钟HH:mm:ss------12:23:12
shh(a):mm:ss-------12(下午):46:12

将String解析为Date

Date(Mon Apr 25 15:15:44 CST 2022) ⇒ SimpleDateFormat(HH:mm:ss)⇒ String 12:34:23

public void testParse() throws ParseException{//将String解析为Date//parse()方法用于按照特定格式将表示时间的String转换为Date对象String str = "2013-12-25";//创建SimpleDateFormatSimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");Date date = sdf.parse(str);System.out.println(date); /*try{Date date = sdf。parse(str);}catch(ParseException e){System.out.println("转不了");}*/
}

将Date格式化为String

public void testFormat(){Date date = new Date();//Wed Dec 25 00:00:00 CST 2013SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String dateStr = sdf.format(date);System.out.println(dateStr);//2022-4-24 16:21:10
}

Calendar简介

  • java.util.Calendar类用于封装日历信息,其主要作用在于其方法可以对时间分量进行运算
  • Calendar是抽象类,其具体子类针对不同国家的日历系统,其中应用最广泛的是GregorianCalendar(格里高历,阳历),对应世界上绝大多数国家/地区使用的标准日历系统

getInstance方法

  • Calendar 提供了一个类方法getInstance,以获取此类型的一个通用的对象
  • Calendar 的getInstance 方法会返回一个Calendar对象,其日历字段已由当前日期和时间初始化
  • Calenda c = Calendar.getInstance();
public void testGetInstance(){Calendar c = Calendar.getInstance();//输出Calendar对象所属的实际对象System.out.println(c.getClass()/getName());//getTime方法返回对应的Date对象System.out.println(c.getTime());//c.getTime()等同于new Date();//GregorianCalendar的默认信息System.out.println(c);//java.util.GregorianCalendar[time=1651026754258,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2022,MONTH=3,WEEK_OF_YEAR=18,WEEK_OF_MONTH=5,DAY_OF_MONTH=27,DAY_OF_YEAR=117,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=4,AM_PM=0,HOUR=10,HOUR_OF_DAY=10,MINUTE=32,SECOND=34,MILLISECOND=258,ZONE_OFFSET=28800000,DST_OFFSET=0]//创建GregorianCalendar并初始化GregorianCalendar c1 = new GregorianCalendar(2013,Calendar.DECEMBER,25);}

设置时间及分量

public void testSet(){Calendar c = Calendar.getInstance();c.set(Calendar.YEAR,2014);c.set(Calendar.MONTH,4);//表示当前月份数值加一c.set(Calendar.DATE,5);SimpleDateFormat sdf = new SimpleDateFormat("yyyy-HH-dd HH:mm:ss");System.out.println(sdf.format(c.getTime()));//如果不是设置时分秒,则默认为系统当前时间
}
  • void add(int intValu,int mount);为给定的时间分量的值加上给定的值,若给定的值为负数则是减去给定的值

获取时间及分量

  • final static int YEAR:指示年份的字段数字(1)
  • final static int MONTH:指示月份的字段数字(2)
  • final static int DATE:指示一个月中的第几天(3)
  • final static int DAY_OF _WEEK:指示一个星期的第几天(7)

使用方法:在get()方法中传入上面的常量

  • int getActualMaximum(int intValues): 传入calendar类的时间值(如:Calendar.DATE)返回给定日历字段的最大值
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR,2014);
for(int month = Calendar.JANURAY;month <= Calendar.DECEMBER;month++ ){c.set(Calendar.MONTH,month);System.out.println(c.getActualMaximum(Calendar.DATE) + " ");//输出2014年每个月的最大值
}

setTime 与getTime

  • Date getTime() : 使用Date描述Calendar表示的日期并返回
  • void setTime(Date date) : 使用Calendar表示Date所描述的日期
Calendar c = Calendar.getInstance();
Date date = new Date(1600800456332L);
c.setTime(date);

集合

List 和set

在实际开发中,需要将使用的对象存储与数据结构的容器中,JDK提供了这样的容器--------集合(Collection);Collection是一个接口,定义了集合相关的操作方法其有两个子接口List,set

  • List : 可以重复集
  • set : 不可重复集
  • 不可以放基本数据类型
  • set在判断是否重复时,会先调用hashCode方法,如果hashCode不存在则插入元素,如果hashCode存在则调用该对象类的equals方法,返回true则说明对象已经存在,返回false则插入元素。

集合持有对象的引用,集合中存储的都是引用类型元素,并且集合中只保存每个元素对象的引用,而并非将元素对象本身存入集合

集合对象
元素对象
元素对象
元素对象
元素地址
元素地址
元素地址
集合地址
Collection<Cell> cells = new ArraysList<Cell>();
cells.add(new Cell(1,3));
Cell cell = new Cell(33,2);
cells.add(cell);
System.out.println(cells);cell.drop();
System.out.println(cells);//输出发生改变(多个引用指向一个对象)
  • boolean add(E e) : 该方法将给定的元素添加进集合,若添加成功则返回true,否则返回false
  • boolean contains(Object object) : 该方法用于判断给定的元素是否包含在集合中,若包含则返回true,否则返回false .
Collection<String> c = new ArrayList<>();
c.add("a");
String str = "a";
System.out.println(c.contains(str));//true
  • int size() :返回当前集合中的元素的总数
  • void clear() : 清空当前集合
  • boolean isEmpty() : 判断当前集合是否包含任何元素
Collection<String> c = new HashSet<>();
c.add("a");
c.add("b");
c.add("a");
System.out.println(c.isEmpty);//false
System.out.println(c);//[a,b]
System.out.println(c.size());//2
c.clear();
System.out.println(c);//[]
  • boolean addAll(Collection<?extends E> c) : 该方法需要传入一个集合,并将该集合中的所有元素添加到当前集合中
  • boolean containsAll(Collection<?> c) : 判断当前集合是否包含给定集合中的所有元素,若包含则返回true
Collection<String> c1 = new ArrayList<>();
c1.add("a");
c1.add("b");
Collection<String> c2 = new ArrayList<>();
c2.addAll(c1);
System.out.println(c2);//[a,b]
Collection<String> c3 = new ArrayList<>();
c3.add("a");
System.out.println(c1.containAll(c3));//true

Iterator

迭代器用于遍历集合元素,获取迭代器可以使用Collection定义的方法(Iterator iterator()); 迭代器Iterator是一个接口,集合在重写Collection 的 iterator()方法是利用内部迭代器实现;Iterator提供了统一的遍历集合的方式,其提供了用于遍历集合的两个方法:

  • boolean hasNext() : 判断集合是否还有元素可以遍历
  • E next() : 返回迭代的下一个元素
Collection<String> c1 = new Hashset<>();
c1.add("a");
c2.add("b");Iterator<String> it = c1.iterator();
while(it.hasNext()){String str = it.next();System.out.println(str);
}
  • void remove() : 在使用迭代器遍历集合时,不能通过集合的remove() 删除元素,否则会抛出并发修改异常,我们可以通过迭代器自身提供的remove()来删除通过next()迭代出的元素;迭代器删除方法是在源集合中删除元素; 需要注意的是,在调用remove()前必须通过迭代器的next()迭代过元素,那么删除的就是这个元素,并且需要再次使用next()后才可以再次调用remove()
Collection<String> c1 =  new HashSet<>();
c1.add("a");
c1.add("b");Iterator<String> it = c1.iterator();
while(it.hasNext()){String str = it.next();if(str.startWith("a")){it.remove();}
} 

增强型for循环

Java5.0之后推出了一个新特性,增强for循环,也称为新循环,该循环不通用于传统的循环工作,其只用于遍历集合或数组;新循环并非新的语法,而是在编译过程中,编译器会将新循环转化为迭代器模式,所有新循环本质上是迭代器

for(元素类型 e : 集合或数组) {循环体
}Collection<String> c1 = new HashSet<>();
c1.add("a");for(String str : c1) {System.out.println(str);
}

泛型机制

泛型是JavaSE 5.0引入的特性,泛型的本质是参数化类型,在类,接口和方法的定义过程中,所操作的数据类型被传入的参数指定;Java泛型机制广泛的应用在集合框架中,所有集合类型都带有泛型参数,这样在创建集合时可以指定放入集合中元素的类型,Java编译器可以据此进行类型检查,这样可以减少代码在运行时出现的错误可能性

ArrayList类的定义中,中的E为泛型参数,在创建对象时可以将类型作为参数传递,此时类中定义的所有E将被替换为传入的参数

集合操作(线性表)

ArrayList和LinkedList :

  • List接口是Collection的子接口,用于定义线性表数据结构,

  • 可以将List理解为存放对象的数组,只不过其元素个数可以动态的增加或减少,

  • List接口的两个常见实现类ArrayList和LinkedList,分别用于动态数组和链表的方式实现了List接口,

  • 可以认为ArrayList和LinkedList方法在逻辑上完全一样,只是在性能上有一定的差别,ArrayList更适合用于随机访问而LinkedList更适合用于插入和删除

  • List : 定义线性表的数据结构,ArrayList 和LinkedList都是线性表结构(线性:有顺序,一个接一个)

  • ArrayList 和 LinkedList方法相同,对于调用者而言没有区别,但是底层逻辑不同,导致性能不同

ArrayList 和LinkedList的底层逻辑(底层结构)

  • ArrayList : 动态数组结构
    在这里插入图片描述

  • LinkedList : 链表结构

上述方法都是线性结构,都可以理解为:存放对象的数组,只不过可以动态改变
在这里插入图片描述

常用方法

List除了继承Collection定义的方法外,还根据其线性表的数据结构定义了一系列的方法,其中最常用的就是基于下标的get 和set方法:

  • E get(int index):获取集合中指定下标对应的元素,下标从0开始
  • E set(int index,E element) :将给定元素存入给定位置,并将原位置的元素返回
List<String> c1 = new ArrayList<>();
c1.add("a");
c1.add("b");
c1.set(0,c1.set(1,c1.get(0)));//交换a,b在集合中的位置
  • void add(int index,E element) : 将给定的元素插入到指定位置,原位置及后续元素都顺序向后移动
  • E remove(int index) : 删除给定位置的元素,并将被删除的元素返回
  • List subList(int fromIndex,int toIndex) : 用于获取子List,截取子List的首尾下标(前包括,后不包括); 需要注意的是,subList 获取的 List 与原 List 占有相同的存储空间,对子 List 的操作会影响原 List
List<Integer> c1 = new ArrayList<>();
for(int i = 0 ; i < 4; i++){c1.add(i);
}//c1:[0,1,2,3]
List<Integer> subList = c1.subList(1,3);//submit : [1,2]
subList.clear();//c1 :[0,3]

List转化为数组

List的toArray方法用于将集合转化为数组,但实际上该方法是Collectoin中定义,所以所有的集合都具备这个功能

  • 其中有两个方法:

    • Object[] toArray();
    • T[] ToArray(T[]a)

    其中第二个方法是比较常用的,我们可以传入一个指定类型的数组,该数组的元素类型应与集合的元素类型一致,返回值是转换后的数组

public void testListArray(){List<String> list = new ArrayList<String>();list.add("a");list.add("b");list.add("c");list.add("d");//Strin[] a1 = new String[]{};String strArr = list.toArray(new String[]{});//1.存入的数组相同可以指定长度,如果长度大于集合的元素个数,则转换后的数组长度与传入数组相同,并且使用null填充数组//2.如果传入的数组长度小于集合元素,则转换后的数组长度为集合元素的长度System.out.println(Arrays.toString(strArr));//[a,b,c,d]
}

数组转换为List

Arrays类中提供了一个静态方法asList,使用该方法我们将一个数组转换为对应的List集合

  • 其方定义为:
    • static list asList<T…a>
    • 返回的List的集合元素类型由传入是数组的元素类型决定
    • 并且要注意的是,返回的集合我们不能对其增删元素,否则会抛出异常,并且对集合的元素进行修改会影响数组对应的元素
public void testArrayToList(){String[] strArr = {"A","B","C","D"};List<String> list  = Array.asList(strArr);System.out.println(list);//list.add("E");//UnsupportedOprationExceptionSystem.out.println(list.getClass().getName());//java.util.Arrays$ArrayListList<String> list1 = new ArraysList<String>();list1.addAll(Arrays.asList(strArr));
}

List排序

Collections.sort方法实现排序
Collections是集合和工具类,它提供了很多便于我们操作集合的方法,其中就有操作集合排序的sort方法

  • 方法定义为:
    -void sort(list)

该方法的作用是对给定的集合元素进行自然排序

public void testSort(){List<Integer> list = new ArrayList<Integer>();Random r = new Random();for(int i = 0 ; i < 10 ;i++){list.add(r.nextInt(100))}System.out.println(list);Collections.sort(list);System.out.println(list);
}

Comparable

  • Collections 的sort方法是对集合元素进行自然排序,那么两个元素就一定要有大小之分.
  • 这个大小之分如何界定呢?
    • 实际上,在使用Collections的sort排序的集合都必须是Comparable接口的实现类,该接口表示其子类是可以比较的,因为实现该接口必须重写抽象方法

    int comparableTo(T t)
    该方法用于使用对象与给定对象进行比较
    若当前对象大于给定对象,那么返回值应为>0的整数
    若当前对象小于给定对象,那么返回值应为<0的整数
    若当前对象等于给定对象,那么返回值因为0

    List<Cell> list = new ArrayList<Cell>();
    list.add(new Cell(1,1));
    list.add(new Cell(5,5));
    list.add(new Cell(2,2));
    list.add(new Cell(3,3));
    list.add(new Cell(6,6));
    list.add(new Cell(4,4));
    System.out.println(list);
    Collections.sort(list);
    System.out.println(list)public class Cell implements Comparable<Cell>{@Overridepublic int compareTo(Cell o){return this.row - o.row;}
    }

Comparator

  • 一旦Java类实现了Comparable接口,其比较逻辑就已经确定,如果希望在排序的操作中临时指定比较规则,可以采用Comparator接口的回调方式
  • Comparator接口要求实现类必须重写其定义方法
  • int compare(T o1,T o2)
    • 该方法的返回值要求
    • 若o1 > o2则返回值应>0
    • 若o1 < o2则返回值应<0
    • 若o1 == o2则返回值应为0

List<Cell> list = new ArrayList<Cell>();
list.add(new Cell(8,1));
list.add(new Cell(4,5));
list.add(new Cell(2,2));
//按照col值的大小排序
Collections.sort(list,new Comparator<Cell>(){@Overridepublic int compare(Cell o1,Cell o2){return o1.getCol() - o2.getCol();}
});
System.out.println(list);

队列和栈

Queue

  • 队列(Queue)是常用的数据结构,可以将队列看成特殊的线性表,队列限制了对线性表的访问方式 : 只能从线性表的一段添加(offer)元素,从另一端取出(poll)元素
  • 队列遵循先进先出(FIFO:First input First Output)的原则
  • JDK中提供了Queue接口,同时使用LinkedList实现了该接口(选择LinkedList实现Queue的原因在于Queue经常需要进行添加和删除操作,而LinkedList在这方面效率比较高)

Queue接口主要方法

  • boolean offer(E e):将一个对象添加至队尾,如果添加成功则返回true
  • E poll() : 从队首删除并返回一个元素
  • E peek() : 返回队首元素(但并不删除)
public viod testQueue(){Queue<String> queue = new LinkedList<String>();queue.offer("a");queue.offer("b");queue.offer("c");queue.offer("d");System.out.println(queue);//[a,b,c,d]while(queue.size() > 0) {String str = queue.poll();System.out.println(str+" ")}System.out.println("最后" + queue);//空了
}

Deque

  • Deque是Queue的子接口,定位了所谓的"双端队列"即从队列的两端分别可以入队(offer)和出队(poll),LinkedList实现了该接口
  • 如果将Deque限制为只能从一端入队和出队,则可实现"栈(Stack)“的数据结构,对于栈而言,入栈称之为"push”,出栈称之为"pop"
  • 栈遵循先进后出(FILO:First Input Last Output)的原则

栈Stack

Java集合没有单独的Stack接口,因为有个遗留类的名字就叫Stack,出于兼容性考虑,没有办法创建Stack接口,能用Deque接口"模拟"一个Stack

当我们把Deque接口作为栈使用时,注意只调用push()/pop()/peek()方法,不要调用addFirst()/removeFirst()/peekFirst…

Deque<String> stack = new LinkedList<String>();
//先进后出
stack.push("a");
stack.push("b");
stack.push("c");
stack.push("d");
System.out.println(stack);//[d,c,b,a]
while(stack.size() > 0) {Stirng str = stack.pop();System.out.println(str + " ");//d c b a
}
System.out.println(stark);//[]

线性存储和链式存储的区别

  1. Java中线性存储的数据结构有 : 数组,ArrayList
    他们的优点是:查找访问快,缺点是在非末尾的位置删除和插入效率低
  2. Java中链表/表存储的数据结构有 : LinkedList
    它们的优点是: 插入和删除效率高,缺点是访问头尾的位置效率低

常用数据结构的理解

  • ArrayLisrt 和 LinkedList实现自List接口,基类接口为Collection
  • HashSet和TreeSet是实现自Set接口,基类接口为Collection
  • ArrayList 和 LinkedList 有序,可重复
  • HashSet无序,不可重复
  • TreeSet排序(存放的排序数据需要实现Comparable接口),不可重复

Map接口

Map接口定义的集合又称为查询表用于存储所谓"Key-Value"的映射对,Key可以看成是Value的索引,作为Key的对象在结合中不可以重复

根据内部数据结构的不同,Map接口有多种实现类,其中常用的有内部为hash表实现的HashMap和内部为排序二叉树实现的TreeMap.

小结:

  1. 存储是Key-Value形式
  2. Key不能重复

put()方法

  • Map接口中定义了向Map中存放元素的put方法

  • V put(K key,V value)

    • 将Key-Value对存入Map,如果在结合中已经包含该Key,则操作将替换该Key所对应的Value,返回值为Key原来所对应的Value(如果没有则返回null)

get()方法

  • Map接口定义了从Map中获取元素的get方法
  • V get(Object key)
  • 返回参数key所对应的Value对象,如果不存在则返回null

ConatinsKey()方法

  • Map接口中定义了判断某个key是否在Map中

  • boolean containsKey(Object key)

  • 若Map中包含给定的key则返回true,否则返回false

@Test
public void testPut(){Map<String,Emp> emplyees = new HashMap<String, Emp>();//向map中添加元素emplyees.put("张三",new Emp("张三",25,'男',5000));emplyees.put("李四",new Emp("李四",24,'女',3300));System.out.println(emplyees.size());Emp emp1 = emplyees.put("李四",new Emp("李四光",56,'男',300));System.out.println(emplyees.size());System.out.println(emp1);Emp emp2 =  emplyees.get("李四");System.out.println(emp2);boolean has = emplyees.containsKey("王二");System.out.println("是否有员工王二:" + has );}

在这里插入图片描述

hashCode()方法

  • 从HashMap的原理中我们可以看到,key的hashCode方法的返回值对HashMap存储元素时会起着很重要的作用,而hashCode()方法实际上是在Object中定义的,那么应该妥善重写该方法

  • 对于重写了equals方法的对象,一般要妥善的重写继承自Object类的hashCode()方法(Object提供的hashCode方法将返回该对象所在内存地址的整数形式)

  • 重写hashCode方法需要注意以下两点:

    • 其一,与equals方法的一致性,即equals比较返回true的两个对象其hashCode方法的返回值应该相同

    • 其二,hashCode返回的数值应该符合hash算法的要求,试想如果有很多对象的hashCode方法返回值都相同,则会大大降低hash表的效率,一般情况下可以使用IDE(如 Eclipse,idea提供的工具自动生成hashCode方法

目前的理解:

相同的类型==> hashCode值应该相等

缺点:数据一旦变大,会很大程度降低hash表的效率

查看重写的hashCode方法

  1. 是否根据对象的属性值进行重写

  2. hashCode方法中用到的属性是否也是equals比较时用到的属性

capacity:容量,hash表里的bucket(桶)的数量,也就是散列数组的大小

initial capacity:初始容量,创建hash表时,初始bucket的数量,默认构建容量是16

size : 大小,当前散列表中存储数据的数量

Loadfactor : 加载因子,默认值是0.75(也就是75%),当散列表增加数据时,如果size/capacity的值大于Loadfactor则发生扩容并且重新散列(rehash)

性能优化 : 加载因子较小时,散列查询性能会提高,同时也浪费散列桶空间容量,0.75是性能和空间相对平衡的结果,在创建散列表时指定合理容量,减少rehash提高性能

Map的遍历

使用keyset()方法

  • Map提供了三种遍历方式
  • 遍历所有的key
  • 遍历所有的key-value
  • 遍历所有的value(不常用)

遍历所有的Key

  • Set keySet()

该方法会将当前Map中所有的key存入一个Set集合后返回

//遍历Set<String>  keys  = map.keySet();for(String key:keys){System.out.println(key + ":" + map.get(key));}

遍历所有的键值对的方法

  • Set<Entry<K,V>> entrySet();

该方法会将当前Map中的每一组key-value对封装为一个Entry对象并存入一个Set集合后返回

//使用entrySet方法遍历
Set<Map.Entry<String,Integer>> entrys = map.entrySet();
for(Map.Entry<String,Integer> entry : entrys){System.out.println(entry.getKey()+":"+entry.getValue());
}

hashmap底层实现原理

  1. hashmap底层是由数组 + 链表 + 红黑树实现

  2. put原理

    1. 根据key计算hash,找到存储的数组位置
    2. 如果该位置为null,直接存储进去
    3. 如果不为null,判断key的equals是否相等,如果相等则覆盖并返回旧的数据,如果如果key不相等,那么会把新的数据以链表格式存储到该位置的末尾.当链表的长度超过8的时候会转换为红黑树(因为链表的长度太长没有红黑树高效).
  3. get原理

    1. 根据key计算hash,找到要获取数据的位置
    2. 判断位置是否为null,为null返回null
    3. 不为null,循环链表或红黑树逐个判断equals是否相等,相等返回值,否则返回null
  4. 扩容,默认hashmap底层大小为16,扩容因子为0.75,每次扩容2倍.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/49672.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于第三方支付,看这篇文章就够了!

随着移动支付的快速发展&#xff0c;第三方支付已经深度融入到生活中&#xff0c;如果生活在一二线城市&#xff0c;从吃饭、购物、看电影、菜市场买菜到搭公交地铁&#xff0c;你能想到的消费场景&#xff0c;基本都可以用移动支付解决。在这些便捷的背后都有第三方支付在支撑…

驭势科技携手大唐高鸿,打造无人驾驶车联网应用新格局

2021年2月22日&#xff0c;驭势科技与中国信科集团旗下大唐高鸿在北京正式签署战略合作协议。双方宣布将联合推动C-V2X与无人驾驶在技术、产品和行业解决方案的深度融合及产业生态构建&#xff0c;实现“全场景、真无人、全天候”无人驾驶的规模化运用。中国信科集团党委常委、…

大唐高鸿公安联网监控系统解决方案

为了落实科技强警战略&#xff0c;进一步提高公安信息化水平&#xff0c;公安部门的联网监控系统在近年来&#xff0c;得到了中央和公安部的高度重视。全国各地的公安机关都在加大投入&#xff0c;积极建设、完善公安网络。 作为承担社会治安管理职能、负责保一方平安重任的地市…

润和软件携手高鸿信安助力构建可信计算生态

近日&#xff0c;润和软件推出的企业级通用操作系统HopeStage与高鸿信安旗下产品CTRUST HTE 操作系统可信增强系统完成兼容性互认证。 经测试&#xff0c;企业级通用系统HopeStageV1.0与高鸿信安CTRUST HTE操作系统可信增强系统V2.0顺利适配&#xff0c;兼容良好&#xff0c;可…

扣非净利润三年亏超6亿元,高鸿股份接连“出售”资产

2021年&#xff0c;高鸿股份营业收入85.48亿元&#xff0c;同比增长21.81%&#xff1b;实现归属上市公司股东的净利润1535.85万元&#xff0c;同比大增112.63%&#xff0c;并且成功实现扭亏为盈&#xff08;2020年同期为亏损1.22亿元&#xff09;。 值得注意的是&#xff0c;虽…

高鸿股份去年净亏1.22亿/主业毛利率仅1.81%,车联网短期难救主

车联网行业备受关注的背景下&#xff0c;身处其中的上市公司&#xff0c;在表面光鲜的同时&#xff0c;实际日子并不好过。 2020年&#xff0c;高鸿股份实现营业收入70.18亿元&#xff0c;同比下滑了38.49%&#xff1b;实现归属母公司的净利润为亏损1.22亿元&#xff0c;同比大…

独立站怎么运营?独立站卖家日常需要做哪些工作?

独立站的运营工作是较为复杂的&#xff0c;尤其是对于新手卖家来说&#xff0c;就更为陌生了。很多卖家稀里糊涂做了一阵子&#xff0c;也没搞清楚究竟要做哪些工作。那我们今天就来系统性地聊一下&#xff0c;独立站卖家的日常工作有哪些&#xff1f; 1.订单处理 处理顾客订…

独立站运营必知:关于聊天机器人的十大好处

聊天机器人&#xff0c;是一种可以与用户聊天的计算机程序。它能通过发送自动消息、合成语音或提供决策按钮来模拟对话&#xff0c;还可以识别用户消息的意图并提供预设的回复。 简单来说&#xff0c;聊天机器人就是一个相对于人工客服的智能存在。它可以将客户代理从繁琐的重…

独立站站群的模式和运营思路笔记

独立站站群打法模式选择&#xff1a; 1、网站搭建数量&#xff0c;10个到500个不等。 2、单个站SKU数量&#xff0c;10到20个最合适。 3、每个站广告预算2K-5KUSD。 4、单站测试周期2-3周。 独立站站群运营的思路&#xff1a; 1、选品&#xff0c;收集情报&#xff0c;市…

【独立站运营】做社交媒体营销的两大关键点

一&#xff0e;花时间研究你的目标受众 做假设对营销人员来说是个坏消息。只有55%的营销人员使用社交数据来更好地了解他们的目标受众&#xff0c;这对领导者和从业者来说都是一个巨大的机会。记住&#xff1a;不同的平台吸引不同的受众。 以今天的社交媒体人口统计学为例。这…

做传统外贸,为什么要搭建独立站?

关于传统外贸建设独立站的原因&#xff0c;米贸搜索整理如下&#xff0c;希望对您有所帮助: 01. 什么是外贸独立站&#xff1f; 外贸独立站是不同于第三方平台网站&#xff08;阿里国际站、中国制造网络等&#xff09;的总称。由企业自行建设、设计和运营&#xff0c;网站的所有…

超实用干货!独立站怎么运营?

众所周知&#xff0c;独立站是卖家可以拥有自己的独立网站&#xff0c;不需要依赖第三方平台进行经营&#xff0c;也是卖家们的出路之一。独立站除了会帮助跨境卖家树立品牌形象以外&#xff0c;还可以帮助卖家提高销售业绩。在如今的跨境电商行业&#xff0c;独立站是不可或缺…

独立站运营 | Shopify店铺使用聊天机器人的好处

通常用户在网购的时候&#xff0c;如果我们的Shopify店铺有即时聊天工具的话用户体验就会好很多&#xff0c;用户关于产品&#xff0c;物流&#xff0c;付款方式等方面的问题都可以直接在线询问&#xff0c;这时候如果Shopify卖家也能够做到及时回复的话&#xff0c;那么毫无疑…

识图在线识图_以图搜图在线搜索软件

各位在找一张图片的时候会不会常常因为不知晓出处而烦恼&#xff0c;现在推荐各位使用一个可以以图搜图的在线搜索利器&#xff0c;当然好不好用&#xff0c;大家可以尽情的尝试&#xff0c;如果好用记得点个好评&#xff0c;废话不多说&#xff0c;下面开始介绍搜索软件&#…

实现了一个简单的以图搜图功能(带代码)

不用训练&#xff0c;直接用在ImageNet上训练的RestNet网络就可以做一个简单的以图搜图功能 1、RestNet网络 上面是resnet网络的结构图&#xff0c;ImageNet是一个有1000类的数据集&#xff0c;我们可以把在该数据集上训练过的Resnet网络当成特征提取器&#xff0c;用来提取图…

如何实现以图搜图

一、前言 在许多搜索引擎中&#xff0c;都内置了以图搜图的功能。以图搜图功能&#xff0c;可以极大简化搜索工作。今天要做的就是实现一个以图搜图引擎。 我们先来讨论一下以图搜图的难点&#xff0c;首当其冲的就是如何对比图片的相似度&#xff1f;怎么样的图片才叫相似&a…

基于内容的图像检索引擎(以图搜图)

基于内容的图像检索引擎(以图搜图) 本文介绍一些基于内容的图像检索技术(Content-Based Image Retrieval,CBIR)的搜索引擎(即以图搜图),这类搜索引擎基本上代表了图像检索和识别的主流技术,其中有些搜索引擎的检索结果融合了多模态的检索(文本、图片内容、上下文等)…

基于深度学习的以图搜图

使用预训练的卷积神经网络提取图片中的特征&#xff0c;生成特征向量。利用图片库中所有图片数据构建 <id, feature vector> 数据。使用 Faiss 创建 Index &#xff0c;利用 <id, feature vector> 数据生成索引。针对待检索图片&#xff0c;使用模型提取图片特征向…

搜索技术之--以图搜图

以图搜图&#xff0c;是通过搜索图像文本或者视觉特征&#xff0c;为用户提供互联网上相关图形图像资料检索服务的专业搜索引擎系统&#xff0c;是搜索引擎的一种细分。通过输入与图片名称或内容相似的关键字来进行检索&#xff0c;另一种通过上传与搜索结果相似的图片或图片UR…

二箱:比谷歌识图更全面,多引擎以图搜图工具

NooBox 二箱 在主流搜索引擎上&#xff0c;如今都已增加了以图搜图功能&#xff0c;大大提高了图片搜索的效率。 以谷歌为例&#xff0c;在谷歌图片的搜索栏中点击图片标识&#xff0c;就可以选择粘贴图片网址或上传本地图片来进行识图。 但一个搜索引擎的图库往往难以满足用户…