【JavaSE 第十三天】
一、 StringBuilder 类的常用方法
1. 常用方法
StringBuilder append(任意类型)
参数追加形成字符串,无论参数写的是什么,变成字符串。相当于是字符串里面的“+” 运算
/**
* StringBuilder 类的方法 append 追加字符串
*/
public static void builderAppend(){
StringBuilder builder = new StringBuilder();
// 方法append追加字符串
builder.append(100);
builder.append(5.8);
builder.append(true);
System.out.println("builder = " + builder); // 最终结果就是字符串
}
- 方法调用链,链式编程 :
链式编程使用方法:保证一个方法的返回值是一个对象,再使用这个对象调用的调用方法:对象.方法().方法().方法()......
链式编程开发中较为常见,代码量较少
/**
* StringBuilder 类的应用,方法调用链
*/
public static void builderAppend(){
StringBuilder builder = new StringBuilder();
// 方法 append() 返回值是 StringBuilder (返回的是 StringBuilder 这个类)
// return this 返回值是 this (谁调用,我就是谁)
builder.append("hehe").append(false).append(1.5).append(1); // 执行的结果,是 builder 对象,所以可以继续使用 builder 对象调用方法
// 这种调用方式就是调用链
System.out.println("builder = " + builder);
}
StringBuilder insert(int 索引, 任意类型)
可以将任意类型的参数,插入到字符串缓冲区,需要指定索引。
/**
* StringBuilder 类的方法 insert,指定位置,插入元素
*/
public static void builderInsert(){
StringBuilder builder = new StringBuilder();
builder.append("bcdef");
// 指定的索引上,添加字符串,原有字符,往后顺延
builder.insert(2,"QQ");
// 不能写出索引范围,会发生越界异常,但是可以紧接着最后一个索引写,比如在这里可以写 5,即在最后一位字符之后添加字符
System.out.println("builder = " + builder);
}
-
StringBuilder 类的其它方法
int length()
返回字符串缓冲区的长度StringBuilder delete(int start,int end)
删除缓冲区中的字符,包含开头索引,不包含结束索引(在 Java 中一般都是包含开头索引,不包含结束索引)void setCharAt(int 索引,char ch)
修改指定元素上的字符,没有返回值StringBuilder reverse()
翻转字符串
public static void main(String[] args) {
buildMethod();
}
/**
* StringBuilder 类的其他方法
*/
public static void buildMethod(){
StringBuilder builder=new StringBuilder();
builder.append("abcdef");
// 1.字符串缓冲区的长度
int length= builder.length();
System.out.println("length = " + length); // 不是数组长度
// 2.删除缓冲区中的字符
builder.delete(0,2);
System.out.println("builder = " + builder);
// 3.修改指定元素上的字符,没有返回值
builder.setCharAt(1,'D');
System.out.println("builder = " + builder);
// 4.翻转字符串缓冲区
builder.reverse();
System.out.println("builder = " + builder);
}
2. StringBuilder 对象 和 String 对象的互转
(1) String 对象转成 StringBuilder 对象
- String 对象转成 StringBuilder 对象 String → StringBuilder
- StringBuilder 类的构造方法
StringBuilder(String str)
- append 方法
append(String str)
- StringBuilder 类的构造方法
/**
* String → StringBuilder
*/
public static void stringToStringBuilder(){
// 1.使用构造方法转换
StringBuilder builder = new StringBuilder("abc");
// 2.使用对象方法 append 转换
builder.append("hello");
}
(2) StringBuilder 对象转成 String 对象
- StringBuilder 对象转成 String 对象 StringBuilder → String
- StringBuilder 的方法
toString()
- String 类的构造方法
- StringBuilder 的方法
/**
* StringBuilder → String
*/
public static void stringBuilderToString(){
StringBuilder builder = new StringBuilder();
builder.append("我是字符串的缓冲区");
// 1. builder 对象转成 String 对象,调用 builder 对象的方法 toString()
String str = builder.toString();
// 由 StringBuilder 中可以改变的字符串 转换为 String 中不可以更改的字符串
System.out.println(str);
// 2. String 类的构造方法
String s = new String(builder);
// 由 StringBuilder 中可以改变的字符串 转换为 String 中不可以更改的字符串
System.out.println(s);
}
二、 System 类
System 是系统类:定义在 java.lang 包中
-
这个类定义了大量常用的字段(成员变量)和方法,该类不能实例化对象,不能使用 new 创建对象,因为类中的成员全部都是静态修饰,使用类名直接调用。
-
System 类中全部都是静态成员,无需对象创建,直接类名调用,该类的构造方法(构造器)被 private 修饰,第一行 super 操作继承 Object 类
1. System 类的方法
static long currentTimeMillis()
返回自1970年1月1日,午夜零时,到你程序运行的这个时刻,所经过的毫秒值,1000毫秒=1秒
/**
* static long currentTimeMillis()
* 返回自1970年1月1日,午夜零时,到你程序运行的这个时刻,所经过的毫秒值
* 1000毫秒=1秒
*/
public static void systemCurrentTimeMillis(){
long timeMillis = System.currentTimeMillis();
System.out.println("timeMillis = " + timeMillis);
}
-
static void arrayCopy(Object src,int srcPos,Object dest, int destPos,int length)
复制数组的元素- src:要赋值的数据源,源数组
- srcPos:源数组的开始索引
- dest:要复制的目标数组
- destPos:目标数组的开始索引
- length:要复制的元素个数
public static void systemArraycopy(){
int[] src = {1,3,5,7,9};
int[] dest = {2,4,6,8,0};
// 数组元素的赋值:src 数组中的 3,5 复制到 dest 数组中从 0 索引开始
System.arraycopy(src,1,dest,0,2);
for(int x = 0 ; x < src.length ;x++ ){
System.out.println(dest[x]); // 打印获得 3 5 6 8 0
}
}
static Properties getProperties()
返回当前的操作系统属性
/**
* static Properties getProperties() 返回当前的操作系统属性
* System.getProperty(String 键名) 返回操作系统
*/
public static void systemGetProperties(){
Properties properties = System.getProperties();
System.out.println(properties);
String str = System.getProperty("os.name");
System.out.println(str);
}
三、 Math 类
它的构造方法被私有修饰符修饰,使用的时候按照静态调用即可:类名调用
static double PI
圆周率static double E
自然数的底数static int abs(int a)
返回参数的绝对值static double ceil(double d)
返回大于或者等于参数的最小整数static double floor(double d)
返回小于或者等于参数的最大整数static long round(double d)
对参数四舍五入static double pow(double a,double b )
a 的 b 次幂static double random()
返回随机数 0.0-1.0之间static double sqrt(double d)
参数的平方根
public static void main(String[] args) {
// 应用这两个数据需要导入包
// System.out.println("Math.PI = " + Math.PI);
// System.out.println("Math.E = " + Math.E);
// 以下是方法:
// 1. static int abs(int a) 返回参数的绝对值
System.out.println(Math.abs(-6));
// 2. static double ceil(double d) 返回大于或者等于参数的最小整数
System.out.println(Math.ceil(12.3)); // 向上取整数
// 3. static double floor(double d) 返回小于或者等于参数的最大整数
System.out.println("Math.floor(5.5) = " + Math.floor(5.5)); // 向下取整数
// 4. static long round(double d) 对参数四舍五入
long round = Math.round(5.5); // 取整数部分 参数+0.5
System.out.println("round = " + round);
// 5. static double pow(double a,double b ) a的b次幂
System.out.println("Math.pow(2,3) = " + Math.pow(2, 3));
// 6. static double sqrt(double d) 参数的平方根
System.out.println("Math.sqrt(4) = " + Math.sqrt(3));
// 7. static double random() 返回随机数 0.0-1.0之间
for(int x = 0 ; x < 10 ; x++){
System.out.println(Math.random()); // 伪随机数
}
}
四、 数组的相关操作
1. 数组的翻转
- 所谓的数组的翻转例子:原始数组 {1,2,3,4} ,翻转后是 {4,3,2,1}
- 数组的翻转不等于倒叙遍历
①数组中元素位置的交换,数组的换位,借助一个变量
②核心问题:数组中最远端的元素交换位置上
③数组的翻转需要用到指针思想:一个指针从索引零开始,进行加加的操作,一个指针从索引最后一位索引开始,进行减减操作,且要保证从零开始的指针一直小于从最后一位开始的指针。
/**
* 数组的翻转
*/
public static void arrayReverse(){
int[] arr = {1,2,7,5,0,22,3,4};
// 最远的元素,交换位置 (使用第三方变量)
for(int min = 0 , max = arr.length -1; min < max ; min++ ,max-- ){
int temp = arr[min] ; // 记录数组的最小索引上的元素
arr[min] = arr[max] ; // 数组最大索引上的元素,赋值到最小元素的位置上
arr[max] = temp;
}
// 遍历看结果
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
2. 数组的二分(折半)搜索法
- 数组的基本搜索法:判断一个元素是否存在于数组中
- 遍历数组,查找就可以
- 二分搜索法提高效率:前提是数组必须是有序的。
(1) 数组元素的基本查询:
public class ArrayTest {
public static void main(String[] args) {
int[] arr={1,2,3,4,5};
int index=baseSearch(arr,3);
System.out.println("index = " + index);
}
/**
* 数组元素的基本查询
* 参数是 数组和要查找的关键字
* 返回关键字所在的索引
*/
public static int baseSearch(int[] arr,int key){
for(int x=0;x<arr.length;x++){
if(arr[x]==key){ // 关键字,存在于数组中,直接返回索引
return x;
}
}
return -1; // 如果没有关键字,就返回 -1
}
}
(2) 数组的二分搜索法:
- 在这里数组的索引就是指针
- 数组折半后的索引 mid =(min + max)/ 2 (都是 int 类型)
- 详解:
数值 | 1 | 5 | 8 | 12 | 15 |
---|---|---|---|---|---|
索引 | 0 | 1 | 2 | 3 | 4 |
- 示例一、 key 是 16 时:
①数组折半后的索引是2:key>arr[2] 则 arr[2] 前面的都不考虑,最小索引移动到3,min = mid + 1
②数组折半后的索引是3:key>arr[3] 则 arr[3] 前面的都不考虑,最小索引移动到4,min = mid + 1
③数组折半后的索引是4:key>arr[4] 则 arr[4] 前面的都不考虑,最小索引移动到5,min = mid + 1,出现问题不能继续,查找结束,key 不在数组中 - 示例二、 key 是 1 时:
①数组折半后的索引是2: key < arr[2] 则 arr[2] 以后的就不考虑,最大的索引移动到1,max = mid - 1
②最后就能锁定索引
/**
* 数组的二分搜索法
* 返回查找的元素在数组中的索引,没有就返回负数
*/
public static int binarySearch(int[] arr,int key){ // 参数列表定义数组和关键字
int min = 0 ; //数组的最小索引
int max = arr.length - 1; //数组的最大索引
int mid ; //数组折半后的,中间位置的索引
// 循环折半,次数不定,使用 while 循环
// 条件:最小索引不能超过最大索引(小于等于)
while (min <= max){
// 开始折半
mid = (min + max) / 2;
// 折半后的 mid 作为索引,取出数组的元素,和关键字比较
if (key > arr[mid])
// 移动最小索引
min = mid + 1;
else if (key < arr[mid])
// 移动最大索引
max = mid - 1;
else {
//查找到了,就返回索引
return mid;
}
}
return -1;
}
// 调用:
public static void main(String[] args) {
int[] arr={1,4,7,9,10,15,18};
int index = binarySearch(arr,7);
System.out.println("index = " + index);
}
3. 数组的排序
- 在无序的数组中,对元素进行排序,默认都是升序, 提高效率
数组排序的问题:元素在内存中的位置交换,效率最低.
数组排序的方式:①选择排序、②冒泡 (选择优化)、③插入排序、④折半排序、⑤希尔排序、⑥快速排序
(1) 冒泡排序 (bubble)
核心思想:元素之间比较换位;
冒泡排序的比较方式:相邻元素比较
- 冒泡排序的结构:
for(int i = 0;i < 数组.length;i++){
for(int j = 0;j < 数组.length - i;j++){
// 比较再换位
if(数组[j] > 数组[j+1]){
// 换位
int temp = 数组[j];
数组[j] = 数组[j+1];
数组[j+1] = temp;
}
}
}
/**
* 排序实现
*/
public static void bubbleSort(int[] arr){
// 外循环,次数固定的
for (int i = 0 ; i < arr.length ; i++){
// 内循环,每次都要进行递减操作
for (int j = 0 ; j < arr.length - i - 1; j++){
//j 的变化是 0-6 ,否则后面会出现越界异常
// 比较换位
if (arr[j] > arr[j + 1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
(2) 选择排序优化
选择排序:元素之间都要比较
进行优化:不是每次比较完成都要换位,而是等到获取到最值,用最值再换位值
示例:
数值 | 2 | 4 | 3 | 1 |
---|---|---|---|---|
索引 | 0 | 1 | 2 | 3 |
- 示例具体做法:
- 0 索引的元素,和后面的元素比较,比较的过程中不换位置,而是记录最小值的索引 3
数组 3 索引上的元素,和数组 0 交换
- 0 索引的元素,和后面的元素比较,比较的过程中不换位置,而是记录最小值的索引 3
/**
* 选择排序的优化
* 最值获取:①利用元素、 ②利用索引
*/
public static void selectSort(int[] arr){
// 获取数组的最值
for (int i = 1 ; i < arr.length ;i++){
// 定义变量,保存数组的第一个元素
int min = arr[i-1];
// 最小值的元素一直发生变化,一开始是索引为0的数值,之后是索引为1的数值......
// 所以采用 i-1 的方式使每一次循环的最值变化
// 定义记录最小值索引
int minIndex = i-1;
// 出现最小值后,索引在每一次外层循环下变换:0、1、2......
for(int j = i ; j < arr.length ; j++){
// 在这里根据最开始 i = 1,所以j = i,刚好达到索引为最值的数值和内层每一次循环之后的数值比较
if (min > arr[j]){
// 记录内层循环比较下,是否为更小的数值的索引
minIndex = j;
// 记录最小值
min = arr[j];
}
}
// 比较完后进行位置交换
if (minIndex != (i-1)){
int temp = arr[i-1];
arr[i-1] = arr[minIndex];
arr[minIndex] = temp;
}
}
}
(3) 数组的容量扩容
public static void main(String[] args) {
arrayCapacity();
}
/**
* 数组的容量扩容
*/
public static void arrayCapacity(){
int[] arr={1,2,3,4,5};
// 如果想要在存储数据进入数组中,但是数组的长度是不可改变的,所以新建一个数组,应用数组的复制功能
// 示例:再索引 5 下添加新元素
int[] newArr=new int[6];
// 数组的复制
System.arraycopy(arr,0,newArr,0,5);
newArr[5]=6;
// 为了节约内存,销毁一个数组
arr=newArr;
newArr=null;
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+",");
}
}
}
(4) 数组元素的添加
public static void main(String[] args) {
arrayElementAdd();
}
public static void arrayElementAdd(){
String[] str= {"张三","李四","王五"};
// 添加一个元素,"赵六" 放在索引 1 的位置
String[] newArr=new String[str.length+1];
for (int i = 0; i < str.length; i++) {
newArr[i]=str[i];
}
// 现在 newArray 的元素是 "张三""李四""王五""null"
System.arraycopy(newArr,1,newArr,2,2);
newArr[1]="赵六";
for (int i = 0; i < newArr.length; i++) {
System.out.print(newArr[i]+",");
}
}
4. Arrays 工具类
java.util 包中定义了类 Arrays,数组操作的工具类,该类不能创建对象,直接静态调用(类名调用)
- Arrays 类的静态方法:
static void sort(数组)
对数组进行升序排列 (目前为止效率最快)static int binarySearch(数组,查找的关键字)
对数组进行二分搜索法static void fill(数组,填充的元素)
填充覆盖原元素,拥有全新的数组元素static String toString(数组)
返回数组的字符串表现形式static List asList(T...t)
多个元素转成 List 集合
(1) static void sort(数组)
对数组进行升序排列 (目前为止效率最快):
public static void main(String[] args) {
int[] arr={2,5,4,97,3,4};
arraySort(arr);
System.out.println(Arrays.toString(arr));
}
/**
* static void sort(数组) 对数组进行升序排列 (目前为止效率最快)
*/
public static void arraySort(int[] arr){
Arrays.sort(arr);
}
(2) static int binarySearch(数组,查找的关键字)
对数组进行二分搜索法
public static void main(String[] args) {
int[] arr={1,5,9,10,15,22,27,30}; // 需要是有序数组
int index = arrayBinarySearch(arr,27);
System.out.println(index);
}
/**
* static int binarySearch(数组,查找的关键字) 对数组进行二分搜索法
* 返回元素在数组中出现的索引
* 如果元素不存在,返回 (-(插入点)-1)
* 插入点,被定义为将键插入数组的那一点,即范围中第一个大于此键的元素索引,如果范围中的所有元素都小于指定的键,则为 toIndex
* 例如:key:4 则最后返回值为 -2 ; key:12 则最后返回 -5
* key:放在数组中,并且保证有序的
*/
public static int arrayBinarySearch(int[] arr,int key){
int index = Arrays.binarySearch(arr, key);
return index;
}
(3) static void fill(数组,填充的元素)
填充覆盖原元素,拥有全新的数组元素
public static void main(String[] args) {
arrayFill();
// 结果为 [6,6,6,6,6] 原来的元素全部被替换掉
}
/**
* static void fill(数组,填充的元素) 填充覆盖原元素,拥有全新的数组元素
*/
public static void arrayFill(){
int[] arr = {1,2,3,4,5};
Arrays.fill(arr,6);
System.out.println(Arrays.toString(arr));
}
(4) static String toString(数组)
返回数组的字符串表现形式:
public static void main(String[] args) {
int[] arr={2,5,4,97,3,4};
arrayToString(arr);
}
/**
* static String toString(数组) 返回数组字符串表现形式
* toString 内部自动遍历数组
*/
public static void arrayToString(int[] arr) {
String str= Arrays.toString(arr);
System.out.println("str = " + str);
}
五、 字符串相关操作
1. 字符串翻转
数组可以转成字符串,字符串也能转成数组 (翻转数字)
public static void main(String[] args) {
String s = stringReverse("abcdefg");
System.out.println(s);
}
/**
* 翻转字符串
* 传递字符串,返回翻转后的字符串
*/
public static String stringReverse(String str){
// 字符串转成数组
char[] chars = str.toCharArray();
// 翻转数组
for(int min = 0 ,max = chars.length - 1; min <= max ; max--,min++){
char temp = chars[min];
chars[min] = chars[max];
chars[max] = temp;
}
// 数组转成字符串
return new String(chars);
}
另一种实现方法:
/**
* 翻转字符串的另一个实现方法
*/
public static String stringReverse(String str){
// str 转成 StringBuilder
StringBuilder builder = new StringBuilder(str);
builder.reverse();
// 字符串缓冲区转成字符串返回
return builder.toString();
}
上述方法的极简写法:
public static String stringReverse(String str){
return new StringBuilder(str).reverse().toString();
}
2. 自定义(模仿)方法 trim()
去掉字符串两边的空格
- 例如:
" abcd efg " ==> “abcd efg”
/**
* 自定义的方法 trim()
* 示例:
* " abcde fg "
* 先转换为:
* "abcde fg "
* 再转换为:
* "abcde fg"
*/
public static String myTrim(String str){
// 去掉字符串开头的空格,使用方法替换
str = str.replaceFirst(" +","");
// " +" 表示空格出现一次到多次,替换为 "" (空字符串)
// 去掉字符串末尾的空格,首先应判断字符串,是不是以空格结尾
while (str.endsWith(" ")){
// subString 截取字符串,永远都是截取的最后一个位置
str = str.substring(0,str.length()-1);
}
return str;
}
3. 字符出现的次数
- 要求:指定字符串 “asdfg3435erAAEExc”,统计出,小写字母,大写字母,数字,各自出现了多少次,不考虑其它字符。
统计的案例:计数器思想 应用:变量++
- 实现思想:字符串换成数组,取出每个元素,分别统计 (要求熟悉 ASCII 码:大写字母 65 ~ 90 、小写字母 97 ~ 122 、数字 48 ~ 57)
/**
* 统计字符串中字符和数字出现的次数
*/
public static void stringCount(String str){
if (str == null){
return;
}
// 定义三个计数器变量
int upper = 0 , lower = 0 , number = 0;
// 字符串转成数组
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
// 取出每个元素
char ch = chars[i];
// 判断 ch 字符的 ASCII 码范围
if ( ch >= 'A' && ch <= 'Z') // ch >= 65 && ch <= 90
// 大写字母
upper ++;
else if ( ch >= 'a' && ch <= 'z') // ch >= 97 && ch <= 122
// 小写字母
lower ++;
else if (ch >= '0' && ch <= '9'){ // ch >= 48 && ch <= 57
// 数字
number ++;
}
}
System.out.println("大写字母;"+upper);
System.out.println("小写字母;"+lower);
System.out.println("数字;"+number);
}