1. 认识java的main方法
比如,文件名为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循环里面的内容了。
2. 如何运行一个java程序
javac 文件名.java
,形成 .class文件。注意:
在cmd上编译文件,需要将当前目录改为文件所在目录,使用命令 cd /d 文件路径
2. 在记事本上写代码,需要先保存,再编译。
编译完后,可在当前目录中看到 .class文件
java 文件名
来运行文件(在JVM(java虚拟机)里运行)注意:java 和 javac 都属于JDK命令。
3. Java当中的注释
- 块注释(快捷键,选中要注释的内容,ctrl+shift+/)
/*这是块注释*/
- 文档注释
/**
* 文档注释:
* 作者:
* 日期:
* 描述:
*/
- 行注释(快捷键:ctrl+/)
// 这是行注释
但是如果程序里面有注释,编译的时候会出现错误,如下图:原因是,代码里面有中文,但是javac编译默认使用GBK来编码的,这就是“字节码格式不匹配导致”的。这时候我们只需要在后面加
-encoding utf-8
编译即可:这就告诉编译器,统统以utf-8来编码。
4. 打印数据
有三种方式打印:结果如下:
5. 数据类型
5.1 基本数据类型
- 长整型(long)
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);
}
- 双精度浮点型(double)
/**
* 双精度 浮点型
* @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);
}
- 单精度浮点型(float):定义变量数值的时候,需要加上
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)
/**
* 字符数据类型:
* 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)
// 字节: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)
//短整型: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);
}
- 布尔型(boolean)
/**
* 布尔类型:
* 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) {
}*/
}
5.2 引用数据类型
String
语法格式: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);
数组(Arrays:操作数组的工具类)
数组的创建
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};
- 若数组中存储元素类型为基类类型,默认值为基类类型对应的默认值,如:
- 如果数组中存储元素类型为引用类型,默认值为null。
#### 数组的使用
数组中元素的访问
数组在内存中是一段连续的空间,空间的编号都是从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的内存分布
内存是一段连续的存储空间,主要用来存储程序运行时的数据。如:
如果对内存中存储的数据不加区分的随意存储,那对内存管理起来将会非常麻烦。因此 JVM 也对所使用的内存按照功能的不同进行了划分:
- **程序计数器(PC Register):**只是一个很小的空间,保存下一条指令的地址。
> - **虚拟机栈(JVM Stack):**与方法调用相关的一些信息,**每个方法在执行时,都会先创建一个栈帧,**栈帧包含**局部变量表、操作数栈、动态链接、返回地址**以及其他的一些信息,保存的都是与方法执行时相关的一些信息。比如:局部变量。**当方法运行结束后,栈帧就被销毁,即栈帧中保存的数据也被销毁了。**
>
> - **本地方法栈(Native Method Stack):**本地方法栈和虚拟机栈的作用类似,只不过**保存的内容是Native方法的局部变量。(Native方法:底层是用C/C++写的,运行速度快)。**
>
> - **堆(Heap):**JVM所管理的最大内存区域。使用**new 创建的对象都是在堆上保存**(例如前面的`new int[]{1,2,3}`),**堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销毁。**
>
> - **方法区(Method Area):**用于**存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。**方法编译出的字节码就是保存在这个区域。
基本类型变量与引用类型变量的区别
基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值。引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址。
public static void func(){
int a = 10;
int b = 20;
int[] arr = new int[]{1,2,3};
}
下面是存放示意图:
认识null
null 在Java中表示“空引用”,也就是一个不指向对象的引用。null 的作用类似于C语言中的NULL(空指针),都是表示一个无效的内存位置。因此不能对这个内存进行任何读写操作,一旦尝试读写,就会抛出 NullPointerException。
注意:java中并没有约定 null 和 0 号地址的内存有任何关联。
#### 数组作为函数的参数
```java
public class Demo_arr2 {
public static void main(String[] args) {
int[] arr = {1,2,3};
func(arr);
System.out.println("arr[0] = " + arr[0]);
}
public static void func(int[] a) {
a[0] = 10;
System.out.println("a[0] = " + a[0]);
}
}

#### 数组作为函数的返回值
```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;
}
}
数组练习
1. 数组转字符串
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]
2. 数组拷贝
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;
}
3. 求数组中元素的平均值
// 求数组中元素的平均值
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;
}
4. 查找数组中指定元素(顺序查找)
// 查找数组中指定元素(顺序查找)
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));
}
5. 查找数组中指定元素(二分查找)
// 二分查找
public static int binarySearch(int[] arr, int data) {
int left = 0;
int right = arr.length-1;
while (left > 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));
}
6. 冒泡排序
// 冒泡排序
public static void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length; ++i) {
// 每一趟排序后,最大值都会跑到数组的最末端
for (int j = 1; j 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));
}
7. 数组逆序
// 数组逆序
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]; // 第二行有两列
}
6. 常量
6.1 字面值常量
6.2 final 关键字修饰的常量
// 常量只能被初始化一次,且使用的时候一定要记得初始化
public static void main (String[] args) {
// 定义常量,建议名称全大写
final int MAXNUM = 10;
System.out.println(MAXNUM);
}
常量不能在程序运行过程中发生修改。
# 7. int 和 String 之间的相互转换
## 7.1 int 转成 String
```java
int num = 10;
//方法1:
String str1 = num + "";
//方法2:
String str2 = String.valueOf(num);
```
## 7.2 String 转成 int
```java
String str = "100";
int num = Integer.parseInt(str);
//如果字符串包含除数字外别的东西,则报错
Stringstr2 = "100abc";
int num2 = Integer.parseInt(str2); //报错
# 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);
详细原因以后再探讨。
9. 程序逻辑控制
9.1 switch 语句
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;
}
【注意事项】:
- 基本类型:byte,char,short,int,char,注意不能是long,float,double,boolean
- 引用类型:String常量串,枚举类型
错误示例:
9.2 补充
像for``while
的循环条件表达式只能为**布尔类型的,**像下面的代码就是错误的:
if (1) {
}
while (1) {
}
10. 方法的概念和使用
方法简而言之就是一个功能函数
10.1 方法定义
语法格式:
修饰符 返回值类型 方法名称(参数列表) {
方法体代码;
返回值;
}
【注意事项】:
public static
固定搭配。原因:因为当前所有的方法 写完之后 会在main方法中调用,因为main方法是public static的。静态的main函数里面只能调用静态的方法。
## 10.2 实参和形参的关系
**在Java中,实参的值永远都是拷贝到形参中,形参和实参本质是两个实体。(这点跟C语言不一样,C语言可以传递地址,来改变实参的值,但是Java只能改变形参的值)。**
解决方法:传引用类型的参数(例如数组)示例:
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
# 11. 方法的重载
**重载即是“一词多义”的意思。****在Java中,如果多个方法的名字相同,参数列表不同,则称该几种方法被重载了。**
示例:
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) {
}
}
# 12. 方法签名
在同一个作用域中不能定义两个相同名称的标识符。如,方法中不能定义两个名字一样的变量,那**为什么类中就可以定义方法名相同的方法呢?**
方法签名:经过编译器编译修改之后方法的最终的名字。具体方式:方法全路径名+参数列表+返回值类型,构成方法的完整的名字。(类似于C++中函数重载中,生成的修饰名会根据函数参数的不同而不同)