Java基础
程序流程
Java默认初始值与无默认区分
public class DefaultValuesExample { int instanceVar; // 默认值: 0 static int staticVar; // 默认值: 0 int[] array = new int[5]; // 数组元素默认值: 0 public void method() { int localVar; // 局部变量,必须显式初始化 // System.out.println(localVar); // 编译错误 } public static void main(String[] args) { DefaultValuesExample example = new DefaultValuesExample(); System.out.println("Instance variable: " + example.instanceVar); System.out.println("Static variable: " + staticVar); System.out.println("Array element: " + example.array[0]); } }局部变量必须有显式初始化
Java简易程序
public class Hello { public static void main(String[] args) { System.out.println("Hello, world!"); } }- 定义称为class(类),这里的类名是
Hello,大小写敏感,class用来定义一个类,public表示这个类是公开的,public、class都是Java的关键字,必须小写,Hello是类的名字,按照习惯,首字母H要大写。而花括号{}中间则是类的定义 - 方法是可执行的代码块,一个方法除了方法名
main,还有用()括起来的方法参数,这里的main方法有一个参数,参数类型是String[],参数名是args,public、static用来修饰方法,这里表示它是一个公开的静态方法,void是方法的返回类型,而花括号{}中间的就是方法的代码 - 方法的代码每一行用
;结束 - 把代码保存为文件时,文件名必须是
Hello.java,而且文件名也要注意大小写
- 定义称为class(类),这里的类名是
运行Java程序
- 需要先用
javac把Hello.java编译成字节码文件Hello.class,然后,用java命令执行这个字节码文件:
┌──────────────────┐ │ Hello.java │◀── source code └──────────────────┘ │ compile ▼ ┌──────────────────┐ │ Hello.class │◀── byte code └──────────────────┘ │ execute ▼ ┌──────────────────┐ │ Run on JVM │ └──────────────────┘第一步,在保存
Hello.java的目录下执行命令javac Hello.java:$ javac Hello.java第二步,执行
Hello.class,使用命令java Hello(注意不是java Hello.class):$ java Hello Hello, world!
- 需要先用
注释
第一种是单行注释,以双斜线开头,直到这一行的结尾结束:
// 这是注释而多行注释以
/*星号开头,以*/结束,可以有多行:/* 这是注释 */特殊的多行注释,以
/**开头,以*/结束,如果有多行,每行通常以星号开头:/** * 可以用来自动创建文档的注释 * * @auther wang */
变量和数据结构
变量:
基本类型变量
在Java中,变量必须先定义后使用,在定义变量的时候,可以给它一个初始值。例如:
int x = 1;不写初始值,就相当于给它指定了默认值。
变量的一个重要特点是可以重新赋值
+ 引用类型变量
基本数据类型:CPU可以直接进行运算的类型
整数类型:byte,short,int,long
浮点数类型:float,double
字符类型:char
布尔类型:boolean
不同数据类型占用的字节数不一样。Java基本数据类型占用的字节数:
┌───┐ byte │ │ └───┘ ┌───┬───┐ short │ │ │ └───┴───┘ ┌───┬───┬───┬───┐ int │ │ │ │ │ └───┴───┴───┴───┘ ┌───┬───┬───┬───┬───┬───┬───┬───┐ long │ │ │ │ │ │ │ │ │ └───┴───┴───┴───┴───┴───┴───┴───┘ ┌───┬───┬───┬───┐ float │ │ │ │ │ └───┴───┴───┴───┘ ┌───┬───┬───┬───┬───┬───┬───┬───┐ double │ │ │ │ │ │ │ │ │ └───┴───┴───┴───┴───┴───┴───┴───┘ ┌───┬───┐ char │ │ │ └───┴───┘byte恰好就是一个字节,而long和double需要8个字节计算机内存的最小存储单元是字节(byte),一字节就是一8位二进制数,即8个bit
整型
- 同一个数的不同进制的表示是完全相同的,例如
15=0xf=0b1111
- 同一个数的不同进制的表示是完全相同的,例如
浮点数
浮点类型的数就是小数
float f1 = 3.14f; float f2 = 3.14e38f; // 科学计数法表示的3.14x10^38 float f3 = 1.0; // 错误:不带f结尾的是double类型,不能赋值给float double d3 = 4.9e-324; // 科学计数法表示的4.9x10^-324
布尔类型
boolean:true与false- Java语言对布尔类型存储没有规定,理论上存储布尔类型只需要1 bit,但是通常JVM内部会把
boolean表示为4字节整数
- Java语言对布尔类型存储没有规定,理论上存储布尔类型只需要1 bit,但是通常JVM内部会把
字符类型
字符类型
char表示一个字符。使用单引号',且仅有一个字符Java的
char类型除了可表示标准的ASCII外,还可以表示一个Unicode字符char a = 'A'; char zh = '中';
引用类型
引用类型的变量类似于C语言的指针,内部存储一个“地址”,指向某个对象在内存的位置
除了上述基本类型的变量,剩下的都是引用类型
例如,引用类型最常用的就是
String字符串:String s = "hello";
常量
定义变量的时候,如果加上
final修饰符常量在定义时进行初始化后就不可再次赋值,再次赋值会导致编译错误
为了和变量区分开来,根据习惯,常量名通常全部大写
final double PI = 3.14; // PI是一个常量 double r = 5.0; double area = PI * r * r; PI = 300; // compile error!
var关键字有些时候,类型的名字太长,写起来比较麻烦。例如:
StringBuilder sb = new StringBuilder();如果想省略变量类型,可以使用
var关键字:var sb = new StringBuilder();使用
var定义变量,仅仅是少写了变量类型而已如果想省略变量类型,可以使用
var关键字:var sb = new StringBuilder();编译器根据赋值语句推断变量
sb的类型StringBuilder。对编译器来说,语句:var sb = new StringBuilder();
变量的作用范围
在Java中,多行语句用
{ ... }括起来。很多控制语句,例如条件判断和循环,都以{ ... }作为它们自身的范围,例如:if (...) { // if开始 ... while (...) { // while 开始 ... if (...) { // if开始 ... } // if结束 ... } // while结束 ... } // if结束
整数运算
整数运算遵循四则运算,可使用任意嵌套的小括号。四则运算规则和初等数学一致
int i = (100 + 200) * (99 - 88); // 3300 int n = 7 * (5 + (i - 9)); // 23072整数的数值不但是精确的,而且整数运算永远是精确的,即使除法也是精确,因为两个整数相除只能得到结果的整数部分:
int x = 12345 / 67; // 184求余运算使用
%:int y = 12345 % 67; // 12345÷67的余数是17整数的除法对于除数为0时运行时将报错,但编译不会报错
溢出
整数由于存在范围限制,如果计算结果超出了范围,就会产生溢出,而溢出不会出错,却会得到一个奇怪的结果
int x = 2147483640; int y = 15; int sum = x + y; System.out.println(sum); // -2147483641要解决上面的问题,可以把
int换成long类型,由于long可表示的整型范围更大long x = 2147483640; long y = 15; long sum = x + y; System.out.println(sum); // 2147483655
自增自减
- 注意
++写在前面和后面计算结果是不同的,++n表示先加1再引用n,n++表示先引用n再加1 - 不建议把
++运算混入到常规运算中,容易自己把自己搞懵了
- 注意
移位运算
左移实际上就是不断地×2,右移实际上就是不断地÷2
正数左移
int n = 7; // 00000000 00000000 00000000 00000111 = 7 int a = n << 1; // 00000000 00000000 00000000 00001110 = 14 int b = n << 2; // 00000000 00000000 00000000 00011100 = 28 int c = n << 28; // 01110000 00000000 00000000 00000000 = 1879048192 int d = n << 29; // 11100000 00000000 00000000 00000000 = -536870912正数右移
int n = 7; // 00000000 00000000 00000000 00000111 = 7 int a = n >> 1; // 00000000 00000000 00000000 00000011 = 3 int b = n >> 2; // 00000000 00000000 00000000 00000001 = 1 int c = n >> 3; // 00000000 00000000 00000000 00000000 = 0负数右移:最高位的
1不动,结果仍然是一个负数int n = -536870912; int a = n >> 1; // 11110000 00000000 00000000 00000000 = -268435456 int b = n >> 2; // 11111000 00000000 00000000 00000000 = -134217728 int c = n >> 28; // 11111111 11111111 11111111 11111110 = -2 int d = n >> 29; // 11111111 11111111 11111111 11111111 = -1无符号的右移运算,使用
>>>不管符号位,右移后高位总是补
0,因此,对一个负数进行>>>右移,它会变成正数,原因是最高位的1变成了0int n = -536870912; int a = n >>> 1; // 01110000 00000000 00000000 00000000 = 1879048192 int b = n >>> 2; // 00111000 00000000 00000000 00000000 = 939524096 int c = n >>> 29; // 00000000 00000000 00000000 00000111 = 7 int d = n >>> 31; // 00000000 00000000 00000000 00000001 = 1
位运算
- 位运算是按位进行与、或、非和异或的运算
- 与运算:必须两个数同时为
1,结果才为1 - 或运算:只要任意一个为
1,结果就为1 - 非运算:
0和1互换 - 异或运算:如果两个数不同,结果为
1,否则为0
- 与运算:必须两个数同时为
- 与运算可以看作两个整数的IP地址
10.0.17.77和10.0.17.0,通过与运算,可以**快速判断一个IP是否在给定的网段内**
- 位运算是按位进行与、或、非和异或的运算
类型自动提升与强制转型
运算过程中,如果参与运算的两个数类型不一致,那么计算结果为较大类型的整型
short s = 1234; int i = 123456; int x = s + i; // s自动转型为int short y = s + i; // 编译错误!将结果强制转型,即将大范围的整数转型为小范围的整数。强制转型使用
(类型)int i = 12345; short s = (short) i; // 12345要注意,超出范围的强制转型会得到错误的结果
浮点数运算
浮点数运算和整数运算相比,只进行加减乘除这些数值计算,不能做位运算和移位运算
浮点数常常无法精确表示,比如
0.1在计算机中就无法精确表示由于浮点数存在运算误差,所以比较两个浮点数是否相等常常会出现错误的结果。正确的比较方法是判断两个浮点数之差的绝对值是否小于一个很小的数:
// 比较x和y是否相等,先计算其差的绝对值: double r = Math.abs(x - y); // 再判断绝对值是否足够小: if (r < 0.00001) { // 可以认为相等 } else { // 不相等 }类型提升
如果参与运算的两个数其中一个是整型,那么整型可以自动提升到浮点型
int n = 5; double d = 1.2 + 24.0 / n; // 6.0在一个复杂的四则运算中,两个整数的运算不会出现自动提升的情况。例如:
double d = 1.2 + 24 / 5; // 结果不是 6.0 而是 5.2
溢出
整数运算在除数为
0时会报错,而浮点数运算在除数为0时,不会报错double d1 = 0.0 / 0; // NaN double d2 = 1.0 / 0; // Infinity double d3 = -1.0 / 0; // -Infinity
强制转型
将浮点数强制转型为整数。在转型时,浮点数的小数部分会被丢掉。如果转型后超过了整型能表示的最大范围,将返回整型的最大值
int n1 = (int) 12.3; // 12 int n2 = (int) 12.7; // 12 int n3 = (int) -12.7; // -12 int n4 = (int) (12.7 + 0.5); // 13 int n5 = (int) 1.2e20; // 2147483647
布尔运算
对于布尔类型
boolean,永远只有true和false两个值boolean isGreater = 5 > 3; // true int age = 12; boolean isZero = age == 0; // false boolean isNonZero = !isZero; // true boolean isAdult = age >= 18; // false boolean isTeenager = age >6 && age <18; // true短路运算:
如果布尔运算的表达式能提前确定结果,则后续的计算不再执行,直接返回结果
// 短路运算 public class Main { public static void main(String[] args) { boolean b = 5 < 3; boolean result = b && (5 / 0 > 0); // 此处 5 / 0 不会报错 System.out.println(result); } }三元运算符
b ? x : y三元运算
b ? x : y会首先计算b,如果b为true,则只计算x,否则,只计算y。此外,x和y的类型必须相同,因为返回值不是boolean,而是x和y之一
字符和字符串
字符类型
char是基本数据类型,一个char保存一个Unicode字符:char c1 = 'A'; char c2 = '中';直接用转义字符
\u+Unicode编码来表示一个字符:// 注意是十六进制: char c3 = '\u0041'; // 'A',因为十六进制0041 = 十进制65 char c4 = '\u4e2d'; // '中',因为十六进制4e2d = 十进制20013字符串
String是引用类型,我们用双引号
"..."表示字符串。一个字符串可以存储0个到任意个字符String s = "ABC\n\u4e2d\u6587"; // 包含6个字符: A, B, C, 换行符, 中, 文字符串连接
String s1 = "Hello"; String s2 = "world"; String s = s1 + " " + s2 + "!"; System.out.println(s); // Hello world!用
+连接字符串和其他数据类型,会将其他数据类型先自动转型为字符串,再连接:int age = 25; String s = "age is " + age; System.out.println(s); // age is 25多行字符串
如果我们要表示多行字符串,使用+号连接会非常不方便:
String s = "first line \n" + "second line \n" + "end";从Java 13开始,字符串可以用
"""..."""表示多行字符串(Text Blocks)了。eg// 多行字符串 public class Main { public static void main(String[] args) { String s = """ SELECT * FROM users WHERE id > 100 ORDER BY name DESC """; System.out.println(s); } }不可变特性
public class Main { public static void main(String[] args) { String s = "hello"; System.out.println(s); // 显示 hello s = "world"; System.out.println(s); // 显示 world } }变的不是字符串,而是变量
s的“指向”空值null :指向一个空值
null,表示不存在,即该变量不指向任何对象String s1 = null; // s1是null String s2 = s1; // s2也是null String s3 = ""; // s3指向空字符串,不是null区分空值
null和空字符串"",空字符串是一个有效的字符串对象,它不等于null
数组类型
Java的数组有几个特点:
- 数组所有元素初始化为默认值,整型都是
0,浮点型是0.0,布尔型是false; - 数组一旦创建后,大小就不可改变。
- 数组所有元素初始化为默认值,整型都是
注意数组是引用类型,并且数组大小不可变。我们观察下面的代码:
public class Main { public static void main(String[] args) { // 5位同学的成绩: int[] ns; ns = new int[] { 68, 79, 91, 85, 62 }; System.out.println(ns.length); // 5 ns = new int[] { 1, 2, 3 }; System.out.println(ns.length); // 3 } }原有的5个元素的数组并没有改变,只是无法通过变量
ns引用到它们而已字符串数组
public class Main { public static void main(String[] args) { String[] names = {"ABC", "XYZ", "zoo"}; String s = names[1]; names[1] = "cat"; System.out.println(s); // "XYZ" } }
数组是同一数据类型的集合,数组一旦创建后,大小就不可变;
可以通过索引访问数组元素,但索引超出范围将报错;
数组元素可以是值类型(如
int)或引用类型(如String),但数组本身是引用类型
流程控制
输入输出
输出
System.out.printf(),通过使用占位符%?,printf()可以把后面的参数格式化成指定格式:// 格式化输出 public class Main { public static void main(String[] args) { double d = 3.1415926; System.out.printf("%.2f\n", d); // 显示两位小数3.14 System.out.printf("%.4f\n", d); // 显示4位小数3.1416 } }占位符 说明 %d 格式化输出整数 %x 格式化输出十六进制整数 %f 格式化输出浮点数 %e 格式化输出科学计数法表示的浮点数 %s 格式化字符串 输入
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // 创建Scanner对象 System.out.print("Input your name: "); // 打印提示 String name = scanner.nextLine(); // 读取一行输入并获取字符串 System.out.print("Input your age: "); // 打印提示 int age = scanner.nextInt(); // 读取一行输入并获取整数 System.out.printf("Hi, %s, you are %d\n", name, age); // 格式化输出 } }$ java Main Input your name: Bob ◀── 输入 Bob Input your age: 12 ◀── 输入 12 Hi, Bob, you are 12 ◀── 输出
if条件判断// 条件判断 public class Main { public static void main(String[] args) { int n = 90; if (n > 90) { System.out.println("优秀"); } else if (n >= 60) { System.out.println("及格了"); } else { System.out.println("挂科了"); } } }前面讲过了浮点数在计算机中常常无法精确表示,并且计算可能出现误差,因此,判断浮点数相等用
==判断不靠谱:// 条件判断 public class Main { public static void main(String[] args) { double x = 1 - 9.0 / 10; if (x == 0.1) { System.out.println("x is 0.1"); } else { System.out.println("x is NOT 0.1"); } } }正确的方法是利用差值小于某个临界值来判断:
// 条件判断 public class Main { public static void main(String[] args) { double x = 1 - 9.0 / 10; if (Math.abs(x - 0.1) < 0.00001) { System.out.println("x is 0.1"); } else { System.out.println("x is NOT 0.1"); } } }判断引用类型相等
使用
==运算符。但是,判断引用类型的变量是否相等,==表示“引用是否相等”,或者说,是否指向同一个对象public class Main { public static void main(String[] args) { String s1 = "hello"; String s2 = "HELLO".toLowerCase(); System.out.println(s1); System.out.println(s2); if (s1 == s2) { System.out.println("s1 == s2"); } else { System.out.println("s1 != s2"); } } }hello hello s1 != s2判断引用类型的变量内容是否相等,必须使用
equals()方法public class Main { public static void main(String[] args) { String s1 = "hello"; String s2 = "HELLO".toLowerCase(); System.out.println(s1); System.out.println(s2); if (s1.equals(s2)) { System.out.println("s1 equals s2"); } else { System.out.println("s1 not equals s2"); } } }hello hello s1 equals s2执行语句
s1.equals(s2)时,如果变量s1为null,会报NullPointerException:// 条件判断 public class Main { public static void main(String[] args) { String s1 = null; if (s1.equals("hello")) { System.out.println("hello"); } } }要避免
NullPointerException错误,可以利用短路运算符&&:// 条件判断 public class Main { public static void main(String[] args) { String s1 = null; if (s1 != null && s1.equals("hello")) { System.out.println("hello"); } } }
switch多重选择public class Main { public static void main(String[] args) { int option = 99; switch (option) { case 1: System.out.println("Selected 1"); break; case 2: System.out.println("Selected 2"); break; case 3: System.out.println("Selected 3"); break; default: System.out.println("Selected other"); break; } } }switch语句根据switch (表达式)计算的结果,跳转到匹配的case结果,然后继续执行后续语句,直到遇到break结束执行当没有匹配到任何
case时,执行default使用
switch时,注意**case语句并没有花括号{}**,而且,case语句具有“穿透性”,漏写break将导致意想不到的结果:// switch public class Main { public static void main(String[] args) { int option = 2; switch (option) { case 1: System.out.println("Selected 1"); case 2: System.out.println("Selected 2"); case 3: System.out.println("Selected 3"); default: System.out.println("Selected other"); } } }当
option = 2时,将依次输出"Selected 2"、"Selected 3"、"Selected other"编译检查
使用IDE时,可以自动检查是否漏写了
break语句和default语句在Idea中,选择
Preferences-Editor-Inspections-Java-Control flow issues,将以下检查标记为Warning:- ‘switch’ statement without ‘default’ branch:缺少
default语句时警告; - Fallthrough in ‘switch’ statement:某个
case缺少break时警告。
当
switch语句存在问题时,即可在IDE中获得警告提示。- ‘switch’ statement without ‘default’ branch:缺少
注意新语法使用
->,如果有多条语句,需要用{}括起来。不要写break语句,因为新语法只会执行匹配的语句,没有穿透效应public class Main { public static void main(String[] args) { String fruit = "apple"; switch (fruit) { case "apple" -> System.out.println("Selected apple"); case "pear" -> System.out.println("Selected pear"); case "mango" -> { System.out.println("Selected mango"); System.out.println("Good choice!"); } default -> System.out.println("No fruit selected"); } } }yield如果需要复杂的语句,我们也可以写很多语句,放到
{...}里,然后,用yield返回一个值作为switch语句的返回值public class Main { public static void main(String[] args) { String fruit = "orange"; int opt = switch (fruit) { case "apple" -> 1; case "pear", "mango" -> 2; default -> { int code = fruit.hashCode(); yield code; // switch语句返回值 } }; System.out.println("opt = " + opt); } }
while循环public class Main { public static void main(String[] args) { int sum = 0; // 累加的和,初始化为0 int n = 1; while (n <= 100) { // 循环条件是n <= 100 sum = sum + n; // 把n累加到sum中 n ++; // n自身加1 } System.out.println(sum); // 5050 } }死循环将导致100%的CPU占用,用户会感觉电脑运行缓慢,要避免编写死循环代码
表面上死循环,Java的
int类型有最大值,达到最大值后,再加1会变成负数,结果,意外退出了while循环public class Main { public static void main(String[] args) { int sum = 0; int n = 1; while (n > 0) { sum = sum + n; n ++; } System.out.println(n); // -2147483648 System.out.println(sum); } }
do while循环while循环:先判断循环条件,再执行循环do while循环:先执行循环,再判断条件把对1到100的求和用
do while循环改写一下:// do-while public class Main { public static void main(String[] args) { int sum = 0; int n = 1; do { sum = sum + n; n ++; } while (n <= 100); System.out.println(sum); } }
for循环for (初始条件; 循环检测条件; 循环后更新计数器) { // 执行语句 }public class Main { public static void main(String[] args) { int sum = 0; for (int i=1; i<=100; i++) { sum = sum + i; } System.out.println(sum); } }注意
for循环的初始化计数器总是会被执行,并且for循环也可能循环0次for each循环public class Main { public static void main(String[] args) { int[] ns = { 1, 4, 9, 16, 25 }; for (int n : ns) { System.out.println(n); } } }除了数组外,
for each循环能够遍历所有“可迭代”的数据类型,包括后面会介绍的List、Map等
break和continuebreak语句跳出当前循环,总是跳出自己所在的那一层循环continue语句可以提前结束本次循环
数组操作:遍历,排序
遍历
public class Main { public static void main(String[] args) { int[] ns = { 1, 4, 9, 16, 25 }; for (int i=0; i<ns.length; i++) { int n = ns[i]; System.out.println(n); } } }public class Main { public static void main(String[] args) { int[] ns = { 1, 4, 9, 16, 25 }; for (int n : ns) { System.out.println(n); } } }
数组排序
// 冒泡排序 import java.util.Arrays; public class Main { public static void main(String[] args) { int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 }; // 排序前: System.out.println(Arrays.toString(ns)); for (int i = 0; i < ns.length - 1; i++) { for (int j = 0; j < ns.length - i - 1; j++) { if (ns[j] > ns[j+1]) { // 交换ns[j]和ns[j+1]: int tmp = ns[j]; ns[j] = ns[j+1]; ns[j+1] = tmp; } } } // 排序后: System.out.println(Arrays.toString(ns)); } }特点:每一轮循环后,最大的一个数被交换到末尾,因此,下一轮循环就可以“刨除”最后的数,每一轮循环都比上一轮循环的结束位置靠前一位
Arrays.sort()就可以排序// 排序 import java.util.Arrays; public class Main { public static void main(String[] args) { int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 }; Arrays.sort(ns); System.out.println(Arrays.toString(ns)); } }对数组排序实际上修改了数组本身。例如,排序前的数组是:
int[] ns = { 9, 3, 6, 5 };在内存中,这个整型数组表示如下:
┌───┬───┬───┬───┐ ns───▶│ 9 │ 3 │ 6 │ 5 │ └───┴───┴───┴───┘当我们调用
Arrays.sort(ns);后,这个整型数组在内存中变为:┌───┬───┬───┬───┐ ns───▶│ 3 │ 5 │ 6 │ 9 │ └───┴───┴───┴───┘即变量
ns指向的数组内容已经被改变了对一个字符串数组进行排序,例如:
String[] ns = { "banana", "apple", "pear" };排序前,这个数组在内存中表示如下:
┌──────────────────────────────────┐ ┌───┼──────────────────────┐ │ │ │ ▼ ▼ ┌───┬─┴─┬─┴─┬───┬────────┬───┬───────┬───┬──────┬───┐ ns ─────▶│░░░│░░░│░░░│ │"banana"│ │"apple"│ │"pear"│ │ └─┬─┴───┴───┴───┴────────┴───┴───────┴───┴──────┴───┘ │ ▲ └─────────────────┘调用
Arrays.sort(ns);排序后,这个数组在内存中表示如下:┌──────────────────────────────────┐ ┌───┼──────────┐ │ │ │ ▼ ▼ ┌───┬─┴─┬─┴─┬───┬────────┬───┬───────┬───┬──────┬───┐ ns ─────▶│░░░│░░░│░░░│ │"banana"│ │"apple"│ │"pear"│ │ └─┬─┴───┴───┴───┴────────┴───┴───────┴───┴──────┴───┘ │ ▲ └──────────────────────────────┘原来的3个字符串在内存中均没有任何变化,但是
ns数组的每个元素指向变化
二维数组
多维数组的每个数组元素长度都不要求相同
果我们定义一个普通数组
arr0,然后把ns[0]赋值给它:// 二维数组 public class Main { public static void main(String[] args) { int[][] ns = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; int[] arr0 = ns[0]; System.out.println(arr0.length); // 4 } }arr0就获取了ns数组的第0个元素。因为ns数组的每个元素也是一个数组,因此,arr0指向的数组就是{ 1, 2, 3, 4 }。arr0 ─────┐ ▼ ┌───┬───┬───┬───┐ ┌───┐ ┌──▶│ 1 │ 2 │ 3 │ 4 │ ns ─────▶│░░░│──┘ └───┴───┴───┴───┘ ├───┤ ┌───┬───┬───┬───┐ │░░░│─────▶│ 5 │ 6 │ 7 │ 8 │ ├───┤ └───┴───┴───┴───┘ │░░░│──┐ ┌───┬───┬───┬───┐ └───┘ └──▶│ 9 │10 │11 │12 │ └───┴───┴───┴───┘
命令行参数
- 这个命令行参数由JVM接收用户输入并传给
main方法:
public class Main { public static void main(String[] args) { for (String arg : args) { System.out.println(arg); } } }- 这个命令行参数由JVM接收用户输入并传给