9 Java数据结构(上):包装类、数组(Array工具类)、lambda表达式、ArrayList、泛型

文章目录


前言

本节会总结Java中各种数据结构里面的使用方法,包括之前的学过的数组、ArrayList、还包括链表、哈希表、树等数据结构一起其中的高级实用API。本博客会详细记录各种用法,作为个人的查询文档。

在学习这些数据结构前,前面有必要先来好好学习一下包装类,由于Java基本数据类型(可变)大部分集合都是不允许放进去的,我们必须要放其对应的包装类(不可变)才被允许放进去,所以学习这些集合第一关就是对应的包装类。

这里是上部分,主要是 数组、和ArrayList这两个数据结构一起其对应的一些工具和辅助知识,有了这些辅助知识再看其他集合类数据结构就简单了。辅助知识包括:包装类、Arrays、泛型、lambda表达式、等等这些不可忽视的。


一、包装类

在前面我们其实简单讲过包装类,但讲的比较简单,这里做一个详细的笔记,方便后续查阅。

  • 包装类:基本数据类型对应的引用数据累加
    将Java中的基本数据类型重新写成引用数据类型,并且是不可变的;这样就和python一样了,Python里面有一句名言,万物皆对象,有了包装类这句话是不是也可以移到Java中,Java中万物皆对象。
  • 并且Java的集合的高级数据结构里面,基本数据类型由于其可变性,是不允许存进集合的;所以我们就需要将不可变的包装类存进集合实现相同的效果。

给出Java中基本数据类型和其对象的包装类内存图就清楚二者的关系了:
在这里插入图片描述

基本数据类型 对应的包装类
byte Byte
short Short
char Character
int Integer
long Long
float Float
double Double
boolean Boolean

可以看到只有char和int的包装类名有点变化要单独记一下,其余的都是首字母大写就可以了。
具体怎么用的建议先了解ArryList,下面给出示例:包装类就可以添加进集合了,表示方法和普通的写法一样,只是泛型要写包装类就是了。
下面以Integer演示包装类的用法,其他的都类似

1、Integer

(1)基本用法

// 创建 Integer
Integer a = 10;
Integer b = 11;

// 进行运算
Integer sum = a + b;
System.out.println(sum);    // 21

Double d = 5.0;
Double v = a * d;
double v1 = a * d;         // 这样也可以
System.out.println(v);     // 50.0  隐式类型转换这些都还有
System.out.println(v1);    // 50.0

可以看到和基本数据类型完全一样的用法,运算也一样,并且包装类和其对于的基本数据类型之间还存在自动隐式转换,使得二者是互通的。(这里设计到了我们等下要将的自动装箱、自动拆箱机制)

再看这个ArrayList list = new ArrayList<>();的例子ArrayList只能包装类进(可以跳到自动装箱哪里)

ArrayList<Integer> list = new ArrayList<>();
list.add(1);    // 自动装箱
list.add(2);
list.add(3);

for (Integer i : list) {
   
    System.out.print(i + " ");   // 1 2 3

这就是典型的自动装箱机制。

(2)JDK5前的包装类用法(了解即可,能更好帮助我们理解下面的自动装箱和自动拆箱机制)

在JDK5以前创建一个Integer对象,要用到一下这些复杂的方法(部分现在都已经废弃了):
在这里插入图片描述
【注】:下面代码高版本jdk运行不了,方法已经废弃,这里只是做一个示例

Integer i1 = new Integer(1);
Integer i2 = new Integer(2);


// 如果要用上面JDK5前的这些方法创建Integer对象,进行计算需要手动拆箱,在装箱
// 因为对象之间不能直接进行运算
// 步骤:
// 1. 先将对象转换为基本数据类型(拆箱)
// 2. 进行运算
// 3. 将基本数据类型转换为对象(装箱)

int result = i1.intValue() + i2.intValue();  // 拆箱并运算
Integer i3 = new Integer(result);  // 装箱
System.out.println(i3);  

可以看到,包装类进行运算如果要手动拆箱后手动装箱,太麻烦了。没错,大佬们也觉得太麻烦了,于是JDK5以后就有了自动拆箱和自动装箱机制。

一个面试问题:

Integer i1 = Integer.valueOf(127);
Integer i2 = Integer.valueOf(127);
System.out.println(i1 == i2); // true

Integer i3 = Integer.valueOf(128);
Integer i4 = Integer.valueOf(128);
System.out.println(i3 == i4); // false

// 下面new出来的好理解,只要new出来的对象地址不同,肯定是false
Integer i5 = new Integer(127);
Integer i6 = new Integer(127);
System.out.println(i5 == i6); // false

Integer i7 = new Integer(128);
Integer i8 = new Integer(128);
System.out.println(i7 == i8); // false

关键在于前两段,为什么127的是true , 128的是false

查看源码会发现 -128到127间(闭区间)的因为在实际开发中应用的比较多,如果每次使用都new对象浪费内存,于是底层这样设计为:

  • 提前把这个[-128,127]范围之内的每一个数据都创建好对象放进一个数组存起来
  • 如果要用到了不会创建新的,而是返回已经创建好的对象,所以127地址一样的是,128地址不一样。

这是一个面试题,所以我也在这里写一下。

(3)自动装箱与自动拆箱机制 — 导致:int和Integer,包装类和对应的基本数据类型在不需要进集合的情况下是互通的(重要重要!!!!!)

Integer i1 = 100;           // 自动装箱
Integer i2 = 100;

Integer sum = i1 + i2;      // 内部会自动拆箱,然后再装箱
System.out.println(sum);

int i3 = 99;
int sum2 = i1 + i3;         // i1会自动拆箱
System.out.println(sum2);     // 199

// 注:除了部分集合只能包装类进,其他情况由于自动装箱拆箱,基本类型和包装类可以互相转换的,底层自动实现

再看这个ArrayList list = new ArrayList<>();的例子ArrayList只能包装类进

ArrayList<Integer> list = new ArrayList<>();
list.add(1);    // 自动装箱
list.add(2);
list.add(3);

for (Integer i : list) {
   
    System.out.print(i + " ");   // 1 2 3

这就是典型的自动装箱机制。

(4)Integer的常用方法

— 进制转换方法
方法名 说明
public static String toBinaryString(int i) 得到二进制
public static String toOctalString(int i) 得到八进制
public static String toHexString(int i) 得到十六进制
// 1 把整数转换成二进制
String str1 = Integer.toBinaryString(100);
System.out.println(str1);   // 1100100

// 2 把整数转换成八进制
String str2 = Integer.toOctalString(100);
System.out.println(str2);   // 144

// 3 把整数转换成十六进制
String str3 = Integer.toHexString(100);
System.out.println(str3);   // 64

2 包装类实现类型转换(重要!!!)

(1)Integer:public static int parseInt(String s):将字符串类型的整数转换成int类型的整数

在python中这个功能 int()就能转,但在Java中必须这样才行

int i = Integer.parseInt("123");     // 字符串转整数  (自动拆箱)
System.out.println(i);      // 123
System.out.println(i + 1);  // 124
// 细节:"123"里面必须是数字,里面有字母无法转,会报错

【注】:除了Character包装类,其他7中包装类都有其对应的paseXxx的方法进行类型转换
有了这个就可以将之前的键盘录入代码做一个规范了 包装类数据类型转换在键盘录入中的应用

(2)Boolean:public static boolean parseBoolean(String s):将字符串类型的布尔转换成boolean

String str = "true";
boolean b = Boolean.parseBoolean(str);  // 字符串转布尔
System.out.println(b);  // true

3 小练习

  • 练习1:键盘录入一些1~100之间的整数,并添加到集合中。直到集合中所有数据求和超过200停止添加。
public class Test {
   
    public static void main(String[] args) {
   
        // 键盘录入一些1~100之间的整数,并添加到集合中。直到集合中所有数据求和超过200停止添加。

        ArrayList<Integer> list = new ArrayList<>();
        Scanner sc = new Scanner(System.in);
        int sum = 0;
        while (true){
   
            System.out.println("请输入一个1~200之间的整数:");
            int input = Integer.parseInt(sc.nextLine());
            if (input < 1 || input > 200){
   
                System.out.println("输入数据范围不在1-200,请重新输入!");
                continue;
            }else {
   
                sum += input;
                if (sum > 200){
   
                    break;
                }
                // input 是 int 类型,但是 ArrayList 集合中存储的是 Integer 类型,添加时触发自动装箱
                list.add(input);
            }
        }
        System.out.println("集合中的数据为:" + list);
    }
}
  • 练习2:自己实现parselnt方法的效果,将字符串形式的数据转成整数。 要求:
    (1)字符串中只能是数字不能有其他字符
    (2)最少一位,最多10位
    (3)0不能开头

本题需要补充一个 字符数字转int数字的ascll表方法,前面也提到过。以 char “5”为例就可以直接 “5” - “0” ,char类型运算都是转成ascll码运算。有了这个本题就好做了。

public class Test {
   
    public static void main(String[] args) {
   
        // 自己实现parselnt方法的效果,将字符串形式的数据转成整数。要求:
        //(1)字符串中只能是数字不能有其他字符
        //(2)最少一位,最多10位
        //(3)0不能开头
        
        String str = "123456";
        // 首先第一步我们需要对字符串进行校验,校验是否符合规则(用正则表达式)
        String regex = "[1-9]\\d{0,9}";
        if (str.matches(regex)) {
   
            // 符合规则,我们就可以将字符串转成整数
            int result = 0;
            for (int i = 0; i < str.length(); i++) {
   
                char c = str.charAt(i);
                int num = c - '0';        // 将字符转成整数,利用char运算是ASCII码运算
                result = result * 10 + num;
            }
            System.out.println(result);      // 123456
            System.out.println(result + 1);  // 123457
        } else {
   
            System.out.println("字符串不符合规则");
        }
    }
}

二、数组 – int[]、String[]…

【注】:java的数组和Python的列表有很大的不同之处,下面的两个不同需要特别注意一下。

  • (1)java的数组里面也可以是任意数据类型、如整数、浮点数、字符、字符串等或者对象(如类的实例),但需要注意的是,一个数组里面只能含有一种数据类型,也就是说java数组里面只能存在同一种数据类型,而Python的一个列表内却是可以同时含有多种不同数据类型,这是一个主要的小区别。
  • (2)数组长度不可变:一旦数组创建并分配了空间,其长度不可改变。这点也是和Python不同,因此,如果需要动态增删元素,建议使用ArrayList等其他动态数组类。
  • (3)java中数组这些没有切片操作这些。

1 数组的创建与初始化

(1)静态初始化

  • 初始化就是在内存中为数组容器开辟空间,并将数据存入容器中的过程

  • 注:数组一旦创建过后其长度就固定了,不可改变
    数组的长度直接访问数组的length属性即可:arr.length

其中语法有下面完整写法和简单写法两种

  • 简单格式:数组类型[] 数组名 = {元素1,元素2,元素3…}
  • 完整格式:数组类型[] 数组名 = new 数组类型[]{元素1,元素2,元素3…}
public class Business {
   
    public static void main(String[] args) {
   

        int[] arr1 = new int[]{
   1,2,3};   // 这种是复杂的写法,一般使用下面的简单写法即可
        int[] arr2 = {
   1,2,3};

        String[] arr3 = new String[]{
   "a","b","c"};
        String[] arr4 = {
   "a","b","c"};
        System.out.println(arr2);  // [I@4eec7777
        System.out.println(arr4);  // [Ljava.lang.String;@3b07d329

    }
}

上面有个小细节,在java中直接打印数组打印的是数组的地址,下面对java中的地址格式做一个解释说明。
java地址格式说明:[I@4eec7777上面的这个地址,[ 表示是数组,I表示里面数据类型是整数 。@没有固定含义,就是一个固定格式,4eec7777这个才是真正的地址值。

(2)动态初始化

动态初始化:初始化时只指定数组长度,由系统为数组分配初始值。
语法: 数据类型[] 数组名 = new 数据类型[数组长度]

【注】:和静态相比,右边大括号没有了,中括号里面变数组长度了,要注意

int[] arr = new int[100]

数组默认的初始化规律:

  • 整数类型:默认初始化为0
  • 小数类型:默认初始化为0.0
  • 字符类型:默认初始化为‘/u0000’ 其实就是空格
  • 布尔类型:默认初始化为false
  • 引用数据类型:默认初始化为 null

2 数组元素访问与修改

语法:

  • 访问: 数组名[索引]
  • 修改:数组名[索引] = 具体数据/变量

【注】:
1、java中的索引也是从0开始的
2、java中数组索引不能是负数,这和Python不一样

String[] arr4 = {
   "a","b","c"};
        String s = arr4[0];
        System.out.println(s);   // a

        arr4[1] = "哈哈";
        System.out.println(arr4
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值