1、数据类型、命名法
8种基本数据类型
4种整数类型(byte、short、int、long);
2种浮点类型(float、double);
1种字符类型char
1种布尔类型boolean
++自增
++a先自增1再参与代码执行
a++先参与代码执行后自增1
int b=9;
System.out.println(b++);
System.out.println(b);
//输出结果:
9
10
比较运算
大于>、等于=、小于<、小于等于<=、大于等于>=、不等于!=
赋值运算
等于、加(减乘除)等于、取余等于
浮点型强制转换为整形,舍弃小数部分,只保留整数部分
什么是跨平台
平台一般指的是,操作系统。跨平台就是一次编写开发,可以在任何操作系统运行。
Java的jdk、jre以及jvm
jdk :Java开发工具包,提供Java开发和编译(javac)、执行等相关支持
jre :Java运行环境,提供Java程序运行的支持(提供jar包)
jvm :虚拟机,运行编译之后的字节码文件
基本语法规范
- 严格大小写
- 类名首字母大写,遵循驼峰命名法,如UserInfo
- 方法名首字母小写,方法名遵循驼峰命名法,如userInfo
- 源文件名必须和类名相同,后缀是Java,编译文件后缀是class
命名法
- 驼峰命名法:若干个单词组成,每个首字母大写,如UserName
- 下划线命名法: 单词小写,每个单词之间同下划线链接,如user_name
- 匈牙利命名法:首字母用变量的数据类型缩写,后面遵循驼峰命名法 如:String UserName
基本数据类型的取值范围
- byte [-27,27-1]
- short [-215,215-1]
- int [-231,231-1]
- long [-263,263-1]
- float 32bit
- double 64bit
- char 16bit
- boolean 表示1位的信息 1bit
2、数据类型简单了解、运算符
2.1、数据类型
package zlx;
public class text {
public static void main(String[] args) {
//基本数据类型
//1.byte字节 比特bit 1bit = 1二进制位
//占用内存空间 1byte = 8bit
//byte的取值范围是[-128,127] 也就是[-2^7,2^7-1]
//默认值为0
/*
2short
占用内存空间 1short = 16bit
取值范围[-2^15,2^15-1 ]
默认值0
*/
/*3 int
* 占用空间 1int = 32bit
* 取值范围[-2^31,2^31-1]
* 默认值为0
*
* !!!int类型是一个数字的默认数据类型
* 没有声明的整数都是int类型
*
* */
System.out.println(12);
/*
* 4 long
* 占用空间 1long = 64bit
* 取值范围[-2^63,2^63-1]
* 默认值0L
* 小写L不好区分所以用大写
* */
long a3 = 123;
long a4 = 123456L;//小写L不好区分所以用大写
//浮点型
/*
* 5 float单精度浮点数
* float = 32bit
* 精度可以理解为,表示数值的精确程度
* 默认值0.0f
*/
float f = 3.154652F;
float f1 = 3.154652F;
/*
* 6 double
* double = 64bit
* 默认值0.0d
*
* */
double d = 3.2;
double d1 = 3.2;
/*
* 7 char字符型
* char类型是一个单一的16位 Unicode字符
* char = 16bit
*
* 最小值 '\u0000' 0
* 最大值'\uFFFF' 65535
* char类型可以存储任何单一字符
* 1)char类型的值必须用英文单引号括起来
* 2)char类型的值只能是单个字符
*/
char a = '菜';
/*
* 8 boolean 类型
* 数据表示1位的信息
* boolean = bit 两家公司对于boolean类型占位数不一样
* 只有true跟false两个取值
* 默认值位false
*
* */
boolean b;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
/*
* 根据精度由低到高排序为
* byte->short,char->int->long->float->double
* 1.自动数据类型转换:根据上有顺序,低精度转为高精度,可以自动转换为高精度的变量
*
* 2.强制类型转换
*
* 高精度转换为低精度时,必须使用强制类型转换,但是会发生溢出或者损失精度
*
*
*数据转换规则,不能对Boolean类型进行类型转换
*高精度转换为低精度时,必须使用强制类型转换,但是会发生溢出或者损失精度
*浮点数转整数是直接舍弃小数部分,而不是四舍五入
* */
double d = 3.14d;
int i = (int)d;
System.out.println(i);
}
2.2、运算符
1.算术运算符:
+ - * / % ++ –
加 减 乘 除 取余 自增 自减
自增:++在变量后,变量先参与代码的执行,后自增
++在变量前,变量先自增,后参与代码的执行
2.逻辑运算符
&& || !
与 或 非
短路与运算,当【与&&】运算符左边的表达式为false时,根据运算规则已经可以判断出整个表达式的结果,不会继续判断右边的表达式。
短路或运算,当【或||】运算符左边的表达式为true时,根据运算规则 已经可以判断出整个表达式的结果,不会继续判断右边的表达式
非运算 表达式的布尔值取反
3.比较运算符
运算结果为布尔值
4.赋值运算符:
= += -= *= /= %=
5.位运算符
1) 二进制的转换
2)原码 反码 补码
1.正数的原码=反码=补码
2.负数反码=原码按位取反
补码=反码+1
3)在计算机世界里。所有的数据都是以补码的形式存在于计算机中的(都是以补码运算)
4)
& 按位与 如果都是1 返回1 否则返回0
} 按位或 如果都是0返回0 否则返回1
^ 异或 对应位相同返回0 否则返回1
~ 非运算 按位取反运算符,二进制的补码按位取反(包括符号位)0->1,1->0
int a = 2;
2 = 0010
取反符号位取反
0 0010
1 1101 补码
1 1100 反码
1 0011 原码
-3
System.out.println(~a);
<< 左移运算符
>>>无符号右移
位运算符的优势:
运算速度更快
应用场景:加密
三元运算符
int a = 0;
boolean t =false;
三元运算符 也叫选择表达式
a = t ? 2 :3;
t成立,2给a,反过来 不成立 3给a
3、选择分支与循环
3.1、选择分支
1、if分支
boolean t = true;
if (t) {
System.out.println("ttt!true");
}else {
System.out.println("ttt!false");
}
//当判断条件可能出现的情况大于两种时,用if else if
if (1 == 1) {
}else if (2 == 2) {
}
//当判断条件只有一种情况需要特殊处理,直接if
if (t) {
System.out.println("!!!!");
}
2、switch分支
int a = 5;
switch (a) {
case 1:
System.out.println("a==1");
break;
case 2:
System.out.println("a==2");
break;
default:
System.out.println("上边都没有");
break;
}
3.2、循环
1、while循环
while(condition){
}
condition 判断是否执行的条件
boolean t = true;
int count = 0;
while (t) {
count++;
if (count == 10) {
t =false;
}
}
2、do while循环
do{} while{condition} 循环结构里的代码,至少执行一次
boolean t = false;
int count = 0;
do {
count++;System.out.println(count);
} while (t);
3、for循环
for(index;condition;i++){
//循环语句
}
第一次循环: index - condition - 循环语句 - step
第二次循环:condition - 循环语句 - step
index:循环的初始值,只在第一次循环的时候完成变量初始化以及赋值
step:每次循环,初始值的增长量,在每次循环结构中的代码执行完毕后执行
3、break和continue
break 跳出循环,循环终止
continue 结束当前循环,进入下次循环,本次循环continue后的代码不再执行
死循环:
for(;😉 {
System.out.println(1);
}
4、嵌套循环
public class Test {
public static void main(String[] args) {
//嵌套循环,至多嵌套不超过3层
for (int i = 0; i < 5; i++) {//父循环,外层循环
System.out.println("---------"+i+"---------");
for (int j = 0; j < 3; j++) {//子循环,内层循环
System.out.println("j");
}
}
}
}
//输出结果
---------0---------
j
j
j
---------1---------
j
j
j
---------2---------
j
j
j
---------3---------
j
j
j
---------4---------
j
j
j
5、嵌套循环中在子循环中跳出父循环
fa:for(int i = 0 ;i < 5; i++){//外层循环取名fa
System.out.println("-----------"+i+"------------");
for(int j = 0; j < 5 ; j++){
if(j == 3) break fa;//满足条件终止此循环以及外层循环
}
}
4、数组
//1.声明一个数组
//数组的长度,指的是数组中可以存储的元素个数
int[] array = new int[5];
int[] array2 = {1,2,4,5,9,7};//声明一个int类型的数组,同时初始化数组的元素
//其他语言的写法,也不会报错
int array3[] = new int[4];
//2.数组的赋值
array[0] = 6;
//3.查看指定位置的值
int a = array[2];
//4.查看数组长度.length方法
int t = array.length;
//5.遍历数组
for (int i : array) {
System.out.println(i);
}
5、String - 字符串常量
1、用法
- .equals()比较两个字符串是否相等(String s = null)s.equals会报错!!
- instanceof 判断前者是否为后面类型
- .length 返回字符串的长度
- .trim()消除开头和结尾的空格
- .replace() 替换字符串 (旧字符串,新字符串)
- .concat() 拼接字符串
- 大小写转换:
- 全大写 toUpperCase
- 全小写 toLowerCase
- .split()字符串切分
- .contains判断字符串是否包含指定字符
- .substring截取字符串
- 从指定下标到结束 只给出开始下标
- 从指定下标到指定下标,但不包括最后一个(左闭右开)
- .indexOf 根据字符获取下标
- .charAt 根据下标获取字符
- .isEmpty 判断是否为空 为null时报错
- .toCharArray 转换为字符数组
- String.valueOf变量转为String类型
// String s1 = null;
// String s2 = new String("asd");
// String s3 = " a d s g ";
// String s4 = "A d S g";
// 1、 equals() 比较两个值是否相等
// s2.equals(s1);
// 2、判断一个变量(或对象) 是否是后面的数据类型
// System.out.println(s1 instanceof String);
// 3、返回字符串的长度
// System.out.println(s2.length());
// 4、trim() 去除字符串两端的空格
// System.out.println(s3.trim());
// 5、replace 替换字符串
// System.out.println(s3.replace(" ", "!"));
// 6、拼接字符串 concat
// System.out.println(s3.concat("444"));
// 7、字符串大小写转换
// 全转小写
// System.out.println(s4.toLowerCase());
// 全转大写
// System.out.println(s4.toUpperCase());
// 8、字符串切分
// String s5 = "aabbccdd";
// String[] arr = s5.split("");
// System.out.println(Arrays.toString(arr));
// 9、 判断字符串中是否包含指定字符
// System.out.println(s4.contains("d"));
// 10、 截取字符串
// String s6 = "123456";
// 从指定下标截取到结束
// System.out.println(s6.substring(1));
// 从开始下标截取到结束下标,但不包括结束下标
// System.out.println(s6.substring(1, 4));
// 11、根据下标获取字符
// System.out.println(s5.indexOf("c"));;
// 12、根据下标获取字符
// System.out.println(s5.charAt(3));
// 13、判断字符串是否为空
// String s13 = "";
// String s13a = null;
// String s13b = "11";
// System.out.println(s13.isEmpty());
// System.out.println(s13a.isEmpty());
// System.out.println(s13b.isEmpty());
// 14、将字符串转换为字符数组
// String s14 = "!@#ASFD";
// char[] arr2 = s14.toCharArray();
// System.out.println(Arrays.toString(arr2));
// 15、将变量转为String类型
// int a = 2;
// String s15 = String.valueOf(a);
// System.out.println(s15);
// System.out.println(s15 instanceof String);
2、相等性原则
1)==比较的是基本数据类型,比较的是 值 是否相等
2)==比较引用类型,比较的是 内存地址 是否相等
3)Object类的equals()比较的是 内存地址 是否相同
4)String类的equals()比较的是 值 是否相同
Object类是Java类的顶级父类,所有类默认继承它
3、String/StringBuffer/StringBuilder的区别
- StringBuffer/Stringbuilder 类的对象能够被多次修改,并且不产生新的对象,即内存地址不变
- 修改String对象的值,内存地址会发生变化
- StringBuffer是线程安全的,StringBuilder是不安全的
- 线程安全会带来额外的开销,所以StringBuilder的执行效率会比StringBuffer高
// 1、声明一个StringBuffer变量
// StringBuffer sb = new StringBuffer("aaa");
//hashCode() 返回一个hash值,在一定程度上这个hash可以表示内存地址
// System.out.println(sb.hashCode());
//2.拼接字符串
// sb.append("bbb");
// System.out.println(sb.hashCode());
//3.reverse方法,将字符串反转输出
// System.out.println(sb.reverse());
//4.删除字符串中指定下标范围的字符
// System.out.println(sb.delete(3, 6));
//5.在指定下标位置插入指定字符
// System.out.println(sb.insert(1, "!!!"));
//6.替换指定索引区间的字符串
// System.out.println(sb.replace(1, 3, "!@#$%^&"));
//7.长度
// System.out.println(sb.length());
//8.容量长度,StringBuffer对象最多可以存储的字符个数,超过该数量自动扩容
// System.out.println(sb.capacity());
/*
容量长度:capacity()
默认为16,在声名StringBuffer时给出初始值。那就是n+16
在addend超出容量后,自动扩容
左移一位+2。
6、构造方法与方法的重载
6.1、构造方法的作用:
用于类在创建对象的时候,完成类对象相关的初始化操作
6.2、构造方法特点:
- 构造方法的方法名必须与类名一致
- 构造方法没有返回值
- 如果一个类没有显示的声明一个构造方法,则Java虚拟机会默认给他添加一个无参的构造方法
//1.成员变量
String name;
int age;
//3.构造方法
/*
作用:
用于类在创建对象的时候,完成类对象相关的初始化操作
构造方法特点:
1构造方法的方法名必须与类名一致
2构造方法没有返回值
3如果一个类没有显示的声明一个构造方法,则Java虚拟机会默认给他添加一个无参的构造方法
4用于完成创建对象后的初始化操作
*/
public test2() {}
public test2(String name1,int age1) {//()里面的部分称为参数列表,也叫形参(形式参数)
this.age = age;
this.name = name;
}
//2.方法
public void speak() {
}
public static void main(String[] args) {
test2 t = new test2();
t.age = 15;
test2 t2 = new test2("张三",52);
}
6.3、访问权限修饰符
访问权限修饰符
- private (私有的) 本类
- 默认的 本类,同包
- pretected(受保护的) 本类 同包 不同包子类
- public (公共的) 本类 同包 不同包子类 不同包的其他类
缺省值 == 默认值
鲁棒性 == 健壮性
返回值
void 无返回值关键字
有返回值,需要在方法签名中声明要返回的数据类型
6.4、重载
重写重载的区别
| 重写 | 重载 | |
|---|---|---|
| 发生位置 | 子父类中 | 同一类中 |
| 改变的位置 | 访问控制修饰符不同,方法体不同 | 参数列表不同、方法体不同 |
| 不变的位置 | 方法名、参数列表、返回值类型都不同 | 方法名不变 |
方法的载重
判断载重的一句:重载的是方法的参数列表
特点:
- 放在同一个类中
- 方法名相同
- 参数列表不同(个数,类型,顺序)注意:参数列表不同跟变量名没关系
- 返回值的类型是否改变,跟方法是否重载没关系,不能作为重载的依据
7、面向对象三要素
- 封装
- 继承
- 多态
1.封装
定义:成员变量私有化,提供公共的set和get方法
public class Test2 {
private String name;
private int age;
//给变量赋值set
public void setName(String name) {
//This关键字表示的是调用该方法的当前对象
this.name = name;
}
//get获取变量的值
public String getName() {
return name;
}
}
class T3{
public static void main(String[] args) {
test2 t = new test2();
t.setName("小明");
System.out.println(t.getName());
}
}
同文档中只能有一个类是public的
快速生成set和get方法
类文件空白位置,点击鼠标右键——source——Generate Getters and Setters
2.继承
定义:子类可以不需要声明,直接调用父类的资源(成员变量与方法)
继承的特点:
- 所有类都有父类,即所有类都派生于Object类
- 只能单亲继承,即每一个子类只能有一个父类
- 子类只能继承父类的非私有方法和变量
- 子类不能继承父类的私有属性
- 如果子类中共有的方法影响到了父亲私有属性,那么私有属性是能够被子类使用的(即通过父类的公有方法访问到父类的私有变量)
- 子类可以直接使用继承的变量和方法,不需要再在子类中声明或写出
重写
- 重写发生在子父类中
- 重写的方法名相同,参数列表相同
- 重写的方法体不同
- 子类重写的方法,权限不能缩小
3.多态
没有继承就没有多态,生成的对象,在调用父类方法时,如果方法被子类重写,则调用的是子类重写的方法。
代码当中体现多态性,其实就是一句话:父类引用指向子类对象
格式:父类 对象名 = new 子类();
再Java中,有两种形式可以实现多态:继承和接口
方法的重载实现的是编译时的多态性(也成为前绑定),而方法的重写实现的是运行时的多态性(也成为后绑定)。
super关键字
表示当前类的父类对象,可以使用super关键字对父类变量和方法的访问
子类方法中无论写不写super(),Java都默认使用super()调用父类的构造方法
特点:
- 用在子类构造方法中
- 无论写不写super(),Java都会默认使用super()调用父类的构造方法
- 只能通过super()调用父类的构造方法一次
- 通过super()调用父类的构造方法,必须放在子类构造方法的第一行
public class Father {
protected String name;
public void test() {
System.out.println("父类方法");
}
}
/*
*面向对象 类为单位
*面向过程 方法为单位
* */
/*
* 重写的特点
* 重写发生在子父类中
* 重写的方法名相同,参数列表相同
* 重写的方法体不同
* 子类重写的方法,权限不能缩小
* */
public class Son extends Father{
@Override
public void test() {
// TODO Auto-generated method stub
System.out.println("子类方法");
}
public static void main(String[] args) {
Father son = new Son();
son.test();
}
}
JVM类加载的顺序(static)
静态代码块>new>代码块>构造方法
public class Son extends Father{
static {
System.out.println("静态代码块");
}
{
System.out.println("代码块");
}
public Son() {
System.out.println("构造方法");
}
public static void main(String[] args) {
new Son();
}
}
特点
- static生命的资源只能被初始化一次
- 修饰变量称为静态变量,局部变量不能被static修饰,因为static有全局的意思
- 修饰方法,称为静态方法,静态方法只能调用其他静态资源,不能调用非静态变量,不能被this和super,因为静态资源的加载先于实例化
- static修饰的变量或者方法独立于任何类,他不依赖类的特定对象,该类被所有对象共享
- 修饰内部类,外部类不需要实例化,可以直接通过外部类名直接调用
面向对象 类为单位
面向过程 方法为单位
final关键字
- 修饰类,类不能被继承
- 修饰方法,方法不能被重写
- 修饰变量,称为常量,常量的值不能被修改;常量名必须大写,且声明常量的时候就得给常量赋值
- 修饰基本数据类型,变量的值不能被改变
- 修饰引用类型(对象),该对象的引用(内存地址)不能被改变
final int NO = 12;
final String NAME = "abc";
8、抽象类
定义:抽象类不能实例化,它的作用是提供给其它类进行继承
抽象类特点:
- 修饰类,类为抽象类,不能被实例化
- 修饰对象,方法为抽象方法,只有方法的签名,没有方法体
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AIdeB291-1666355976917)(C:\Users\19912\AppData\Local\Temp\1665459012674.png)]
public class GrandFather {
public GrandFather(String name) {
}
}
/*抽象类
* 定义:抽象类不能实例化,它的作用是提供给其它类进行继承
*
* 抽象关键字abstract
* 特点:
* 1 修饰类,类为抽象类,不能被实例化
* 2 修饰对象,方法为抽象方法,只有方法的签名,没有方法体
* */
public abstract class Father extends GrandFather{
public Father(String name) {
super(name);
}
//方法的签名
public abstract void run();
}
public class Son extends Father{
public Son(String name) {
super(name);
// TODO Auto-generated constructor stub
}
@Override
public void run() {
// TODO Auto-generated method stub
}
}
9、接口
Java遵循:
单继承多实现
先继承后实现
接口的特点:
- 接口只有方法的签名和静态常量
- 接口变量默认public final static修饰
- 接口的签名方法,会默认用public abstract修饰
- 接口不能自身实例化,接口的实现类可以实例化
- 子类实现接口,必须重写就扣的所有签名方法
- 接口可以实现多个,而父类只有一个
- 遵循 单继承多实现,先继承后实现
接口的优点:
- 解决Java开发的单继承问题
- 接口可以实现并行开发
- 便于重构
/*
* implements实现接口关键字
*
*继承与实现的规则
* java中遵循
* 单继承多实现
* 先继承后实现
*
* 接口的特点:
*
* */
public class Tom implements IPerson,IPlayer{
@Override
public void speak() {
// TODO Auto-generated method stub
}
@Override
public String fun1() {
// TODO Auto-generated method stub
return null;
}
@Override
public int fun2() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void run() {
// TODO Auto-generated method stub
}
}
9.1、向上转型、向下转型
1、向上转型:子类对象向父类转型
父类类型–>父类引用–>子类对象
- 将一个【父类的引用】指向一个子类对象,称为向上转型,此时自动进行类型转换(即可以理解为创建了一个父类类型的子类对象)
- 通过父类的引用调用的方法是子类重写或继承父类的方法,而不是父类原本的方法,更不是子类特有的方法
- 通过父类的引用无法调用子类特有的方法,即向上转型的子类对象只能调用继承自父类的方法,而不能调用子类独有的方法,方法数量缩小,安全
2、向下转型:父类对象向子类转型
子类类型–>子类引用–>父类对象
父类对象向子类转换需要强制类型转换
- 将一个父类对象赋给一个子类类型的引用称为向下转型
- 只有Object有向下转型的可能
10、常用工具类
10.1、日期类
java.util.Date;日期
java.time.LocalDate;
java.time.LocalDateTime;Java8后的日期
java.lang.Math 数学运算
java.util.Arrays 数组工具类
package d12;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.util.Date;
public class D12 {
public static void main(String[] args) {
//java.time.LocalDateTime Java8后新增的日期类
//获取当前日期时间
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
System.out.println(localDateTime.getYear());//获取年份
System.out.println(localDateTime.getMonthValue());//获取月份
System.out.println(localDateTime.getMonth());//获取月的名字
System.out.println(localDateTime.getDayOfMonth());//或租所在月的第几天
System.out.println(localDateTime.getDayOfWeek());//获取所在周的第几天
System.out.println(localDateTime.getHour());//获取小时
System.out.println(localDateTime.getMinute());//获取分钟
System.out.println(localDateTime.getSecond());//获取秒
//自定义一个日期
LocalDate date2 = LocalDate.of(2014, Month.JULY, 20);
System.out.println(date2);
// //java.util.Date 日期
//
//
// Date date = new Date();//创建一个日期对象
// System.out.println(date);
//
// //java.text.Sim
// //new SimpleDateFormat(日期格式模板) 创建一个日期格式化工具类
// SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
// String dateString = sf.format(date);
// System.out.println(dateString);
// //java.lang.Math 数学运算
// byte a = 2;
// short b = 4;
// //加法
// int h = Math.addExact(a,b);
// System.out.println(h);
//
// //减法
// int j = Math.subtractExact(a, b);
//
// //乘法
// int c = Math.multiplyExact(a, b);
//
// //除法
// int chu = Math.floorDiv(a, b);
//
// System.out.println("----------------------");
//
// //求最大值
// int max = Math.max(12, 3);
// System.out.println(max);
// //最小
// int min = Math.min(2, 3);
// System.out.println(min);
//
// //绝对值
//
// double ab = Math.abs(-3.14);
// //圆周率
// System.out.println(Math.PI);
// //pow(a,b)a的b次方
// double r1 = Math.pow(2, 10);
// System.out.println(r1);
}
}
10.2、包装类
10.2.1、8个基本数据类型分别对应的包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
10.2.2、数组工具类
package d12;
import java.util.Arrays;
public class D12 {
public static void main(String[] args) {
//java.util.Arrays 数组工具类
int[] a = {2,1,3,4,5};
//1.打印数组
System.out.println(Arrays.toString(a));
//2.数组赋值
Arrays.fill(a, 0);//给数组所有元素赋值为0
//fill(数组,开始下标,结束下标,替换值)
//从开始下标(包括开始下标)到结束下标(不包括结束下标)范围内的所有元素都替换为11
// Arrays.fill(a, 1, 3, 11);
//3.数组排序
// Arrays.sort(a);
//4.二分查找 前提:数组排好序
// int index = Arrays.binarySearch(a, 3);
// System.out.println(index);
//5.数组扩容 copyOf(原数组,新数组长度)
int[] b = Arrays.copyOf(a, 12);
System.out.println(Arrays.toString(b));
//6.比较数组中的元素以及顺序是否相同
int[] c = {2,1,3,4,5};
boolean tar = Arrays.equals(a, c);
System.out.println(tar);
}
}
package d12;
import java.util.Arrays;
public class D12 {
public static void main(String[] args) {
int a = 12;
Integer b = a;
Integer b2 = 20;
String str = "110";
//valueOf()将其他类型,转换为整数类型
Integer b3 = Integer.valueOf(str);
//取值范围
int max = Integer.MAX_VALUE;
int min = Integer.MIN_VALUE;
System.out.println();
/*
* valueOf的原理
* Integer会缓存[-128,127]这个范围内的数,当传入的参数在这个范围内时,会直接返回缓存中的数字
* 否则超出这个范围才创建新的Integer对象
* */
//1.比较两个数的大小
int res = Integer.compare(2, 4);//compare(a,b)返回1表示a>b返回-1表示a<b返回0表示a=b
//2.数字转字符串
String s = Integer.toString(res);
}
}
11、集合
Collection接口又有3种子类型,List、Set和Queue,在下面是一些抽象类,最下面具体实现类
Collection的实现类只能存储引用类型,所以对于基本数据类型,Collection的实现类只能存储他们的包装类(位于java.lang包)
1、List
有序,可重复
ArrayList是实现了基于动态数组的数据结构,在未声明长度的情况下,默认长度是10,数据填满会自动扩充原长度的一半
public static void main(String[] args) {
//创建一个List集合
List<String> list = new ArrayList<>();
//添加元素
list.add("AAA");
//指定下标添加元素
list.add(1,"CCC");
//获取元素的值
// System.out.println(list.get(1));
//集合的长度
// System.out.println(list.size());
//遍历集合
for (String s : list) {
System.out.println(s);
}
//List是有序的,允许重复的
list.add("BBB");
list.add("BBB");
}
2、Set
特点:
1.集合中的元素无序,不可重复
public static void main(String[] args) {
//创建一个set集合
Set<Integer> set = new HashSet<Integer>();
//添加元素
set.add(1);
set.add(2);
//获取集合的长度size
//遍历元素
//判断是否存在指定元素
boolean tar = set.contains(1);
//移除元素
set.remove(2);
//清空集合
set.clear();
}
3、Queue
队列:先进先出
栈:后进先出
package d12;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
/*
队列Queue
*/
public class D13 {
public static void main(String[] args) {
//创建一个set集合
Queue<Integer> queue = new LinkedList<Integer>();
//添加元素
queue.add(12);
queue.add(4);
//获取队列长度size()
//1.获取队列头部元素,但不删除,队列为空,引发异常
// int firstEle = queue.element();
//2获取队列头部元素,不删除,队列为空返回null
// Integer fristEle2 = queue.peek();
//3.获取并删除头部元素,队列为空,返回null
// Integer fristEle3 = queue.poll();
// System.out.println(fristEle3);
//
// System.out.println(queue.poll());
//4.在不超过容量长度的情况下,可以立即插入一个元素到队列尾
//当插入元素超出容量长度时(插入失败),add()方法会报异常,而offer()方法会返回布尔值false
queue.offer(7);
//5.遍历队列
Integer ele = null;
while ((ele = queue.poll()) != null) {
System.out.println(ele);
}
}
}
4、vector
允许重复
1.基于动态数组的数据结构
2.是线程同步(线程安全),执行效率慢
3.数据填满时会自动扩容原长度的一倍,因此ArrayList更节省空间
package d12;
import java.util.List;
import java.util.Vector;
/*
Vector
1.基于动态数组的数据结构
2.是线程同步(线程安全),执行效率慢
3.数据填满时会自动扩容原长度的一倍,因此ArrayList更节省空间
*/
public class D13 {
public static void main(String[] args) {
List<Integer> vector = new Vector<Integer>();
//添加
vector.add(1);
vector.add(1);
vector.add(2);
vector.add(3);
//集合长度
System.out.println(vector.size());
//获取指定下标的元素
Integer ele = vector.get(3);
System.out.println(ele);
for (Integer integer : vector) {
System.out.println(integer);
}
}
}
5、Map
特点:
- 存储的是键值对
- k和v只能存储引用类型
- map的key不允许重复,多次给一个key赋值,后面的会把前面的赋值覆盖Map
| Map实现类 | Key | Value |
|---|---|---|
| HashMap | 允许为null | 允许为null |
| TreeMap | 不允许为null | 允许为null |
| ConcurrentMap | 不允许为null | 不允许为null |
| HashTable | 不允许为null | 不允许为null |
package d12;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/*
Map
*/
public class D13 {
public static void main(String[] args) {
//创建一个Map集合,map中存储的元素,k-v键值对
Map<String, Integer> map = new HashMap<String, Integer>();
//添加元素
map.put("name", 12);//k-v键值对 key键,value值
//获取值,根据键名
Integer v = map.get("name");
System.out.println(v);
map.put("name", 24);//map中的键名是唯一的,多次对同一个键赋值,后面的值会覆盖前面的值
System.out.println(map.get("name"));
//集合长度
int len = map.size();
//获取集合中所有键的Set集合
Set<String> kSet = map.keySet();
for (String k : kSet) {
System.out.println(map.get(k));
}
//清空
// map.clear();
//是否包含指定键
boolean hasK = map.containsKey("name");
//是否包含指定值
boolean hasV = map.containsValue(24);
System.out.println(hasV);
//获取所有键值对的Set集合
Set<Entry<String, Integer>> eSet = map.entrySet();
for (Entry<String, Integer> entry : eSet) {
System.out.println(entry.getKey()+entry.getValue());
}
//判断是否为空集合
boolean t = map.isEmpty();
//根据键删除键值对
// System.out.println(map);
// map.remove("name");
// System.out.println(map);
//替换
map.replace("name", 100);
System.out.println(map);
}
}
HashMap的实现原理
- HashMap底层原理是数组加链表的结构,在java8后又增加了红黑树
- 当添加一个元素key-value时,首先计算键值对的Key的hash值,以此来确定插入到数组的位置
- 如果根据Hash值确定的数组位置已经存在元素,就添加到同一个Hash值的元素的后面,于是形成了链表
- 当链表长度大于8,并且数组中元素k-v键值对个数超过64时,链表就转成红黑树,这样就提高了查找的速率
- 当红黑树中的节点数个数小于6时,红黑树又重新转换为链表
12、枚举
特点:
-
应enum关键字定义枚举类
-
枚举类默认继承java.util.Enum类
-
枚举类的构造方法只能使用private修饰符,如果构造方法省略修饰符,则默认使用private
-
枚举类的所有对象(实例)必须在枚举中显式列出,否则这个枚举类将永远不能创建实例对象
-
枚举类的所有对象,系统会自动添加public static final修饰符
final的作用是内存地址不变,枚举类中对象的常量可以用get/set方法修改
package d14;
/*
枚举
特点:
1.应enum关键字定义枚举类
2.枚举类默认继承java.util.Enum类
3.枚举类的构造方法只能使用private修饰符,如果构造方法省略修饰符,则默认使用private
4.枚举类的所有对象(实例)必须在枚举中显式列出,否则这个枚举类将永远不能创建实例对象
5.枚举类的所有对象,系统会自动添加public static final修饰符
final的作用是内存地址不变,枚举类中对象的常量可以用get/set方法修改
作用/使用场景:
存储固定不变的账户、IP地址、密钥等信息
不经常换的,但是需要与第三方对接
*/
public enum User {
//定义对象
u1(),u2("张三","abc123",100.00);
private String name;
private String pass;
private double money;
private User() {
}
private User(String name, String pass, double money) {
this.name = name;
this.pass = pass;
this.money = money;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
13、单例模式
设计模式:软件开发规范
单例模式 一个类,有且只能有一个对象
单例模式的写法:
- 枚举
- 懒汉式
- 饿汉式
懒汉式例子
public static Person p;
private Person(){
}
public static Person getInstance(){
if (p == null) {
p = new Person();
}
return p;
}
饿汉式例子
//饿汉式:在类初始化时,已经自行实例化(在程序执行之前,先完成实例化,在程序执行过程中直接返回创建好的实例化对象)
private static final Person P = new Person();
private Person() {
}
public static Person geInstance() {
return P;
}
14、异常
package d14;
//执行顺序ctr/catch>finally>return
public class TestExpe {
public static void main(String[] args) {
}
public static int showException() {
try {//可能出现的异常用try包括
int[] a = new int[5];
System.out.println(a[4]);
return 1;
} catch (Exception e) {捕获异常
//打印异常信息
e.printStackTrace();
System.out.println("出现异常");
return 2;
}finally {
//无论出不出现异常,这里边的代码都会执行
//如果try中有return返回值,则先执行完finally中的代码,在返回数据
System.out.println("666666666");
}
}
}
15、多线程
多线程示例:
一家公司账户有100元,这天两个会计同时操作了公司的银行账户,会计A取50,会计B存100,可能会发生以下几种情况:
- 账户余额变成50(A和B同时读到了账户余额等于100,A最后更改了账户)
- 账户余额变成200(A和B同时读到了账户余额等于100,B最后更改了账户)
- 账户余额变成150 (A和B顺序读取到账户余额)
1、进程
- 是执行中的应用程序
- 一个进程可以包含一个或多个线程
- 一个进程至少要包含一个线程(比如Java中运行main方法的主线程)
比如:B站看视频的同时,还可以点赞收藏等等,这些操作都是Bilibili这个应用程序的子任务,也就是这个进程的子任务
2、线程
- 线程本身依靠进程(程序)运行
- 线程是程序中的顺序控制流,只能使用分配给程序(进程)的资源和环境
解释:运行一个Java程序的实质是启动一个Java虚拟机进程,也就是说一个运行的Java程序就是一个Java虚拟机进程。
线程是进程中可独立执行的最小执行单元,一个进程中有多个进程,同一线程中的线程共享该进程的资源(内存、空间、变量、方法)
2.1、单线程
程序中只存在一个主线程,实际上主方法(main)就是一个主线程
线程是进程中所要完成的一个计算过程,也被称为进程的任务
2.2、多线程
多线程是在一个进程中同时运行多个任务
多线程的目的:更好的使用cpu资源,提高程序的计算效率
2.3、串行、并行、并发
2.3.1 串行:一个人做一件件做所有任务
2.3.2 并发:一个人,交替的做多个任务
即一个人先执行一个任务,在这个任务执行期间,有一段时间人是空闲的,他利用这段时间再去执行另一个任务,这样交替执行任务。
示例:蒸馒头的同时,馒头没熟之前,这段时间可以拖地、洗衣服等等
2.3.3 并行:多个人,同时做多个任务;总耗时取决于耗时最长的任务
3、创建线程的方式
- 继承Thread类,extends Thread
- 实现Runable接口,implement Runable
- 通过Collection接口和FutureTask对象创建线程
- 通过线程创建对象
创建线程
//方法1
package d17thread;
public class Demo {
public static void main(String[] args) {
CrThr c = new CrThr();
c.start();
}
}
class CrThr extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("创建线程");
}
}
//方法2
package d17thread;
public class Demo {
public static void main(String[] args) {
CrThr c = new CrThr();
Thread t = new Thread(c);
t.start();
}
}
class CrThr implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("创建线程");
}
}
package d17thread;
/*创建线程类的方式
* 1.继承Thread类,extends Thread
* 2.实现runable接口,implements Runable
* 3.通过Callable接和FutureTask对象创建线程
* 4.通过创建线程池创建对象
*/
public class Test {
public static void main(String[] args) {
//创建线程对象
Worker w = new Worker();
w.setName("tt1");
//启动线程类
w.start();
/*
* 调用start()方法不是立即调用run()
* 而是先去争用cpu时间片,一旦获取cpu时间片,才会去调用run()方法
*/
Worker2 w2 = new Worker2();
Thread t = new Thread(w2,"t1");
t.start();
}
}
class Worker extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
/*
* sleep()属于Thread类,wait()类属于Object类
* sleep()方法表示线程休眠指定的时间,休眠时间结束,线程继续执行
* wait()方法表示线程等待,此时线程会让出cpu资源,知道其他线程通过nodify()/nodifyAll()方法唤醒该线程
*
*/
try {
sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("线程开始执行");
}
}
class Worker2 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
System.out.println("重写Runable接口");
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FT8AyC0a-1666355976928)(C:\Users\19912\AppData\Local\Temp\1665997650707.png)]
3.1、线程的一生
新建、就绪、运行、阻塞、死亡
-
新建:创建线程对象后,即进入阻塞状态
-
就绪:当调用线程对象的start()方法,线程进入就绪状态,处于就绪状态的线程,只是说明该线程已经做好了准备,随时等待cpu调度执行,并不是说执行了start()方法线程就会立即执行
-
运行:当cpu开始调度处于就绪状态的线程时,此时线程才开始执行(执行run()方法),即进入运行状态,注意,就绪状态是进入到运行状态的唯一入口,也就是说,线程想要进入运行状态执行,首先必须处于就绪状态种
-
阻塞:处于运行状态中的线程由于某种原因,暂时放弃对cpu的使用权,停止执行,此时进入阻塞状态,直到其重新进入到就绪状态
根据阻塞产生的原因不同,阻塞状态又分为三种
- 等待阻塞:运行状态中的线程执行Object.wait()方法
- 同步阻塞:线程在获取synchronized内部锁失败(因为所被其他线程占用)
- 其他阻塞:通过调用线程的Thread.sleeo()、join()方法或发出I/O请求时,线程会进入到阻塞状态,当sleep()状态超时(sleep休眠结束)、join()方法等待线程终止或超时,或者I/O处理完毕时,线程重新进入就绪状态
-
死亡:线程执行完毕或者因为异常推出了run()方法,该线程结束生命周期,线程销毁
4、线程的同步机制
同步机制:多个线程按照一定顺序执行的方案
4.1 同步锁 synchronized
- Java 中的任何一个对象,都有唯一一个与之相关联的锁
- 这种锁被称为监听器(monitor)或内部锁(Intrinsic Lock)
- 内部锁是一种排它锁,即哪个线程拿到锁,该线程才能电泳同步方法,其他线程阻塞状态
- 内部锁是通过synchronized关键字实现的
- synchronized关键字可以用来修饰方法以及代码块
package d17thread;
public class Th1 {
/*
* 同步机制:多个线程按照一定顺序执行的方案
*
* 同步锁 synchronized
*
* Java 中的任何一个对象,都有唯一一个与之相关联的锁
* 这种锁被称为监听器(monitor)或内部锁(Intrinsic Lock)
* 内部锁是一种排它锁,即哪个线程拿到锁,该线程才能电泳同步方法,其他线程阻塞状态
* 内部锁是通过synchronized关键字实现的
* synchronized关键字可以用来修饰方法以及代码块
*/
public static void main(String[] args) {
Thre t = new Thre();
t.start();
Thre t1 = new Thre();
t1.start();
}
static int count;
static synchronized void add() {
for (int i = 0; i < 80000; i++) {
count++;
System.out.println(count);
}
}
}
class Thre extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
Th1.add();
}
}
package d17thread;
public class Th1 {
/*
* 同步机制:多个线程按照一定顺序执行的方案
*
* 同步锁 synchronized
*
* Java 中的任何一个对象,都有唯一一个与之相关联的锁
* 这种锁被称为监听器(monitor)或内部锁(Intrinsic Lock)
* 内部锁是一种排它锁,即哪个线程拿到锁,该线程才能电泳同步方法,其他线程阻塞状态
* 内部锁是通过synchronized关键字实现的
* synchronized关键字可以用来修饰方法以及代码块
*/
public static void main(String[] args) {
Thre t = new Thre();
t.start();
Thre t1 = new Thre();
t1.start();
}
static int count;
static synchronized void add() {
for (int i = 0; i < 80000; i++) {
count++;
System.out.println(count);
}
}
}
class Thre extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
Th1.add();
}
}
16 、I/O流
1、定义
数据在两个设备之间的传输称为流,流是一组有顺序的
2、使用
2.1、字节
字节输入流
- 新建File类对象
- 创建字节输入流
- 返回接下来从此输入流读取的字节数
- 循环输出
字节输出流
- 新建File类对象
- 输入要输出的内容
- 创建字节输出流
- 写入内容的字节组到输出流
2.2、字符
字符输入流
- 新建File类对象
- 创建字节输入流文件
- 对字节输入流进行编码
- 创建字符流对象
- 关闭所有资源
字符输出流
- 新建File类对象
- 创建字节输出流文件
- 设置编码并返回字符输出流
- 创建字符输出流
3、File类常用方法
package d1018IO;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
public class FileDemo {
public static void main(String[] args) {
File file = new File("C:\\Users\\19912\\Desktop\\不准删除.txt");
//1 判断文件是否存在
boolean has = file.exists();
//2判断是否是一个文件
// System.out.println(file.isFile());
//3判断是否是一个文件夹(目录)
// System.out.println(file.isDirectory());
//4获取当前目录下的所有文件
// String[] s = file.list();
// System.out.println(Arrays.toString(s));
//5获取当前目录下的所有文件对象
// File[] files = file.listFiles();
// System.out.println(Arrays.toString(files));
//6删除文件或者文件夹
// boolean tar = file.delete();
//7当文件存在时删除文件或者文件夹
// file.deleteOnExit();
//8创建文件夹
// boolean b = file.mkdir();
// System.out.println(b);
//9创建一个新文件
// try {
// file.createNewFile();
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//10判断文件是否可读
System.out.println(file.canRead());
//11判断文件是否可写
System.out.println(file.canWrite());
}
}
复制大文件
package d1018IO;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class BigFile {
public static void main(String[] args) throws IOException {
InputStream in = new FileInputStream(new File("C:\\Users\\19912\\Desktop\\新建文本文档.txt"));
OutputStream out = new FileOutputStream(new File("C:\\Users\\19912\\Desktop\\文本文档.txt"));
//获取字节输入流的长度
int size = in.available();
System.out.println(size);
for (int i = 0; i < size; i++) {
out.write(in.read());
}
//效率提高1024倍
// byte[] bt = new byte[1024];
// int len = in.read(bt);//每次读指定数组长度的字节数,并将读到的字节传入大数组中返回读到的字节长度
// while(len != -1) {
// out.write(bt);//将字节数组中的字节写入到输出流中
// len = in.read(bt);
// }
out.close();
in.close();
}
}
17、序列化与反序列化
序列化的两种主要用途:
- 把对象的字节序列永久的保存到硬盘上,通常存放在同一个文件中
- 在网络上传送对象的字节序列
包serizlizable
1、序列化id的作用
序列化ID起着关键的作用,Java的序列化机制是通过在运行时判断类的seriaVersionUID来验证版本一致性的
反序列化时,JVM会把传进来的字节流中的seriaVersionUID与本地实体类中的seriaVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常
2、序列化
将 对象 转换成特定格式的字节文件叫做序列化
//序列化
File file = new File("C:\\Users\\19912\\Desktop\\User.ser");
OutputStream out;
try {
out = new FileOutputStream(file);
ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(u);
objOut.flush();
objOut.close();
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
3、反序列化
将特定的字节文件转换为对象叫做反序列化
//反序列化
try {
File file2 = new File("C:\\\\Users\\\\19912\\\\Desktop\\\\User.ser");
InputStream in = new FileInputStream(file2);
ObjectInputStream objIn = new ObjectInputStream(in);
User user = (User) objIn.readObject();
objIn.close();
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
18、计网
1、计算机网络五层模型-网络层次划分
- 应用
- 网络
- 传输
- 数据链路
- 物理层
2、TCP三次握手
seq: 我发送了x个数据过去
ack:返回并告诉我收到了x+1之前的数据
SYN:请求同步 SYN=1 ACK确认标志确认是否有效,一般置为1 成功后返回SYN=1,ACK=1,ack=x+1,seq=y
第一次握手(请求建立连接),客户端发送连接请求报文
第二次握手(回答),服务器接收连接请求后回复ACK确认报文,并为此次连接分配资源
第三次握手(建立连接),客户端接收到ACK报文后也给服务端发送ACK报文,并分配资源,发送完毕后,客户端、服务端进入TCP连接成功状态完成三次握手
3、TCP四次挥手
第一次握手(请求结束连接),客户端发送FIN = 1,发送seq = x
第二次握手(第一次回答),回答已收到请求,等待回答 ACK=1,ack= x+1,seq = y
第三次握手(第二次回答),回答可以结束连接,FIN=1,ACK=1,seq =z,ack = x+1
第四次握手(回答收到)ACK= 1,ack = z+1,seq = z+1
-
Client端发起中断连接请求,也就是发送FIN报文;
-
Serer端接收到FIN报文后,先发送ACK报文,确认接收到了Client端的请求,然后进入准备状态,此时Server端如果还有没发送完的数据,可以继续发送;
-
Client端接收到Server端的ACK报文,进入FIN_WAIT状态,继续等待Server端的FIN报文;
-
当Server端确定数据已发送完成,则向Client端发送FIN报文;
-
Client端接收到FIN报文后,再次发送ACK报文,然后进入TIME_WAIT状态,如果Server端没有接收到ACK报文可以重传;
-
Server端收到ACK后,断开连接,Client端等待2MSL后依然没有收到回复,则证明Server端已正常关闭,Client端也可以关闭连接了。TCP连接就这样关闭了。
19、Socket编程
客户端
package d20;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
//客户端
public class ClientNode {
public static void main(String[] args) {
int serverPort = 8081;//服务端端口号
String serverIp = "127.0.0.1";//服务端IP地址
try {
//1首先直接创建socket,端口号1~1023为系统保存,一般设在1023之外
Socket socket = new Socket(serverIp, serverPort);
InputStreamReader reader = new InputStreamReader(System.in);
//2创建 获取键盘输入内容的 字符输入流
BufferedReader systemIn = new BufferedReader(reader);
//3创建 字符输出流,向服务端输出内容
PrintWriter socketOut = new PrintWriter(socket.getOutputStream());
//4创建字符输入流 接收客户端输入的内容
BufferedReader socketIn = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(true){
//输入流获取键盘输入内容
String readline = systemIn.readLine();
//输出流向服务端发送数据
socketOut.println(readline);
socketOut.flush();
//读取服务端返回的数据
String serverStr = socketIn.readLine();
System.out.println("服务端:" + serverStr);
if(readline.equals("bye")) {
break;
}
}
//关闭资源
systemIn.close();
socketIn.close();
socketOut.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服务端
package d20;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
//服务端
public class ServerNode {
public static void main(String[] args) {
int port = 8081;
try {
//1 创建ServerSocket,监听端口8081
ServerSocket serverSocket = new ServerSocket(port);
//2 调用服务器的accept方法,接受来自客户端的连接请求。
//在接收到客户端连接请求之前,此方法会进行阻塞(程序会在这等待),
//当有申请连接时会建立连接并返回一个socket
Socket socket = serverSocket.accept();
InputStreamReader reader = new InputStreamReader(socket.getInputStream());
//4 创建客户端输入流:获取客户端传输的数据
BufferedReader socketIn = new BufferedReader(reader);
BufferedReader systemIn = new BufferedReader(new InputStreamReader(System.in));
//5 创建输出流:用于向客户端返回数据
PrintWriter socketOut = new PrintWriter(socket.getOutputStream());
while (true) {
//读取客户端输入内容
String clientStr = socketIn.readLine();
System.out.println("客户端:" + clientStr);
if (clientStr.equals("bye")) {
//服务端 向 客户端 输出内容
socketOut.println(systemIn.readLine());
socketOut.flush();
break;
}
//服务端 向 客户端 输出内容
socketOut.println(systemIn.readLine());
socketOut.flush();
}
systemIn.close();
socketIn.close();
socketOut.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
20、反射
反射reflect定义:
- Java的反射(reflection)机制是指在程序的运行状态中
- 可以创建任意一个类的对象
- 可以了解任意一个对象所属的类
- 可以了解任意一个类的成员变量和方法
- 可以调用任意一个对象的变量和方法
- 这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制
- 反射被视为动态语言的关键
package d1020反射;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/*
* 反射reflect
* 定义:
* Java的反射(reflection)机制是指在程序的运行状态中
* 可以创建任意一个类的对象
* 可以了解任意一个对象所属的类
* 可以了解任意一个类的成员变量和方法
* 可以调用任意一个对象的变量和方法
* 这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制
* 反射被视为动态语言的关键
*
* 1 Class
*
* 2 Field
*
* 3 Method
*/
public class Shop {
public static void main(String[] args) {
//Class类表示的是一个类的.class文件
Class c = Man.class;
try {
//1创建该类的对象
Man m = (Man) c.newInstance();
//2获取类中的指定变量(包括私有变量)
Field f = c.getDeclaredField("name");
System.out.println(f.getName());
//3获取类中的指定变量(不包括私有变量)
c.getField("name");
//4获取类中所有变量,返回Field类型的数组
Field[] fs = c.getDeclaredFields();
for (Field field : fs) {
//f.getType()获取变量的数据类型
System.out.println(f.getType());
}
//5 根据指定方法名和制定的参数列表数据类型,获得方法对象
//getMethod(String name,Class...,parametersType)
//name:方法名
//parametersType:参数列表的数据类型
Method mt = c.getMethod("speak", null);
Method mt2 = c.getDeclaredMethod("speak", String.class,int.class);
//6获取类的构造方法对象
Constructor c1 = c.getConstructor(null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
1、Class是什么
Java在将.class文件载入时,JVM将产生一个java.lang.Class对象代表该.class的字节码文件,从该Class对象中可以获得类的许多基本信息,这就是反射机制。
2、创建一个类对象有几种方式
- 通过new关键字创建对象
- 通过反射的Class类的newInstance方法创建对象
3、创建Class类对象的方法
- 通过类名调用.class
- 通过对象调用getClass()方法
- 给指定对象的该变量赋值
4、Field对象的机制与实现
- Java.lang.reflect.Field类是记录对象属性的类
- 可以操作类中私有、以及公有等全部属性和属性的信息
4.1、Field对象的常用方法
package d1020反射;
import java.lang.reflect.Field;
public class Demo {
public static void main(String[] args) {
//创建Class类对象的方法
//1 通过类名调用.class
Class cl = Man.class;
Man mi = new Man();
mi.name = "zzz";
try {
Field fi = cl.getDeclaredField("name");
//1获取变量的数据类型
System.out.println(fi.getType());
//2取得obj对象中的这个属性的值
String str = (String) fi.get(mi);
System.out.println(str);
//3给指定对象的该变量赋值
fi.set(mi, "lll");
Field fi2 = cl.getDeclaredField("age");
fi2.setAccessible(true);//开启私有变量的访问权限
fi2.set(mi, 12);
System.out.println(mi.getAge());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// //2 通过对象调用getClass()方法
// Man ma = new Man();
// Class cl2 = ma.getClass();
//
// //3根据完整包路径,获取Class对象
// try {
// Class cl3 = Class.forName("d1020反射.Man");
// } catch (ClassNotFoundException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// //创建一个类对象有几种方式
// //1 通过new关键字创建对象
// //2 通过反射的Class类的newInstance方法创建对象
}
}
21、正则表达式
1 、简介
正则表达式用于处理字符串,它通过约束字符的排列规则,可以:
- 验证字符串是否匹配正则规则;
- 检索符合规则的字符串;
完整的正则表达式包括:
- 特殊字符(或“元字符”)
- 文字(或“普通文本字符”)
2、元字符
2.1、
| 字符 | 关键词 | 解释 |
|---|---|---|
| \d | 数字字符 | 匹配一个数字字符,等价于[0,9] |
| \D | 匹配一个非数字字符 | |
| \n | 换行符 | 匹配一个换行符 |
| \r | 回车符 | 匹配一个回车符 |
| \s | 空白字符 | 匹配任何空格字符,包括空格、制表符、换页符等,等价于[\f\n\r\t\v] |
| \S | 匹配任何非空白字符 | |
| \w | 单词字符 | 匹配一个单词字符(包括下划线字符),等价于[A-Za-z0-9] |
| \W | 匹配任何非单词字符 |
2.2、
| . | 匹配任意一个字符 |
|---|---|
| \ | (反斜杠)转义字符,将特殊字符转义成普通字符 |
2.3、
| () | 标记一个子表达式,一个子表达式可以匹配一段字符串 |
|---|---|
| | | 意为’或’,|两边的子表达式称为多选分支 |
形如(子表达式a|子表达式b)这样的结构称为“多选结构”,|两边的子表达式称为“多选分支”。
2.4、限制符
| ? | 匹配前面的子表达式或字符0或1次 | 至多1次 |
|---|---|---|
| ***** | 匹配至少0次 | [0,n] |
| + | 匹配至少1次 | [1,n] |
| {min,max} | 匹配至少min次,至多max次 | [min-max] |
| {n} | 匹配n次 | |
| {n,} | 至少匹配n次 |
注意:***** 和 + 限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个**?**就可以实现非贪婪或最小匹配。
贪婪匹配:贪婪模式会尽可能多的匹配
**非贪婪匹配:**非贪婪模式会尽可能少的匹配
当**?*紧跟在任何一个其他限制符、+、?、{n}、{n,}、{n,m}后面时,匹配模式都是非贪婪的。
2.5、
| ^ | 匹配文本的开始位置,^称为脱字符 |
|---|---|
| $ | 匹配文本的结束位置 |
3、字符组
字符组用**[]表示,一个字符组匹配一个字符的位置**,且该位置可以匹配字符组中的任一个字符。
3.1 连字符
字符组元字符 -(连字符),表示一个范围,注意如果用在字符组开头,如[-]或[^-],则只代表是一个 - 字符,不表示范围
3.2 排除字符
排除型字符组:[^…] 匹配 除字符组内所有字符 之外的 任何字符
注意:在字符组内部,元字符的定义规则(及他们的意义)是不一样的。例如,在字符组外部,点号是元字符,但是在内部则不是如此。相反,连字符只有在字符组内部才是元字符,否则就不是。
Pattern 类:
pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。
Matcher 类:
Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
//1 正则校验
//写一个正则表达式,匹配手机号
String str = "31415";
String regx = "\\d\\d+";
boolean tar = Pattern.matches(regx, str);
System.out.println(tar);
//2 正则检索
String ip = "192.168.1.141";
//
String r2 = "\\d{2,}?";
//编译指定的正则表达式
Pattern p2 = Pattern.compile(r2);
//将传入的字符串匹配指定的正则表达式
Matcher m = p2.matcher(ip);
while(m.find()) {//向下查找一次,是否存在匹配的字符串,返回布尔值
System.out.println(m.group());//打印匹配到的字符串
}
22、Java内存模型
1、 Java内存模型JMM (Java Memory Model)
Java虚拟机(JVM)在执行Java程序的过程中,会把它管理的内存划分为几个不同的数据区域(也就是运行时的数据区域),这些区域都有各自的用途、创建时间、销毁时间。
2、 Java虚拟机运行时数据区(JVM Runtime Data Area)
在Java虚拟机规范(JVMS)中定义了多种程序运行时会用到的存储不同类型数据的内存区域,统称为“Java虚拟机运行时数据区”,有的数据区是全局共享的(static),有的是线程私有的(局部变量)。
全局共享:随着JVM启动而创建,随着JVM退出而销毁
线程私有:随着线程开始而创建,随着线程结束而销毁
2.1 运行时数据区划分
-
程序计数器 (program counter register)
-
Java虚拟机栈 (VM stack)
-
本地方法栈 (native method stack)
-
堆 (heap)
-
方法区 (method area)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WLFK1HAh-1666355976933)(file:///C:\Users\19912\AppData\Local\Temp\ksohtml20800\wps1.jpg)]
jdk1.8之前的JMM模型图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fSV7dgAz-1666355976933)(file:///C:\Users\19912\AppData\Local\Temp\ksohtml20800\wps2.png)]
JDK1.8以后的JMM模型图
2.2 程序计数器(Program Counter Register)
-
一块较小的内存空间,他的作用可以看做是:当前线程所执行的字节码的行号指示器
-
如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法(JDK自带的方法),这个计数器值为空。
-
此内存区域是唯一一个在JVM规范中没有规定任何OutOfMemoryError(内存溢出)情况的区域
2.3 虚拟机栈(VM Stack)
-
线程私有
-
后进先出(LIFO)栈 last in first out
-
存储栈帧,支撑Java方法的调用,执行和退出
-
可能出现OutOfMemeoryError异常和StackOverFlowError异常
OutOfMemeoryError(内存溢出):当jvm栈被设计成可动态扩展,在动态扩展时无法申请到足够的内存
StackOverFlowError(栈溢出):线程请求的栈深度大于jvm允许的最大深度
2.4 本地方法栈(Native Method Stack)
在HotSpot中本地方法栈与VM Stack合并
本地方法栈与Java虚拟机栈基本相同,区别在于:
-
Java虚拟机栈为JVM执行字节码所服务
-
本地方法栈为JVM执行Native方法所服务,支撑Native方法的调用,执行和退出
2.5 方法区: static final
方法区存放了要加载的类的信息Class(名称、修饰符等)、类中的静态常量、类中定义为final类型的常量、类中的Field信息、类中的方法信息Method,当在程序中通过Class类的方法来获取对象信息时,这些数据都来源于方法区。方法区是被Java线程所共享的,不像Java堆中其他部分一样会频繁被GC回收,它存储的信息相对比较稳定,在一定条件下会被GC,当方法区要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。方法区也是堆中的一部分,就是我们通常所说的Java堆中的永久区 Permanet Generation,大小可以通过参数来设置,可以通过-XX:PermSize指定初始值方法区包含所有的class和static变量、final变量,-XX:MaxPermSize指定最大值。
· 又叫静态区,跟堆一样,被所有的线程共享。
· 方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。(两者区别为堆区存放new出来的对象信息,方法区存放类信息)
2.6 堆heap
堆是JVM所管理的内存中最大的一块,是被所有Java线程共享的,不是线程安全的,在JVM启动时创建。堆是存储Java对象的地方,这一点Java虚拟机规范中描述是:所有的对象实例以及数组(即所有的引用类型)都要在堆上分配。Java堆是GC管理的主要区域,从内存回收的角度来看,由于现在GC基本都采用分代收集算法,所以Java堆还可以细分为:新生代和老年代;新生代再细致一点有Eden空间、From Survivor空间、To Survivor空间等。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Btq9m7pc-1666355976934)(file:///C:\Users\19912\AppData\Local\Temp\ksohtml20800\wps3.jpg)]私有内存区——伴随线程的产生而产生,一旦线程终止,私有内存区也会自动消除

1246

被折叠的 条评论
为什么被折叠?



