JAVA入门基础_JAVA常用的引用类型及其API(三)

目录

JAVA常用的引用类型及其API(三)

数组

数组的定义及使用场景

数组的定义:数组是用于存储多个相同类型数据的集合。
使用场景:1.当需要存储大量**相同类型的数据**且这些数据不需要**多次增删**时(先了解)

数组的几个知识点(内存、增删改查、长度、数据类型)

  1. 数组对象在内存中是一片连续的内存空间

  2. 增删慢、修改和查询快

  3. 数组的长度在创建时就已经固定了(无法修改)。

  4. 数组所存储的数据类型在创建时就已经固定了(无法修改)。

数组的创建方式

静态创建(创建时就已经将数据写死,2种方式)

1、 第一种
int[] arr = {1,8,6,8,9};
2、第二种
int[] arr2 = new int[]{9,5,4,2,3};

动态创建(创建时仅指定长度,之后再增添数据,1种方式)

// 定义一个int数组
int[] arr3 = new int[15];
// 为数组赋值
arr3[0] = 11;
arr3[1] = 15;...

如何获取数组中的数据

// 数组中的每一个元素都有一个唯一的索引(下标),从0开始
int[] arr = {14,13,15,22};

/* 假如现在需要获取到15这个数据,那么数组下标从0开始数
	{14,13,15,22}
	 0   1  2  3
	因此想要得到15这个数据,则可以使用arr[2]获取到。
*/

System.out.println("想要获得数组中15这个数据: " + arr[2]);

数组的内存模型(内存的嵌套)

 int arr[] = new int[3];
//  当main方法执行如上的语句时,会进行如下操作
// 1.在栈内存中创建一个整形数组类型的引用 arr
// 2.在堆内存中创建一个整形数组的对象,并将该对象的地址赋值给arr这个引用
// 注意:创建数组时,其数组中的空间也有对应的内存地址。理解为数组对象有一个地址,它的元素也有地址(并且是连续的内存空间)。

数组增删慢、查询快的原因

  1. 数组使用的是索引,一个索引关联一个数据,可以通过索引计算出该数据的内存地址。

  2. 每次使用索引查找数据时,都会通过一个算法(第一个索引地址 + 当前索引 * 数据大小[不确定])来快速定位到当前索引所指向的内存地址,因此查询的速度快。

数组的两种遍历方式及区别

fori的遍历方式(遍历出的是每个数据的引用,引用类型时)

int[] arr = {5,95,1,26,51};
for (int i = 0; i < arr.length; i++){
	System.out.println(arr[i]);
}

foreach遍历方式(遍历出的是一个临时局部变量)

int[] arr = {5,95,1,26,51};
for(int i : arr) {
	System.out.println(i);
}

fori与foreach两种遍历方式的区别(2个)

  1. fori有索引位置、而foreach没有索引位置
  2. fori遍历出的每个元素都指向内存地址,而foreach拿到的是一个获取了数据的局部变量
  3. fori可以在循环中修改数据,foreach不能在循环中修改数据

在数组的指定索引处添加元素

使用fori循环的方式实现

public class Calculate {
    public static void main(String[] args) {

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

        System.out.println("当前数组的值为:" + Arrays.toString(arr)); // [1, 2, 3, 4, 5]

        // 在数组索引2的位置添加一个元素:15,那么添加后的数组应该为:{1, 2, 15, 3, 4, 5}
        arr = arrAddElement(arr, 2, 15);

        // 插入数据后数组的值为:
        System.out.println("插入数据后数组的值为:" + Arrays.toString(arr)); // [1, 2, 15, 3, 4, 5]
    }

    public static int[] arrAddElement(int[] arr, int index, int element) {
        // 由于数组创建后就不能改变长度,因此需要一个新的数组来存储数据,由于需要插入一个元素,所以数组长度需要在原数组的基础上加一
        int[] newArr = new int[arr.length + 1];

        // 将索引前的数据赋值给新数组
        for (int i = 0; i < index; i++) {
            newArr[i] = arr[i];
        }

        // 对指定索引位置赋值需要插入的元素
        newArr[index] = element;

        // 将索引后的数据赋值给新数组
        for (int i = index; i < arr.length; i ++) {
            newArr[i + 1] = arr[i];
        }

        // 返回新数组
        return newArr;
    }
}

使用System.arraycopy()方法实现

  • 这里仅提供arrAddElement()方法的代码
public static int[] arrAddElement(int[] arr, int index, int element) {
        // 由于数组创建后就不能改变长度,因此需要一个新的数组来存储数据,由于需要插入一个元素,所以数组长度需要在原数组的基础上加一
        int[] newArr = new int[arr.length + 1];

        // 将索引前的数据赋值给新数组
        System.arraycopy(arr, 0, newArr, 0, index);

        // 对指定索引位置赋值需要插入的元素
        newArr[index] = element;

        // 将索引后的数据赋值给新数组
        System.arraycopy(arr, index, newArr, index + 1, arr.length - index);

        // 返回新数组
        return newArr;
    }

删除数组指定索引处的元素

使用fori循环的方式实现

public class Calculate {
    public static void main(String[] args) {

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

        System.out.println("当前数组的值为:" + Arrays.toString(arr)); // [1, 2, 3, 4, 5]

        // 在数组索引2的位置删除一个元素:那么删除后的数组应该为:{1, 2, 4, 5}
        arr = arrDeleteElementByIndex(arr, 2);

        // 插入数据后数组的值为:
        System.out.println("删除元素后数组的值为:" + Arrays.toString(arr)); // [1, 2, 4, 5]
    }

    public static int[] arrDeleteElementByIndex(int[] arr, int index) {
        // 由于数组创建后就不能改变长度,因此需要一个新的数组来存储数据,由于需要删除一个元素,所以数组长度需要在原数组的基础上减一
        int[] newArr = new int[arr.length - 1];

        // 将索引前的数据赋值给新数组
        for (int i = 0; i < index; i++) {
            newArr[i] = arr[i];
        }

        // 将索引后的数据赋值给新数组
        for (int i = index; i < arr.length -1; i++) {
              newArr[i] =  arr[i + 1];
        }

        // 返回新数组
        return newArr;
    }
}

使用System.arraycopy()方法实现

  • 这里仅提供arrDeleteElementByIndex()方法的代码
    public static int[] arrDeleteElementByIndex(int[] arr, int index) {
        // 由于数组创建后就不能改变长度,因此需要一个新的数组来存储数据,由于需要删除一个元素,所以数组长度需要在原数组的基础上减一
        int[] newArr = new int[arr.length - 1];

        // 将索引前的数据赋值给新数组
        System.arraycopy(arr, 0, newArr, 0, index);

        // 将索引后的数据赋值给新数组
        System.arraycopy(arr, index + 1, newArr, index, arr.length - index - 1);

        // 返回新数组
        return newArr;
    }

System.arraycopy()方法各参数解释(5个参数)

/*
 * 作用: 复制整个数组
 * Object src: 原始数组
 * int srcPos: 从原始数组的第几个下标开始复制
 * Object dest: 目标数组,也就是要复制到该数组中
 * int destPos: 从目标数组的第几个下标开始复制
 * int length: 一共需要复制几个元素
 * 提示一点:源数组与目标数组必须为相同类型的数组
*/

String字符串

字符串的创建方式以及常量池

// 1、创建String对象
// 虚拟机会在堆内存的Eden区创建一个String的对象
String str1 = new String("今天天气不错Abc");

// 虚拟机会直接将字符串放在常量池中
String str2 = "今天天气不错Abc";
String str3 = "今天天气不错Abc";

// 判断两个字符串对象地址是否一致  false
System.out.println(str1 == str2);

// 判断两个字符串对象地址是否一致  true, 这是因为常量池的存在
System.out.println(str2 == str3);

String对象的基本方法

// 1 判断两个字符串内容是否相等
System.out.println(str1.equals(str2));

// 2 获取字符串的长度
System.out.println(str1.length());

// 3 去除字符串两端空格
System.out.println(str1.trim());

// 4 判断字符串是否为空(判断长度是否为0)
System.out.println(str1.isEmpty());

// 5 判断是否以指定的字符串开头
System.out.println(str1.startsWith("今天天气"));

// 5 判断是否以指定的字符串结尾
System.out.println(str1.endsWith("Abc"));

// 6 将字符串中的英文字母转换为全大写
System.out.println(str1.toUpperCase());

// 7 将字符串中的英文字母转换为全小写
System.out.println(str1.toLowerCase());

// 8 判断字符串中是否包含指定的字符串
System.out.println(str1.contains("今天天气不好"));

// 9 截取字符串,
    // 9.1获取从索引位置开始及再往后的全部元素
    str1.substring(0);
    // 9.2 从字符串索引2的位置开始,截取到索引3(因为含头不含尾)的位置
    str1.substring(2, 4);

String对象的其他方法

// 1 根据索引查找字符串中指定的字符
System.out.println(str1.charAt(0));

// 2 根据字符串查找第一次出现的索引位置,从左到右
System.out.println(str1.indexOf("Abc"));

// 3 根据字符串查找第一次出现的索引位置,从右到左
System.out.println(str1.lastIndexOf("Abc"));

// 4 将查找到的字符串替换成另一个字符串,只替换查找到的第一个匹配的字符串
System.out.println(str1.replace("今天", "明天"));

// 5 将查找到的字符串(查找的规则可以是正则表达式)替换成另一个字符串,找到几个就替换几个
System.out.println(str1.replaceAll("今天", "明天"));

// 6 将字符串转换为字节数组,一个中文在UTF-8占用3个字节,一个字母一个字节
byte[] buf = str1.getBytes();
System.out.println(Arrays.toString(buf));

// 7 将字节数组转换为字符串
str1 = new String(buf);
System.out.println(str1);

String类的原理(底层结构、2个字符串拼接时)

1. String类是一个final修饰的类,不可被继承
2. 底层存储数据的实际上是一个字符数组final char value[],看出字符串是**不可变**的
3. 当两个字符串拼接时,将会**创建一个新的字符数组**,将2个字符串拼接在一起,很**影响效率**

StringBuffer 及 StringBuilder

StringBuffer及StringBuilder是什么?

它两是可变的字符序列,底层是一个不带final修饰的字符数组,这2个对象的方法是一致的。

StringBuffer/StringBuilder的常用方法

StringBuilder str = new StringBuilder();

// 追加内容
str.append("abc");
// 在指定索引处插入内容
str.insert(1, "d");
// 删除指定索引处的数据
str.deleteCharAt(0);
// 删除指定索引范围的数据
str.delete(0, 1);
// 截取字符串
str.substring(2, 3);

// 将字符串反转
str.reverse();
// 将索引0~2的元素替换为ddd
str.replace(0, 2 ,"abc");
// 将其转换为String
System.out.println(str.toString());

StringBuffer及StringBuilder什么时候用?

  • 由于String底层是一个不可变的字符数组,因此如果进行字符串拼接时效率会很低

  • 所以如果字符串拼接操作比较多的时候就可以使用可变字符序列StringBuffer或StringBuilder

既然底层是数组,那么是如何扩容的?

  • 数组每次扩容时,会将当前 数组长度*2+2
  • 如果扩容后的长度仍不够装下新追加的数据,则数组长度会扩容为 当前数组长度 + 追加的数组长

什么时候使用StringBuffer?什么时候使用StringBuilder呢?

  • StringBuffer是线程安全的,也就意味着效率会低一些,因此在多线程的时候可以使用。

  • StringBuilder是线程不安全的,速度快。在不存在线程安全问题的时候使用。

Date 日期类、SimpleDateFormat 日期格式化类、Calendar 日历类

Date日期类的基本使用

/*
 创建一个Date对象,会用当前时间创建Date对象
 Date date = new Date();

 使用指定时间创建Date对象
 Date date2 = new Date(1999, 10, 12);
*/


// 创建一个用于格式化日期的类,后续会说
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

// 创建2个日期类
Date date1 = sdf.parse("2022-7-27 13:27:27");
Date date2 = sdf.parse("2022-7-26 13:11:20");

// 判断日期date1是否在date2之后   结果: true
date1.after(date2);

// 判断日期date1是否在date2之前   结果: false
date1.before(date2);

// 若日期date1在date2之前,则为-1,在date2之后为1,一致则为0   结果: 1
date1.compareTo(date2);

// 获取时间戳,返回的数据类型为long
date1.getTime();

SimpleDateFormat 日期格式化类基本使用

作用: 用于格式化日期,让日期的格式满足我们的需求

// 对象的创建
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

// 将一个字符串转换为日期类
Date date = sdf.parse("2022-7-27 14:23:59");

// 将一个日期类转换为具体的时间
String formatDate = sdf.format(date);

// 输出已经被转换为字符串的时间   结果为:2022-07-27 02:23:59
System.out.println(formatDate);

Calendar 日历类的使用

// 对象的创建
Calendar cal = Calendar.getInstance();

// 年份
System.out.println(cal.get(Calendar.YEAR));

// 月份, 1月是 0, 2月是1,以此类推
System.out.println(cal.get(Calendar.MONTH) + 1);

// 当月中的第几天
System.out.println(cal.get(Calendar.DAY_OF_MONTH));

// 当月的第几周
System.out.println(cal.get(Calendar.DAY_OF_WEEK_IN_MONTH));

// 一周中的第几天 , 1代表星期日,2代表星期一,以此类推
System.out.println(cal.get(Calendar.DAY_OF_WEEK));

// 判断今天是否为周五
System.out.println(cal.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY);

Math数学类、Random随机类、枚举类

Math数学类的常用方法

int a = 10;
int b = 20;

// 返回2个数值之间更大的值 , 结果为:20
Math.max(a, b);

// 返回2个数值之间更小的值 , 结果为:10
Math.min(a, b);

// 向上取整 , 结果为:3.0
Math.ceil(2.2222);

// 向下取整 , 结果为:2.0
Math.floor(2.222);

// 四舍五入 , 结果为:5
Math.round(5.4);

// 返回一个数的绝对值
Math.abs(-22);

// 求几的几次幂,这里是求2的3次幂,因此结果为: 2 * 2 * 2 = 8
Math.pow(2, 3);

// 判断数值是正数、负数还是0,分别返回:1、-1、0 ,结果为:-1
Math.signum(-3);

使用Math与Random生成指定范围的随机数

  • 使用Math.random()方法实现指定范围的随机数
/*
	Math.random() 生成一个从0-1的伪随机数,不包含1
	求 51 ~ 100 的整数
解析:
	1. 由于是生成一个0 - 1且不包含1的随机数,因此只要与一个数(x)相乘,就可以得到从0到x
的数值,但是不包含x
	2. 因此使用生成的数乘以x时,需要进行**加一**操作
	3. 因为有一个最小范围,因此需要最小范围,就可以实现指定范围的随机数了
	4. 再将值转换为一个整数。
	分析:100 - 51 = 49,由于还需要包含100,因此需要 +1 等于50,最后再加上51即可
*/
int random = (int)(Math.random() *  50 + 51);
System.out.println(random);
  • 使用Random类的成员方法实现指定范围的随机数
// 创建一个随机数类的对象
Random random = new Random();
// 调用其nextInt方法获得一个随机整数,其实跟Math.random差不多
int number = random.nextInt(50) + 51;

System.out.println(number);

枚举类

枚举类的用途

  • 当需要定义一组常亮时使用枚举类

枚举类的基本使用

public class Calculate {
    public static void main(String[] args){
        // 结果为: man
        System.out.println(Gender.man); 
        
        // 结果为woman
        System.out.println(Gender.woman);
    }
}
enum Gender {
    man,woman
}

File文件类

获得文件或文件夹的属性信息(是否存在、文件/夹名称、绝对路径、父绝对路径、是否为文件、是否为文件夹、字节大小、是否可读/可写/可执行、最后修改的毫秒值、获得路径下所有文件及文件夹)

// File类对象的创建
// 创建一个File文件类的时候可以指定一个文件夹的路径、也可以指定一个文件的路径,我这指定的是文件夹
File file = new File("d:/test");

// 判断文件是否存在,返回boolean类型
file.exists();

// 获得文件或文件夹的名称,返回String类型
file.getName();

// 获取文件的绝对路径,返回String类型
file.getAbsolutePath();

// 获取父级文件夹的绝对路径,返回String类型
file.getParent();

// 判断是否是一个文件,返回boolean类型
file.isFile();

// 判断是否是一个文件夹,返回boolean类型
file.isDirectory();

// 获得文件的字节大小,返回long类型
file.length();

// 判断文件是否可读,返回boolean类型
file.canRead();

// 判断文件是否可写,返回boolean类型
file.canWrite();

// 判断文件是否可执行,返回boolean类型
file.canExecute();

// 文件最后修改时间的毫秒值,返回long类型
file.lastModified();

// 获取当前目录下所有的文件与文件夹,并用File封装,生成一个File数组,类型为:File[]
file.listFiles();

创建/删除文件或文件夹

File file = new File("d:/test/abc");

// 创建单个文件夹
file.mkdir();

// 创建多级文件夹
file.mkdirs();

// 创建文件
file.createNewFile();

// 删除文件/文件夹
file.delete();

// 判断文件是否存在,存在则删除
file.deleteOnExit();

小练习,删除一个文件夹

public class Calculate {
    public static void main(String[] args) throws IOException {
        File dir = new File("d:/test");

        // 调用方法删除该路径
        deleteDir(dir);
    }

    /**
     *
     * @param dir 传入一个File类型的对象,应该满足是一个文件夹的条件
     */
    public static void deleteDir(File dir) {

        // 获取到该文件夹中所有的文件及子文件夹
        File[] files = dir.listFiles();

        // 将文件及文件夹进行遍历
        for (File file : files) {
            // 判断是否为一个文件夹,如果为文件夹则递归调用该方法
            if(file.isDirectory()) {
                deleteDir(file);
            }else {
                // 如果不是一个文件夹,则代表是一个文件,将其删除
                file.delete();
            }
        }

        // 最后删除父文件夹
        dir.delete();
    }
}
posted @ 2022-07-27 12:09  CodeStars  阅读(107)  评论(0编辑  收藏  举报