day 2基本数据类型 运算符 流程控制语句 函数 数组
标识符
java程序中有些名字是可以自定义的,那么这些名字我们就称为自定义的标识符
标识符细节:
1 组成元素由字母 (a-z, A-Z) 数字0-9 下划线_ 和 $ 但是#和@不能用,
2 标识符不能以数字开头,可以以下划线和$开头
3 标识符是严格区分大小写的
4 标识符长度无限制
5 标识符的命名一般有意义(要做到让人见名知意)
自定义的标识符规范:
1 类名和接口的单词的首字母大写,其他单词小写: class Runtime 。class要小写
2 变量名与方法名首单词小写,其他单词首字母大写。如cookMeal()。这是camel case的命名方式
3 包package名,全部单词小写
4 常量名const,全部字母大写,单词与单词中间用下划线分隔 UP_DIRECTION
关键字:在Java程序中具备特殊含义的标识符。一般用于描述一个程序的结构或数据类型
关键字不能作为自定的标识符。保留字也不行,比如goto


备注:不必死记硬背,如果使用关键字作为标识符,编译器能提示错误。
goto 是java的保留关键字,意思是java并没有使用goto,以后是否使用未定。
注释的类别:
1 单行注释。//注释内容
2 多行注释。/* 注释内容 */
3 文档注释。/** 注释内容 */
软件 = 数据 + 指令 + 文档 (使用者文档 + 开发者文档)
多行注释和文档注释的区别:
多行注释:内容不能用于生成一个开发者文档
文档注释:内容可以用于生成一个开发者文档
文档注释 (编写软件说明书)
1. 需要使用sum给我们提供的javadoc工具生成一个html的说明文档。
2. 只能抽取public的属性或者方法内容。
使用bin里的javadoc程序(在cmd里输入javadoc回车来查用法)
格式:
Javadoc –d 指定存储文档的路径 -version –author(可选) 目标文件
使用javadoc工具的注意细节:
1 如果一个类需要使用javadoc工具生成一个软件开发者文档,该类必须要使用public修饰
2 文档注释的内容一般位于类或者方法的上面(类上面的说明类,在方法上面的说明方法)

@author 作者
@version 版本
@param 方法的参数
@return 返回值
注释的使用细节:
三种注释可以出现在程序的任何地方,但是不推荐找任意位置。
1. 注释习惯:
1. 给那条语句进行说明,注释应该写在该语句的旁边。
2. 单行注释一般写在语句的后面多行注释和文档注释一般写在语句的上面
注意:文档注释只能出现在类、属性、方法的上面。
2. 单行注释可以嵌套,多行或者文档注释不能嵌套

使用注释来调试:
部分代码打上注释,放开一个测试一个,若没问题再放开一个测试下一句。
常量:
程序运行中,其值不发生改变的量
常量的类别:
整数常量: 10
小数常量:3.14
布尔常量:true和false
字符常量:单引号引起的单个字符’5’ 或者‘a’
字符串常量:双引号引起的内容“hello world”
转义:
注意:特殊字符的转义序列:转义字符
转义字符的概述:
特殊字符使用”\”把其转化成字符的本身输出,那么使用”\”的字符称作为转移字符。
需求:使用输出语句,打印出带引号的信息例如输出。
System.out.println("teacher said"java is fun"");编译是无法正常通过的。语法有错误,编译器读到第二个引号就认为是字符串的结束,剩余的不知道怎么处理。如何解决这个问题:java中使用转义字符来表示特殊的字符。一个转义字符以反斜杠(\)开始。
问题:想要打印带引号的字符串怎么办,就可以使用反斜杠(\)后跟字符,这个反斜杠就是转义字符

上述问问题解决:System.out.println("teacher said\"java is fun\"");
注意:换行符就是另起一行,回车符就是回到一行的开头,所以我们平时编写文件的回车符应该确切来说叫做回车换行符
在windows中回车换行需要\n\r,别的系统中只要\n就可以了
进制的转换
二进制->十进制:每一位都是2的n次方,128 64 32 16 8 4 2 1

八进制->十进制:每一位都是8的n次方

十六进制->十进制:每一位都是16的n次方

八进制:二进制书写繁琐,每三位二进制记录一个数字
十六进制:每四位二进制记录一个数字
将十进制转换为任意进制就是用该数,不停除以进制数,取余数,最后把余数从下往上串起来
八进制:二进制书写繁琐,每三位二进制记录一个数字
十六进制:每四位二进制记录一个数字
将十进制转换为任意进制就是用该数,不停除以进制数,取余数,最后把余数从下往上串起来
一个数据的前边没有加上任何的标识之前,默认就是十进制
System.out.println(10); //十进制 System.out.println(0b10); //二进制数据,要在数字前加0b开头 //二进制似乎不能这么直接输出,需要Integeer.parseInt() System.out.println(Integer.parseInt("1001", 2));二进制数据打印 System.out.println(0x10); //十六进制数据要以0x开头
任何进制转十进制:
int num = Integer.parseInt(“1001”, n进制)
十进制转二进制, 八进制,十六进制

Integer.toBinaryString(int n)十进制转二进制
Integer.toHexString(int n)十进制转十六进制
Integer.toOctalString(int n)十进制转八进制
变量:
程序执行过程中,其值发生改变的量
基本数据类型
1. 整型
byte 代表一个字节的大小 8bit 2(8) -128~127 256
short 代表两个字节的大小 16bit 2(16) -2(15)~2(15)-1
int 代表四个字节的大小 32bit 2(32) -2(31)~2(31)-1
long 代表八个字节的大小 64bit 2(64) -2(63)~2(63)-1
如果一个数值没有采取特殊的处理,那么该整数默认的类型是int。
可以使用数值后面添加L或小写L改变默认的整数类型。
2. 浮点型
float 单精度浮点型:代表四个字节的大小 32bit 末尾要加f
double 双精度浮点型:代表八个字节的大小 64bit 末尾要加d
java程序中所有的小数默认的类型是double类型,所以需要使用特殊的符号改变默认的小数类型。
3. 字符型
char 代表两个字节的大小 16bit 2(16)
原理:将字符映射为ASCII码表中对应的十进制数据加以存储。
4. 布尔型
boolean 占一个字节或4个字节。只有true与false两个值。
如果使用boolean声明一个基本类型变量时,那么该变量占4字节
如果使用boolean声明一个数组类的时候,每个数占一个字节
long allMoney = 1000000000000000L; float pi = 3.1415926f; //最多小数点后有7位
理论上:满足使用的前提下,能小就小,节省空间。
实际开发中:一般存储整数都用int类型,小数类型都用double类型
字符串的数据类型 String 属于引用数据类型
String aaa = "Hello";
声明变量的方式:
方式一:
数据类型 变量名;
方式二:
数据类型 变量名1, 变量名2… 一次性声明了多个相同类型的变量
int age, weight; age = 12; weight = 59;
声明与初始化一起:
数据类型 变量名 = 数据;
声明一个变量的时候需要确定变量的大小,类型、名字三个特点
有基本数据类型和引用数据类型
注意:
1 变量必须先声明,再使用
2 在同一个作用域中不能声明同名的变量
字符串即使””空,也是字符串,用双引号的就是字符串
数据类型转换:
自动类型转换(隐式转换),小数据类型 转换为 大的数据类型转换:不会出错
byte b = 11; //小数据类型,byte一字节 short s = b; //大数据类型,short2字节 System.out.println(s);
强制类型转换(显式转换),大数据类型 转换为 小的数据类型:
short b = 11; byte s = (byte) b; System.out.println(s);
强制转换的原理,转换为byte类时,只会取short类的低8位,也就是一字节
int b = 128; byte s = (byte) b; System.out.println(s); //-128
也就是b = 0000000010000000两个字节 那么转换为s的时候只取低8位,所以取到了10000000 首位为1的就为负数,所以就变成了-128
负数在计算机中存储的是补码
计算机中如果一个数的最高位是0那么肯定是正数,如果最高位是1那么肯定是负数
负数的存储过程:相对应正数按位取反再加1
1 先取负数的绝对值,求该绝对值的二进制形式(原码)
2 原码按位取反得到反码
3 反码 + 1得到补码
查看一个数的二进制形式Integer.toBinaryString(int n)
通过补码求出真实的数据:
1 补码先减1
2 取反
3 在数据前加负号
数据类型转换注意:
1 char, short, byte数据类型自动升级的问题:char, short, byte类型运算中都会自动转换成int型再运算,所以结果要int型来接收
byte b1 = 1; byte b2 = 2; byte b3 = (byte)(b1 + b2); //直接b1 + b2是会转换成int型 //计算结果是int型,如果要byte b3来接收,就要强制转换类型
那么char作为字符类型怎么转为int呢,char类型是被转换为ASCII码值来做运算的
//单引号的是字符char,双引号是字符串String类型 System.out.println('a' + 1); // 98 System.out.println('a' + 'b'); // 195 System.out.println('a' + "b"); // ab
可以看到基本类型变量char可以转为ASCII码值,而引用类型变量 字符串"b"却不行
2 两个不同类型数据运算时,结果取决于大的数据类型
- 如果一个操作数是long型,计算结果就是long型;
- 如果一个操作数是float型,计算结果就是float型;
- 如果一个操作数是double型,计算结果就是double型。
int i = 10; long l = 20L; i = (int)(i + l); // 两个运算的结果是long类型,而我们用int型来接受,所以要强制类型转换 System.out.println(i);
3 常量变量的区别
byte b = 10; // 一个整数,没有加任何标识的情况下是int型,但是这样把int赋给byte型,为什么不报错呢 //10是一个常量,编译器在编译的时候,就能够确认常量的值,Java编译器就会检查到10并没有超出byte的范围
但是如果
int i = 10; byte b = i;
这时候就会报错了。java编译器在编译的并不确认变量所存储的值,变量存储的值是在运行的时候才分配内存空间的
因为编译的时候byte b = i 编译器并不知道i的值,它只知道是把一个int类型赋值给了byte类型,会有可能超出范围。
算术运算符:
-
- * / %取模,取余数 ++自增,--自减
加号的三个含义:正数,加号,连接符
连接符的作用:让任何的数据都能与字符串进行拼接。任何类型数据与字符串使用连接符连接,结果都是字符串型的数据
System.out.println(1 + 2 + 3 + "Hello" + 1 + 2 + 3); // 6Hello123
计算机在运算的时候每次取两个数据运算,从左到右依次来。先取1 + 2就做了纯加法,遇到了字符串,就都变为字符串
两个数运算,a 和 b都是int型,那么结果也是int型
int a = 10; int b = 3; System.out.println(a / b); // 3
如果类型不同, 结果取决于大的数据类型
double a = 10d; int b = 3; System.out.println(a / b); // 3.33333
Java在做取模运算时,结果符号取决于被除数
System.out.println(10 % 3); // 1 System.out.println(10 % -3); // 1 System.out.println(-10 % 3); // -1 System.out.println(-10 % -3); // -1
++自增:操作数+1
前自增:++位于操作数之前,先自增,再使用
后自增:先使用,后自增
int a = 1; int sum = a++; System.out.println(sum); // 1 System.out.println(a); // 2
JVM 中后自增的运行原理,因为后自增要使用到没有+1之前的值,那么Java虚拟机会先声明一个变量,保存没有+1的之前的值
int temp = i; i = i + 1; return temp;
--自减,操作数减1
前自减:先自减后使用
后自减:先使用后自减
赋值运算符:
= += -= *= /= %=
A += 1 也就是A = A+1
byte a = 1; byte b = 2; // b = a + b; // 报错,运算结果为int型,不能给byte型 b += a; // 编译器自动做了强制类型转换
Java 编译器+=也做了强制类型转换,无需手动转换
比较运算符
== > < >= <= != instanceof 检查是否是类的对象
==号用于比较两个基本数据类型的时候,比较的是两个变量存储的值是否相等
==号用于比较两个引用类型变量的时候,比较的是两个变量的内存地址是否相等
比如 'a' == 'a' 比较值是否相等,"hello".equals("hello")这是字符串比较值是否相等的算式
两个不同类型数据的比较,也属于运算,结果取决于大的数据,但是必须是兼容的数据
byte b = 10; long l = 30; System.out.println(l > b);
不能用byte和boolean比较, 数据类型不兼容
byte和float也是可以比较的
byte b = 10; float l = 3.14f; System.out.println(l > b); // false
逻辑运算符:
&与,并且,同真则真
| 或,一真则真
^ 异或 相异为真,相同为假
! 非
&& 短路与
|| 短路或
短路与&&和&:
- 相同点: 运算结果相同
- 不同点:如果左边为false,那么短路与不会再判断右边的表达式,直接返回false
短路或||和|:
- 相同点:运算结果相同
- 不同点:如果左边为true,则不管右边,也直接为true
位运算符:直接操作二进制位,效率相对会高一些
原理:把1当成true,把0当成false
&与: 两个对应的二进制位都是1 结果才为1,一个是0,结果就是0
|或 :两个对应的二进制位有一个是1,结果就为1
^异或 :两个对应的二进制位不同,结果就为1
~取反
异或的规律:如果一个操作数连续异或同一个操作数两次,那么还是他本身(6 ^ 3) ^ 3 = 6
利用这个规律,我们可以实现文件加密,或者两个变量交换数据
import java.io.*; class ImageTest { /* * 使用异或加密和解密图片 * */ public static void main(String[] args) throws Exception { //找到图片文件 File inFile = new File("E:\\Java_Workspace\\src\\pic1.png"); File outFile = new File("E:\\Java_Workspace\\src\\pic2.png"); //建立数据通道,让图片的二进制数据流入 FileInputStream input = new FileInputStream(inFile); FileOutputStream output = new FileOutputStream(outFile); //边读,把读到的数据异或一个数据,把数据写出 int content = 0; //该变量适用于存储读到的数据 while((content = input.read()) != -1) { // 如果没有到文件末尾,那么继续读数据 //读到的数据保存在了content变量里 output.write(content ^ 12); // 将文件的二进制码进行异或 } //关闭资源 output.close(); input.close(); } }
位运算可能出现的笔试题目:
1 交换两个变量的值
temp法:
int a = 11; int b = 12; int temp; temp = a; a = b; b = temp; System.out.println(a); System.out.println(b);
2加减交换法:
int a = 11; int b = 12; a = a + b; b = a - b; a = a - b; System.out.println(a); System.out.println(b);
缺点:两个int数相加,有可能会超出link的表示范围
3 异或法:
int a = 11; int b = 12; a = a ^ b; b = a ^ b; a = a ^ b; System.out.println(a); System.out.println(b);
2 取出一个二进制数据的指定位数
取出一个二进制数的低四位。可以用&实现
不要的部分就&0,要的部分就&1
移位运算符:
<<左移 :一个操作数左移的位数,结果就等于操作数* 2的n次方,n是左移的位数
>>右移 :一个操作数右移,结果就是等于该操作数/ 2的n次方
>>>无符号右移
无符号右移和右移的区别:右移运算时,如果操作数为正,右边缺位补0;若操作数为负,缺位补1
无符号右移:无论操作数为正还是负,左边缺位补0
笔试题目:使用最高效率算出2 * 8的结果(让2左移3位)
2 << 3 = 2 * 2的3次方
三元运算符(三目运算符)
int age = 11; String people = age > 18 ? "adult" : "child"; System.out.println(people);
格式:变量名 = 布尔表达式判断 ? 值1 : 值2
如果布尔表达式为true,那么变量名得到值1,
三元运算符使用时,一定要用其返回的结果或者定义一个变量接受其返回的结果
控制流程语句:
语句:使用分号分隔的代码就是一个语句,分号是一个语句的结束
只有一个;号无代码,也不会报错,是个空语句
判断语句if
if(......){ /*代码*/ }else if(......){ /*代码*/ }else{ /*代码*/ } int age = 16; String ret; if(age > 18){ ret = "adult"; }else{ ret = "child"; }
if 注意事项:
1 如果符合条件后只有一句代码执行,那就可以省略大括号,建议不省略
2 if语句判断条件后不能加分号,会影响执行效果
三元运算符不能用于执行语句,只能返回一个值
接受键盘输入的数据:
1 创建一个扫描器对象 Scanner scanner = new Scanner(System.in);
2 调用扫描器对象的next Int方法扫描数据 int num = scanner.nextInt();
扫描器使用完了最后要关闭一下scanner.close();
3 导入包 import java.util.*
System.out.println("请输入");
Scanner scanner = new Scanner(System.in); // 创建一个扫描器对象
int num = scanner.nextInt(); //扫描器扫描键盘录入的数据
// 也可以输入字符串String str = scanner.next()
System.out.println("输入的数据是" + num);
注意如果要输入接受一个int型,要用int num = scanner.nextInt()
字符串是String str = scanner.next();
Switch语句
int month = 3; switch(month){ case 3: case 4: case 5: System.out.println("Spring"); break; case 6: case 7: case 8: System.out.println("Summer"); break; case 9: case 10: case 11: System.out.println("Fall"); break; case 12: case 1: case 2: System.out.println("Winter"); break; default: System.out.println("invalid input"); }
如果没有break会向下贯通. 使用语法形式类似于if语句
Switch 语句的注意事项:
1 switch语句使用的变量只能是byte, char, short, int, String类型,不能用long, float, double 类型,String类型是从JDK7.0开始的,String类型要加上双引号
2 case后面跟的数据必须是一个常量
3 switch语句停止条件,一旦匹配其中的一个case,那么就执行,完毕后如果没有遇到break,或switch的大括号,那么就继续向下执行,一直到结束为止
4 switch语句中不管代码顺序如何,永远都会先判断case,如果没有符合条件的才执行default
if 语句和switch语句相似,switch语句不适用于判断条件为区间范围的情况
While 循环:
while(循环条件){ 循环语句 }
注意事项:
1 while循环一般是通过一个变量控制循环次数
2 while循环如果只有一句代码,可省略大括号,一般不省略
3 while循环语句判断条件后不能跟分号
//实现100以内7的倍数的总和 int count = 1; int sum = 0; while(count <= 100) { if(count % 7 == 0) { sum += count; } count ++; } System.out.println(sum);
随机数
Import java.util.*; 导包
Random random = new Random(); 创建随机数对象
int num = random.nextInt(11); 创建0-10的随机数
int num = random.nextInt(n); 随机数[0, n)
int num = (int)(Math.random() * (最大数 - 最小数 + 1) + 最小数); 随机数[最小数, 最大数]
Do-while 循环语句:
do{ ... }while();
While 与do-while循环语句的区别:
While循环是先判断再循环,do-while是先循环再判断,不管条件是否满足,至少执行一次。
不要受至少执行一次这句话的影响,要达到相同的效果,do-while和while的执行条件是一样的
For 循环
for(int i = 0; i < 10; i ++){ System.out.println("Hello world"); }
1 for循环语句条件里的两个分号不能省,三个条件可以写在别处for(; ;)相当于while(true)
2 初始化语句只在第一次时执行
3 for循环的循环体只有一句时,可以省略大括号, 一般不省略
System.out.println(); 什么都不写,相当于换行
System.out.print(“\n\r”); 换行
System.out.print(....); 输出内容之后,光标停在同一行
System.out.println(....);输出内容之后,换行,因为这个是打印一行的意思
For 循环打印三角形
for(int i = 0; i < 10; i ++){ for(int j = 0; j < i; j ++){ System.out.print("*"); } System.out.println("\n\r"); }
九九乘法表
for(int i = 1; i < 10; i ++){ for(int j = 1; j <= i; j ++){ System.out.print(j + "*" + i + "=" + i * j + "\t"); } //用制表符来对齐公式 System.out.println("\n\r"); }
倒立直角三角形
for(int i = 0; i < 10; i ++){ for(int j = 0; j < 10 - i; j ++){ System.out.print("*"); } System.out.print("\n\r"); }
如果在Windows下使用换行回车时,要用\n\r,其他的系统里只用\n就可以
Break,Countinue 关键字
Break关键字:适用范围:只能用于switch和循环语句中
Break的作用:1 用于switch语句中是结束一个switch分支
2 用于循环语句是结束当前所在的循环
for(int i = 0; i < 5; i ++) { for(int j = 0; j < 2; j ++){ System.out.println("Hello"); break; //只能输出5次,因为是外循环在起作用 }
笔试题目:break目前位于内层的for循环,如何才能让break语句作用于外层循环呢?
解决:给for循环起个名字(标记, 命名空间) (outer和inner都是标记)
outer: for(int i = 0; i < 5; i ++) { inner: for(int j = 0; j < 2; j ++){ System.out.println("Hello"); break outer; //只能输出1次,因为直接结束了外循环 } }
Continue关键字:
适用范围:只能用于循环内部
作用:跳过本次循环,执行下一次循环
for(int i = 0; i < 6; i ++) { if(i == 4) { continue; } System.out.println(i); // 0 1 2 3 5 }
Continue也可以配合标记使用
outer: for(int i = 0; i < 6; i ++) { inner: for(int j = 0; j < 2; j ++){ System.out.println("Hello"); continue outer; //会输出6次,外循环有几次就输出几次 } }
计算1 - 100的偶数总和
//计算 1 - 100的偶数总和 int sum = 0; for(int i = 1; i < 100; i ++){ if(i % 2 == 0) { sum += i; } } System.out.println("The sum is " + sum);
//计算 1 - 100的偶数总和 int sum = 0; for(int i = 1; i < 100; i ++){ if(i % 2 != 0) { continue; } sum += i; } System.out.println("The sum is " + sum);
函数:
函数也称方法,提高功能代码复用性
函数定义格式:
修饰符 返回值类型 函数名(形参列表) {
函数代码
}
函数定义和调用
public static void main(String[] args) { System.out.println(add(1, 2)); } public static int add(int a, int b){ return a + b; }
函数定义好后,需要被调用才会执行的
函数名需要符合命名规范,首单词小写,其他单词首字母大写,camel case
public static 就是修饰符
int表示返回值类型,表示函数运行后,return的值得类型
有时候,函数可能不需要返回值,这个时候就写void,参照main主函数
public static 修饰符, 返回值类型 void 函数名main 参数是String[]字符串数组类型 args
public static void main(String[] args) { show(); } public static void show(){ System.out.println("Hello"); }
打印n * n的乘法表
public static void show(int n){ if(n > 9){ System.out.println("n cannot be larger than 9"); return; } for(int i = 1; i < n + 1; i ++){ for(int j = 1; j <= i; j ++){ System.out.print(j + "*" + i + "=" + i * j + "\t"); } System.out.print("\n\r"); } }
函数的特点:
1 封装一段功能代码,以提高代码的复用性
2 函数定义好后,需要调用才执行
3 如果一个函数没有返回值类型,需要写void
如果一个函数的返回值类型是具体的,那么该函数必须在任意情况下都保证有返回值,除了void
比如在if语句中返回,那么必须要cover所有的情况来让他返回
return 关键字的作用
1 返回数据给函数的调用者
2 函数一旦执行到了return关键字,那么该函数马上结束(return 可以结束一个void返回类型的函数,不可写return a; 但是可以只写一个return;)
break关键字和return关键字区别
break: 结束一个循环
return: 结束一个函数
void 函数可以出现return,但不能返回值
函数的重载:在一个类中,出现两个或两个以上的同名函数,称为函数的重载
作用:同一个函数名,出现了不同的函数,以对应对不同个数或者不同数据类型的参数
定义一个加法函数,几个数相加
public static int add(int a, int b){} public static int add(int a, int b, int c){} public static int add(int a, int b, int c, int d){}
函数通过形参列表来确认执行哪一个函数。如果函数名和形参列表都相同就不是重载而是重复了
函数重载的要求:
1 函数名一致
2 形参列表不一致(形参个数或对应的类型不一致)
3 函数重载与返回值类型无关(即使返回值类型不同,函数名相同,形参列表也相同,也是重复)
public static int add(int a, int b){} public static String add(int a, int b){}
数组:同种类型的数据容器,数组也是引用数据类型
数组定义格式:
数据类型[] 变量名 = new 数据类型[长度];
表示定义一个全为某种数据类型的的数组,固定长度
定义一个数组存储50位同学的成绩
int[] arr = new int[50];
左边 int[] 表示定义了一个全为整型的数组, 数组名为arr
右边 new 关键字,创建一个新的数组对象
Java虚拟机,管理两片内存(栈内存stack 和 堆内存heap)
栈内存stack:栈内存存储都是局部变量,变量一旦出了自己的作用域,马上会从内存中小时,释放内存空间
局部变量:如果声明一个变量实在一个方法(函数)内部声明,那么该变量就是一个局部变量
成员变量:定义在方法之外,类之内的
作用域:该方法的大括号范围,一旦出了该作用域,即从栈内存消失
public static int add(int a, int b) { int sum = a + b; // 这个sum即是局部变量,出了大括号就消失 return sum; }
堆内存特点heap: 堆内存存储的都是对象数据,对象一旦被使用完,并不会马上从内存中消失,而是等垃圾回收器不定时把垃圾对象回收,该对象才从内存消失,释放内存
对象数据: 除了那8种基本数据类型数据外,都是对象数据,也叫引用类型数据
对象被使用完:对象如果没有变量引用了,那么该对象就是一个垃圾对象
凡是以new关键字创建的对象,JVM都会在内存中开辟一个新的空间,创建一个新的对象
int arr = new int[50] 这里的=号是把数组对象内存地址赋给了arr

int[] arr = new int[4]; for(int i = 0; i < arr.length; i ++) { arr[i] = i; // 循环赋值 } System.out.print(Arrays.toString(arr));// [1, 2, 3, 4]
想要查看数组内容,需要遍历查看
Array.toString(arr) 也可以查看
for遍历数组:arr.length表示属性,数组长度
for(int i = 0; i < arr.length; i ++){ System.out.println(arr[i]); }
或者 foreach循环
for(int item: arr){ System.out.println(item); }
定义数组的时候是把堆内存内的数组地址传给了arr变量
int[] arr = new int[4]; int[] arr1 = arr;// 将arr的内存地址交给了arr1 for(int i = 0; i < arr.length; i ++) { arr[i] = i; // 循环赋值 } arr1[1] = 100; System.out.println(arr[1]);// 100
所以arr和arr1操作的都是同一个数组对象
int[] arr = new int[2]; arr = null; // 让该变量不要引用对象,不要记录任何内存地址 arr[1] = 10; System.out.println(arr[1]);//报错
空指针异常java.lang.NullPointerException
原因:引用类型变量没有指向任何对象,而访问了对象的属性或调用了对象的方法所引发的
本来 int[] arr = new int[2] 里arr还指向了这个数组,而arr = null把这个关联给打破了,就无法访问了
arr在栈内存,而数组实际在堆内存,arr只保存了这个堆内存里arr的地址
下标越界 ArrayIndex out of boundary exception
比如int[] arr = new int[2] 但是你访问了arr[2] 就会越界,因为数组内索引只有0和1
数组的初始化方式:
动态初始化:
数据类型[] 变量名 = new 数据类型[长度]
静态初始化:
数据类型[] 变量名 = {1, 2, 3, 4}
如果程序一开始就已经确定了数据,建议使用静态初始化。若数据一开始还不明确,就用动态初始化
定义一个函数,找出数组中的最大值:
public static void main(String[] args) { int[] arr = {1, 2, 3, 4, 5}; System.out.println(getMax(arr)); } public static int getMax(int[] arr){ int max = arr[0]; for(int i = 1; i < arr.length; i ++){ if(arr[i] > max) { max = arr[i]; } } return max; }
for循环也可以用for(int item: arr)来代替
先让max等于第一个值,然后遍历,一旦找到有比自己大的值,就记录这个值。
排序算法:
内置方法:数组工具类 Arrays 可以用Arrays.sort(arr)排序
Arrays.sort()内部使用选择排序法实现的
选择排序法和冒泡排序法:
外循环: for(int i = 0; i < arr.length - 1; i ++){}
内循环: 选择排序法: for(int j = i + 1; j < arr.length; j ++) if(arr[i] > arr[j]) 交换,一个i一个j 冒泡排序法: for(int j = 0; j < arr.length - i - 1; j ++) if(arr[j] > arr[j + 1]) 交换 ,都是j
选择与排序算法,外循环都是控制比较几轮。选择法内循环j是表示下一个元素,而冒泡排序j是控制每轮要比较几次
选择:自己与别的元素比较
public static void main(String[] args) { int[] arr = {12, 102, 7, 35, 10, 2, 5}; int[] arr1 = selectSort(arr); System.out.println(Arrays.toString(arr1)); } public static int[] selectSort(int[] arr){ for(int i = 0; i < arr.length - 1; i ++){ for(int j = i + 1; j < arr.length; j ++){ if(arr[i] > arr[j]){ int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } return arr; }
冒泡 相邻元素比较
public static void main(String[] args) { int[] arr = {12, 102, 7, 35, 10, 2, 5}; int[] arr1 = bubbleSort(arr); System.out.println(Arrays.toString(arr1)); } public static int[] bubbleSort(int[] arr){ for(int i = 0; i < arr.length - 1; i ++){ for(int j = 0; j < arr.length - i - 1; j ++){ if(arr[j] > arr[j + 1]){ int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } return arr; }
二分查找法:
查找某元素在数组中的位置,一般也需要先将数组排好序再使用
一般的查找法:低效,找到返回索引,找不到返回-1
二分查找法只适用于有序数组:
定义三个变量:分别记录要查找的元素的范围最大索引值,最小索引值,中间索引值。每次都使用中间索引值与目标元素比较一次,如果不是我们所需要的,就缩小查找范围。
public static void main(String[] args) { int[] arr = {12, 102, 7, 35, 10, 2, 5}; Arrays.sort(arr); System.out.println(Arrays.toString(arr)); int pos = halfSearch(arr, 35); System.out.println(pos); } public static int halfSearch(int[] arr, int target){ int max = arr.length; int min = 0; int mid = (min + max) / 2; while(true){ if(target < arr[mid]){ max = mid - 1; }else if(target > arr[mid]){ min = mid + 1; }else{ return mid; } if(max < min) { return -1;//没找到 } mid = (min + max) / 2;//重新计算索引值 } }
// version 1: with jiuzhang template public class Solution { /** * @param A an integer array sorted in ascending order * @param target an integer * @return an integer */ public int findPosition(int[] nums, int target) { if (nums == null || nums.length == 0) { return -1; } int start = 0, end = nums.length - 1; while (start + 1 < end) { int mid = start + (end - start) / 2; if (nums[mid] == target) { return mid; } else if (nums[mid] < target) { start = mid; } else { end = mid; } } if (nums[start] == target) { return start; } if (nums[end] == target) { return end; } return -1; } }
数组的工具类:Arrays
需要先导包才能用 improt java.util.*
Arrays.sort(arr) 数组排序,无返回值,直接操作
Arrays.binarySearch(arr,[from], [to], value) 二分查找,返回一个索引值, 还可以加两个参数表明起始和终止查找的索引位置. 如果找不到返回一个负数,if(Arrays.binarySearch(..) < 0)
二分法使用之前要排序
二维数组:二维数组就是数组中的数组;
定义格式:
数据类型[][] 变量名 = new 数据类型[长度1][长度2]
第一维数组内记录了第二维数组的地址

int[][] arr = new int[3][20]; System.out.println(arr.length); // 3 System.out.println(arr[0].length); // 20
因为arr记录了0x98的地址,而该地址数组只有3个变量元素,分别存地址,所以长度为3.
arr[0].length 结果为20,因为arr1指向的数组有20个元素
二维数组的初始化
动态初始化 int[][] arr = new int[3][4]
静态初始化 int[][] arr = {{1, 2, 3}, {1}, {3, 4}}
静态初始化的时候,每一维的长度可以不同
遍历二维数组:
int[][] arr = {{1, 2, 3}, {4, 5}, {7}}; for(int i = 0; i < arr.length; i ++) { for(int j = 0; j < arr[i].length; j ++) { System.out.println(arr[i][j]); } }
定义一个二维数组,计算二维数组中偶数的总和
public static void main(String[] args) { int[][] arr = {{1, 2, 3}, {4, 5}, {7}}; System.out.println(getSum(arr)); } public static int getSum(int[][] arr) { int sum = 0; for(int i = 0; i < arr.length; i ++) { for(int j = 0; j < arr[i].length; j ++) { if(arr[i][j] % 2 != 0){ continue; } sum += arr[i][j]; } } return sum; }
数组的特点:
1 数组只能存储同种类型的数据
2 数组会给存储到的元素分配索引值 0 ~ arr.length - 1
3 数组一旦初始化,长度固定,不可以再新加元素改变数组长度
4 数组中元素与元素间的内存地址是连续的。但数组对象间的内存不一定连续
...............................................
浙公网安备 33010602011771号