JB1-2-基础启航(二)

Java道经第1卷 - 第2阶 - 基础启航(二)


传送门:JB1-2-基础启航(一)
传送门:JB1-2-基础启航(二)

S04. 引用数据类型

心法:除了基本数据类型之外,都是引用数据类型,如类,数组,接口等。

引用数据类型使用 A a = new A() 格式进行声明赋值。

E01. 字符串类型

心法:String 底层是 char 数组,表示串字符,字符串值需要使用双引号包裹起来。

字符串所属 java.lang 包,该包下的所有类在使用时都无需导包,可直接使用。

1. 字符串声明赋值

心法:字符串有两种声明方式,目前阶段先理解为两种声明方式完全相同即可,后续学习到 String 池的概念后,再颠覆自己的认知也来得及。

String 标准声明格式: String 变量名 = new String("变量值")

String 简易声明格式: String 变量名 = "变量值"

武技:测试 String 字符串的声明赋值

package basic;

/** @author 周航宇 */
public class StringTest {

    @Test
    public void build() {

        // 标准格式: String 变量名 = new String("变量值")
        String strA = new String("hello strA!!!!");
        System.out.println("strA = " + strA);

        // 简易格式: String 变量名 = "变量值"
        String strB = "hello strB!!!!";
        System.out.println("strB = " + strB);
    }
}

2. 字符串所占内存

心法:不同编码下,一个字符所占用的内存大小是不同的。

编码环境一个中文字符占位(单位字节)一个英文字符占位(单位字节)
GBK2字节1字节
UTF83字节1字节
UTF164字节4字节

武技:测试不同编码下,一个字符串所占字节数

package basic;

/** @author 周航宇 */
public class StringTest {

    @Test
    public void size() throws Exception {
        System.out.println("a".getBytes("GBK").length);
        System.out.println("中".getBytes("GBK").length);
        System.out.println("a".getBytes("UTF-8").length);
        System.out.println("中".getBytes("UTF-8").length);
        System.out.println("a".getBytes("UTF-16").length);
        System.out.println("中".getBytes("UTF-16").length);
    }
}

3. 字符串编程接口

心法:应用程序编程接口 Application Programming Interface(API)是 Java 提供给调用方的一组方法,而 API 文档是 API 的说明文档,是一个 HTML 文件。

参考 JDK17官网API文档

API文档使用流程描述
1看方法名称Java 中使用分量符 .方法名() 进行方法的调用
2看形式参数方法要求我们传入怎样的形参,就传入什么类型的变量
3看返回类型方法返回给我们什么类型,就用什么类型的变量去接收,void 方法不接收
4看静态修饰非静态方法需要使用实例调用,静态方法直接使用类名调用
5看方法作用必须做到心中有数

String 常用 API 方法如下

  • str.length():返回 str 包含的字符个数。
  • str.isEmpty():返回 str 是否为空字符串,仅包含空格的字符串不视为空字符串。
  • str.isBlank():返回 str 是否为空字符串,仅包含空格的字符串也视为空字符串。
  • str.charAt(7):返回 str 中的 7 号位字符。
  • str.equals("a"):返回 str 是否和 a 相等,不忽略大小写。
  • str.equalsIgnoreCase("a"):返回 str 是否和 a 相等,忽略大小写。
  • str.startsWith("a"):返回 str 是否以 a 开头。
  • str.endsWith("a"):返回 str 是否以 a 结尾。
  • str.indexOf("a"):返回 str 中,第一次出现的 a 的位置。
  • str.lastIndexOf("a"):返回 str 中,最后一次出现的 a 的位置。
  • str.substring(1, 5):截取 str 中,1 到 5 号位置的子串,左边包括右边不包括。
  • str.concat("a"):将 a 追加在 str 末尾。
  • str.replace("a", "b"):将 str 中全部的 a 替换为 b。
  • str.contains("a"):返回 str 中是否包含 a。
  • str.repeat(7):将 str 重复拼接 7 次。
  • str.split(","):将 str 按逗号拆分为字符数组。
  • str.toLowerCase():返回 str 的全小写形式。
  • str.toUpperCase():返回 str 的全大写形式。
  • str.trim():返回 str 两端去空格(半角空格)之后的结果。
  • str.strip():返回 str 两端去空格(全角空格)之后的结果。
  • str.stripLeading():返回 str 头部去空格(全角空格)之后的结果。
  • str.stripTrailing():返回 str 尾部去空格(全角空格)之后的结果。
  • String.format(""):格式化字符串。
  • String.valueOf(7):将 7 转为字符串 7。

武技:测试字符串常用 API 方法

package basic;

/** @author 周航宇 */
public class StringTest {

    @Test
    public void api() {

        // 返回指定该字符串的长度(char的个数)
        System.out.println("length():\t\t\t" + "china中国\n\n".length());
        System.out.println("length():\t\t\t" + "".length());

        // 当且仅当该字符串长度为0时,才返回true
        System.out.println("isEmpty():\t\t\t" + "HelloWorld".isEmpty());
        System.out.println("isEmpty():\t\t\t" + "".isEmpty());

        // 判断字符串是否为空白字符串,仅包含空格的字符串也视为空白字符
        System.out.println("isBlank():\t\t\t" + "".isBlank());
        System.out.println("isBlank():\t\t\t" + "    ".isBlank());

        // 返回该字符串指定索引处的字符,索引越界爆发 StringIndexOutOfBoundsException 异常
        System.out.println("charAt():\t\t\t" + "HelloWorld".charAt(1));

        // 将该字符串与指定字符串进行比较
        System.out.println("equals():\t\t\t" + "HelloWorld".equals("HELLOWORLD"));

        // 不考虑大小写,将该字符串与指定的字符串进行比较
        System.out.println("equalsIgnoreCase():\t" + "HelloWorld".equalsIgnoreCase("HELLOWORLD"));

        // 测试该字符串是否以指定的字符串前缀开头
        System.out.println("startsWith():\t\t" + "HelloWorld".startsWith("Hello"));

        // 测试该字符串是否以指定的字符串后缀结尾
        System.out.println("endsWith():\t\t\t" + "HelloWorld".endsWith("World"));

        // 返回第一次出现的指定子字符串在该字符串中的索引,不存在返回-1
        System.out.println("indexOf():\t\t\t" + "HelloWorld".indexOf("o"));

        // 返回最后一次出现的指定子字符串在该字符串内的索引,不存在返回-1
        System.out.println("lastIndexOf():\t\t" + "HelloWorld".lastIndexOf("o"));

        // 从指定位置截取该字符串,并返回一个子字符串,顾头不顾尾
        System.out.println("substring():\t\t" + "HelloWorld".substring(0, 5));

        // 将指定的字符串连接到该字符串的末尾
        System.out.println("concat():\t\t\t" + "HelloWorld".concat("~~~"));

        // 使用newChar替换该字符串中所有的oldChar,并返回最终的字符串
        System.out.println("replace():\t\t\t" + "HelloWorld".replace("o", "*"));

        // 当且仅当该字符串包含指定的字符串时,才返回true
        System.out.println("contains():\t\t\t" + "HelloWorld".contains("He"));

        // 将指定字符串重复拼接10遍后返回
        System.out.println("repeat():\t\t\t" + "hello".repeat(10));

        // 按指定的字符进行分割,分割结果中不包含指定字符
        System.out.println("split():\t\t\t" + Arrays.toString("Hello World !!!".split(" ")));

        // 将该字符串中的所有字符转换为小写
        System.out.println("toLowerCase():\t\t" + "HelloWorld".toLowerCase());

        // 将该字符串中的所有字符转换为大写
        System.out.println("toUpperCase():\t\t" + "HelloWorld".toUpperCase());

        // 对字符串两端去半角空格
        System.out.println("trim():\t\t\t\t" + "  hello world  ".trim());

        // 对字符串两端去半角/全角空格
        System.out.println("strip():\t\t\t" + "  hello world  ".strip());

        // 对字符串头部去半角/全角空格
        System.out.println("stripLeading():\t\t" + "  hello world  ".stripLeading());

        // 对字符串尾部去半角/全角空格
        System.out.println("stripTrailing():\t" + "  hello world  ".stripTrailing());

        // 使用指定的格式和参数对该字符串进行格式化,并返回最终的字符串
        System.out.println("format():\t\t\t" + String.format("我叫%s,我今年%d岁了", "赵四", 58));

        // 返回参数的字符串表示形式,相当于 (param + "") 操作
        System.out.println("valueOf():\t\t\t" + String.valueOf(120) + 1);
    }
}

E02. 正则表达式

心法:正则表达式 Regular Expression (RE) 是一个字符串表达式,用于对字符串进行匹配,对空格敏感。

普通字符:基础字符,包含数字和字母等,必须被中括号包裹:

  • [abc]:必须是 abc 中的任意一个字符。
  • [^abc]:必须不是 abc 中的任意一个字符。
  • [a-z]:必须是 a~z 范围内的任意一个字符,包括两端值。
  • [^a-z]:必须不是 a~z 范围内的任意一个字符,包括两端值。

特殊字符:具有功能的特殊字符,Java 字符串中使用时需要进行转义:

  • .:必须是除了换行符和回车符外的任意一个字符,等价于 [^\\n\\r] 写法。
  • \d:必须是一个数字字符,等价于 [0-9] 写法。
  • \D:必须不是一个数字字符,等价于 [^0-9] 写法。
  • \w:必须是一个字符,数字或下划线,等价于 [a-zA-Z0-9_] 写法。
  • \W:必须不是一个字符,数字或下划线,等价于 [^a-zA-Z0-9_] 写法。
  • \n:必须是一个换行符。
  • \r:必须是一个回行符。
  • \t:必须是一个制表符。

限定字符:限定表达式出现的次数。

  • {n}:表达式必须恰好出现 n 次。
  • {n,}:表达式必须至少出现 n 次。
  • {n,m}:表达式必须出现 n 到 m 次,包括两端值。
  • *:表达式必须出现任意次,等价于 {0,} 写法。
  • +:表达式必须至少出现一次,等价于 {1,} 写法。
  • ?:表达式必须出现 0 或 1 次,等价于 {0,1} 写法。

边界字符:限定匹配以指定内容开头或结尾的字符串:

  • ^abc:必须是以 abc 开头的字符串。
  • abc$:必须是以 abc 结尾的字符串。

1. RE正则匹配

常用 API 方法如下

  • str.matches("RE"):对字符串 str 进行 RE 匹配,返回布尔型结果,等价于 Pattern.compile("RE").matcher(str).matches() 的写法。

武技:测试 RE 正则匹配

package basic;

/** @author 周航宇 */
public class RegularExpressionTest {

    @Test
    public void matches() {

        // 测试普通字符
        String regexA = "[ab][^c][e-h][^a-c]";
        System.out.println("abfd".matches(regexA));

        // 测试特殊字符
        String regexB = ".\\d\\D\\n\\t\\r\\w\\W";
        System.out.println("A9a\n\t\r_$".matches(regexB));

        // 测试限定字符
        String regexC = "\\d{2}[a-c]+[h-k]?";
        System.out.println("14aaaah".matches(regexC));
    }
}

2. RE正则替换

常用 API 方法如下

  • str.replaceAll("RE", "a"):将字符串 str 中满足 RE 规则的内容全部替换为 a 并返回替换后的字符串。

武技:测试 RE 正则替换

package basic;

/** @author 周航宇 */
public class RegularExpressionTest {

	@Test
    public void replaceAll() {

        // 将str中满足RE规则的内容全部替换为 "*"
        System.out.println("My Name Is 9527".replaceAll("[a-z]", "*"));
    }
}

3. RE正则切割

常用 API 方法如下:

  • str.split("RE"):将字符串 str 按照 RE 规则拆分成字符串数组,结果中不含 RE 内容。

武技:测试 RE 正则切割

package basic;

/** @author 周航宇 */
public class RegularExpressionTest {

    @Test
    public void spilt() {

        // 将str按照RE规则拆分成字符串数组
        String str = "Test A. Test B. Test C.";

        // 数组必须使用 Arrays.toString(数组) 查看
        System.out.println(Arrays.toString(str.split("\\. ")));
        System.out.println(Arrays.toString(str.split("\\. *")));
    }
}

4. RE常用模板

常用 RE 模板如下:

String TITLE_RE = "^.{1,42}$";
String TITLE_RE_MSG = "标题长度必须在1~42之间";
String AUTHOR_RE = "^.{1,42}$";
String AUTHOR_RE_MSG = "作者名称长度必须在1~42之间";
String CODE_RE = "^.{1,42}$";
String CODE_RE_MSG = "兑换口令长度必须在1~42之间";
String SN_RE = "^.{1,42}$";
String SN_RE_MSG = "订单编号长度必须在1~42之间";
String INFO_RE = "^.{1,170}$";
String INFO_RE_MSG = "描述长度必须在1~170之间";
String CONTENT_RE = "^.{1,170}$";
String CONTENT_RE_MSG = "内容长度必须在1~170之间";
String MENU_URL_RE = "^/[a-zA-Z]{0,256}$";
String MENU_URL_RE_MSG = "跳转地址必须以 / 开头,后续内容仅支持0~256个英文字母";
String MENU_ICON_RE = "^[a-zA-Z]{1,256}$";
String MENU_ICON_RE_MSG = "图标仅支持1~256个英文字母";
String USERNAME_RE = "^[a-zA-Z0-9]{4,20}$";
String USERNAME_RE_MSG = "账号必须由4到20个英文字母或数字组成";
String NICKNAME_RE = "^[\\u4e00-\\u9fa5_a-zA-Z0-9]{4,10}$";
String NICKNAME_RE_MSG = "昵称必须由4到10个中文,英文字母,数字或下划线组成";
String PASSWORD_RE = "^[a-zA-Z0-9]{4,20}$";
String PASSWORD_RE_MSG = "密码必须由4到20个英文字母或数字组成";
String REALNAME_RE = "^[\\u4e00-\\u9fa5]{2,6}$";
String REALNAME_RE_MSG = "真实姓名必须由2到6个中文组成";
String ID_CARD_RE = "^[1-9]\\d{5}(19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$";
String ID_CARD_RE_MSG = "身份证号格式不正确";
String PHONE_RE = "^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\\d{8}$";
String PHONE_RE_MSG = "手机号码格式不正确";
String EMAIL_RE = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";
String EMAIL_RE_MSG = "电子邮箱格式不正确";
String ZODIAC_RE = "^[\\u4e00-\\u9fa5]{2,4}$";
String ZODIAC_RE_MSG = "星座必须由2到4个中文组成";
String PROVINCE_RE = "^[\\u4e00-\\u9fa5]{2,20}$";
String PROVINCE_RE_MSG = "省份必须由2到20个中文组成";
String VCODE_RE = "^\\d{6}$";
String VCODE_RE_MSG = "验证码必须为6位数字";

E03. 运行数据区

心法:运行时数据区域 Runtime Data Area 是 JVM 中的一块内存区域,Java 程序在运行的时候,绝大部分的数据都在运行时数据区中活动。

1. 堆栈存储模式

心法:运行时数据区在逻辑上又被划分成 Stack 和 Heap 两块区域。

Java Stack 栈:相当于小区中的物业室,空间小,功能少,访问方便:

  • 用于存储八大基本数据类型的真正值。
  • 用于存储引用数据类型的内存地址(也称引用)。

Java Heap 堆:相当于小区中的住宅区,空间大,功能多,访问麻烦:

  • 用于存储引用数据类型的真正值。

在这里插入图片描述

武技:测试引用数据类型的内存地址

package basic;

/** @author 周航宇 */
public class RuntimeDataAreaTest {

    @Test
    public void address() {

        // 基本类型变量中存储的是数值
        int money = 100;
        System.out.println(money);

        // 引用类型变量中存储的是内存地址
        RuntimeDataAreaTest runtimeDataAreaTest = new RuntimeDataAreaTest();
        System.out.println(runtimeDataAreaTest);
    }
}

2. 比较内存地址

心法:比较内存地址有 == 符号和 equals() 方法两种方案。

==:用来比较基本类型的数值和引用类型的内存地址。

equals():来自 Object 类,原本也是比较内存地址,而 String 类将其重写为比较内容。

武技:测试两种比较内存地址的方案的区别

package basic;

/** @author 周航宇 */
public class RuntimeDataAreaTest {

    @Test
    public void compare() {

        // 基本数据类型的 ==,比较的是数值
        double numA = 100.0;
        int numB = 50 * 2;
        System.out.println(numA == numB);

        // 引用数据类型的 ==,比较的是内存地址
        String strA = new String("abc");
        String strB = new String("abc");
        System.out.println(strA == strB);

        // 引用数据类型使用equals比较值
        String strC = new String("abc");
        String strD = new String("abc");
        System.out.println(strC.equals(strD));
    }
}

3. 数据装箱拆箱

心法:八个基本数据类型都有相对应的引用数据类型,称为包装类。

装箱:基本类型转成对应包装类的过程,JDK1.5 后是自动装箱的。

拆箱:包装类转成对应基本类型的过程,JDK1.5 后是自动拆箱的,且对包装类进行数学计算的时候会自动触发拆箱操作。

基本数据类型对应的包装类手动装箱手动拆箱
bytejava.lang.Bytenew Byte(基本类型变量)包装类型变量.byteValue()
shortjava.lang.Shortnew Short(基本类型变量)包装类型变量.shortValue()
intjava.lang.Integernew Integer(基本类型变量)包装类型变量.intValue()
longjava.lang.Longnew Long(基本类型变量)包装类型变量.longValue()
floatjava.lang.Floatnew Float(基本类型变量)包装类型变量.floatValue()
doublejava.lang.Doublenew Double(基本类型变量)包装类型变量.doubleValue()
booleanjava.lang.Booleannew Boolean(基本类型变量)包装类型变量.booleanValue()
charjava.lang.Characternew Character(基本类型变量)包装类型变量.charValue()

武技:测试自动装箱和自动拆箱

package basic;

/** @author 周航宇 */
public class RuntimeDataAreaTest {

    @Test
    public void boxing() {

        // 自动装箱: 基本类型 -> 引用类型(包装类)
        Byte bigByte = 100;
        Short bigShort = 200;
        Integer bigInt = 300;
        Long bigLong = 400L;
        Float bigFloat = 1.0F;
        Double bigDouble = 1.1;
        Boolean bigBoolean = true;
        Character bigChar = 'Z';

        // 自动拆箱: 引用类型(包装类) -> 基本类型
        byte smallByte = new Byte((byte) 100);
        short smallShort = new Short((short) 200);
        int smallInt = new Integer(300);
        long smallLong = new Long(400L);
        float smallFloat = new Float(1.0F);
        double smallDouble = new Double(1.1);
        boolean smallBoolean = new Boolean(true);
        char smallChar = new Character('Z');
    }
}

S05. 常用运算符号

E01. 基本运算符

1. 数学运算符

心法:数学运算符是最简单的运算符。

加法运算 +

  • 若加号任意一端出现字符串则变为字符串拼接效果。
  • 对一个数据类型的最大值加 1 后,会变为该类型的最小值。

减法运算 -:对一个数据类型的最小值减 1 后,会变为该类型的最大值。

乘法运算 *:无。

除法运算 /

  • 若操作数都是整数,则除法运算的结果也是必然是一个整数。
  • 任何数除以 0 都会抛出异常。
  • 任何数除以 0.0 的结果都为无穷大,在 Java 中显示为 Infinity 内容。

取余运算 %

  • 0 取余任何数都等于 0。
  • 取余运算结果的正负号,只和第一操作数保持一致。

武技:测试数学运算符

package basic;

/** @author 周航宇 */
public class OperatorTest {

    @Test
    public void math() {

        // 除法运算中,如果操作数都是整数,则结果也是整数
        System.out.println(10 / 4);
        System.out.println(10.0 / 4);

        // 0取余任数都为0
        System.out.println(0 % 3);

        // 取余的结果的正负号只和左边的操作数一致
        System.out.println(-5 % 3);
        System.out.println(-5 % -3);
        System.out.println(5 % -3);

        // 任何数除以0.0都等于无穷大
        System.out.println(1 / 0.0);

        // 除数为0时会抛异常
        System.out.println(1 % 0);
    }
}

2. 赋值运算符

心法:赋值运算优先级最低。

赋值符号(等号):将等号符号后的字面量或变量中的常量赋值给等号前的变量中。

追算符号

  • 追加:a += b 等价于 a = a + b,即将 a + b 的结果重新赋值给 a 变量。
  • 追减:a -= b 等价于 a = a - b,即将 a - b 的结果重新赋值给 a 变量。
  • 追乘:a *= b 等价于 a = a * b,即将 a * b 的结果重新赋值给 a 变量。
  • 追除:a /= b 等价于 a = a / b,即将 a / b 的结果重新赋值给 a 变量。
  • 追模:a %= b 等价于 a = a % b,即将 a % b 的结果重新赋值给 a 变量。

武技:测试赋值相关运算符

package basic;

/** @author 周航宇 */
public class OperatorTest {

    @Test
    public void assign() {

        int a = 1;
        // a+=1 => a=a+1 => ++a
        System.out.println(a += 5);
        System.out.println(a -= 4);
        System.out.println(a *= 3);
        System.out.println(a /= 5);
        System.out.println(a %= 7);
        System.out.println(a);
    }
}

3. 自运算符

心法:自运算优先级最高,且计算过程中不发生任何类型转换。

自增a++ 等价于 a = a + 1,分为 a++ 先用后加和 ++a 先加后用。

自减a-- 等价于 a = a - 1,分为 a-- 先用后减和 --a 先减后用。

武技:测试自我相关运算符

package basic;

/** @author 周航宇 */
public class OperatorTest {

    @Test
    public void self() {

        int a = 1;
        // 先用后加
        System.out.println(a++);
        // 先加后用
        System.out.println(++a);

        // 自运算不发生任何类型转换
        short num = 100;
        num = ++num;
        System.out.println(num);
    }
}

4. 关系运算符

心法:关系运算符不支持连续比较,且均返回布尔类型。

比较符号

  • ==:用来比较基本类型的数值和引用类型的内存地址。
  • >:大于符号,大于等于符号使用 >= 即可。
  • <:小于符号,小于等于符号使用 <= 即可。
  • !=:不等于符号,Java中不支持 <> 的不等符号写法。

武技:测试关系相关运算符

package basic;

/** @author 周航宇 */
public class OperatorTest {

    @Test
    public void relation() {
        int a = 9;
        // 不等式的关系运算符不允许连算
        System.out.println(a > 11);
        System.out.println(a == 11);
        System.out.println(a != 11);
        System.out.println(a < 11);
        System.out.println(a <= 11);
        System.out.println(a >= 11);
    }
}

5. 逻辑运算符

心法:逻辑运算优先级: 非 > 与 > 或,且均返回布尔类型。

逻辑与 &&:与中有假则假,与中全真才真,会发生短路现象。

逻辑或 ||:或中有真则真,或中全假才假,会发生短路现象。

逻辑非 !:非真即假,非假即真。

武技:测试逻辑相关运算符

package basic;

/** @author 周航宇 */
public class OperatorTest {

    @Test
    public void logic() {

        int a = 7;

        // 与中有假则假,与中全真才真
        System.out.println(a < 9 && a == 7);

        // 或中有真则真,或中全假才假
        System.out.println(a == 9 || a != 7);

        // 非真则假,非假则真
        System.out.println(!(a == 9));

        // 与的优先级高于或
        System.out.println(a != 9 || a == 1 && a == 8);
        System.out.println((a != 9 || a == 1) && a == 8);

        // 逻辑运算有短路现象
        System.out.println(false && a++ == 0);
        System.out.println(a);
    }
}

6. 位运算符

心法:位运算符直接操作比特位,效率更高。

位与 &:与中有 0 则 0,与中全 1 才 1,不会发生短路现象。

位或 |:或中有 1 则 1,或中全 0 才 0,不会发生短路现象。

按位取反 ~:0 变 1,1 变 0,包括符号位。

按位异或 ^:相同为 0,不同为 1:

  • 按位异或操作等效于按位无进位相加。
  • 按位异或操作满足交换律,即 a ^ b ^ c = a ^ c ^ b
  • 按位异或操作满足结合律,即 (a ^ b) ^ c = a ^ (b ^ c)
  • 按位异或操作中规定 N ^ 0 = N 以及 N ^ N = 0

按位移动

  • <<:按位左移动,溢出忽略,用 0 右补,左移 N 位相当于乘以 2 的 N 次方。
  • >>:按位右移动,溢出忽略,用符号位左补,右移 N 位相当于除以 2 的 N 次方。
  • >>>:按位无符号右移动,溢出忽略,用 0 左补。

在这里插入图片描述

武技:测试位运算符

package basic;

/** @author 周航宇 */
public class OperatorTest {

    @Test
    public void bit() {

        // 位运算符也可以用于逻辑判断,但不会发生短路现象
        int a = 1;
        System.out.println(false & a++ == 0);
        System.out.println(a);

        // 按位与有0则0
        System.out.println("4 & 6计算补码: " + Integer.toBinaryString(4 & 6));
        System.out.println("4 & 6计算真值: " + (4 & 6));

        // 按位或有1则1
        System.out.println("4 | 6计算补码: " + Integer.toBinaryString(4 | 6));
        System.out.println("4 | 6计算真值: " + (4 | 6));

        // 按位取反: 0变1,1变0
        System.out.println("~4 计算补码: " + Integer.toBinaryString(~4));
        System.out.println("~4 计算真值: " + ~4);

        // 按位异或: 相同为0,不同为1
        System.out.println("4 ^ 6计算补码: " + Integer.toBinaryString(4 ^ 6));
        System.out.println("4 ^ 6计算真值: " + (4 ^ 6));

        // 左移动: 溢出忽略,右边用0补位
        System.out.println("-2 << 3计算补码: " + Integer.toBinaryString(-2 << 3));
        System.out.println("-2 << 3计算真值: " + (-2 << 3));

        // 带符号右移动: 溢出忽略,左边用符号位补位
        System.out.println("-2 >> 3计算补码: " + Integer.toBinaryString(-2 >> 3));
        System.out.println("-2 >> 3计算真值: " + (-2 >> 3));

        // 无符号右移动: 溢出忽略,左边用0补位
        System.out.println("-2 >>> 3计算补码: " + Integer.toBinaryString(-2 >>> 3));
        System.out.println("-2 >>> 3计算真值: " + (-2 >>> 3));
    }
}

E02. 三目运算符

心法:三目运算符,也叫三元运算符或三步运算符,支持嵌套。

公式:X ? Y : Z,表示当 X 为 true 时返回 Y,当 X 为 false 时返 Z。

要求:Y 和 Z 的类型必须一致,且三元运算符的返回值类型为 Y 或 Z 的返回值类型。

武技:测试三目逻辑运算符

package basic;

/** @author 周航宇 */
public class OperatorTest {

    @Test
    public void ternary() {
        int num = -1;

        // 公式: X ? Y : Z
        String result = num > 0 ? "大于等于零" : "小于零";
        System.out.println(result);
    }
}

S06. 流程结构控制

E01. 选择结构

心法:选择结构也叫分支结构,表示多选一。

当大括号中仅一行代码时,可以省略大括号,但是并不建议这么写。

1. IfElse结构

心法:if 选择适用于范围条件匹配业务。

if 结构

if (条件) {
	代码;
} else if(条件) {
	代码;
} else {
	代码;
}
组成部分描述允许存在的数量
if ( 条件 ) { 代码块 }当满足条件时进入代码块必须有,而且只能有一个
else if ( 条件 ) { 代码块 }当满足条件时进入代码块可以有 N 个,N>=0
else { 代码块 }当全部条件都不满足时进入代码块要么只有一个,要么没有

武技:测试 IF/ELSE 选择结构

package structure;

/** @author 周航宇 */
public class ChooseTest {

    @Test
    public void ifElse() {

        int score = 60;

        // if(条件){满足条件时执行的代码}
        if (score >= 60) {
            System.out.println("你及格了...");
        }

        // if(条件){满足条件时执行的代码} else {其他情况}
        if (score >= 60) {
            System.out.println("你及格了...");
        } else {
            System.out.println("你没及格...");
        }

        // if(条件){满足条件时执行的代码} else if(条件) {满足条件时执行的代码} else {其他情况}
        if (score >= 80) {
            System.out.println("你很优秀...");
        } else if (score >= 60) {
            System.out.println("你及格了...");
        } else if (score >= 0) {
            System.out.println("你没及格...");
        } else {
            System.out.println("分数异常...");
        }
    }
}

2. Switch结构

心法:switch 选择适用于定值条件匹配业务。

switch 结构

switch (表达式) { 
	case 匹配值: 
		代码; 
		break; 
	case 匹配值: 
		代码;
		break; 
	default: 
		代码;
		break; 
}
组成部分描述
switch (定值)定值可选 byte/short/int/char/String 类型变量,表达式以及枚举类型
case 匹配值: 代码块 break;当定值匹配到匹配值时,进入代码块
default: 代码块 break;当全部匹配值都匹配失败时,进入代码块

switch 穿透现象:若 case 后无 break 则不会跳出,会继续按顺序向下执行,直到遇到 break 或所有代码执行完为止。

武技:测试 switch 选择结构

package structure;

/** @author 周航宇 */
public class ChooseTest {

    @Test
    public void switchCase() {
        int num = 1;

        // 括号中是表达式而不是条件
        switch (num + 1) {
            case 1:
                System.out.println("你的数字是0...");
                break;
            case 2:
                System.out.println("你的数字是1...");
            case 3:
                System.out.println("你的数字是2...");
                break;
            case 4:
                System.out.println("你的数字是3...");
                break;
            case 5:
                System.out.println("你的数字是4...");
                break;
            default:
                System.out.println("数字不是1234中的一个...");
                break;
        }
    }
}

3. Switch表达式

心法:从 JDK12 开始,支持了 switch 表达式,可以进一步简化 switch 结构,并使其可以拥有返回值。

switch 表达式结构

返回值类型 变量名 = switch(表达式){
	case 匹配值 -> 返回值; 
	case 匹配值, 匹配值 -> 返回值; 
	case 匹配值, 匹配值 -> {
		yield 返回值;
	}; 
	default -> 返回值;
};

武技:测试 SWITCH 表达式用法

package structure;

/** @author 周航宇 */
public class ChooseTest {

    @Test
    public void switchExpression() {
        int day = 8;
        String result = switch (day) {
            case 1, 2, 3, 4, 5 -> "工作日";
            case 6, 7 -> "休息日";
            default -> {
                yield "输入有误";
            }
        };
        System.out.println(result);
    }
}

E02. 循环结构

心法:循环就是重复性做事,但必须是有逻辑有规律的事情才可使用循环。

当大括号中仅一行代码时,可以省略大括号,但是并不建议这么写。

无论那种循环,都满足初判变法则:

  • : 初始化变量(只执行一遍)。
  • : 循环判断条件(只有满足条件的时候才执行循环)。
  • : 每次循环体结束之后将执行变量的变化。

1. While循环

心法:while 循环的特点是先判断后循环,当条件不满足时,循环体一次都不会执行。

while 循环结构

while(条件) { 
	代码;
}

武技:测试 while 循环结构

package structure;

/** @author 周航宇 */
public class LoopTest {

    @Test
    public void whileLoop() {

        // 初
        int i = 1;

        // 判
        while (i <= 10) {
            System.out.println(i);

            // 变
            i++;
        }
    }
}

2. DoWhile循环

心法:do-while 循环的特点是先循环后判断,即使条件不满足,循环体也会先执行一次。

do-while 循环结构

do { 
	代码;
} while (条件);

武技:测试 do-while 循环结构

package structure;

/** @author 周航宇 */
public class LoopTest {

    @Test
    public void doWhileLoop() {

        // 初
        int i = 100;

        do {
            System.out.println(i);

            // 变
            i++;

            // 判
        } while (i <= 10);
    }
}

3. For循环

心法:FOR 循环的初、判、变三要素均在一行编写,简单明了。

for 循环结构

for(;;){
	代码;
}

武技:测试 for 循环结构

package structure;

/** @author 周航宇 */
public class LoopTest {

    @Test
    public void forLoop() {
        // fori + tab
        for (int i = 1; i <= 10; i++) {
            System.out.println(i);
        }
    }
}

E03. 流控关键字

1. continue

心法:循环体中使用 continue 关键字可以立即结束本次循环,并开启下一次循环。

武技:测试 continue 流控关键字

package structure;

/** @author 周航宇 */
public class LoopTest {

    @Test
    public void continueLoop() {
        for (int i = 0; i < 10; i++) {
            if (i == 3) {
                continue;
            }
            System.out.println(i);
        }
    }
}

2. break

心法:循环体中使用 break 关键字可以立即结束所有轮次的循环。

break 关键字可配合循环别名如 out: 跳出指定某一层循环。

武技:测试 break 流控关键字

package structure;

/** @author 周航宇 */
public class LoopTest {

    @Test
    public void breakLoop() {
        out:
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (i == 2) {
                    break out;
                }
            }
            System.out.println(i);
        }
    }
}

S07. 数组数据类型

心法:数组 array 是内存中一段内存连续的线性数据结构,属于引用数据类型。

数组结构特点描述
拥有下标数组的下标从 0 开始,支持使用 数组[索引] 的格式来操作数组元素
拥有默认值数组中的每个最底层元素都具有默认值,如 0, 0.0, false, \u0000, null 等
定长数组在创建之后,长度不可更改
增删慢数组长度不可改变,导致增删操作必须使用创新数组,效率低
查询快数组中每个元素的内存地址连续可计算,所以在明确位置的情况下,查询效率更高

E01. 一维数组

心法:一维数组中的每个元素都是一个单一数据类型,且全部元素的数据类型必须一致。

1. 内存分布

心法:数组在内存中分为两部分存储,变量名在栈中,值在堆中。

栈变量中存放的是数组中,第一个元素的内存地址,即数组首地址。

一维数组内存分布如图

在这里插入图片描述

2. 声明赋值

心法:一维数组在声明时,int[] arr / int []arr / int arr[] 效果相同。

数组创建原则:数组在创建的时候,要么指定内容,要么指定长度,但二者不可同时指定。

输出数组对象

  • 字符数组:可以直接输出值,对字符数组拼接空字符串或调用其 toString() 方法可获取其内存地址。
  • 非字符数组:直接输出的结果为堆内存中,数组的首地址。
一维数组创建方式示例
仅指定长度int[] arr = new int[5]
仅指定内容int[] arr = new int[]{5, 2, 77}
仅指定内容(简化版)int[] arr = {5, 2, 77}

武技:测试一维数组的创建

package array;

/** @author 周航宇 */
public class OneArrayTest {

    @Test
    public void build() {

        // 创建数组: 要么指定内容,要么指定长度,但不可同时指定
        byte[] arrA = new byte[]{5, 2, 77};
        long[] arrB = {1L, 3L, 5L, 7L, 9L};
        char[] arrC = new char[3];
        arrC[0] = 'B';
        arrC[1] = 'O';
        arrC[2] = 'Y';

        // 直接对非字符数组进行打印,输出的是数组的内存地址
        System.out.println(arrA);
        System.out.println(arrB);

        // 使用数组的索引取值
        System.out.println(arrA[0]);
        System.out.println(arrB[0]);

        // 仅字符数组可以直接输出值,对其拼接字符串或调用toString()方法,可以获得内存地址
        System.out.println(arrC);
        System.out.println("" + arrC);
        System.out.println(arrC.toString());
    }
}

3. 数组遍历

心法:一维数组有 fori,for-each 和 Arrays 工具三种遍历方式。

FOR-I 遍历:适用于遍历过程中需要操作索引变量的场景:

for(int i = 0, j < 数组.length; i < j; i++){
	System.out.println(数组[i]);
}

FOR-E 遍历:适用于遍历过程中无需操作索引变量的场景:

for(元素类型 e: 数组){
	System.out.println(e);
}

Arrays工具:适用于仅查看数组中的全部元素的场景:

Arrays.toString(数组);

武技:测试一维数组的遍历

package array;

/** @author 周航宇 */
public class OneArrayTest {

    @Test
    public void iterator() {

        String[] arr = {"你好", "世界"};

        // 数组.length 返回数组中有多少个元素
        // 利用普通的for循环进行遍历
        for (int i = 0, j = arr.length; i < j; i++) {
            System.out.print(i + "-" + arr[i] + "\t");
        }
        System.out.println();

        // 如果需要从头到尾遍历,可以使用for-each循环
        for (String e : arr) {
            System.out.print(e + "\t");
        }
        System.out.println();

        // 使用Arrays工具类查看数组中的元素
        System.out.println(Arrays.toString(arr));
    }
}

E02. 多维数组

心法:二维数组的本质也是一维数组,只不过其中的每个元素都是一个一维数组类型。

二维数组中元素的类型必须一致,但元素的长度可以不同。

1. 内存分布

心法:二维数组本身是内存连续的,但其指向的 N 个一维数组未必是内存连续的。

二维数组内存分布如图

在这里插入图片描述

2. 声明赋值

心法:二维数组在声明时,int[][] arr / int[] []arr / int[] arr[] / int [][]arr / int arr[][] 效果相同。

数组创建原则:数组在创建的时候,要么指定内容,要么指定长度,但二者不可同时指定。

输出数组对象:直接输出二维数组,打印的是该数组的内存地址,即使是字符数组也一样。

创建方式示例代码描述
仅指定长度int[][] arr = new int[3][2]生成 3 行 2 列的数组
仅指定内容int[][] arr = new int[][]{ {5, 2}, {77} }生成 2 行 2 列的数组
仅指定内容(简化版)int[][] arr = { {5, 2}, {77} }生成 2 行 2 列的数组

武技:测试二维数组的创建

package array;

/** @author 周航宇 */
public class TwoArrayTest {

    @Test
    public void build() {
        // 创建数组: 要么指定内容,要么指定长度,但不可同时指定
        byte[][] arrA = new byte[][]{{3, 1, 3}, {5}, {2, 77}};
        long[][] arrB = {{3L, 1L, 3L}, {5L}, {2L, 77L}};
        char[][] arrC = new char[2][3];
        arrC[0][0] = 'H';
        arrC[0][1] = 'I';
        arrC[1][0] = 'B';
        arrC[1][1] = 'O';
        arrC[1][2] = 'Y';

        // 直接输出二维数组,打印的是该数组的内存地址,即使是字符数组也一样
        System.out.println(arrA);
        System.out.println(arrB);
        System.out.println(arrC);

        // 使用数组的索引取值
        System.out.println(arrA[0]);
        System.out.println(arrB[1]);
        System.out.println(arrC[1]);
        System.out.println(arrA[0][0]);
        System.out.println(arrB[0][1]);
        System.out.println(arrC[0][2]);
    }
}

3. 数组遍历

心法:二维数组有 fori,for-each 和 Arrays 工具三种遍历方式。

FOR-I 遍历:适用于遍历过程中需要操作索引变量的场景:

for(int i = 0, j < 数组.length; i < j; i++){
	for(int m = 0, n < 数组[i].length; m < n; i++){
		System.out.println(数组[i][m]);
	}
}

FOR-E 遍历:适用于遍历过程中无需操作索引变量的场景:

for(元素类型 e1: 数组){
	for(元素类型 e2: e1){
		System.out.println(e2);
	}
}

Arrays工具:适用于仅查看数组中的全部元素的场景:

Arrays.deepToString(数组);

武技:测试二维数组的遍历

package array;

/** @author 周航宇 */
public class TwoArrayTest {

    @Test
    public void iterator() {

        int[][] arr = {
                {3, 1, 3, 1, 44, 5, 6, 788, 3, 12},
                {5, 2, 13, 4, 5, 56, 7},
                {2, 77, 5, 45, 1, 3, 13}
        };

        // 使用ForI遍历二维数组
        for (int i = 0, j = arr.length; i < j; i++) {
            for (int m = 0, n = arr[i].length; m < n; m++) {
                System.out.print(arr[i][m] + "\t");
            }
            System.out.println();
        }

        System.out.println("---------divider---------");

        // 使用ForE遍历二维数组
        for (int[] e1 : arr) {
            for (int e2 : e1) {
                System.out.print(e2 + "\t");
            }
            System.out.println();
        }

        // 使用Arrays工具类查看数组中的元素
        System.out.println(Arrays.deepToString(arr));
    }
}

Java道经第1卷 - 第2阶 - 基础启航(二)


传送门:JB1-2-基础启航(一)
传送门:JB1-2-基础启航(二)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值