JavaSE第13篇:常用API、冒泡排序、二分查找、正则

编程

第一章:Object类

1.1-概述(了解)

java.lang.Object类是Java语言中的根类,每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。

如果一个类没有特别指定父类, 那么默认则继承自Object类。例如:

public class MyClass /*extends Object*/ {

// ...

}

1.2-本地方法(了解)

在Object类的源码中定义了native修饰的方法,native修饰的方法称为本地方法。

本地方法的特点:

  • 被native修饰的方法,非Java语言编写,是由C++语言编写。
  • 本地方法在运行时期进入本地方法栈内存,本地方法栈是一块独立内存的区域。
  • 本地方法的意义是和操作系统进行交互。

如Object类中部分源码:

private static native void registerNatives();

static {

registerNatives();

}

当程序运行的时候,Object类会最先被加载到内存中。类进入内存后首先加载自己的静态成员,static代码块中调用了本地方法registerNatives(),和操作系统进行交互。

查看Object类源码:在IDEA编辑器中,新建一个类,在类中一个main方法中new Object(),鼠标停留在Object类上,按住ctrl + 点击鼠标,进入Object类源码中。

1.3-toString方法(理解)

认识toString方法

方法声明:public String toString():返回该对象的字符串表示。

Object类toString()方法源码:

public String toString() {

return getClass().getName() + "@" + Integer.toHexString(hashCode());

}

源码分析:

  • getClass().getName()返回类的全限定名字。
  • hashCode()方法返回int值,可以暂时理解为对象的内存地址。
  • Integer.toHexString()将int类型的值转成十六进制。
  • 因此调用对象的toString()方法将看到内存的地址值。

创建Person类,并调用方法toString()

public static void main(String[] args){

Student stu = new Student();

String str = stu.toString();

System.out.println(str); // www.penglei666.com.demo01.Student@5f2050f6

System.out.println(stu); // www.penglei666.com.demo01.Student@5f2050f6

}

通过程序运行,得到结论,在输出语句中打印对象,就是在调用对象的toString()方法。

重写toString方法

由于toString方法返回的结果是内存地址,而在开发中,内存地址并没有实际的应用价值,经常需要按照对象的属性得到相应的字符串表现形式,因此也需要重写它。

public class Student {  

private String name;

private int age;

@Override

public String toString() {

return "Student:" + name + "," + age;

}

// 省略构造器与Getter Setter

}

1.4-equals方法(理解)

认识equals方法

方法声明:public boolean equals(Object obj):指示其他某个对象是否与此对象“相等”。

Object类equals()方法源码:

public boolean equals(Object obj) {

return (this == obj);

}

源码分析:

  • this是当前对象,哪个对象调用的equals方法就表示哪个对象。
  • obj表述传递的参数,参数类型Object,可以传递任意类型对象。
  • this==obj 比较两个对象的内存地址是否相同

equals方法默认比较两个对象的内存地址是否相同,相同则返回true。

重写equals方法

实际应用中,比较内存地址是否相同并没有意义,我们可以定义对象自己的比较方式,比较对象中成员变量的值是否相同。需要对方法进行重写。

需求:重写equals()方法,比较两个对象中姓名和年龄是否相同,如果姓名和年龄都相同返回true,否则返回false。

public class Person {

private String name;

private int age;

public boolean equals(Object obj){

//判断两个对象地址弱相同,即为同一个对象

if(this == obj)

return true;

//obj对象为空,无需比较,返回false

if(obj == null)

return false;

//obj如果是Person类型对象,则强制转换

if(obj instanceof Person){

Person person = (Person)obj;

//比较两个对象的name属性和age属性,如果相等,返回true

return this.name.equals(person.name) && this.age == person.age;

}

return false;

}

}

第二章:日期操作类

2.1-Date类(记忆)

构造方法

  • public Date():从运行程序的此时此刻到时间原点经历的毫秒值,转换成Date对象,分配Date对象并初始化此对象,以表示分配它的时间(精确到毫秒)。
  • public Date(long date):将指定参数的毫秒值date,转换成Date对象,分配Date对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即1970年1月1日00:00:00 GMT)以来的指定毫秒数。

public class Test01 {

public static void main(String[] args) {

Date date = new Date();

System.out.println(date); // Fri Jul 31 11:59:20 CST 2020

Date date2 = new Date(0);

System.out.println(date2); // Thu Jan 01 08:00:00 CST 1970

}

}

常用方法

  • public long getTime() 把日期对象转换成对应的时间毫秒值。
  • public void setTime(long time) 把方法参数给定的毫秒值设置给日期对象。

public class Test02 {

public static void main(String[] args) {

Date date = new Date();

System.out.println(date.getTime()); // 1596168137169

date.setTime(15961681371611L);

System.out.println(date); // Tue Oct 22 00:22:51 CST 2475

}

}

毫秒值(时间戳)和日期对象互相转换

日期对象转换为毫秒值:日期对象.getTime();

毫秒值转换为日期对象:new Date(long time);

获取当前时间的毫秒值:System.currentTimeMillis()

public class Test02 {

public static void main(String[] args) {

// 从1970年到现在的总毫秒值(也叫时间戳)

long millis = System.currentTimeMillis();

System.out.println(millis); // 1596168719242

// 毫秒值转日期对象

Date date = new Date(millis);

System.out.println(date); // Fri Jul 31 12:11:59 CST 2020

// 日期对象转毫秒值

long millis2 = date.getTime();

System.out.println(millis2); // 1596168719242

}

}

2.2-DateFormat类(记忆)

概述

java.text.DateFormat 是日期/时间格式化子类的抽象类,我们通过这个类可以帮我们完成日期和文本之间的转换,也就是可以在Date对象与String对象之间进行来回转换。

  • 格式化:按照指定的格式,把Date对象转换为String对象。
  • 解析:按照指定的格式,把String对象转换为Date对象

构造方法

由于DateFormat为抽象类,不能直接使用,所以需要常用的子类java.text.SimpleDateFormat。这个类需要一个模式(格式)来指定格式化或解析的标准。构造方法为:

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

参数pattern是一个字符串,代表日期时间的自定义格式。

常用的格式规则为:

标识字母(区分大小写)

含义

y

M

d

H

m

s

备注:更详细的格式规则,可以参考SimpleDateFormat类的API文档。

转换方法

  • String format(Date date) 传递日期对象,返回格式化后的字符串。
  • Date parse(String str) 传递字符串,返回日期对象。

  public static void main(String[] args) throws ParseException {

// 创建当前日期对象

Date date = new Date();

// 创建格式化对象

DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

String dateStr = format.format(date);

System.out.println(dateStr); // 2019-12-07 05:37:53

// 把格式化日期转换为日期对象

Date date2 = format.parse("2100-12-12 12:12:12");

System.out.println(date2); // Sun Dec 12 00:12:12 CST 2100

}

2.3-Calendar类(记忆)

概述

java.util.Calendar是日历类,在Date后出现,替换掉了许多Date的方法。该类将所有可能用到的时间信息封装为静态成员变量,方便获取。日历类就是方便获取各个时间属性的。

获取日历对象

Calendar是抽象类,不能创建对象,需要使用子类对象。java.util.GregorianCalendar类是Calendar的子类,但是创建日历对象需要根据本地的时区,语言环境来创建,比较困难,Calendar类提供了静态方法 getInstance()直接获取子类的对象。

public static Calendar getInstance():使用默认时区和语言环境获得一个日历。

  public static void main(String[] args) {

// 获取日历对象

Calendar calendar = Calendar.getInstance();

}

常用方法

常用方法

  • public int get(int field):返回给定日历字段的值。
  • public void set(int field, int value):将给定的日历字段设置为给定值。
  • public abstract void add(int field, int amount):根据日历的规则,为给定的日历字段添加或减去指定的时间量。
  • public Date getTime():返回一个表示此Calendar时间值(从历元到现在的毫秒偏移量)的Date对象。

field:Calendar类中提供很多成员常量,代表给定的日历字段:

字段值

含义

YEAR

MONTH

月(从0开始,可以+1使用)

DAY_OF_MONTH

月中的天(几号)

HOUR

时(12小时制)

HOUR_OF_DAY

时(24小时制)

MINUTE

SECOND

DAY_OF_WEEK

周中的天(周几,周日为1,可以-1使用)

代码:

  public static void main(String[] args) {

// 获取日历对象

Calendar calendar = Calendar.getInstance();

// 获取当前日期的部分数据

System.out.println(calendar.get(Calendar.YEAR));

System.out.println(calendar.get(Calendar.MONTH)); // 月份 0-11

System.out.println(calendar.get(Calendar.DAY_OF_MONTH));

System.out.println(calendar.get(Calendar.HOUR_OF_DAY));

System.out.println(calendar.get(Calendar.MINUTE));

System.out.println(calendar.get(Calendar.SECOND));

System.out.println(calendar.get(Calendar.DAY_OF_WEEK));

}

练习

需求:获取任意一年的二月有多少天

分析:

  • 可以将日历设置到任意年的三月一日
  • 向前偏移一天
  • 获取偏移后的日历即可

代码:

public static void main(String[] args) {

//键盘录入任意的年份

Scanner sc = new Scanner(System.in);

System.out.println("请输入年:");

int year = sc.nextInt();

//设置日历对象的年、月、日

Calendar c = Calendar.getInstance();

c.set(year, 2, 1);

//3月1日往前推一天,就是2月的最后一天

c.add(Calendar.DATE, -1);

//获取这一天输出即可

int date = c.get(Calendar.DATE);

System.out.println(year + "年的2月份有" + date + "天");

第三章:System类

3.1-概述(了解)

java.lang.System类中提供了大量的静态方法,可以获取与系统相关的信息或系统级操作。System类私有修饰构造方法,不能创建对象,直接类名调用。

3.2-常用方法(记忆)

3.3-测试程序运行时长(练习)

需求:在控制台输出1-10000,计算这段代码执行了多少毫秒

public static void main(String[] args) {

//获取当前时间毫秒值

System.out.println(System.currentTimeMillis());

// 计算程序运行时间

long start = System.currentTimeMillis();

for (int i = 1; i <= 10000; i++) {

System.out.println(i);

}

long end = System.currentTimeMillis();

System.out.println("共耗时毫秒:" + (end - start));

}

3.4-arryCopy方法(记忆)

参数

  • Object src:要复制的数据源数组
  • int srcPost:数据源数组的开始索引
  • Object dest:复制后的目的数组
  • int destPos:目的数组开始索引
  • int length:要复制的数组元素的个数

代码

将源数组中从1索引开始,复制3个元素到目的数组中

public static void main(String[] args){

int[] src = {1,2,3,4,5};

int[] dest = {6,7,8,9,0};

//将源数组中从1索引开始,复制3个元素到目的数组中

System.arraycopy(src,1,dest,0,3);

for(int i = 0 ; i < dest.length;i++){

System.out.println(dest[i]);

}

3.5-gc方法(了解)

运行垃圾回收器,JVM将从堆内存中清理对象,清理对象的同时会调用对象的finalize()方法,JVM的垃圾回收器是通过另一个线程开启的,因此程序中的效果并不明显。

Person类

public class Person {

protected void finalize() throws Throwable {

System.out.println("对象被回收");

}

测试类:

public static void main(String[] args){

new Person();

new Person();

new Person();

new Person();

new Person();

new Person();

System.gc();

}

第四章:数组的冒泡排序

数组的排序,是将数组中的元素按照大小进行排序,默认都是以升序的形式进行排序,数组排序的方法很多,我们讲解的是数组的冒泡排序。

排序,都要进行数组 元素大小的比较,再进行位置的交换。冒泡排序法是采用数组中相邻元素进行比较换位。

4.1-什么是冒泡排序(了解)

冒泡排序(Bubble Sort),是一种较简单的排序算法。

它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。

这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。

实 质:把小(大)的元素往前(后)调

4.2-冒泡排序的分析和实现(练习)

需求

对数组 { 3, 6, 4, 2, 1, 5 } 进行从小到大的排序。

该数组共6个元素。

图解冒泡算法解析过程

代码实现

经上述图解分析:代码实现需要

  1. 双重循环

    • 外层循环,控制躺数(躺数从0开始,因为数组索引从0开始,比较好计算)。 躺数 = 数组长度 - 1
    • 内层循环,控制每趟比较的次数。每趟比较的次数 = 数组的长度 - 当前躺数 - 1

  2. 比较相邻的两个数字,若位置错误,则两个数字交换

public class Test06 {

public static void main(String[] args) {

// 定义要排序的数组

int[] arr = {3, 6, 4, 2, 1, 5};

System.out.println("数组排序前:" + showArray(arr));

/**

* 冒泡排序

*/

for (int i = 0; i < arr.length - 1; i++) {

// 外层循环控制躺数

// i表示当前躺数

for (int j = 0; j < arr.length - i - 1; j++) {

// 内层循环控制每趟比较的次数

// 相邻的两个数字开始比较:arr[j] 和 arr[j+1]

if (arr[j] > arr[j + 1]) {

// 位置错误发生交换

int temp = arr[j];

arr[j] = arr[j + 1];

arr[j + 1] = temp;

}

}

}

System.out.println("数组排序后:" + showArray(arr));

}

/**

* 查看数组

*/

public static String showArray(int[]arr) {

StringBuilder sb = new StringBuilder();

sb.append("{ ");

for (int i = 0; i < arr.length; i++) {

if (i == arr.length - 1) {

sb.append(arr[i]);

} else {

sb.append(arr[i] + ", ");

}

}

sb.append(" }");

return sb.toString();

}

}

执行结果:

/*

数组排序前:{ 3, 6, 4, 2, 1, 5 }

数组排序后:{ 1, 2, 3, 4, 5, 6 }

*/

第五章:数组的二分查找

目的:从数组中查询一个元素,比较高效的查询方式,就是二分查找。

5.1-什么是二分查找(了解)

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法,但是,折半查找要求查询的数组的元素是有序排列的。

查找过程如下:

  • 首先,假设数组中的元素是按升序排列;

  • 将数组中间位置记录的元素值与要查找的元素值比较,如果两者相等,则查找成功;

  • 否则利用中间位置的记录将数组分成前、后两个子数组;

  • 如果中间位置记录的元素值大于要查找元素值,则进一步查找前一子数组,否则进一步查找后一子数组。

  • 重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

5.2-二分查找的分析和实现(练习)

需求:

从数组{ 2, 5, 9, 10, 18, 20, 24 }中分别查询出元素5203

折半查找,不能简单的除以2,需要确认最小索引和最大索引。因为可能会多次折半(一次 折半可能查找不成功),索引最小索引和最大索引可能会变化。所以需要确定以下变量:

最小索引:min = 0

最大索引:max = 数组的长度 - 1

中间索引:(max + min)/2

图解分析

图解分析查询元素5的过程:

图解分析查询元素20的过程:

图解分析查询元素3(一个不存在的元素)的过程:

结论

对于要查询的元素:

  1. 折半次数不确定(可能是多次),使用while循环更简便。
  2. 折半过程中,若查询的值小于mid位置的值,则更改索引max为:max = mid - 1
  3. 折半过程中,若查询的值大于mid位置的值,则更改索引min为:min = mid + 1
  4. 查询成功,要查询的元素 和 mid值相等时,终止查询。
  5. 元素中不存在该元素,条件是索引min大于索引max时,终止查询。

代码

public class Test06 {

public static void main(String[] args) {

// 定义数组

int[]arr = { 2, 5, 9, 10, 18, 20, 24 };

// 查询元素5

int index1 = binarySearch(arr,5);

System.out.println("从数组:{ 2, 5, 9, 10, 18, 20, 24 }查询元素5的索引是:" + index1);

// 查询元素20

int index2 = binarySearch(arr,20);

System.out.println("从数组:{ 2, 5, 9, 10, 18, 20, 24 }查询元素20的索引是:" + index2);

// 查询元素3

int index3 = binarySearch(arr,3);

System.out.println("从数组:{ 2, 5, 9, 10, 18, 20, 24 }查询元素3的索引是:" + index3);

}

/**

* 二分查找,返回要查找的元素的索引

* @param arr 数组

* @param key 要查询的元素值

* @return 查询的结果,-1表示不存在该元素

*/

public static int binarySearch(int[]arr, int key) {

// 最小索引初始化为0

int min = 0;

// 最大索引初始化为数组的长度 -1

int max = arr.length - 1;

// 中间索引

int mid = 0;

// 定义查询后的元素的索引,默认为-1,表示不存在该元素

int index = -1;

// 循环查询

while (min <= max){

mid = (max + min)/2;

if(key > arr[mid]) {

min = mid + 1;

}else if(key < arr[mid]){

max = mid - 1;

}else {

index = mid;

break;

}

}

return index;

}

}

查询结果:

/*

从数组:{ 2, 5, 9, 10, 18, 20, 24 }查询元素5的索引是:1

从数组:{ 2, 5, 9, 10, 18, 20, 24 }查询元素20的索引是:5

从数组:{ 2, 5, 9, 10, 18, 20, 24 }查询元素3的索引是:-1

*/

第六章:Arrays类

我们发现操作数组时,不论是排序、二分查找等,每次实现都需要自己分析写代码。在开发过程中,影响开发效率。所以Java中提供了操作数组的工具类Arrays。

6.1-概述(了解)

java.util.Arrays 此类包含用来操作数组的各种方法,比如排序和搜索等。Arrays类私有修饰构造方法,其所有方法均为静态方法,调用起来非常简单。

6.2-常用方法(记忆)

了解更多方法可查询API

    public static void main(String[] args) {

// 定义数组

int[]arr = { 2, 9, 5, 10, 24, 20, 18 };

// 排序

Arrays.sort(arr);

// 排序后的数组

System.out.println(Arrays.toString(arr));

// 二分查找元素5的索引

System.out.println(Arrays.binarySearch(arr,5));

// 二分查找元素20的索引

System.out.println(Arrays.binarySearch(arr,20));

// 二分查找元素3的索引

System.out.println(Arrays.binarySearch(arr,3));

}

第七章:正则表达式

在实际开发中,我们经常会对一些字符串做验证,比如验证邮箱格式、手机号码、身份证号码等。此时,最有效的验证方式就是正则表达式,只需要用正则描述验证规则,然后直接匹配字符串即可。

7.1-概述(了解)

正则表达式是对字符串操作的一种规则,事先定义好一些字符串,这些字符串称为规则字符串,使用规则字符串表达一些逻辑功能。

例如:指定一个字符串704181501@qq.com,判断出这个字符串是否符合电子邮件的规则。使用字符串String对象的方法是可以完成的,但是非常复杂,若使用正则表达式则会非常的简单实现。

7.2-正则规则-字符类(记忆)

在中括号中定义的字符

7.3-正则规则-预定义字符类(记忆)

预定义字符,具有特殊含义的字符。

注意:对于w、d、W、D 在java中表示时用双杠如\w表示,因为在java的字符串中表示转义。

7.4-正则规则-数量词(记忆)

7.5-正则规则-分组(记忆)

分组,就是将多个字符看做一个整体,用小括号表示。

比如:"(李){4}" 表示字符“李”必须出现四次

比如:"(李小龙){4}" 表示字符"李小龙"必须连续出现四次

7.6-正则规则-转义符(记忆)

对于,具有特殊含义的字符若表示为普通字符,可以使用转义符,如.就在正则中表示任意字符,但若就是表示为普通的点的话,则需要转义. java字符串中表示用\.

7.5-Java中使用正则表达式(练习)

String类matches方法使用正则表达式

**方法:boolean matches(String regex)**传递正则表达式规则,检测字符串是否匹配正则表达式规则,匹配返回true。

需求:检查手机号,检查邮件地址。

分析:

  • 手机号:只能1开头,第二位可以是345678任意一个,第三位开始全数字,总长11位。
  • 邮件地址:@前面可以是数字,字母,下划线。@后面是字母和.。

public static void main(String[] args){

//【验证手机号码】

String tel = "13800138000";

// 规则

String telRegex = "1[345678][0-9]{9}";

// 检测

boolean flag = tel.matches(telRegex);

System.out.println(flag);

//【验证邮件地址】

String email = "lpl2015@vip.qq.com";

String emailReg = "\w+@(\w+\.)+\w+";

flag = email.matches(emailReg);

System.out.println(flag);

}

String类split方法使用正则表达式

**方法:String[] split(String regex)**传递正则表达式规则,以正则规则对字符串进行切割,返回数组。

public static void main(String[] args){

String str1 = "ab a bbb abc aa c";

//对空格进行切割

String[] strArr =str1.split(" +");

System.out.println(Arrays.toString(strArr));

String str2 = "192.168.1.121";

strArr = str2.split("\.");

System.out.println(Arrays.toString(strArr));

}

注意:输出数组元素时会看到存在一个多余空格,Arrays.toString()方法源码中追加的空格。

以上是 JavaSE第13篇:常用API、冒泡排序、二分查找、正则 的全部内容, 来源链接: utcz.com/z/518995.html

回到顶部