Java基础
概述
第一个Java程序
1 | public class HelloWorld { |
HelloWorld是一个类,文件名必须与类名相同,为HelloWorld.java
打开终端,依次输入
1 | javac HelloWorld.java |
1 | java HelloWorld |
会看到终端中输出HelloWorld。
四个概念
- 类: 一个模板,描述一类 对象 的行为和状态
- 对象: 类 的一个实例,有状态和行为
- 方法: 就是行为,比如逻辑运算,数据修改……
- 实例变量: 决定 对象 的状态
example:
Dog 是一个 类 ,Dog1,Dog2,Dog3是Dog类里的三个 对象 ,eat(),run()等是 方法 ,品种、大小等是 实例变量 。
第二个Java程序
1 | public class MyDog { |
这段代码首先定义了一个 类 MyDog,然后第二、三行定义了两个 实例变量 ,第五行开始主程序,第六行通过 方法 MyDog()定义了一个 对象 Dog1,第七、八行分别输出Dog1的名字和年龄。
Java内存分配
- 栈:方法运行时使用的内存
- 堆:存储对象或者数组,用new创建的
- 方法区:存储可执行的class文件
- 本地方法栈:JVM使用操作系统功能时使用
- 寄存器:CPU使用
基本数据类型
byte
- 8位、有符号的二进制整数
- 取值范围
[-128 , 127]
默认值为0
short
- 16位、有符号的二进制整数
- 取值范围
[-215 , 215 - 1]
,默认值为0
int
- 32位、有符号的二进制整数
- 取值范围
[-231 , 231 - 1]
,默认值为0
- 一般的整形变量默认为int类型
long
- 64位、有符号的二进制整数
- 取值范围
[-263 , 263 - 1]
,默认值为0L
- “L”理论上不分大小写,但“l”容易与“1”混淆
float
- 单精度、32位、符合IEEE 754标准的浮点数
- 默认值
0.0f
- 不能表示精确的值
double
- 双精度、64位、符合IEEE 754标准的浮点数
- 默认值
0.0d
- 浮点数类型默认为double类型
- 不能表示精确的值
boolean
- 表示1位的信息
- 只有两个取值
true
和false
- 默认为
false
char
- 单一的16位Unicode字符
- 取值范围
[\u0000 , \uffff]
变量命名规则
使用有意义的名字,避免关键词
驼峰命名法
除第一个单词外,其余单词首字母大写
- 局部变量:小写字母开头
- 实例变量:小写字母开头
- 静态变量:小写字母开头,或全大写,单词间用下划线分割,比如
MAX_SIZE
- 常量:全大写,单词间下划线分割
- 参数:小写字母开头
- 类名:大写字母开头
修饰符
访问控制修饰符
- default:默认,同一包内可见
- private:同一类可见,不能修饰类(外部类)
- public:所有类可见
- protected:同一包内的类和子类可见,不能修饰类(外部类)
非访问修饰符
- static:声明静态变量和静态方法,不可声明局部变量
- final:修饰变量的值无法改变,且必须显式指定初始值
- abstract:不可实例化对象
- synchronized:声明的方法只能被一个线程访问,可用于四个访问修饰符
- transient:预处理类和变量的数据类型
- volatile:统一不同线程中,修饰的变量的值
运算符
算数运算符
1 | int a = 15, b = 5; |
运算符 | example |
---|---|
+(加法) | a + b = 20 |
-(减法) | a - b = 10 |
*(乘法) | a * b = 75 |
/(除法) | a / b = 3 |
%(取余) | a % b = 0 |
++(自增) | a++ = 16 ; ++a = 16 |
–(自减) | a– = 14 ; –a = 14 |
PS. 前缀自增/减,先进行算术运算,后赋值运算。后缀自增/减先赋值运算后算数运算
1 | public class Test { |
1 | public class selfAddMinus{ |
关系运算符
1 | int a = 15, b = 5; |
运算符 | example |
---|---|
==(相等) | (a == b) = false |
!=(不相等) | (a != b) = true |
>(大于) | (a > b) = true |
<(小于) | (a < b) = false |
>=(大于等于) | (a >= b) = true |
<=(小于等于) | (a <= b) = false |
1 | public class Test { |
位运算符
1 | A = 0011 1100 |
运算符 | 描述 | example |
---|---|---|
& | 相对应位都是1,则结果为1 | (A&B) = 0000 1100 |
| | 相对应位都是0,则结果为0 | (A|B) = 0011 1101 |
^ | 相对应位值相同,则结果为0 | (A^B) = 0011 0001 |
~ | 翻转操作数的每一位,即0变成1,1变成0 | (~A) = - 1100 0011 |
<< | 左操作数按位左移右操作数指定的位数 | (A<<2) = 1111 0000 |
>> | 左操作数按位右移右操作数指定的位数 | (A>>2) = 1111 |
>>> | 左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充 | (A>>>2) = 0000 1111 |
1 | public class Test { |
逻辑运算符
1 | boolean A = true, B = false |
运算符 | 描述 | example |
---|---|---|
&& | 逻辑与,同真则真 | (A && B) = false |
|| | 逻辑或,同假则假 | (A || B ) = true |
! | 逻辑非,反转真假 | (!A) = false ; (!B) = true |
1 | public class Test { |
赋值运算符
运算符 | 运算符 |
---|---|
= | <<= |
+= | >>= |
-= | &= |
*= | ^= |
/= | |= |
(%)= |
PS. 右侧变量算数运算或位运算结束后赋值给左侧变量,右侧变量值不变
1 | public class Test { |
条件运算符(?:)
variable x = (expression) ? value /if true/ : value /if false/
1 | public class Test { |
instanceof运算符
检查该对象是否是一个特定类型(类类型或接口类型)
( Object reference variable ) instanceof (class/interface type)
1 | class Vehicle {} |
语法结构
判断结构
if条件判断
1
2
3
4
5
6
7if (/*condition*/) {
/*do1*/
}else if (/*condition*/) {
/*do2*/
}else {
/*do3*/
}switch选择判断
1
2
3
4
5
6
7
8
9
10
11
12switch (/*expression*/) {
case value1:
/*do1*/
break;
case value2:
/*do2*/
break;
……
default:
/*don*/
break;
}1
2
3
4
5
6
7
8
9
10
11
12switch (/*expression*/) {
case value1 -> {
/*do1*/
}
case value2 -> {
/*do2*/
}
......
default -> {
/*don*/
}
}
循环结构
for循环
1
2
3for (int i = 1; i <= 10; i++) {
/*do*/
}while循环
1
2
3while (/*condition*/) {
/*do*/
} //先判断后执行do…while循环
1
2
3do {
/*do*/
} while (/*condition*/) //先执行后判断跳转控制语句
- continue:跳出当次循环,执行下次循环
- break:退出整个循环
数组
数组初始化
静态初始化
数据类型[] 数组名 = new 数据类型[] {元素1,元素2,元素3...};
1
2int[] array1 = new int[] {1, 2, 3};
int[] array2 = {1, 2, 3};动态初始化
数据类型[] 数组名 = new 数据类型[数组长度];
1
int[] arr = new int[3];
数组默认初始化值:
- 整数类型:0
- 小数类型:0.0
- 字符类型:‘/u0000’ 空格
- 布尔类型:false
- 引用数据类型:null
数组的地址与元素访问
数组的地址
1
2int[] arr = {1, 2, 3};
System.out.println(arr); // [I@6d03e736“I”是数组类型,“6d03e736”是数组在内存中的位置
元素访问
1
2
3
4
5
6
7
8
9
10
11
12
13int[] arr = {1, 2, 3};
System.out.println(arr[0]); // 1
System.out.println(arr[1]); // 2
System.out.println(arr[2]); // 3
//获取
int num = arr[0];
System.out.println(num); // 1
//存储
arr[0] = 10;
System.out.println(arr[0]); // 10
数组的内存图
各自指向不同空间
1
2int[] arr1 = new int[2];
int[] arr2 = new int[2];此时arr1和arr2通过new在堆内存中占用两个内存空间。arr1和arr2相互独立。
指向同一空间
1
2int[] arr1 = new int[2];
int[] arr2 = arr1;这段代码中,arr1通过new在堆内存中占据空间。但是arr2并没有使用new方法,而是指向了arr1的空间,共用同一个内存空间。arr1的值改变,arr2的值也会改变。
方法
方法的定义
简单方法定义
1
2
3
4
5public static void 方法名() {
/*方法体*/
}
方法名(); //调用带参数的方法定义
1
2
3
4
5public static void 方法名(参数数据类型 参数, ...) {
/*方法体*/
}
方法名(参数数据类型 参数, ...); //调用带返回值得到方法定义
1
2
3
4public static 返回值类型 方法名 (参数数据类型 参数, ...) {
/*方法体*/
return 返回值;
}
方法的重载
同一个类中,方法名相同,参数(个数,类型,顺序)不同。一般将同类操作的方法定义为同一方法名。
注意点
方法调用时存储在栈内存,内部的参数,也在栈内存。调用结束后,内存全部释放。因此:
传递基本数据类型时,传递的是真实的数据,形参的改变,不影响实际参数的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public class Test1 {
public static void main(String[] args) {
int num = 100;
sout(num); // 100
change1(num);
sout(num); // 100
num = change2(num);
sout(num); // 200
}
public static void change1(int num) {
num = 200;
}
public static int change2(int num) {
num = 200;
return num;
}
}传递引用数据类型时,传递的是地址值,形参的改变,影响实际参数的值
1
2
3
4
5
6
7
8
9
10
11
12
13public class Test2 {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
sout(arr[1]); // 100
change1(arr[1]);
sout(arr[1]); // 200
}
public static void change1(int[] arr) {
arr[1] = 200;
}
}
标准的JavaBean类
要求
- 类名要见名知意
- 成员变量使用
private
修饰 - 提供至少两个构造方法
- 无参构造方法
- 带全部参数的构造方法
- 成员方法
- 提供每一个成员变量对应的
setXxx() / getXxx()
- 其他行为
- 提供每一个成员变量对应的
Example
1 | package myPackage001; |
字符串
构造
直接赋值
1
2String s1 = "abc"
System.out.println(s1); //abcnew方法构造
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18//空参构造
String s2 = new String();
System.out.println(s2); //""
//传递字符串
String s3 = new String("abc");
System.out.println(s3); //"abc"
//传递字符数组
char[] chs = {'a', 'b', 'c', 'd'};
String s4 = new String(chs);
System.out.println(s4); //"abcd"
//传递字节数组
byte[] bytes = {97, 98, 99, 100};
Strings s5 = new String(bytes);
System.out.println(s5); //"abcd"
比较
==
基本数据类型比较的是值,引用数据类型比较的是地址值
1
2
3
4
5
6
7
8String s1 = new String("abc");
String s2 = new String("abc");
String s3 = "abc";
String s4 = "abc";
System.out.println(s1 == s2); //false
System.out.println(s1 == s3); //false
System.out.println(s3 == s4); //true方法
boolean equals() 完全一样为true
1
2
3
4
5
6String s1 = "abc";
String s2 = "abc";
String s3 = "ABC";
System.out.println(s1.equals(s2)); //true
System.out.println(s1.equals(s3)); //falseboolean equalsIgnoreCase() 忽略大小写
1
2
3
4
5
6String s1 = "abc";
String s2 = "abc";
String s3 = "ABC";
System.out.println(s1.equalsIgnoreCase(s2)); //true
System.out.println(s1.equalsIgnoreCase(s3)); //true
遍历
- 方法
- char charAt(int index) 根据索引返回字符
- int length() 返回字符串的长度
拼接
1 | String a = "a"; |
逆序
1 | public static String reverser(String s) { |
截取
1 | String a = "0123456789"; |
替换
1 | String a = "123" |
StringBuilder
构造方法
- public StringBuilder():创建空白可变字符串对象
- public StringBuilder(String str):根据字符串str内容,创建可变字符串对象
常用方法
- public StringBuilder append(任意数据类型):容器末尾添加数据,返回对象本身
- public StringBuilder reverse():反转容器中的内容
- public int length():返回长度
- public String toString():把StringBuilder转化为String
- public String insert(index, String[]):在
索引
位置插入字符 - public String delete(index1, index2):删除
索引1
和索引2
之间的字符(不包含两端)
example
1 | public class RunoobTest{ |
StringBuffer
与StringBuilder99%相似,区别在于:
- StringBuilder 的方法不是线程安全的(不能同步访问)
- StringBuilder 相较于 StringBuffer 有速度优势
- 一般使用StringBuilder