比如,文件名为HelloWorld.java,所以此处的类名为HelloWorld
如,一个.java文件里面有两个类,则有两个字节码文件。
那为什么要这样设置呢?
为了方便使用,Java当中,用到哪个类就加载哪个类。
public static void main (String[] args) { }
上述main函数的形参String[] args
是运行时命令行参数。我们下面做个测试:
public static void main (String[] args) { int i = 0; for (i = 0; i < args.length; ++i) { System.out.println(args[i]); } System.out.println("kaixin"); }
可以看到只输出了“kaixn”,没有输出for循环里面的值。
当我们在java 文件名
后输入一些字符串,字符串就被存储到args
里面了,就可以打印出for循环里面的内容了。
javac 文件名.java
,形成 .class文件。注意:
- 在cmd上编译文件,需要将当前目录改为文件所在目录,使用命令
cd /d 文件路径
- 在记事本上写代码,需要先保存,再编译。
编译完后,可在当前目录中看到 .class文件
java 文件名
来运行文件(在JVM(java虚拟机)里运行)注意:java 和 javac 都属于JDK命令。
/*这是块注释*/
/** * 文档注释: * 作者: * 日期: * 描述: */
// 这是行注释
但是如果程序里面有注释,编译的时候会出现错误,如下图:
原因是,代码里面有中文,但是javac编译默认使用GBK来编码的,这就是“字节码格式不匹配导致”的。
这时候我们只需要在后面加-encoding utf-8
编译即可:
这就告诉编译器,统统以utf-8来编码。
有三种方式打印:
结果如下:
public static void main1 (String[] args) { long a = 10L; System.out.println(a); System.out.println("最大值:" + Long.MAX_VALUE); // + 为拼接 System.out.println("最小值:" + Long.MIN_VALUE); int b = 10; int c = 20; System.out.println(b + c); //注意:任何类型的数据 和 字符串进行拼接,结果都是字符串 System.out.println("hhh" + b + c); }
/** * 双精度 浮点型 * @param args [description] */ public static void main3 (String[] args) { double d = 12.5; System.out.println(d); System.out.println(Double.MAX_VALUE); System.out.println(Double.MIN_VALUE); }
f
或F
/** * 单精度 float * 1. double 8个字节 * 2. float 4个字节 */ public static void main4 (String[] args) { // float f = 12.3; 会出现错误,不允许从double类型转到float类型 float f = 12.3f; System.out.println(f); System.out.println(Float.MAX_VALUE); System.out.println(Float.MIN_VALUE); }
/** * 字符数据类型: * char 2个字节 0 ~ 65535 * Unicode --> 包含很多字符集,如中文,拉丁文等等 */ public static void main5 (String[] args) { char ch = 'a'; System.out.println(ch); char ch2 = '高'; System.out.println(ch2); char ch3 = 97; System.out.println(ch3); }
// 字节:byte 1个字节 数值:-128 ~ 127 // 每一种数据类型,在给其赋值的时候,一定不能超过它的范围 public static void main6 (String[] args) { byte b = 12; byte c = 21; System.out.println(b + " " + c); // byte d = Byte.MAX_VALUE + 1;此处会进行整型提升,从int->byte会编译错误 System.out.println(Byte.MAX_VALUE + 1); //默认输出整型,整型是可以保存数值128的 System.out.println(Integer.MAX_VALUE); //int i1 = 2147483648; //报错,超出数据类型的范围(Java只会检查 直接赋值的字面值常量是否超出) //下面的均不会编译报错 int i2 = 2147483647 + 1; System.out.println(i2); int i3 = Integer.MAX_VALUE + 1; System.out.println(i3); System.out.println(Integer.MAX_VALUE + 1); }
//短整型:short 2个字节 数值:-32768 ~ 32767 public static void main7 (String[] args) { short sh = 12; System.out.println(Short.MAX_VALUE); System.out.println(Short.MIN_VALUE); }
/** * 布尔类型: * 1.在JAVA中,布尔类型 没有明确的大小 * 2.在JAVA中,布尔类型 只有两个取值 true 和 false * 3.在JAVA中,没有 所谓的 0是假 非0是真 */ public static void main7 (String[] args) { boolean flg = true; System.out.println(flg); //报错,只能为布尔值 /*if (1) { }*/ }
语法格式:String 变量名 = "初始值";
String name = "My name is \"张三\"";
+
操作,表示字符串拼接:String a = "hello"; String b = "world"; String c = a + b; //输出 helloworld System.out.println(c);
String str = "result = "; int a = 10; int b = 20; String result = str + a + b; //输出为result = 1020 System.out.println(result);
T[] 数组名 = new T[N];
T:表示数组中存放元素的类型。
T[]:表示数组的类型。
N:代表数组的长度。
int[] arr1 = new int[10]; //创建一个可以容纳10个int类型元素的数组 double[] arr1 = new double[5]; //创建一个可以容纳5个double类型元素的数组
跟C语言不同,Java数组是创建在堆上的,不像C语言创建在栈上的。
分为两种:动态初始化,静态初始化。
int[] array = new int[10]; //里面存放了10个0
语法格式:T[] 数组名称 = {data1,data2,.....,datan};
int[] array = new int[]{1,2,3,4};
array是开辟在栈上,存储的是数组的首地址,数组是开辟在堆上的。也就是说,array是指向{1,2,3,4}这个对象的。
这个时候就有个问题:我们能拿到栈上的地址吗?(比如 int a = 10; 能拿到a 的地址吗?)
答案是:不能,Java很安全,不会让你拿到栈上的地址的。
【注意事项】:
int[] array1; array1 = new int[10]; int[] array2; array2 = new int[]{10, 20, 30}; //注意省略格式不可以拆分,否则编译失败 // int[] array3; // array3 = {1, 2, 3};
数组在内存中是一段连续的空间,空间的编号都是从0开始的,依次递增,该编号称为数组的下标,可通过下标访问数组任意位置的元素。
但是,如果下标越界则会报出下标越界异常。
int[] arr = {1,2,3}; System.out.println(arr[3]); //会抛出越界异常
上面代码的异常为java.lang.ArrayIndexOutOfBoundsException
。
有三种遍历方式:
int[] arr = new int[]{1,2,3,4,5,6,7}; for(int i = 0; i < arr.length;++i) { System.out.print(arr[i] + " "); }
在数组中可以通过 数组对象
.length
来获取数组的长度。
int[] arr = new int[]{1,2,3,4,5,6,7}; for (int e : arr) { System.out.print(e + " "); }
Arrays
的方法toString
,将数组以字符串的形式输出import java.util.Arrays; // 需包含该类 int[] arr = new int[]{1,2,3,4,5,6,7}; System.out.println(Arrays.toString(arr)); //输出 //[1,2,3,4,5,6,7]
内存是一段连续的存储空间,主要用来存储程序运行时的数据。如:
如果对内存中存储的数据不加区分的随意存储,那对内存管理起来将会非常麻烦。
因此 JVM 也对所使用的内存按照功能的不同进行了划分:
- 程序计数器(PC Register):只是一个很小的空间,保存下一条指令的地址。
基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值。
引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址。
public static void func(){ int a = 10; int b = 20; int[] arr = new int[]{1,2,3}; }
下面是存放示意图:
null 在Java中表示“空引用”,也就是一个不指向对象的引用。
null 的作用类似于C语言中的NULL(空指针),都是表示一个无效的内存位置。因此不能对这个内存进行任何读写操作,一旦尝试读写,就会抛出 NullPointerException。
注意:java中并没有约定 null 和 0 号地址的内存有任何关联。
public static void func(int[] a) { a[0] = 10; System.out.println("a[0] = " + a[0]); }
}
![image.png](https://cdn.nlark.com/yuque/0/2022/png/22870205/1646487657133-17ad7d74-6868-4498-bb07-7f44041e9974.png#clientId=u296f67bb-fb04-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=98&id=u12553f3c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=101&originWidth=348&originalType=binary&ratio=1&rotation=0&showTitle=false&size=7100&status=done&style=none&taskId=u38f0bb07-560b-4922-aa77-5a065be8101&title=&width=337.99998474121094) <a name="AggJi"></a> #### 数组作为函数的返回值 ```java import java.util.Arrays; public class Demo_arr2 { public static void main(String[] args) { int[] array = {1,2,3,4,5,6}; int[] ret = func2(array); System.out.println(Arrays.toString(ret)); } //将数组a里面的元素扩大两倍,并返回,不改变原有的数组 public static int[] func2(int[] a) { int[] tmp = new int[a.length]; for (int i = 0;i < a.length; ++i) { tmp[i] = a[i] * 2; } return tmp; } }
import java.util.Arrays; int[] arr = {1,2,3,4,5,6}; String newArr = Arrays.toString(arr); System.out.println(newArr); //执行结果 [1,2,3,4,5,6]
import java.util.Arrays; public class Demo1 { // 数组拷贝 public static void main(String[] args) { int[] arr = {1,2,3,4,5,6}; // newArr和arr引用的是同一个数组 int[] newArr = arr; newArr[0] = 100; System.out.println("newArr: " + Arrays.toString(arr)); // 使用Arrays中copyOf方法完成数组的拷贝 // copyOf方法在进行数组拷贝时,创建了一个新数组 arr[0] = 1; // arr和newArr引用的不是同一个数组 newArr = Arrays.copyOf(arr,arr.length); System.out.println("newArr: " + Arrays.toString(newArr)); // 修改arr引用的内容时,对newArr没有影响 arr[0] = 90; System.out.println("arr: " + Arrays.toString(arr)); System.out.println("newArr: " + Arrays.toString(newArr)); // 拷贝某个范围 int[] newArr2 = Arrays.copyOfRange(arr,2,4); System.out.println("newArr2: " + Arrays.toString(newArr2)); } }
注意:数组当中存储的是基本数据类型时,无论怎么拷贝基本都不会出现什么问题,但如果存储的是引用数据类型时,拷贝时需要考虑深浅拷贝的问题,这样以后细说。
实现自己版本的拷贝数组:
// 实现自己版本的拷贝数组 public static int[] myCopyOf(int[] arr) { int[] ret = new int[arr.length]; for (int i = 0; i < arr.length; ++i) { ret[i] = arr[i]; } return ret; }
// 求数组中元素的平均值 public static void main(String[] args) { int[] arr = {1,2,3,4,5,6,7}; System.out.println(avg(arr)); } public static double avg(int[] arr) { int sum = 0; for (int x : arr) { sum += x; } return (double)sum / (double)arr.length; }
// 查找数组中指定元素(顺序查找) public static int find(int[] arr, int data) { for (int i = 0; i < arr.length; ++i) { if (arr[i] == data) { return i; } } return -1; } public static void main(String[] args) { int[] arr = {1,2,3,4,5,6,7}; System.out.println(find(arr,3)); System.out.println(find(arr,0)); }
// 二分查找 public static int binarySearch(int[] arr, int data) { int left = 0; int right = arr.length-1; while (left <= right) { int mid = left + (right >> 1); if (arr[mid] > data) { //到左半区间找 right = mid - 1; } else if (arr[mid] < data) { // 到右半区间找 left = mid + 1; } else { return mid; //找到了 } } return -1; //代表没找到 } public static void main(String[] args) { int[] arr = {1,2,3,4,5,6}; System.out.println(binarySearch(arr,6)); }
// 冒泡排序 public static void bubbleSort(int[] arr) { for (int i = 0; i < arr.length; ++i) { // 每一趟排序后,最大值都会跑到数组的最末端 for (int j = 1; j < arr.length - i; ++j) { if (arr[j-1] > arr[j]) { int tmp = arr[j-1]; arr[j-1] = arr[j]; arr[j] = tmp; } } } } public static void main(String[] args) { int[] arr = {9,5,2,7}; bubbleSort(arr); System.out.println(Arrays.toString(arr)); }
冒泡排序性能较低,java中内置了更高效的排序算法:
public static void main(String[] args) { //java中更高效的排序算法 int[] arr = {9,5,2,7}; Arrays.sort(arr); System.out.println(Arrays.toString(arr)); }
// 数组逆序 public static void reverse(int[] arr) { int left = 0; int right = arr.length - 1; while (left < right) { int tmp = arr[left]; arr[left] = arr[right]; arr[right] = tmp; ++left; --right; } } public static void main(String[] args) { int[] arr = {1,2,3,4,5}; reverse(arr); System.out.println(Arrays.toString(arr)); }
基本语法:数据类型[][] 数组名称 = new 数据类型 [行数][列数] {初始化数据};
代码示例:
// 二维数组 public static void main(String[] args) { int[][] arr = { {1,2,3,4}, {5,6,7,8}, {9,10,11,12} }; for (int row = 0; row < arr.length; ++row) { for (int col = 0; col < arr[row].length; ++col) { System.out.print(arr[row][col] + "\t"); } System.out.println(); } }
打印二维数组的方法Arrays.deeptoString();
int[][] arr = { {1,2,3,4}, {5,6,7,8}, {9,10,11,12} }; // 打印二维数组的方法 System.out.println(Arrays.deepToString(arr));
不规则的二维数组:
// 不规则的二维数组 public static void main(String[] args) { int[][] array = new int[2][]; // 注意:C语言 是可以指定列,行可以自动推导 // Java中,行必须指定,列不可以自动推导 array[0] = new int[3]; // 第一行有三列 // 也可以进行初始化:array[0] = new int[]{1,2,3}; array[1] = new int[2]; // 第二行有两列 }
// 常量只能被初始化一次,且使用的时候一定要记得初始化 public static void main (String[] args) { // 定义常量,建议名称全大写 final int MAXNUM = 10; System.out.println(MAXNUM); }
常量不能在程序运行过程中发生修改。
//如果字符串包含除数字外别的东西,则报错
Stringstr2 = "100abc";
int num2 = Integer.parseInt(str2); //报错
<a name="uvx9U"></a> # 8. 运算符 这里没什么好说的,跟C语言的差不多。此处只提及Java与C语言不同的部分。 - % 不仅可以对整型取模,还可以对double类型取模,但是没有意义,一般对整型取模。 ```java System.out.println(11.5 % 2.0); //运行结果 1.5
int i = 10; i = i++; //输出10,这个跟C语言不同 System.out.println(i);
详细原因以后再探讨。
switch 语法基本和C语言一致,下面给出示例:
int day = 1; switch(day) { case 1: System.out.println("1"); break; case 2: System.out.println("2"); break; default: System.out.println("输入有误"); break; }
【注意事项】:
错误示例:
像for``while
的循环条件表达式只能为布尔类型的,像下面的代码就是错误的:
if (1) { } while (1) { }
方法简而言之就是一个功能函数
语法格式:
修饰符 返回值类型 方法名称(参数列表) { 方法体代码; 返回值; }
【注意事项】:
public static
固定搭配。原因:因为当前所有的方法 写完之后 会在main方法中调用,因为main方法是public static的。静态的main函数里面只能调用静态的方法。
解决方法:传引用类型的参数(例如数组)
示例:
public class Demo { public static void main(String[] args) { int[] arr = {10,20}; swap(arr); System.out.println("arr[0] = " + arr[0] + " arr[1] = " + arr[1]); } public static void swap(int[] arr) { int tmp = arr[0]; arr[0] = arr[1]; arr[1] = tmp; } } //运行结果 arr[0] = 20 arr[1] = 10
示例:
public class Demo2 { // 方法的重载 public static int maxNum(int a, int b) { return a > b ? a : b; } public static double maxNum(double a, double b) { return a > b ? a : b; } public static int maxNumOf3(int a, int b, int c) { return maxNum(maxNum(a,b),c); } public static double maxNumOf3(double a, double b, double c) { return maxNum(maxNum(a,b),c); } public static void main(String[] args) { int a = 10; int b = 20; int c = 40; System.out.println(maxNumOf3(a,b,c)); double d1 = 2.134; double d2 = -1.739; double d3 = 9.087; System.out.println(maxNumOf3(d1,d2,d3)); } }
【注意事项】:
示例:
public class Demo2 { // 方法的重载 public static int maxNum(int a, int b) { return a > b ? a : b; } //仅仅是返回类型不同,无法构成重载 public static double maxNum(int a, int b) { return a > b ? a : b; } public static void main(String[] args) { } }
方法签名:经过编译器编译修改之后方法的最终的名字。具体方式:方法全路径名+参数列表+返回值类型,构成方法的完整的名字。
(类似于C++中函数重载中,生成的修饰名会根据函数参数的不同而不同)