Java学习之基础语法
本文主要是对于有了其他语言基础的人总结的资料,因此本文只写出了Java与C语言,C++等语言的区别之处与部分重点。
1.基础语法:
1.1.包与类:
1.1.1.包:
在Java中,包(package)是一种用来组织和管理Java类的机制。以下是关于Java包的一些关键点:
-
包可以将一组相关的类组织在一起,方便管理和使用。
-
包提供了命名空间管理和访问保护的功能,可以避免命名冲突。
-
在Java中,每个类都必须属于一个包,如果没有指定包名,则默认为无名包(unnamed package)。
-
包声明应该在源文件的第一行,每个源文件只能有一个包声明,这个文件中的每个类型都应用于它。
-
如果一个源文件中没有使用包声明,那么其中的类,函数,枚举,注释等将被放在一个无名的包(unnamed package)中。
1.1.2.类:
在Java中,类是一种用来描述对象的模板或蓝图。它定义了对象的属性和行为,可以包含属性(变量)和方法(函数)。
在Java中,public
是一个访问修饰符,可以用于修饰类、方法、属性等,在一个Java文件中,关于public
的使用有以下规则:
-
一个Java源文件中只能有一个
public
类,这个public
类的类名必须与源文件名保持一致,例如,如果源文件中public
类的类名是Employee
,那么源文件应该命名为Employee.java
。 -
一个Java源文件中可以有多个非
public
类。 -
在一个类中,可以有多个
public
方法和public
属性。
注意,以下是一些有效的Java方法声明:
public class MyClass {
public static void main(String[] args) {..} // 主方法
public void doSomething() {..} // 非静态方法,无参数,无返回值
private static int calculateSum(int a, int b) {..} // 静态方法,有参数,有返回值
protected String sayHello(String name) {..} // 非静态方法,有参数,有返回值
}
在这个例子中,MyClass
类中有四个方法,它们的访问修饰符、返回类型、是否为静态以及参数列表都是不同的,所以,并不是所有的方法都需要写成public static void
的格式。
在java中,非public类也可以使用public修饰,但是,需要注意的是,如果一个类没有被声明为public
,那么这个类只能被同一个包内的其他类访问,类似于C++中的private。
1.2.方法:
在Java中,方法是一种封装了一系列语句的代码块,用于执行特定的任务,方法是语句的集合,它们在一起执行一个功能,方法是解决一类问题的步骤的有序组合,方法包含于类或对象中,方法在程序中被创建,在其他地方被引用。
Java中,定义一个方法需要明确其方法名、参数列表、返回类型和方法体,方法名用于标识方法,参数列表用于接收调用者传入的参数,返回类型表示方法执行完后返回的数据类型,方法体中包含了具体的执行语句。
例如,下面的代码定义了一个名为max
的方法,该方法接收两个整数参数并返回它们中的最大值:
public class TestMax {
public static void main(String[] args) {
int i = 5;
int j = 2;
int k = max(i, j);
System.out.println(i + " 和 " + j + " 比较,最大值是:" + k);
}
public static int max(int num1, int num2) {
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
}
本人认为,每一次调用包,如import java.util.Random;
,就相当于C++中调用库函数的声明,比如调用vector库#include <vector>
,而每一次创建一个类或者实例,例如,Random random = new Random();
,就相当于调用C++中创建一个函数,比如:vector<int>v;
,而每一次使用类的方法:int number = random.nextInt(100);
,就相当于使用C++vector下面的push_back函数。
1.3.注释:
Java有单行,多行,文档注释,这里只讲文档注释:
格式:以斜杠星号两个连续(/**)开头,以星号斜杠(*/)结尾,中间是注释内容。
用途:用于为类、接口、方法、字段等元素添加详细的说明,包括功能、用法、参数、返回值等信息。文档注释通常用于自动生成文档。
示例:
/**
* 这是一个文档注释,用于描述类、接口、方法或字段的详细信息
* 包括功能、用法、参数、返回值等
*/
public class MyClass {
// ...
}
1.4.数据类型:
Java有八种基本数据类型:
-
整型:包括
byte
、short
、int
和long
。 -
浮点型:包括
float
和double
。 -
字符型:
char
,单一的16位Unicode字符。 -
布尔型:
boolean
,只有两个取值:true
和false
。
在实际运用中,浮点数的精度不高,在实际开发中,要使用BigDecimal类替换。
对其它语言的补充:
char的四种表现形式:
-
直接赋值字符:可以直接使用单引号
' '
将字符赋值给char
变量。例如:char ch = 'a';
-
Unicode字符表示:可以使用
\u
后跟四位十六进制数来表示Unicode字符。例如:char uniChar = '\u039A';
3.转义字符:Java支持一些特殊的字符,这些字符不能直接输入,但可以通过转义序列来表示。转义序列以反斜杠\
开头。例如:
char newline = '\n'; // 表示换行符
char tab = '\t'; // 表示制表符
char backslash = '\\'; // 表示反斜杠本身
4.使用asc码赋值:
char c = 97;
注意,如果unicode使用出错,即使被注释掉,依然会报错,这是因为在Java中,Unicode转义序列(例如\uXXXX
,其中XXXX
是四位十六进制数)会在解析代码之前得到处理,包括注释中的Unicode转义序列,这意味着,即使Unicode转义序列在注释中,它仍然会被Java编译器解析。
1.5.类型提升与转换:
在实际运算的过程中,运算规则主要是自动类型提升和强制类型转换,当容量小的变量与容量大的变量进行运算时,结果自动转换为容量大的数据类型,此时的容量小或大并非只占用的内存空间的大小,而是指表示数据的范围大小。
一般情况下:
byte->short->int->long->float->double->String
但是,存在特殊情况:
1.byte+short
至少用int类型,byte+byte
也要用int,同理short+short
也是。
2.char
类型运算也是int接收。
注意区分:
long a=123123123123;//错误用法,超过精度
long b=123123123123L;//正确
long c=123;//正确
a,c都没有‘L’或者‘l’,都被理解为将int类型强制转换成long类型,而a会超过int的范围,会出错,同理,float定义必须要加F;
注意:在其他语言中,对强制类型转换的管理并不严格,而在Java中,将容量大的数据结构向下转换,必须要转换符:()
。
在传参也要遵守以上规则。
1.6.string:
注意,S要大写。String与其他数据结构之间只能做连接:
boolean b = true;
String str = "hello";
System.out.println(str+b);
且结果为String类型。
注意,在计算机计算时,往往是从左到右的,那么如果String str = a + b +String;且a,b类型不能相加,就会报错。
1.7.进制:
在Java中,你可以使用以下的格式来表示二进制,八进制和十六进制的数:
// 二进制
int binary = 0b1010; // "0b" 或 "0B" 开头表示二进制
// 八进制
int octal = 01234; // "0" 开头表示八进制
// 十六进制
int hex = 0x1a2b; // "0x" 或 "0X" 开头表示十六进制,即0-9,a-f
请注意,这些前缀(“0b”, “0”, “0x”)是大小写敏感的。例如,“0B” 和 “0b” 都可以用来表示二进制,但 “0O” 或 “0o” 则不能用来表示八进制。同样,“0X” 和 “0x” 都可以用来表示十六进制。而且,如果你需要0b表示二进制,那么后面的数字必须符合规范,即只有0,1。
在计算机储存数据时,都是先转化成2进制补码储存,此外,在计算机储存的数据中,最高位为符号位,0表示’+‘,1表示’-'。正数的补码反码原码是一样的,称为三码合一。而负数的补码反码和原码是不一样的,负数的原码是先把十进制转化为二进制,然后最高位设置为1,然后反码是在原码的基础上最高位不变,其余位全部取反,负数的补码则是等于负数的反码加一。
二进制转化成八进制,或者16进制,只需要记住,八进制是二的三次方,十六进制是二的四次方,那么我们就可以把二进制的每三位或者每四位看作一个数,然后把这个数记录下来,就得到了它的二进制表示,反之亦然。
1.8.运算符:
补充:
1.取模后符合与被模数相同。
2.前面说到short等类型无法进行与另外的数加减,都是可以用++,–,+=,-=等符合改变它的值。但是不会改变变量的数据类型。
3.instanceof
:在Java中,instanceof
是一个二元运算符,用于测试一个对象是否为给定类型的实例]。instanceof
运算符的结果是 true
或 false
],它也被称为类型比较运算符,因为它将实例与类型进行比较。instanceof
运算符的基本语法是:(object) instanceof (type)
。在对未知对象进行强制类型转换之前,应始终使用 instanceof
检查,这样做可以帮助避免在运行时出现 ClassCastException
。这个在后面会着重写。
4.&与&&,|与||的区别:
& :如果符号左边是 false,则继续执行符号右边的操作
&&:如果符号左边是 false,则不再继续执行符号右边的操作
| :如果符号左边是 true, 则继续执行符号右边的操作
||:如果符号左边是 true,则不再继续执行符号右边的操作
5.>>>
:在JAVA中,>>>
是一个位于运算符称为无符号右移运算符,它能将二进制数的所有位向右移动指定的位数,左边空出的位用零补齐,而右边溢出的直接被丢弃,因为其不考虑最高位即符号位,所以被称之为无符号运算符。而>>
是算术右移运算符,它将二进制数的所有位向右移动指定的位数,左边空出的位用符号位填充,也就是说,如果数字是正数,左边会填充0;如果数字是负数,左边会填充1。这是因为 >>
运算符会保留数字的符号。
6.取反等操作是对二进制的补码进行操作,我们在推算的时候,要将数据先转化成二进制的补码,然后再操作,再将操作后的二进制转回原码。
1.9.输入与输出:
输出
在Java中,你可以使用以下方法将输出发送到标准输出(屏幕):
System.out.println();:打印一个字符串并换行。
System.out.print();:打印一个字符串但不换行。
System.out.printf();:格式化输出。
例如:
System.out.println("Hello, World!"); // 输出 "Hello, World!" 并换行
System.out.print("Hello, "); // 输出 "Hello, " 但不换行
System.out.print("World!"); // 输出 "World!" 但不换行
System.out.printf("Hello, %s!", "World"); // 格式化输出 "Hello, World!"
int i = 100;
double pi = 3.14;
String str = "Java";
System.out.printf("%d\n", i); // 输出整数
System.out.printf("%f\n", pi); // 输出浮点数
System.out.printf("%s\n", str); // 输出字符串
输入
Java提供了不同的方法来从用户那里获取输入。在本教程中,你将学习使用Scanner类的对象从用户那里获取输入。
首先,我们需要导入java.util.Scanner包,然后创建Scanner类对象。我们可以使用该对象从用户那里获取输入。
例如,从用户获取整数输入:
import java.util.Scanner;
class Input {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("输入一个整数: ");
int number = input.nextInt();
System.out.println("您输入 " + number);
input.close();
}
}
在上面的示例中,我们创建了一个名为Scanner类的input对象。然后,我们调用Scanner类的nextInt()方法以从用户获取整数输入。同样,我们可以使用nextLong(), nextFloat(), nextDouble()和next()方法来分别从用户获取long, float, double和string输入。
注意,Java没有直接读入char类型的操作,但是可以用一些方法:
一种常见的方法是先使用 Scanner 的 next() 方法读取一个字符串,然后使用 String 类的 charAt() 方法来获取这个字符串的第一个字符。以下是一个示例:
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个字符:");
char c = scanner.next().charAt(0);
System.out.println("你输入的字符是:" + c);
scanner.close();
}
}
别忘了close()关闭。
1.10.流程控制语句:
1.10.1:比较:
注意:在Java中使用 == 运算符来比较字符串时。在Java中,== 运算符比较的是对象的引用,而不是它们的值。因此,当使用 s == “是” 等时,实际上是在比较 s 和 “是” 是否指向同一个对象,而不是它们的值是否相等。为了比较两个字符串的值,我们应该使用 String 类的 equals() 方法:
import java.util.Scanner;
public class test {
public static void main(String[] args){
Scanner input = new Scanner(System.in);
String s ;
System.out.print("输入: ");
s = input.next();
if(s.equals("是")){
System.out.println("好");
}
input.close();
}
}
总之,在Java中,== 运算符可以用于比较基本数据类型(如 int, char, float,char 等)的值。比如,s 是一个 int 类型的变量,所以 s == 1 是正确的。然而,对于引用类型(如 String, Array, Class 等),== 运算符比较的是它们的引用,而不是它们的值。也就是说,== 运算符检查两个引用是否指向内存中的同一个对象。因此,如果想比较两个字符串的值,你应该使用 String 类的 equals() 方法,而不是 == 运算符。
1.10.2:生成随机数:
在Java中,你可以使用 Math.random() 方法或 Random 类来生成随机数。
Math.random() 方法会返回一个大于等于0.0且小于1.0的double类型的随机数。你可以通过一些数学运算来获取指定范围内的随机数。例如,(int)(Math.random() * (max - min + 1)) + min 可以生成一个在 [min, max] 区间内的随机整数。
Random 类提供了更丰富的随机数生成方法。你可以使用 Random 类的 nextInt(), nextDouble(), nextFloat(), nextLong(), nextBoolean() 等方法来生成不同类型的随机数。例如,Random().nextInt(100) 会生成一个在 [0, 100) 区间内的随机整数。
以下是一些示例代码:
// 使用 Math.random() 生成 [0, 1) 区间的随机小数
double random1 = Math.random();
// 使用 Math.random() 生成 [1, 10] 区间的随机整数
int random2 = (int)(Math.random() * 10) + 1;
// 创建一个 Random 对象
Random random = new Random();
// 使用 Random 对象生成 [0, 100) 区间的随机整数
int random3 = random.nextInt(100);
// 使用 Random 对象生成一个随机布尔值
boolean random4 = random.nextBoolean();
1.10.3.switch case:
在Java中,switch 语句可以支持以下类型:
- 基本数据类型:byte, short, char, int
- 包装数据类型:Byte, Short, Character, Integer
- 枚举类型:Enum
- 字符串类型:String(从Java 7开始支持)
1.11.开方函数:
在Java中,可以使用Math.sqrt()函数来计算一个数的平方根。例如:
double num = 16;
double squareRoot = Math.sqrt(num);
System.out.println("The square root of " + num + " is " + squareRoot);
这段代码将输出:
The square root of 16 is 4.0
1.12.数组:
1.12.1.定义一维数组:
// 定义数组类型为整数的数组,动态初始化
int[] arr1 = new int[5]; // 定义一个长度为5的整数数组
// 定义并初始化数组,静态初始化简写,类型推断,不可拆
int[] arr2 = {1, 2, 3, 4, 5}; // 定义并初始化一个整数数组
// 交换数组名字与[]
int arr3 [] = new int[3]; // 使用new关键字创建一个长度为3的整数数组
//先定义,后赋值
int[] arr;
arr = new int[3];
//静态初始化
int[] arr = new int[]{1,2,3,4,5};
// 可以拆分
int[] arr;
arr = new int[]{1,2,3,4,5};
Arrays.fill快速初始化,填充一个数组
java中的数组初始值都为零,若快速填充一个其他值的数组,即将数组批量填充相同的值,可以用 Arrays.fill 方法,但只能填充一个一维数组,多维数组还得用循环。
import java.util.Arrays;
public class HelloWorld {
public static void main(String[] args) {
int[] arr = new int[5];
Arrays.fill(arr, 1);
System.out.println(Arrays.toString(arr)); // [1, 1, 1, 1, 1]
}
}
在java中,无法在声明阶段指定数组大小,即无法int a[7],int [9]a;
一旦成功初始化,长度就确定了,并且无法更改。并且有{},[]内就不会有数字,有数字,就不会有{}。
1.12.1.2.调用数组元素:
Java中赋予了数组的一个属性,可以获取到数组的长度,语句为:数组名.length ,属性length的执行结果是数组的长度,int类型结果。由次可以推断出,数组的最大索引值为数组名.length-1。
public static void main(String[] args) {
int[] arr = new int[]{1,2,3,4,5};
//打印数组的属性,输出结果是5
System.out.println(arr.length);
}
索引访问数组中的元素:
-
数组名[索引] = 数值,为数组中的元素赋值
-
变量 = 数组名[索引],获取出数组中的元素
public static void main(String[] args) {
//定义存储int类型数组,赋值元素1,2,3,4,5
int[] arr = {1,2,3,4,5};
//为0索引元素赋值为6
arr[0] = 6;
//获取数组0索引上的元素
int i = arr[0];
System.out.println(i);
//直接输出数组0索引元素
System.out.println(arr[0]);
}
1.12.1.3.数组默认初始化值:
整形:0;
浮点型:0.0;
字符型:0;//并非字符'0',而是\u0000;
boolean:false;
string及其他引用类型:null;
1.12.1.4.一维数组内存解析:
图片来自尚硅谷~~
总之,出现new表示申请新地址,反之则是指针的操作赋值。
1.12.2.二维数组:
1.12.2.1.二维数组初始化:
同一维数组一样,共有4总不同形式的定义方法:
int[][] array1 = new int[10][10];
int array2[][] = new int[10][10];
int array3[][] = { { 1, 1, 1 }, { 2, 2, 2 } };
int array4[][] = new int[][] { { 1, 1, 1 }, { 2, 2, 2 } };
不定长二维数组:
int[][] array = new int[3][];
int array[][] = {{1,2},{1,4,6}};
array[0] = new int[1];
array[1] = new int[2];
array[2] = new int[3];
获取二维数组的长度
int length1 = array.length;
int length2 = array[0].length;
// 获取二维数组的第一维长度(3)
System.out.println(length1);
// 获取二维数组的第一维的第一个数组长度(1)
System.out.println(length2);
二维数组可以让它的某一位等于一维数组:
a[0] = b;//a是二维数组,b是一维数组
1.12.2.2.调用:
int [][]array = {{1,2,3},{1,2}};
System.out.println(array[0][0]);
System.out.print(array[0]);
打印结果:第一个为1,第二个事实上是{1,2,3}的地址。
也可以这样:
int [][]array = new int[][]{{1,2,3},{1,2}};
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();
}
1.12.2.3.默认值:
整型外层数组默认值:地址;
整型内层默认值:0;
Boolean外层数组默认值:地址;
Boolean内层默认值:false;
........
外层都是地址,内层与一位数组一样。
但是,对于不定长二维数组,外层为null,内层会报错,因为有空指针。
1.12.2.4.二维数组内存解析:
1.12.3.数组的算法操作:
3.1.数组之间的赋值:
int array[] = {1,2,3};
int arr[];
arr = array;
arr[0] = 9;
System.out.print(array[0]);
输出的是9,在java里面,使用数组直接赋值,那么它们就会指向同一块内存,因此,改变其中的一个值,就会改变另外一个值。
3.2.数组的扩容缩容:
int arr[] = {1,2,3,4,5};
int newarr[] = new int[arr.length<<1];
arr = newarr;
3.3.排序:
事实上,在不同语言中,算法的逻辑是差不多的,这里,简单写几个就可:
比如手写一个快排:
public class test {
public static void my_sort(int []arr,int l,int r){
if(l>=r){
return ;
}
int temp=arr[l],i=l-1,j=r+1;
while(i<j){
do{
i++;
}while(arr[i]<temp);
do{
j--;
}while(arr[j]>temp);
if(i<j){
int k=arr[i];
arr[i]=arr[j];
arr[j]=k;
}
}
my_sort(arr,l,j);
my_sort(arr,j+1,r);
}
public static void main(String[] args){
int []arr = {1,5,7,2,4,8,2};
my_sort(arr,0,arr.length-1);
for(int k:arr){
System.out.print(k);
}
}
}
1.12.4.数组常见的API:
-
length: 返回数组的长度
-
clone: 复制数组
-
equals: 比较两个数组是否相等
-
fill: 将数组的所有元素都设置为指定值
-
sort: 对数组进行排序
-
binarySearch: 在排序后的数组中查找指定元素
-
copyOf: 复制数组的一部分
-
asList: 将数组转换为List
-
toString: 将数组转换为字符串
-
hashCode: 返回数组的哈希码值
1.length:
int[] array = {1, 2, 3, 4, 5};
int length = array.length;
System.out.println("数组的长度为:" + length);
2.clone:
int[] array = {1, 2, 3, 4, 5};
int[] newArray = array.clone();
System.out.println("复制的数组为:" + Arrays.toString(newArray));
3.equals:
int[] array1 = {1, 2, 3, 4, 5};
int[] array2 = {1, 2, 3, 4, 5};
boolean isEqual = Arrays.equals(array1, array2);
System.out.println("两个数组是否相等:" + isEqual);
4.fill:
int[] array = new int[5];
Arrays.fill(array, 10);
System.out.println("填充后的数组为:" + Arrays.toString(array));
5.sort:
int[] array = {5, 3, 8, 2, 1};
Arrays.sort(array);
System.out.println("排序后的数组为:" + Arrays.toString(array));
6.binarySearch:
int[] array = {1, 2, 3, 4, 5};
int index = Arrays.binarySearch(array, 3);
System.out.println("元素3的索引为:" + index);
7.copyOf:
int[] array = {1, 2, 3, 4, 5};
int[] newArray = Arrays.copyOf(array, 3);
System.out.println("复制的数组为:" + Arrays.toString(newArray));
8.asList:
String[] array = {"A", "B", "C"};
List<String> list = Arrays.asList(array);
System.out.println("转换后的List为:" + list);
9.toString:
int[] array = {1, 2, 3, 4, 5};
String arrayString = Arrays.toString(array);
System.out.println("数组转换为字符串:" + arrayString);
10.hashCode:
int[] array = {1, 2, 3, 4, 5};
int hashCode = Arrays.hashCode(array);
System.out.println("数组的哈希码值为:" + hashCo