2023/09/10:java 0 to 1

随手记

1.Java源文件以.java为扩展名,源文件的基本组成是类(class)
2.Java应用程序的执行入口为main()方法,格式:public static void main(String[] args){...}
3.严格区分大小写
4.一个源文件最多一个public类,且文件名同此类名
5.其他类个数不限,可将main方法写在非public类中,然后指定运行非public类,这样入口方法就是非public的main方法,且编译时每个类会生成对应的.class文件
6.变量的使用大致同C
7.关于+
1.左右两边都是数值型时,做加法运算
2.左右两边有一为字符串,做拼接
3.运算从左到右
8.数据类型
1.基本数据类型
byte 1字节 -128 —— 127(二进制)
short 2字节 -(2^15) —— (2^15)-1
int 4字节 -(2^31) —— (2^31)-1 整型常量默认int
long 8字节 -(2^63) —— (2^63)-1 long型常量需在数字后加l或L,如long n = 1L
float 4字节 -3.403E38 —— 3.403E38 float常量需加f或F
double 8字节 -1.798E308 —— 1.798E308 浮点常量默认double
char 2字节 可放汉字,使用单引号,本质为整数,输出unicode(兼容ASCII)对应字符,可直接运算
boolen 1字节 仅可true或false
浮点储存:符号位+指数位+尾数位,尾数可能丢失->精度损失,运算结果比较应采用Math.abs(a - b)<0.001形式,直接赋值或查询得到可==
2.引用类型
类 接口 数组
9.数据类型转换
1.自动
精度小转大
char->int->long->float->double
byte->short->int->long->float->double
多种混合运算时,先将所有数据转换为容量最大类型
(byte,short)与char不可相互转换,但可计算,会转为int
精度大赋给精度小报错
boolen不转换
表达式结果自动提升为操作数最大类型
2.强制
例:(int)1.9
注意精度降低和可能的溢出
仅对最近操作数有效
char可保存int常量值不保存变量值
10.string
基本转string:基本类型值+””
string转基本类型:基本类型包调用方法,如Long.parseLong("123")
转换为基本类型时注意是否能转换为有效数据,如hello无法转为整数
11.运算符
1.&& 和 & 使用区别
&& 短路与:如果第一个条件为 false,则第二个条件不会判断,最终结果为 false,效率高
& 逻辑与:不管第一个条件是否为 false,第二个条件都要判断,效率低
2.|| 和 | 使用区别
||短路或:如果第一个条件为 true,则第二个条件不会判断,最终结果为 true,效率高
| 逻辑或:不管第一个条件是否为 true,第二个条件都要判断,效率低
开发中,我们基本使用 |
12.复合赋值会进行类型转换
13.三元运算符...?表达式1:表达式2
表达式 1 和表达式 2 要为可以赋给接收变量的类型(或可以自动转换)
14.键盘输入
1.导入该类的所在包, java.util. (Scanner类,import java.util.Scanner;)
2.创建对象声明变量(如Scanner myScanner = new Scanner(System.in);)
3.调用,如输入int:int age = myScanner.nextInt();
15.进制
二进制 0B或0b开头 八进制 0开头 十六进制 0x或0X开头
16.位运算
1.算术右移 >>:低位溢出,符号位不变,并用符号位补溢出的高位
2.算术左移 <<: 符号位不变,低位补 0
3. >>> 逻辑右移也叫无符号右移,运算规则是: 低位溢出,高位补 0
17.数组
1.初始化
定义
数据类型 数组名[] = new 数据类型[大小]可分两行
声明
数据类型 数组名[]; 或 数据类型[] 数组名;
int a[]; 或者 int[] a;
注意
数组中的元素可以是任何数据类型,包括基本类型和引用类型,但是不能混用。
数组创建后,如果没有赋值,有默认值
int 0,short 0, byte 0, long 0, float 0.0,double 0.0,char \u0000,boolean false,String null
数组属引用类型,数组型数据是对象(object)
2.赋值
数组在默认情况下是引用传递,赋的值是地址
int[] arr1 = {1,2,3};int[] arr2 = arr1;
3.二维数组
int[][] arr
每个元素是一维数组,同C,动态初始化int[][] arr = new int[3][]
声明:int[][] y 或者 int[] y[] 或者 int y[][]
二维数组实际上是由多个一维数组组成的,它的各个一维数组的长度可以相同,也可以不相同。比如:map[][] 是一个二维数组,由 map[0] 是一个含有两个元素的一维数组 ,map[1] 是一个含有三个元素的一维数组构成,我们也称为列数不等的二维数组
18.类与对象
1.对象的属性默认值,遵守数组规则
2.一个方法最多有一个返回值,返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)
3.引用类型传递的是地址(传递也是值,但是值是地址),可以通过形参影响实参
4.可变参数
int… 表示接受的是可变参数,类型是 int ,即可以接收多个 int(0-多)
使用可变参数时,可以当做数组来使用,本质就是数组
可与普通参数一起放在列表里,需保证可变参数在最后,如:public void f2(String str, double… nums)
一个形参列表中只能出现一个可变参数
19.作用域
1.全局变量(属性)可不赋值,有默认值,可加修饰符,可被其他类使用(对象调用)
2.局部变量不可加修饰符
3.构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化,类似C++,但构造器的修饰符可以默认,也可以是 public protected private
4.this表示当前对象,会分给每个对象,哪个对象调用,就代表哪个对象;可以用来访问本类的属性、方法、构造器;用于区分当前类的属性和局部变量;访问成员方法的语法:this.方法名(参数列表),访问构造器语法:this(参数列表); 注意只能在构造器中使用(即只能在构造器中访问另外一个构造器, 必须放在第一条语句);this 不能在类定义的外部使用,只能在类定义的方法中使用
20.IDEA
1.使用 IDEA 创建 Java 项目(project),IDEA 是以项目的概念,来管理 java 源码
2.Settings->File Encodings改编码
21.包
1.作用:区分相同名字的类,便于管理,控制访问范围
2.本质为创建不同的文件夹来保存文件
3. package com.hspedu package:关键字,表示打包 com.hspedu表示包名
4.常用包
java.lang.* lang 包是基本包,默认引入,不需要再引入
java.util.* util 包,系统提供的工具包, 工具类,使用 Scanner
java.net.* 网络包,网络开发
java.awt.* 是做 java 界面开发,GUI
5.引入包
import java.util.Scanner; 引入Scanner类
import java.util.*; 引入所有类
6.package
package 的作用是声明当前类所在的包,需要放在类(或者文件)的最上面,一个类中最多只有一句 package
import 指令位置放在 package 的下面,在类定义前面,可以有多句且没有顺序要求
7.访问修饰符:控制方法和属性(成员变量)的访问权限(范围)
类似类的对象修饰符,默认级别:没有修饰符号,向同一个包的类公开
22.继承
1.语法
class 子类 extends 父类{

}
2.父类又叫超类,基类 子类又叫派生类
3.super
super(参数列表)指定使用父类的哪个构造器完成对父类的初始化工作,默认情况下总会去调用父类的无参构造器,在使用时,必须放在构造器第一行(super 只能在构造器中使用)
super.属性名 访问父类属性
super.方法名(参数列表) 访问方法
4.java 所有类都是 Object 类的子类, Object 是所有类的基类
5.父类构造器的调用不限于直接父类
6.子类最多只能继承一个父类(指直接继承)
7.关于查找
    1.看子类是否有该属性
    2.如果子类有这个属性,并且可以访问,则返回信息
    3.如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
    4.如果父类没有就按照3的规则,继续找上级父类,直到 Object..

23.override重写
1.定义
子类有一个方法与父类方法的名称、返回类型、参数一样,就是子类重写父类方法
2.注意
不能缩小访问权限 public>protected>默认>private
子类方法的返回类型和父类一样或为父类的子类
属性不可重写,属性值看编译类型
24.多态
1.一个对象的编译类型和运行类型可以不一致
2.编译类型在定义对象时已确定不可改变
3.运行类型可改变
4.编译类型看定义时=左,运行类型=右
如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Animal{
...
}

public class Cat extends Animal{
...
}

public class Dog extends Animal{
...
}

public class test{
public static void main(String[] args){
Animal animal = new Dog();
animal = new Cat()
//合法
}
}

5.多态向上转型
1.本质:父类引用指向子类对象
2.语法: 父类类型 引用名 = new 子类类型()
3.特点:编译类型看左边,运行类型看右边;可以调用父类中的所有成员(需遵守访问权限);不能调用子类特有成员;最终效果看子类实现
6.多态向下转型
1.语法: 子类类型 引用名 = (子类类型) 父类引用
2.只能强转父类的引用,不能强转父类对象
3.要求父类的引用必须指向的是当前目标类型的对象
4.向下转型后,可调用子类类型所有成员
7.Java动态绑定机制
1.调用对象方法时,该方法会和该对象的内存地址/运行类型绑定
2.调用对象属性时,无动态绑定机制,哪声明哪使用
8.多态参数 多态数组 …
(先放着 偷懒)
25.Object
1.equals方法
只能判断引用类型,默认判断地址是否相等,一般重写
2.hashCode方法
返回该对象哈希码值;哈希值主要根据地址号来的,不能完全将哈希值等价于地址;
3.toString方法
默认返回:全类名+@+哈希值的十六进制;重写需@Override
4.finalize方法
当对象被回收时,系统自动调用该对象的 finalize 方法;当某个对象没有任何引用时,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用 finalize 方法;垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过 System.gc() 主动触发垃圾回收机制;重写需@Override
26.static
1.类变量
一个类所有对象共享,静态变量也叫类变量、静态属性
访问: 类名.类对象名
2.类方法
使用: 类名.方法名
不允许使用和对象有关关键字,只能访问静态变量方法
无this
27.main方法
1.可以直接调用 main 方法所在类的静态方法或静态属性
2.不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员
3.接受String类型数组参数,该数组保存执行java命令时传递给所运行的类的参数
4.必须为 public static
28.代码块
1.语法

1
2
3
$[修饰符,要写只能写static]{
$ 代码
$};
2.相当于另一种形式构造器,代码块调用的顺序优先于构造器(构造方法),
3.在创建对象实例(new)加载/创建子类对象实例父类加载/使用类的静态成员加载,静态代码块随类的加载执行且仅一次,普通代码块每创建一个对象就执行
4.创建对象时的调用顺序
    静态代码块/静态变量初始化->普通代码块和普通属性->构造函数
5.子类对象调用顺序
父类静态代码块/静态属性->子类静态代码块和静态属性->父类普通代码块和普通属性->父类构造函数->子类普通代码块和普通属性->子类构造函数

29.单例
1.含义
保证整个软件系统中对某个类只存在一个对象实例,且该类只提供一个取得对象实例的方法
2.实现
构造器私有(防new)->类内部创建对象->向外暴露一个静态公共方法
3.饿汉与懒汉
创建对象时机:饿汉在类加载,懒汉在使用时
线程安全:饿汉无,懒汉有
浪费资源可能:饿汉有,懒汉无
30.final
1.修饰类、属性、方法
2.使用情况
不希望类被继承 不希望父类某方法被子类重写 不希望类的某属性被修改 不希望某个局部变量被修改
3.注意
final修饰的属性也叫常量,需赋初值,在定义时或构造器或代码块;若该属性静态,不可在构造器赋值;不能继承但可实例化对象;若类不是final,但有final方法,则该方法不可被继承但可被重写;不能修饰构造器;包装类(如Integer Double Float Boolean等)均为final,String也是
31.抽象类
abstract声明
32.接口
1.定义
将没有实现的方法封装到一起,要使用时再把方法写出来
2.语法

1
2
3
4
5
6
7
8
9
interface 接口名{
属性
抽象方法
}
class 类名 implements 接口{
自己属性
自己方法
要实现的抽象方法,要@Override
}

3.接口属性只能final,访问: 接口名.属性名
4.一个类可有多个接口
5.接口不能继承其他类,但可继承多个接口
33.内部类
1.定义:一个类内部又完整嵌套另一个类,可直接访问外部类私有属性
2.语法
1
2
3
4
5
class Outer{
ckass Inner{

}
}

3.匿名内部类无类名
4.访问外部类成员: 外部类名.this.成员
5.外部类访问内部类需先创建对象
6.不可用修饰符,可final,本质局部变量
7.匿名类
1.语法
1
2
3
new 类/接口(参数列表){
类体
};

2.注意
仅可使用一次;外部其他类不能访问;外部类与匿名类重名且匿名类访问时,遵循就近原则,访问外部类同上
8.静态内部类
可访问外部类所有静态成员,包含私有,无法访问非静态成员;可以任意添加访问修饰符;作用整个类;同上有就近原则
34.枚举
1.实现:自定义类/使用enum关键字
2.注意
通常只读;使用final+static;可有多个属性
3.enum
使用关键字 enum 替代 class;直接使用 常量名(实参列表);有多个常量,使用逗号隔开;将定义的常量对象写在前面;使用无参构造器创建常量对象可省略括号
当我们使用 enum 关键字开发一个枚举类时,默认会继承 Enum 类, 而且是一个 final 类;如果使用无参构造器 创建 枚举对象,则实参列表和小括号都可以省略;传统的 public static final Season2 SPRING = new Season2(“春天”, “温暖”); 简化成 SPRING(“春天”, “温暖”), 这里必须知道,它调用的是哪个构造器;有多个枚举对象时,使用,间隔,最后有一个分号结尾;枚举对象必须放在枚举类的行首
可使用Enum类相关方法
接口: enum 类名 implements 接口 1,接口 2{}
35.注解
不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息
在 JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在 JavaEE 中注解占据了更重要的角色,例如用来配置应用程序的任何切面
基本注解(Annotation)
@Override: 限定某个方法,是重写父类方法, 该注解只能用于方法
@Deprecated: 用于表示某个程序元素(类, 方法等)已过时
@SuppressWarnings: 抑制编译器警告
36.常用类
1.包装类
针对8种基本数据类型(boolean->Boolean char->Character byte->Byte short->Short int->Integer long->Long float->Float double->Double)
2.包装类与基本数据类型转换
1.jdk5前手动,形式: 装箱:基本类型->包装类型
2.自动装箱底层调用valueOf方法,如Integer.valueOf()
3.Integer类常用方法
Integer.MIN_VALUE 返回最小值
Integer.MAX_VALUE 返回最大值
4.Character类常用方法
Character.isDigit() 判断是不是数字
Character.isLetter() 判断字母
Character.isUpperCase() 判断大写
Character.isLowerCase() 判断小写
Character.isWhitespace() 判断空格
Character.toUpperCase() 转换大写
Character.toLowerCase() 转换小写
5.String类
1.保存字符串/一组字符序列
2.字符串常量对象用双引号包括
3.用Unicode编码,1字符占2字节
4.常用构造:
new String();
new String(String original);
new String(char[] a);
new String(char[] a,int startIndex,int count);

5.final 不可继承
6.有属性 private final char value[] 用于存放字符串内容 字符串不可变,一旦对象被分配,其内容不可变
7.实现接口 Serializable(String可串行化,可网络传输) Comparable(String对象可比较大小)
8.创建方式
1.直接赋值
如:String s = “hsp”;
先从常量值查看是否有”hsp”数据空间,有则直接指向;没有则重新创建再指向;s最终指向常量池的空间地址
2.调用构造器
如:String s = new String(“hsp”);
先在堆中创建空间,内维护value属性,指向常量池hsp空间;若没有hsp,重新创建;有,则直接通过value指向
9.常用方法
equals() 区分大小写判断内容是否相等
equalslgnoreCase() 忽略大小写,同上
length() 字符串长度
indexOf() 获取字符在字符串中第1次出现的索引,从0开始,没有则返回-1
lastIndexOf() 最后1次出现的索引,余同上
substring() 截取指定范围的子串
trim() 去前后空格
charAt() 获取某索引处空格,不能用Str[index]形式
replace() 替换字符串中字符
split() 分割字符串,某些需转义
compareTo() 比较字符串大小
toCharArray() 转换为字符数组
format() 格式字符串
6.StringBuffer类
1.很多方法同String,但其可变长度,是个容器
2.直接父类 是 AbstractStringBuilde
3.实现了 Serializable, 即 StringBuffer 的对象可以串行化
4.在父类中 AbstractStringBuilder 有属性 char[] value,不是 final
5.final类
6.保存字符串变量,可更改,更新不用更改地址,效率较高
7.互换
1.String->StringBuffer
1
2
3
4
5
6
      String str = "111";
StringBuffer stringBuffer = new StringBuffer(str);//法一,返回的才是 StringBuffer 对象,对 str 本身没有影响

StringBuffer stringBuffer1 = new StringBuffer();
stringBuffer1 = stringBuffer1.append(str);//法二
2.StringBuffer->String

StringBuffer stringBuffer3 = new StringBuffer(“111”);
String s = stringBuffer3.toString();//法一
String s1 = new String(stringBuffer3);//法二
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
        8.常用方法
append() 增
delete() 删
replace() 改
insert() 插入
indexOf() 同前
length() 同前
7.StringBuilder类:简易的StringBuffer类替换
8.Math类
常用方法
abs() 绝对值
pow() 求幂
ceil() 向上取整,返回>=该参数的最小整数(转成 double
floor() 向下取整,返回<=该参数的最大整数(转成 double
round() 四舍五入
sqrt() 开方
random() 随机数
min() 最小
max() 最大
9.Array
常用方法
toString() 返回字符串形式
sort() 排序(自然和定制)
binary() 二分法搜索,但需先排序
copyOf() 复制元素
fill() 元素填充
equals() 比较数组内容是否一致
asList() 将一组值转换为list
10.System类
常用方法
exit() 退出当前程序
arraycopy() 复制数组元素
currentTimeMillens() 返回时间:距离1970-1-1毫秒数
gc() 垃圾回收机制
11.BigInterger和BigDecimal
1.区别
BigInterger 适合保存较大整型
BigDecimal 适合保存精度更高的浮点型
2.常用方法
add() 加
subtract() 减
multiply() 乘
divide() 除
在对 BigInteger 进行加减乘除的时候,需要使用对应的方法
12.日期类
1.第一代
精确到毫秒
SimpleDateFormat对象 格式和解析日期的类
Date d1 = new Date(); //获取当前系统时间
Date d2 = new Date(1111); //通过指定毫秒数得到时间
可以把一个格式化的 String 转成对应的 Date;得到 Date 仍然在输出时,还是按照国外的形式,如果希望指定格式输出,需要转换;在把 String -> Date,使用的 sdf 格式需要和你给的 String 的格式一样,否则会抛出转换异常
2.第二代
主要为Calendar类
Calendar 是一个抽象类,并且构造器是 private;可以通过 getInstance() 来获取实例;没有提供对应的格式化的类;如果需要按照24小时进制来获取时间, Calendar.HOUR ==改成=> Calendar.HOUR_OF_DA;返回月时候,是按照 0 开始编号
3.第三代
使用 now() 返回表示当前日期时间的 对象
使用 DateTimeFormatter 对象来进行格式化
提供 plus 和 minus 方法可以对当前时间进行加或者减
4.DateTimeFormatter 格式日期类:类似SimpleDateFormat
5.Instant 时间戳
静态方法 now() 获取表示当前时间戳的对象
通过 from 可以把 Instant 转成 Date
通过 date 的 toInstant() 可以把 date 转成 Instant 对象
6.其他日期类...
37.集合
1.Collection 接口和常用方法
add() 添加单个元素
remove() 删除指定元素
size() 查找元素是否存在
contains() 获取元素个数
isEmpty() 判断是否为空
clear() 清空
addAll() 添加多个元素
containsAll() 查找多个元素是否存在
removeAll() 删除多个元素
2.Iterator(迭代器)
主要用于遍历Collection集合中的元素,不存放对象
所有实现Collection接口的集合类都有一个Iterator()方法,用以返回一个实现Iterator接口的对象
使用例:
{% asset_img diedaiqi.png %}
3.List接口
是Collection子接口
1. List 集合类中元素有序(即添加顺序和取出顺序一致)、且可重复
2. List 集合中的每个元素都有其对应的顺序索引,即支持索引;索引是从 0 开始
3.常用方法
add() 在指定位置插入元素
addAll() 从指定位置开始添加所有元素
get() 获取指定位置元素
indexOf() 返回在集合初次出现的位置
lastIndexOf() 返回在当前集合中末次出现的位置
remove() 移除指定位置的元素,并返回此元素
set(int index, Object ele) 设置指定 index 位置的元素为 ele , 相当于是替换
4.ArrayList
1.基本等同于Vector
2.由数组实现存储
...
5.Vector
1.是个对象数组
2.Vector 和 ArrayList 的比较
{% asset_img vector.png %}
6.LinkedList
{% asset_img linklist.png %}
7.Set接口
1.Collection子接口
2.set 接口的实现类的对象(Set 接口对象), 不能存放重复的元素, 可以添加一个 null
3. set 接口对象存放数据是无序(即添加的顺序和取出的顺序不一致)
8.Set 接口实现类-HashSet
{% asset_img hashmap.png %}
9.Set 接口实现类-LinkedHashSet
{% asset_img linkset1.png %}
10.Map
1. Map 与 Collection 并列存在。用于保存具有映射关系的数据:Key-Value(双列元素)
2. Map 中的 key 和 value 可以是任何引用类型的数据,会封装到 HashMap$Node 对象中
3. Map 中的 key 不允许重复,原因和 HashSet 一样,前面分析过源码.
4. Map 中的 value 可以重复
5. Map 的 key 可以为 null, value 也可以为 null ,注意 keynull,只能有一个,value 为 null ,可以多个
6. 常用 String 类作为 Map 的 key
7. key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到对应的 value
8.常用方法
put() 添加k-v
remove() 根据键删除映射关系
get() 根据键获取值
size() 获取元素个数
isEmpty() 判断个数是否为 0
clear() 清除 key-value
containsKey() 查找键是否存在
9.接口实现
HasMmap
{% asset_img hashmap1.png %}
HashTable
{% asset_img hashtable.png %}
Properties
{% asset_img properties.png %}
10.小结
{% asset_img littletotal.png %}
38.线程
1.创建线程两种方式:1.继承Thread类,重写run方法 2.实现Runnable接口,重写run方法
2.start0() 是本地方法,是 JVM 调用,底层是 c/c++实现,真正实现多线程的效果, 是 start0(), 而不是 run
3.当 main 线程启动一个子线程 Thread-0,主线程不会阻塞,会继续执行,这时,主线程和子线程是交替执行
4.Thread类
1.当一个类继承了 Thread 类, 该类就可以当做线程使用
2.我们会重写 run 方法,写上自己的业务代码
3.run Thread 类 实现了 Runnable 接口的run方法
5.Runnable接口:本质与上无区别,更适合多线程共享一个资源,避免单继承限制
6.线程终止
{% asset_img xianchengzhongzhi.png %}
7.常用方法
{% asset_img xianchengchangyongfangfa1.png %}
{% asset_img xianchengchangyongfangfa2.png %}
8.用户线程&守护线程
{% asset_img userxiancheng.png %}
没有进行设置即使main线程执行完毕守护线程也不退出
9.线程的生命周期
{% asset_img xianchengalive.png %}
10.线程状态转换
{% asset_img xianchengalive2.png %}
11.线程的同步
1.同步机制
在多线程编程中,一些敏感数据不允许被多个线程同时访问,此时可使用同步访问技术,保证数据在任何统一时刻最多只有一个线程访问,即当有一个线程对内存进行操作时,其他线程都不能对这个内存地址进行操作,直到该线程完成操作,以此保证数据完整性
2.具体方法
{% asset_img tongbu1.png %}
12.互斥锁
39.

## 小项目:坦克大战
### 先画个圆

package com.hspedu.draw;

import javax.swing.;
import java.awt.
;

public class DrawCircle extends JFrame{
private MyPanel mp = null;
public static void main(String[] args){
new DrawCircle();
}
public DrawCircle(){
mp = new MyPanel();
//初始化面板
this.add(mp);
//放入窗口
this.setSize(400,300);
//设置大小
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//点叉结束程序
this.setVisible(true);
//可显示
}
}
//定义一个面板,类似画板
class MyPanel extends JPanel{
@Override
public void paint(Graphics g){//绘图方法,自动调用 3种情况:repaint 窗口最小后最大 窗口大小变化(组件第一次显示)
super.paint(g);//调用父类完成初始化
g.drawOval(10,10,100,100);
}
}