文章目录
- 复习
- 1. Java编译和运行
- 2. Java运行环境
- 3. Java注释
- 4. Java中的打印
- 5. 数据类型
- 整形
- 浮点型
- 字符类型
- 字节类型
- 布尔类型
- 数据类型转换
- 强制类型转换
- 隐式类型转换
- 小结
- 6. 变量命名规范
- 7. 运算符
- 算数运算符
- 逻辑运算符
- 移位运算符
- 关系运算符
- 8. switch
- 9. 方法
- 方法的重载
- 可变参数变程
- 方法的调用
- 10. 数组
- 一维数组的创建方式
- 一维数组在内存中的存储
- 数组的拷贝
- 一维数组的打印
- 二维数组的创建
- 二维数组在内存中的存储
- 二维数组的打印
复习
1. Java编译和运行
public class Main{
public static void main(String[] args) {
System.out.println("hello world!");
}
}
假设Java代码文件名为Main.java
-
通过
javac
文件名(需要带后缀)编译Java代码文件,生成一个.class
的字节码文件(一个class类生成一个.class
文件)javac Main.java
-
如果代码里包含中文,想解决乱码就需要在编译时指定编码格式,
-encoding
javac -encoding Main.java
-
-
一个Java文件只能包含一个
public
类,一但这个类被public
所修饰,那么这个类名要和文件名相同 -
通过
java 文件名
运行Java文件(文件名不需要带后缀)java Main
-
String[] args
,args是一个数组,也是Java运行时参数下面的代码只要在
java
命令运行时文件名后面加上参数,就能存放导 args数组中并打印出来java Main 1 2 3
public class Main{ public static void main(String[] args) { for (int i = 0; i < args.length; i++) { System.out.println(args[i]); } } }
2. Java运行环境
一个Java代码,也就是一个.java
文件通过编译生成一个.class
-
JDK(Java开发者工具)
Java开发工具包,提供给Java程序员使用,包含了JRE,同时还包含了编译
器javac与自带的调试工具Jconsole、jstack等 -
JRE(Java运行时环境)
- Java运行时环境,包含了JVM,Java基础类库。是使用Java语言编写程
序运行的所需环境
- Java运行时环境,包含了JVM,Java基础类库。是使用Java语言编写程
-
JVM(Java虚拟机)
- 编译完的
.class
文件是跑在Java虚拟机上的,JVM也是Java跨平台的关键。
- 编译完的
3. Java注释
-
单行注释
public class Main{ // 单行注释 public static void main(String[] args) { System.out.println("hello"); } }
-
多行注释
public class Main{ /* 多 行 注 释 */ public static void main(String[] args) { System.out.println("hello"); } }
-
文档注释
文档注释也时多行注释的一种
public class Main{ /** * 文档注释 * @param args */ public static void main(String[] args) { System.out.println("hello"); } }
4. Java中的打印
-
打印且换行
System.out.println();
-
打印不换行
System.out.print();
-
格式化打印
Java中也提供了和C语言类似的格式化打印
System.out.printf("%d\n",10);
5. 数据类型
在Java中一共有8种数据类型,8种数据类型都分别对应各自的包装类。且在Java中不存在无符号数,无论在什么平台上数据类型的大小都是一致的,这也是Java跨平台的体现。
数据类型 | 所占内存空间 | 对应包装类 |
---|---|---|
int | 4个字节 | Integer |
long | 8个字节 | Long |
float | 4个字节 | Float |
double | 8个字节 | Double |
char | 2个字节 | Character |
short | 2个字节 | Short |
boolean | JVM中没有规定大小 | Boolean |
byte | 1个字节 | Byte |
比如int能表示的数据范围为 − 2 31 2 31 − 1 -2^{31}~2^{31}-1 −231 231−1,那拿int的最大值加上1会发生什么?或者拿int的最小值减去1又会发生什么?
public class Main{
public static void main(String[] args) {
int max = Integer.MAX_VALUE;/
int min = Integer.MIN_VALUE;
System.out.println(max);
System.out.println(min);
System.out.println("========");
System.out.println(max+1);
System.out.println(min-1);
}
}
运行结果
2147483647
-2147483648
========
-2147483648
2147483647
我们发现最大值+1变成了最小值,最小值-1变成了最大值,其它基本数据类型也时存在的(浮点数除外)。
又或者是
public static void main(String[] args) {
int a = 128;
byte b = (byte)a;
System.out.println(b);
}
打印结果
-128
整形
Java中短整形short有整形int和长整形long,如果要声明一个整形是长整形只需在数字后面加上L或者l(建议使用大写L)
short a = 10;
int b = 20;
long c = 30;
long d = 40L;
long f = 50l;
浮点型
Java中有单精度浮点型float和双精度浮点型double,注意在Java中浮点数默认是double类型。所以如果要使用float就得在变量后面加上F来声明这是一个float类型的数字,或者使用强制类型转换。
float a = 3.14f;
float b = 3.14F;
float c = (float)3.14;
字符类型
在Java中用char表示字符型,Java中字符采用Unicode编码,一个字符占两个字节。且可以保存一个汉字,一个汉字也是占两个字节。需要注意char类型在Java中是不能够给负数的。
char ch = '好';
char c = 'a';
char n = 100;
字节类型
在Java中有一个字节类型byte,它占一个字节对标的是C语言中的char,取值范围为-128~127
byte a = 127;
byte b = -128;
来看一段代码
public class Main{
public static void main(String[] args) {
byte b1 = 10;
byte b2 = 20;
byte b3 = 10+20;
byte b4 = b1+b2;//编译错误
byte b5 = b1 + 1;//编译错误
}
}
这段代码byte b4 = b1+b2;
和byte b5 = b1 + 1;
都会编译错误,而前面的byte b3 = 10+20;
并没有报错这是为什么呢?
- b3不报错是因为在编译期间就被替换成
byte b3 = 30;
了,所以不会报错 - b4报错是因为,编译器不确定b1和b2里的值是啥,因为它们两个是变量所以为了安全,编译器就会报错。
- 而b5报错就牵扯到类型提升了,计算机在读取数据的时候都是4个字节来读取的,在计算的时候当一个数据不足4个字节时,为了提高计算速度,就会进行整形提升,将byte提升成int类型。
布尔类型
boolean的取值只能是true
或者false
boolean flag = false;
boolean t = true;
数据类型转换
强制类型转换
public static void main(String[] args) {
double a = 3.14;
int b = (int)a;
}
- 强制类型转换可能会导致精度丢失. 如刚才的例子中, 赋值之后,3.14 就变成 3 了, 小数点后面的部分被忽略.
- 强制类型转换不是一定能成功, 互不相干的类型之间无法强转,比如int和booean之间就不能进行强制类型转换。
隐式类型转换
java 作为一个强类型编程语言, 当不同类型之间的变量相互赋值的时候, 会有教严格的校验.
public static void main(String[] args) {
double a = 3.14;
long b = 10L;
int c = 20;
a = b;
a = c;
b = c;
// 下面写法都是错误的
b = a;
c = b;
c = a;
}
结论: 不同数字类型的变量之间赋值, 表示范围更小的类型能隐式转换成范围较大的类型, 反之则不行.
从上往下,说明double可以接收它下面的所有类型。
注意:char比较特别,因为它不能接收负数,所以char不能接收byte的值。
double a = 3.14;
float b = (float)1.23;
long c = 10;
int d = 20;
short e = 30;
char f = 10;
byte g = 6;
- 不同数字类型的变量之间赋值, 表示范围更小的类型能隐式转换成范围较大的类型.
- 如果需要把范围大的类型赋值给范围小的, 需要强制类型转换, 但是可能精度丢失.
- 将一个字面值常量进行赋值的时候, Java 会自动针对数字范围进行检查.
小结
注意事项:
Java是一个强类型语言,在使用数据类型的时候需要注意。
- 数字默认是整形
- 小数默认是double类型
- 不要把char类型和整形挂勾,char是不能够接受负数的
- 在给变量赋值时不能超过它的数据范围
- byte类型其实对应的是C语言的char类型
- boolean的值,只能是True或者False
- boolean类型的大小由于没有规定,有的书上书上说是1个位,或者说一个字节。
- char采用Unicode编码占两个字节
- 对于 short, byte 这种比 4 个字节小的类型, 会先提升成 4 个字节的 int , 再运算
- 不同数字类型的变量之间赋值, 表示范围更小的类型能隐式转换成范围较大的类型.
- 局部变量在使用之前一定要初始化
6. 变量命名规范
- Java的变量名可以有数字母下划线和
$
符组成,但不能以数字开头。 - 关键字不能作为变量名
- 变量名一般以小驼峰形式(多个单词除第一个外,其他单首字母大小
7. 运算符
算数运算符
+、-、*、/、%
,没啥好说的。
注意点:在Java中是可以对浮点数使用%
的,且0不能作为除数不然会抛出异常。
public static void main(String[] args) {
double num = 1.25;
System.out.println(num%1);
}
//输出0.25
还有+=、-=、/=、*=、%=、>>=、<<=、>>>=
代码示例:
下面这段代码b = b+a;
编译错误,b += a;
正常运行,是因为+=
自动进行了强制类型转换,
public static void main(String[] args) {
long a = 10;
int b = 20;
b = b+a;//编译错误
b += a;// 正常运行
}
逻辑运算符
逻辑运算符有:
-
逻辑与
&&
(短路与) -
逻辑或
||
(短路或) -
逻辑非
!
(只能对布尔类型使用) -
对于
&&
, 如果左侧表达式值为 false, 则表达式的整体的值一定是 false, 无需计算右侧表达式 -
对于
||
, 如果左侧表达式值为 true, 则表达式的整体的值一定是 true, 无需计算右侧表达式 -
&
和|
如果操作数为 boolean 的时候, 也表示逻辑运算. 但是和&&
以及||
相比, 它们不支持短路求值
移位运算符
- 左移
<<
:最高位不要,末尾补0 - 右移
>>
:最低位不要,最高位补符号位 - 无符号右移:
>>>
:最低位不要,最高位补0
关系运算符
== != < > <= >=
都是关系运算符,它们的返回值都是boolean类型
8. switch
long float double boolean
都不可以作为switch的参数
除了这些基本数据类型,后续说道的枚举enum
,String
也可以作为Switch的参数
9. 方法
方法的重载
重载的要求
- 方法名相同
- 方法的参数类型和个数不相同
- 返回值是不做要求的
可变参数变程
在Java中存在一种非常特殊的语法,可变参数编程,就是一个方法的参数我们不知道有几个的时候,可以使用int...
这种类型来接收1个或者多个整形变量。
public class Main {
public static int sum(int... array) {
int sum = 0;
for (int num : array) {
sum += num;
}
return sum;
}
public static void main(String[] args) {
System.out.println(sum(1));
System.out.println(sum(1,2));
System.out.println(sum(1,2,3));
System.out.println(sum(1,2,3,4));
System.out.println(sum(1,2,3,4,5,6,7,8,9,10));
}
}
方法的调用
方法的调用实在栈的也就是JVM中的Java虚拟机栈,局部变量也是在栈栈开辟空间。
- 在Java中是拿不到栈上的地址的,但能拿到堆区的地址
- 每一次函数的调用,操作系统都会在内存的栈区上开辟一块空间,称为栈帧
- 栈区的空间是有限的,如果一个方法递归程度过深就会出现栈溢出异常。
假设有这么一段代码
public class Main {
public static int Add(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
public static void main(String[] args) {
int a = 10;
int b = 20;
int ret = Add(a, b);
}
}
10. 数组
一维数组的创建方式
注意等号左边的[]
里是不能写数字的
public static void main(String[] args) {
int[] arr1 = {1,2,3,4,5};
int[] arr2 = new int[]{1,2,3,4,5};
int[] arr3 = new int[5];//定义未使用,里面的元素默认是0
int[] arr4;//未初始化不能使用
//这种写法也是可以的
int arr[] = {1,2,3,4,5};
}
一维数组在内存中的存储
假设有这么几个数组,它们是在哪存储的?
int[] arr1 = {1,2,3,4,5};
int[] arr2 = new int[]{1,2,3,4,5};
int[] arr3 = new int[5];
我们知道局部变量是在栈上开辟空间的,而只要new
了的就会在堆上开辟内存。
堆上的对象是由JVM自动回收的,回收的原则是如果当前对象没有人引用的时候,JVM的垃圾回收器就会自动回收该对象
其实向arr1
这些数组名,其实就是一个变量,它是一个引用存放的是数组的地址,简单来说就是arr1是一个引用它指向了一个数组对象。
我们可以直接打印数组名就得到一个地址,但这个地址不是真实的地址,而是通过hash得到的一个唯一的地址。
数组的拷贝
以下几种方式其实都是浅拷贝,但如果单纯的拷贝基本数据类型那也算是深拷贝。
数组的拷贝一共有三种方式
- Arrays.copyOf(原数组, 新数组长度)
public static int[] copyOf(int[] original, int newLength) {
int[] copy = new int[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
-
System.arraycopy(原数组,原数组起始下标,目标数组,目标数组其实下标,要拷贝的长度)
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
这种
native
方法是本地方法,运行在本地方法栈上的,底层是由C/C++实现,速度快。而上面的copyOf
函数的实现也是调用这个方法 -
数组名.clone
这种方法是直接产生一个新的副本
一维数组的打印
一维数组的三种打印方式
public class Main {
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6};
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+" ");
}
System.out.println();
for (int tmp : array) {
System.out.print(tmp+" ");
}
System.out.println();
System.out.println(Arrays.toString(array));
}
}
二维数组的创建
int[][] array1 = {{1,2,3},{4,5,6}};
int[][] array2 = new int[2][3];
int[][] array3 = new int[][]{{1,2,3},{4,5,6}};
二维数组在内存中的存储
在Java中二维数组的每一行都是一个一维数组,每一行存的都是对应一维数组的地址。
假设有那么一个数组
int[][] array1 = {{1,2,3},{4,5,6}};
二维数组的打印
三种打印二维数组的方式
public class Main {
public static void main(String[] args) {
int[][] array = {{1,2,3},{4,5,6}};
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j]+" ");
}
System.out.println();
}
for (int[] arr: array) {
for (int tmp : arr) {
System.out.print(tmp+" ");
}
System.out.println();
}
System.out.println(Arrays.deepToString(array));
}
}
`