JAVA基础


文章目录

  • JAVA基础
  • 变量
  • 整形(INT)
  • 浮点型(float/double)
  • 字符型(char)
  • 布尔类型(boolean)
  • 基础数据类型的转换
  • 自动类型转换
  • 强制类型转换
  • 重载
  • 可变参数
  • 基本概念
  • 基本语法
  • 注意事项和使用细节
  • 属性
  • 作用域
  • 注意事项和细节使用
  • javap的使用
  • 构造方法(构造器)
  • 基本概念
  • 注意事项和使用细节
  • 对象创建流程分析
  • this
  • 什么是this
  • this的注意害项和使用细节
  • 包的三大作用
  • 包的本质分析(原理)
  • 包的命名
  • 常用的包
  • 注意事项和使用细节
  • 访问修饰符
  • 基本介绍
  • 使用的注意事项
  • 封装
  • 封装介绍
  • 封装的理解和好处
  • 封装的实现步骤
  • 继承
  • 继承基本介绍和示意图
  • 继承的基本语法
  • 继承给编程带来的便利
  • 继承的深入讨论/细节问题
  • 继承的本质分析
  • super关键字
  • 基本介绍
  • super给编程带来的便利/细节
  • super和this的区别
  • 方法重写/覆盖
  • 基本介绍
  • 注意事项和使用细节
  • 多态
  • 基本介绍
  • 多态的具体实现
  • 多态注意事项和细节讨论
  • 多态的向上转型
  • 多态的向下转型
  • 属性没有重写之说
  • instanceOf
  • java动态绑定机制*
  • 多态应用
  • 多态数组
  • 多态参数
  • Objcet
  • ==运算符
  • equals方法
  • hashcode
  • toString方法
  • finalize方法
  • 断点调试(debug)
  • 一个实际需求
  • 断点调试介绍
  • 断点调试的快捷键
  • java中段
  • 类变量(静态变量)
  • 什么是类变量
  • 如何定义类变量
  • 如何访问类变量
  • 类变量使用注意事项和细节讨论
  • 类方法(静态方法)
  • 类方法基本介绍
  • 类方法的调用:
  • 类方法经典的使用场景
  • 类方法使用注意事项和细节讨论
  • mian方法
  • 深入理解main方法
  • 特别提醒
  • 代码块/static代码块
  • 基本介绍
  • 基本语法
  • 理解
  • 代码块使用注意事项和细节讨论
  • 设计模式
  • 什么是设计模式
  • 什么是单例模式
  • 饿汉式
  • 懒汉式
  • 饿汉式VS懒汉式
  • 小结
  • final关键字
  • 基本介绍
  • final使用注意事项和细节讨论
  • 抽象类
  • 抽象类的介绍
  • 抽象类使用的注意事项和细节讨论
  • 模板模式
  • 接口
  • 基本介绍
  • 小结
  • 注意事项和绍节
  • 接口vs继承
  • 接口和继承解决的问题不同
  • 接口比继承更加灵活
  • 接口在一定程度上实现代码解耦
  • 接口的多态特性
  • 四种内部类
  • 基本语法
  • 内部类的分类
  • 局部内部类的使用
  • 匿名内部类的使用(重要!!!)
  • 匿名内部类的最佳实践
  • 成员内部类
  • 静态内部类
  • 小结
  • 枚举
  • 基本内容
  • 枚举的两种实现方式
  • 自定义类实现枚举
  • 使用enum关键字实现枚举
  • enum关键字实现枚举注意事项
  • 枚举的常用方法
  • enum的注意试想和细节讨论
  • 注解(Annotation)
  • 三个基本的Annotation
  • @Override
  • @Deprecated
  • @SuppressWarnings
  • 元注解--JDK的Annotation(了解)
  • 元注解的基本介绍
  • 元注解的种类
  • @Retention
  • @Target
  • @Documented
  • @lnherited注解
  • 异常
  • 基本概念
  • 异常体系图(一部分)
  • 小结
  • 五大运行时异常
  • 编译异常
  • 异常处理
  • 基本介绍
  • 异常处理的方式
  • try-catch异常处理
  • try-catch实践
  • throws异常处理
  • 自定义异常
  • throw与throws的区别
  • 常用类
  • 包装类
  • 八种包装类
  • 包装类与基本数据类型的转换
  • 包装类方法
  • String类
  • String类的理解与创建对象
  • 创建String对象的两种方式
  • String的特性
  • String的常用方法
  • String翻转题
  • StringBufer类
  • 基本介绍
  • String Vs StringBuffer
  • StringBuffer构造器
  • StringBuffer转换
  • StringBuffer方法
  • StringBuilder
  • 基本介绍
  • StringBuilder的常用方法
  • String、StringBuffer 和StringBuilder的比较
  • 效率比较测试
  • 选择方式的总结
  • Math类
  • 基本介绍
  • Arrays类
  • Arrays的常用方法
  • 定制排序源码分析
  • 模拟定制排序
  • 其他常见方法
  • System类
  • 常见方法
  • Biglnteger类和BigDecimal类
  • 基本介绍
  • 日期类
  • 第一代日期类Date
  • 第二代日期类Calendar
  • 第三代日期类LocalDateTime


变量

java 隔几秒执行几次后停止_java 隔几秒执行几次后停止

整形(INT)

  1. Java各整数类型有固定的范围和字段长度,不受具体OS[操作系统]的影响,以
    保证java程序的可移植性。
  2. Java的整型常量(具体值)默认为int型,声明long型常量须后加1或L
  3. java程序中变量常声明为int型,除非不足以表示大数,才使用long
  4. bit:计算机中的最小存储单位。byte:计算机中基本存储单元,1byte =8 bit

类型

占用存储空间

byet[字节]

1字节

short[短整型]

2字节

int[整形]

4字节

long[长整型]

8字节

浮点型(float/double)

1.与整数类型类似,Java浮点类型也有固定的范围和字段长度,不受具体OS的影响。

2**.Java的浮点型常量默认为double型**,声明float型常量,须后加‘f或‘F

3.浮点型常量有两种表示形式十进制数形式:如:5.12 512.0f .512(必须有小数点)

4.科学计数法形式:如:5.12e2[5.12*10的2次方] 5.12E-2 [5.12/10的2次方]

5.通常情况下,应该使用double型,因为它比float型更精确。

类型

占用存储空间

单精度float

4字节

双精度double

8字节

double num11 = 2.7;
double num12 = 8.1 / 3;
system.out.println(num12);//接近2.7的一个小数,而不是2.7
//这是因为,我们在double num12 = 8.1中存储时,计算机不知道我们的后面存储的是啥,有可能是8.10000001,自然运算结果就是一个接近2.7的小数
//得到一个重要的使用点:当我们对运算结果是小数的进行相等判断是,要小心
//应该是以两个数的差值的绝对值,在某个精度范围类判断
if(num11 == num12) {
    system.out.println("相等");
}
//正确的写法,
if(Math.abs (num11 - num12)< 6.000001 ) {
    system.out.println("差值非常小,到我的规定精度,认为相等...");
}
//可以通过java API来看
System.out.println(Math.abs ( num11 - num12));
//细节:如果是直接查询得的的小数或者直接赋值,是可以判断相等

字符型(char)

1.字符常量是用单引号(‘’)括起来的单个字符。例如:char c1 = ‘a’; char c2 = ‘中’; char c3 = ‘9’;

2.Java中还允许使用转义字符’‘来将其后的字符转变为特殊字符型常量。例如:char c3 = ‘\n’; //’\n’表示换行符

3.在java中,char的本质是一个整数,在输出时,是unicode码对应的字符

4.可以直接给char赋一个整数,然后输出时,会按照对应的unicode字符输出

5.char类型是可以进行运算的,相当于一个整数,因为它都对应有Unicode码.

字符类型本质探讨
1.字符型存储到计算机中,需要将字符对应的码值(整数)找出来,比如’a’
存储:‘a’ >码值97>二进制(110 0001) >存储
读取:二进制=>97
=> ‘a’=>显示
2.字符和码值的对应关系是通过字符编码表决定的(是规定好)
ASCIl (ASCII编码表一个字节表示,一共128个字符)

Unicode (Unicode编码表固定大小的编码使用两个字节来表示字符,字母和汉字统一都是字节,这样浪费空间)

utf-8(编码表,大小可变的编码字母使用1个字节,汉字使用3个字节)

gbk(可以表示汉字,而且范围广,字母使用1个字节,汉字2个字节)

gb2312(可以表示汉字,gb2312<gbk)

big5码(繁体中文,台湾,香港)

布尔类型(boolean)

1.布尔类型也叫boolean类型,booolean类型数据只允许取值true和false,无null

2.boolean类型占1个字节。

3.boolean类型适于逻辑运算,一般用于程序流程控制

不可以0或非0的整数替代false和true,这点和C语言不同

基础数据类型的转换

自动类型转换

1.有多种类型的数据混合运算时,系统首先自动将所有数据转换成容量最大的那种数据类型,然后再进行计算。

2.当我们把精度(容量)大的数据类型赋值给精度(容量)小的数据类型时,就会报错,反之就会进行自动类型转换。(自动类型换只能小转大)

3.(byte, short)和char之间不会相互自动转换。

4.byte,short, char他们三者可以计算,在计算时首先转换为int类型。

5.boolean不参与转换

6.自动提升原则:表达式结果的类型自动提升为操作数中最大的类型

byte b2 = 1;
byte b3 = 2;
short s1 = 1;
// short s2 = b2 + s1;//错,b2 + s1 => int
int s2 = b2 + s1;//对,b2 + s1 => int
byte b4 = b2 + b3;//错误:b2 + b3 => int
强制类型转换

自动类型转换的逆过程,将容量大的数据类型转换为容量小的数据羑型。使用时要加上强制转换符(),但可能造成精度降低或溢出,格外要注意。

1.当进行数据的大小从大->小,就需要使用到强制转换

2.强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级

3.char类型可以保存int的常量值,但不能保存int的变量值,需要强转

4.byte和short类型在进行运算时,当做int类型处理。

//强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级
//int x = (int)10*3.5+6*1.5;//编译错误:double -> int
int x = (int) (10*3.5+6*1.5);// (int)44.0 ->44
system.out.println(x);//44
char c1 = 100;/ /ok
int m = 100; //ok
// char c2 = m;//错误
char c3 = (char)m;//ok
system.out.println(c3);//100对应的字符,d字符

重载

注意事项和使用细节:

1.方法名:必须相

2.形参列表:必须不同(形参类型或个数或顺序,至少有一样不同,参数名无要求)3)返回类型:无要求

可变参数

基本概念

java允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。

基本语法

访问修饰符返回类型方法名(数据类型…形参名){}

例如:方法 sum【可以计算2个数的和,3个数的和,4,5, 。。】

//1. int...表示接受的是可变参数,类型是int ,即可以接收多个int(0-多)
//2.使用可变参数时,可以当做数组来使用即numS可以当做数组
// 3.逼历nums求和即可
public int sum(int. . . nums) { 
    // System.out.println("接收的参数个数="+ nums.length);int res = 0;
    for(int i = 0; i < nums. length; i++){
        res += nums[i];
    }
    return res;
}

注意事项和使用细节

1.可变参数的实参可以为0个或任意多个。

2.可变参数的实参可以为数组。

3.可变参数的本质就是数组.

4.可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后

5.一个形参列表中只能出现一个可变参数

属性

1.属性的定义语法同变量,示例:访问修饰符属性类型属性名;

有四种访问修饰符public, proctected,默认, private

2.属性的定义类型可以为任意类型,包含基本类型或引用类型

3.属性如果不赋值,有默认值,规则和数组一致。

具体说: int 0, short 0.byte 0, long O, float 0.0,double 0.0,char \u0000, boolean false,String null

作用域

1.在java编程中,主要的变量就是属性(成员变量)和局部变量。

2.我们说的局部变量一般是指在成员方法中定义的变量。【举例Cat类:cry)

3.java中作用域的分类
全局变量:也就是属性,作用域为整个类体
局部变量:也就是除了属性之外的其他变量,作用域为定义它的代码块中

4**.全局变量可以不赋值,直接使用,因为有默认值,局部变量必须赋值后,才能使**
用,因为没有默认值。

注意事项和细节使用

1.属性和局部变量可以重名,访问时遵循就近原则。

2.在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名。

3.属性生命周期较长,伴随着对象的创建而创建,伴随着对象的死亡而死亡。局部变量,生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而死亡。即在一次方法调用过程中。

4、作用域不同

全局变量:可以被本类使用,或其他类使用(通过对象调用)

局部变量:只能在本类中对应的方法中使用

5.修饰符不同

全局变量/属性可以加修饰符

局部变量不可以加修饰符

javap的使用

  1. javap是JDK提供的一个命令行工具,javap能对给定的class文件提供的字节代码进行反编译
  2. 通过它,可以对照源代码和字节码,从而了解很多编译器内部的工作,对更深入地理解如何提高程序执行的效率等问题有极大的帮助。
  3. 使用格式
    javap 常用: javap -c -v 类名
    其中, 可能的选项包括:
    -help --help -? 输出此用法消息
    -version 版本信息
    -v -verbose 输出附加信息
    -l 输出行号和本地变量表
    -public 仅显示公共类和成员
    -protected 显示受保护的/公共类和成员
    -package 显示程序包/受保护的/公共类和成员 (默认)
    -p -private 显示所有类和成员
    -c 对代码进行反汇编
    -s 输出内部类型签名
    -sysinfo 显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列)
    -constants 显示最终常量
    -classpath 指定查找用户类文件的位置
    -cp 指定查找用户类文件的位置

构造方法(构造器)

基本概念

构造方法是初始化对象,不是创造对象

[修饰符] 方名(形参列表){
方法体;
}

1)构造器的修饰符可以默认,也可以是public protected private

2)构造器没有返回值

3)方法名和类名字必须一样

4)参数列表和成员方法一样的规则

5)构造器的调用系统完成(在创建对象时,系统会自动的调用该类的构造器完成对对象的初始化。

注意事项和使用细节

1.一个类可以定义多个不同的构造器,即构造器重载
比如:我们可以再给Person类定义一个构造器,用来创建对象的时候,只指定人名,不需要指定年龄

2.构造器名和类名要相同

3.构造器没有返回值

4.构造器是完成对象的初始化,并不是创建对象

5.在创建对象时,系统自动的调用该类的构造方法

6.如果程序员没有定义构造器,系统会自动给类生成一个默认无参构造方法(也叫默认构造方法),

比如Dog(){},使用javap指令反编译看看

java 隔几秒执行几次后停止_java 隔几秒执行几次后停止_02

7.一旦定义了自己的构造器,默认的构造器就覆盖了,就不能再使用默认的无参构造器,除非显式的定义一下,即: Dog(){}

对象创建流程分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PRQAWGhk-1636722245107)(http://www.gdx0326.top:20014/static/java笔记.assets/image-20211027203420273.png)]

1.加载Person信息(Person.class),只会加载一次

2.在堆中分配空间(地址)

3.完成对象的初始化

3.1 默认初始化 age = 0 name = null

3.2显示初始化 age = 90 name = null

3.4构造器初始化 age = 20 name = 小倩

4.将对象在堆中的地址。返回给p(p是对象名,也可以理解是对象的引用)

this

什么是this

java虚拟机会给每个对象分配 this,代表当前对象。

使用this解决了变量命名问题

this本质的理解:

java 隔几秒执行几次后停止_后端_03

this的注意害项和使用细节

1.this关键字可以用来访问本类的属性、方法、构造器

2.this用于区分当前类的属性和局部变量

3.访问成员方法的语法:this.方法名(参数列表);

4.访问构造器语法:this(参数列表);注意只能在构造器中使用(即只能在构造器中访问另外一个构造器)

注意:访问构造器语法:this(参数列表);必须放置第一条语句

5.this不能在类定义的外部使用,只能在类定义的方法中使用。

包的三大作用

1.区分相同名字的类

2.当类很多时,可以很好的管理类[例如Java API文档]

3.控制访问范围

包的本质分析(原理)

包的本质:实际上就是创建不同的文件夹来保存类文件

java 隔几秒执行几次后停止_java 隔几秒执行几次后停止_04

包的命名

命名规则:
只能包含数字、字母、下划线、小圆点“.”,但不能用数字开头,不能是关键字或保留字

demo.class.exec1//错误,使用了关键字
demo.12a//错误,数字开头
demo.ab12.oa/正确

命名规范

一般是小写字母+小圆点一般是com.公司名.项目名.业务模块名

比如:com.hspedu.oa.model; com.hspedu.oa.controller;

举例:
com.sina.crm.user/用户模块

com.sina.crm.order//订单模块

com.sina.crm.utils //工具类

常用的包

一个包下,包含很多的类,java中常用的包有:
java.lang.* //lang包是基本包,默认引入,不需要再引入.
java.util.* //util包,系统提供的工具包,工具类,使用 Scanner

java.net.* //网络包,网络开发
java.awt.* //是做java的界面开发,GUI

注意事项和使用细节

1.package的作用是声明当前类所在的包,需要放在class的最上面,一个类中最多只有一句package

2.import指令位置放在package的下面,在类定义前面,可以有多句且没有顺序要求。

访问修饰符

基本介绍

java提供四种访问控制修饰符号控制方法和属性(成员变量)的访问权限(范围):

1.公开级别:用public修饰,对外公开

2.受保护级别:用protected修饰,对子类和同一个包中的类公开

3.默认级别:没有修饰符号,向同一个包的类公开

4.私有级别:用private修饰,只有类本身可以访问,不对外公开

权限大小顺序:public > protected >默认>private

访问级别

访问控制修饰符

同类

同包

子类

不同包

公开

public





受保护

protected




×

默认

没有修饰符号



×

×

私有

private


×

×

×

使用的注意事项

1)修饰符可以用来修饰类中的属性,成员方法以及类

2)只有默认的和public才能修饰类!,并且遵循上述访问权限的特点。

3)因为没有学习继承,因此关于在子类中的访问权限

4)成员方法的访问规则和属性完全一样.

封装

封装介绍

封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作。

封装的理解和好处

1.隐藏实现细节:方法(连接数据库)<–调用(传入参数…)

2.可以对数据进行验证,,保证安全合理

封装的实现步骤

1)将属性进行私有化【不能直接修改属性】

2)提供一个公共的(public)set方法,用于对属性判断并赋值

public void setXxx(类型 参数名){
	//加入数据验证的业务
	逻辑属性=参数名;
}

3)提供一个公共的(public)get方法,用于获取属性的值

public 数据类型 getXxx(){//权限判断
	return xx;
}

继承

继承基本介绍和示意图

继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。

java 隔几秒执行几次后停止_后端_05

继承的基本语法

class 子类 extends 父类{
    
}

1.子类就会自动拥有父类定义的属性和方法

2.父类又叫超类,基类。

3.子类又叫派生类。

继承给编程带来的便利

1.代码的复用性提高了

2.代码的扩展性和维护性提高了

继承的深入讨论/细节问题

1.子类继承了所有的属性和方法,非私有的属性和方法可以直接访问,但是私有属性和方法,不能在子类直接访问,要通过父类提供的公共的方法去访问

2.子类必须调用父类的构造器,完成父类的初始化

3.当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过[举例说明]

4.如果希望指定去调用父类的某个构造器,则显式的调用一下

5.super在使用时,必须放在构造器第一行

6.super()和 this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器

7.java所有类都是Object类的子类, Object是所有类的基类

8.父类构造器的调用不限于直接父类!将一直往上追溯直到Object类(顶级父类)

9.子类最多只能继承一个父类(指直接继承),即java中是单继承机制。

10.不能滥用继承,子类和父类之间必须满足is-a的逻辑关系

继承的本质分析

找属性时,顺序是:

(1)首先看子类是否有该属性

(2)如果子类有这个属性,并且可以访问,则返回信息

(3)如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息…)

(4)如果父类没有就按照(3)的规则,继续找上级父类,直到Object. . .

class GrandPa {//爷类
	string name ="大头爷爷";
    string hobby ="旅游";
}
class Father extends GiandPa {//父类
	string name = "大头爸爸";
	int age = 39;
}
class Son extends Father {//子类
	string name ="大头儿子";
}

java 隔几秒执行几次后停止_开发语言_06

super关键字

基本介绍

super代表父类的引用,用于访问父类的属性、方法、构造器●基本语法

1.访问父类的属性,但不能访问父类的private属

super.属性名;

2.访问父类的方法,不能访问父类的private方法

super.方法名(参数列表);

3.访问父类的构造器(这点前面用过):

super(参数列表);//只能放在构造器的第一句,只能出现一句!

super给编程带来的便利/细节

1.调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化)

2.当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、直接访问是一样的效果!

3.super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A->B->C,当然也需要遵守访问权限的相关规则

找类的方法时,顺序是:
(1)先找本类,如果有,则调用

(2)如果没有,则找父类(如果有,并可以调用,则调用

(3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到0bject类

提示:

如果查找方法的过程中,找到了,但是不能访问,则报错
如果查找方法的过程中,没有找到,则提示方法不存在

super和this的区别

No.

区别点

this

super

1

访问属性

访问本类中的属性,如果本类没有此属性则从父类开始查找属性

从父类中继续查找

2

调用方法

访问本类中的方法,如果本类没有此方法则从父类继续查找

从父类中继续查找

3

调用构造器

调用本类构造器,必须放在构造器的首行

调用父类构造器,必须放在子类构造器的首行

4

特殊

表示当前对象

子类中访问父类对象

方法重写/覆盖

基本介绍

简单的说:方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的那个方法

注意事项和使用细节

方法重写也叫方法覆盖,需要满足下面的条件

1.子类的方法的参数,方法名称,要和父类方法的参数,方法名称完全一样。

2.子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类
比如父类返回类型是Object ,子类方法返回类型是String

3.子类方法不能缩小父类方法的访问权限

多态

基本介绍

多[多种]态[状态]

方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

多态的具体实现

1.方法的多态

2.对象的多态

(1)一个对象的编译类型和运行类型可以不一致

(2)编译类型在定义对象时,就确定了,不能改变

(3)运行类型是可以变化的.

(4)编译类型看定义时 = 号的左边,运行类型看 = 号的右边

多态注意事项和细节讨论

多态的前提是:两个对象(类)存在继承关系

多态的向上转型

1.本质:父类的引用指向了子类的对象

2.语法:父类类型 引用名 = new 子类类型();

3)特点:编译类型看左边,运行类型看右边。

可以调用父类中的所有成员(需遵守访问权限),不能调用子类中特有成员;最终运行效果看子类的具体实现!

多态的向下转型

1)语法:子类类型 引用名 = (子类类型) 父类引用;

2)只能强转父类的引用,不能强转父类的对象

3)要求父类的引用必须指向的是当前目标类型的对象

class Animal{
    
}
class Cat extends Animal{
    
}
Animal animal = new Cat();
Cat c = (Cat) animal//必须要有Animal animal = new Cat();才能这样写,否则运行时报错:类异常(类构造)错误

4)当向下转型后,可以调用子类类型中所有的成员

属性没有重写之说

属性没有重写之说!属性的值看编译类型

public static void main(String[] args) {
    System.out.println(base.count);// ? 看编译类型10 
    Sub sub = new Sub();
    System.out.println(sub.count);//? 20
}
class Base { //父类
    int count = 10;//属性
}
class Sub extends Base {//子类
    int count = 20;//属性
}
instanceOf

instanceOf 比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的子类型

java动态绑定机制*

1.当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定

2.当调用对象属性时,没有动态绑定机制,哪里声明,那里使用

A a = new B();//向上转型
System.out.println(a.sum());//40-->30(注释1后)
System.out.println(a.sum1());//30-->20(注释2后)

class A{//父类
    public int i= 10;
    
    public int sum() {
        return getI()+ 10;//运行时会动态绑定,从而运行a.getI()
    }
    
    public int sum1(){
        return i+ 10;
    }
    
    public int getl() {
        return i;
    }
}
class B extends A{//子类
    public int i = 20;

//注释1
//	public int sum() {
//        return i+ 20;
//    }
    
	public int getI(){
        return i;//属性时,没有动态绑定机制,哪里声明,那里使用
    }
    
//注释2    
//  public int sum1(){
//  	return i + 10;
//  }
}

多态应用

多态数组

数组的定义类型为父类类型,里面保存的实际元素类型为子类类型

public static void main(String[] args) {
        
    Person[] persons = new Person[5];
    persons[0] = new Person( "jack",20);
    persons[1] = new Student("mary",18,100);
    persons[2] = new Student( "smith",19,30.1);
    persons[3] = new Teacher( "scott",30,20000);
    persons[4] = new Teacher( "king",50,25000);
    
    
    //循环遍历多态数组,调用say
	for (int i =0; i < persons.length; i++) {
        //person[i]编译类型是 Person ,运行类型是是根据实际情况有JVM来判断
        System.out.println(persons[i].say();//动态绑定机制
		if(persons[i] instanceof Student){//判断person[i]的运行类型是不是Student
            Student student = (Student)persons[i];//向下转型
			student.study();
			//也可以使用一条语句((Student) persons[i]).study();
		}else if(persons[i] instanceof Teacher) {
			Teacher teacher = (Teacher)persons[i];
			teacher.teach();
        }
    }
}

多态参数

方法定义的形参类型为父类类型,实参类型允许为子类类型

public static void main(String[] args){
    public void showEmpAnnual(Employee e) {
        System.out.println(e.getAnnual());//动态绑定机制。
    }
    //添加一个方法,testWork ,如果是普通员工,则调用work方法,如果是经理,则调用manage方法
    public void testWork(Employee e) {
        if(e instanceof Worker) {
            ((Worker) e).work();//有向下转型操作
        }else if(e instanceof Manager){
            ((Hanager) e).manage();//有向下转型操作
        }
    }
}

Objcet

==运算符

1.==:既可以判断基本类型,又可以判断引用类型

2.==:如果判断基本类型,判断的是值是否相等。示例:int i=10; double d=10.0;

3.==:如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象

equals方法

4.equals:是Object类中的方法,只能判断引用类型,如何看Jdk源码。

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String aString = (String)anObject;
            if (!COMPACT_STRINGS || this.coder == aString.coder) {
                return StringLatin1.equals(value, aString.value);
            }
        }
        return false;
    }

@HotSpotIntrinsicCandidate
    public static boolean equals(byte[] value, byte[] other) {
        if (value.length == other.length) {
            for (int i = 0; i < value.length; i++) {
                if (value[i] != other[i]) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

5.默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如
Integer,String

hashcode

1)提高具有哈希结构的容器的效率!

2)两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!

3)两个引用,如果指向的是不同对象,则哈希值是不一样的

4)哈希值主要根据地址号来的!,不能完全将哈希值等价于地址。

5)案例演示:

public static void main(String[] args) {
    A aa = new A(); 
    A aa2 = new A(); 
    A aa3 = aa;
    System.out.println("aa.hashCode()=" + aa.hashCode());
    System.out.println("aa2.hashCode()=" + aa2.hashcode());
    System.out.println("aa3.hashCode()=" + aa3.hashCode());//与aa.hashCode()相等
}
class A{}

6)后面在集合,中hashCode 如果需要的话,也会重写

toString方法

默认返回:全类名+@+哈希值的十六进制

//Object的toString方法
public String toString() {
    //getClass().getName() 类的全类名(包名+类名)
    //Integer.toHexString(hashCode())将对象的hashCode值转成16进制字符串
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

子类往往重写toString方法,用于返回对象的属性信息

重写toString方法,打印对象或拼接对象时,都会自动调用该对象的toString形式.
案例演示:

当直接输出一个对象时,toString方法会被默认的调用

finalize方法

1.当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作

//程序员就可以在finalize中,写自己的业务逻辑代码(比如释放资源:数据库连接,或者打开文件..)
//如果程序员不重写 finalize,那么就会调用0bject类的 finalize,即默认处理
//如果程序员重写了finalize,就可以实现自己的逻辑

2.什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。

3.垃圾回收机制的调用,是由系统来决定(即有自己的GC算法),也可以通过System.gc()主动触发垃圾回收机制

我们在实际开发中,几乎不会运用finalize,所以更多就是为了应付面试.

断点调试(debug)

一个实际需求

1.在开发中,新手程序员在查找错误时,这时老程序员就会温馨提示,可以用断点调试,一步一步的看源码执行的过程,从而发现错误所在。

2.重要提示:在断点调试过程中,是运行状态,是以对象的运行类型来执行的.

断点调试介绍

1.断点调试是指在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住,然后你可以一步一步往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码行即显示错误,停下。进行分析从而找到这个Bug

2.断点调试是程序员必须掌握的技能。

3.断点调试也能帮助我们查看java底层源代码的执行过程,提高程序员的Java水平。

断点调试的快捷键

F7(跳入):跳入方法内

F8(跳过):逐行执行代码

shift+F8(跳出):跳出方法

F9(resume,执行到下一个断点)

java中段

类变量(静态变量)

JDK7以上版本,静态域存储于定义类型的Class对象中,Class对象如同堆中其他对象一样,存在于GC堆中。

不管static变量在哪里,共识

(1) static变量是同一个类所有对象共享

(2) static类变量,在类加载的时候就生成了.

java 隔几秒执行几次后停止_后端_07

什么是类变量

类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。这个从前面的图也可看出来。

如何定义类变量

访问修饰符 static 数据类型 变量名;//推荐
static 访问修饰符 数据类型 变量名;

如何访问类变量

类名.类变量名//推荐使用
或者 对象名.类变量名//静态变量的访问修饰符的访问权限和范围和普通属性是一样的。

类变量使用注意事项和细节讨论

1.什么时候需要用类变量

当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量):比如:定义学生类,统计所有学生共交多少钱。Student (name, static fee)

2.类变量与实例变量(普通属性)

区别:类变量是该类的所有对象共享的,而实例变量是每个对象独享的。

3.加上static称为类变量或静态变量,否则称为实例变量/普通变量/非静态变量

4.类变量可以通过 类名.类变量名 或者 对象名.类变量名 来访问,但java设计者推荐我们使用 类名.类变量名 方式访问。【前提是满足访问修饰符的访问权限和范围】

5.实例变量(普通变量/属性)不能通过 类名.类变量名 方式访问。

6.类变量是在类加载时就初始化了,也就是说,即使你没有创建对象,只要类加载了,就可以使用类变量了。

7.类变量的生命周期是随类的加载开始,随着类消亡而销毁。

类方法(静态方法)

类方法基本介绍

类方法也叫静态方法。形式如下:

访问修饰符 static 数据返回类型 方法名(){}//推荐
static 访问修饰符 数据返回类型 方法名(){}

类方法的调用:

//前提是满足访问修饰符的访问权限和范围
类名.类方法名
对象名.类方法名

类方法经典的使用场景

当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率。

如果我们希望不创建实例,也可以调用某个方法(即当做工具来使用),这时,把方法做成静态方法时非常合适

在程序员实际开发,往往会将一些通用的方法,设计成静态方法,这样我们不需要创建对象就可以使用了,比如打印一维数组,冒泡排序,完成某个计算任务等…

类方法使用注意事项和细节讨论

1)类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区:

类方法中无this的参数

普通方法中隐含着this的参数

2)类方法可以通过类名调用,也可以通过对象名调用。

3)普通方法和对象有关,需要通过对象名调用,比如 对象名.方法名(参数) ,不能通过类名调用。

4)类方法中不允许使用和对象有关的关键字,比如this和super。普通方法(成员方法)可以。

5)类方法(静态方法)中只能访问静态变量或静态方法。

6)普通成员方法,既可以访问普通变量(方法),也可以访问静态变量(方法)。

小结:

静态方法,只能访问静态的成员。

非静态的方法,可以访问静态成员和非静态成员(必须遵守访问权限)

mian方法

深入理解main方法

public static void main(String[] args){}

1.mian方法是java虚拟机调用的。

1.java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public

2.java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static

3.该方法接收String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数。

4.java执行的程序 参数1 参数2 参数3

特别提醒

1)在main()方法中,我们可以直接调用main方法所在类的静态方法或静态属性。

2)但是,不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员

3.idea中也可以运行,运行参数在下图添加后运行:

java 隔几秒执行几次后停止_java 隔几秒执行几次后停止_08

java 隔几秒执行几次后停止_开发语言_09

代码块/static代码块

基本介绍

1.代码化块又称为初始化块,属于类中的成员[即是类的一部分],类似于方法,将逻辑语句封装在方法体中,通过{}包围起来。

2.但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。

基本语法

[修饰符]{
     代码
 };

注意:
1)修饰符可选,要写的话,也只能写static

2)代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通代码块。

3)逻辑语句可以为任何逻辑语句(输入、输出、方法调用、循环、判断等)

4);号可以写上,也可以省略。

理解

1)相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作

2)场景:如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的重用性

代码块使用注意事项和细节讨论

1.static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次如果是普通代码块,每创建一个对象,就执行

2)类什么时候被加载

①创建对象实例时(new)

②创建子类对象实例,父类也会被加载

③使用类的静态成员时(静态属性,静态方法)

④类加载只会加载一次,不会重复加载

3)普通的代码块,在创建对象实例时,会被隐式的调用。

被创建一次,就会调用一次。

如果只是使用类的静态成员时,普通代码块并不会执行。

小结:

1.static代码块是类加载时,执行,只会执行一次

2.普通代码块是在创建对象时调用的,创建一次,调用一次

4)创建一个对象时,在一个类调用顺序是:(重点,难点)∶
①调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)

②调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用)

③调用构造方法。

5)构造方法(构造器)的最前面其实隐含了super()和调用普通代码块,新写一个类演示[截图+说明],静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于构造器和普通代码块执行的

6)我们看一下创建一个子类时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:
①父类的静态代码块和静态属性(优先级一样,按定义顺序执行)

②子类的静态代码块和静态属性(优先级一样,按定义顺序执行)

③父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)

④父类的构造方法

⑤子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)

⑥子类的构造方法

package com.gx.test;

public class Test {
    public static void main(String[] args) {
        //(1) 进行类的加载
        //1.1 先加载 父类 A02 2.2 再加载 子类 B02
        //(2) 创建对象
        //2.1 从子类构造器开始
        new B02();//对象
    }
}

class A02{//父类
    private static int n2 = getVal01();
    static {
        System.out.println("A02的一个静态代码块");//(2)
    }
    {
        System.out.println("A02的第一个普通代码块");//(5)
    }
    public int n3 = getVal02();

    private static int getVal01() {
        System.out.println("getVal01");//(1)
        return 10;
    }
    private int getVal02() {
        System.out.println("getVal02");//(6)
        return 10;
    }
    public A02(){
        //隐藏了
        //super()
        //普通代码块的普通属性的初始化。。。。。
        System.out.println("A02的构造器");//(7)
    }

}

class B02 extends A02{
    private static int n3 = getVal03();
    static {
        System.out.println("B02的一个静态代码块");//(4)
    }
    public int n4 = getVal04();
    {
        System.out.println("B02的第一个普通代码块");//(9)
    }
    private static int getVal03() {
        System.out.println("getVal03");//(3)
        return 10;
    }
    private int getVal04() {
        System.out.println("getVal04");//(8)
        return 10;
    }
    public B02(){
        //隐藏了
        //super()
        //普通代码块的普通属性的初始化。。。。。
        System.out.println("B02的构造器");//(10)
    }
}

7)静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调
用任意成员。

设计模式

什么是设计模式

1.静态方法和属性的经典使用

2.设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索

什么是单例模式

1.所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
2.单例模式有两种方式:1)饿汉式 2)懒汉式

步骤如下:
1)构造器私有化 => 防止直接new

2)类的内部创建对象

3)向外暴露一个静态的公共方法。

饿汉式

//有一个类 GirlFriend
//只能有一个女朋友
class GirlFgiend {
    private String name;
	//为了能够在静态方法中,返回gf对象,需要将其修饰为static
    //对象,通常是重量级的对象,且饿汉式可能造成创建了对象,但是没有使用
    private static GirlFriend gf= new GirlFriend("小红红");//如何保障我们只能创建一个 GirlFriend对象
	//步骤[单列模式--饿汉式]
    //1。将构造器私有化
    //2.在类的内部直接创建对象(该对象的static)
    //3.提供一个公共的static方法,返回 gf对象
    private GirlFriend(String name) {
        this.name = name;
    }
    
    public static GirlFriend getInstance() {
        return gf;
    }

}

懒汉式

//希望在程序运行过程中,只能创建一个Cat对象
//使用单例模式
class Cat {
    private String name;
    private String name;
    private static Cat cat ;
    //步骤[单列模式--懒汉式]
    //1.仍然将造器私有化
    //2.定义一个static静态属性方法
    //3.提供一个public的static方法,可以返回一个Cat对象
    //4.懒汉式,只有当用户使用getInstance时,才返回cat对象,后面再次调用时,会返回上次创建的cat对象
    //	从而保证了单列
    private Cat(String name) {
        this.name = name;
    }
    public static Cat getInstance() {
        if(cat == null) {//如果还没有创建cat对象
            cat = new Cat("小可爱");
        }
        return cat;
    }
}

饿汉式VS懒汉式

1.二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建。

2.饿汉式不存在线程安全问题,懒汉式存在线程安全问题。

3.饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题。

4.在我们javaSE标准类中,java.lang.Runtime就是经典的单例模式。

小结

1.单例模式的两种实现方式: ⑴饿汉式 (2)懒汉式

2.饿汉式的问题:在类加载时候就创建,可能存在资源浪费问题

3.懒汉式的问题:线程安全问题

final关键字

基本介绍

final中文意思:最后的,最终的.

final可以修饰类、属性、方法和局部变量.

在某些情况下,程序员可能有以下需求,就会使用到final:

1)当不希望类被继承时,可以用final修饰

2)当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰

访问修饰符 final 返回类型 方法名

3)当不希望类的的某个属性的值被修改,可以用final修饰

public final double TAX_RATE = 0.08

4)当不希望某个局部变量被修改,可以使用final修饰

final double TAX_RATE = 0.08 //这时 TAX_RATE 被称为局部常量

final使用注意事项和细节讨论

1)final修饰的属性又叫常量,一般用xx xx _Xx来命名

2)final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一[选择一个位置赋初值即可]:

①定义时:如public final double TAX_RATE=0.08;

②在构造器中

③在代码块中

class AA{
    public final double TAX_RATE = 0.08;
    public final double TAX_RATE2 ;
    public final double TAX_RATE3 ;
    public AA() {
        TAX_RATE2 = 1.1;
    }
    {
        TAX_RATE3 = 8.8;
    }
}

3)如果final修饰的属性是静态的,则初始化的位置只能是

①定义时

②在静态代码块

注:但不能在构造器中赋值(防止类加载了但是构造器没有调用的情况出现,这时就没有给final修饰的属性赋值,显然是不行的)

4)final类不能继承,但是可以实例化对象。

5)如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承。

6)一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法。(既然已经不能被继承了,就肯定不能被重写了)

7)final不能修饰构造方法(即构造器)

8)final和static往往搭配使用,效率更高,不会导致类加载,底层编译器做了优化处理。

class Test{
    public static void main(String[] args) {
        system.out.println(BBB.num);//结果:100 所以显示类没有加载
    }
}

class BBB{
    public static final int num=100;
    static{
        System.out.println("BBB 静态代码块被执行");
    }
}

8)包装类(Integer,Double,Float,Boolean等都是final),String也是final类。

抽象类

当父类的一些方法不能确定时,可以用abstract关键字来修饰该方法,这个方法就是抽象方法,用abstract 来修饰该类就是抽象类。

抽象类的介绍

1)用abstract关键字来修饰一个类时,这个类就叫抽象类

访问修饰符 abstract 类名{
}

2)用abstract关键字来修饰一个方法时,这个方法就是抽象方法

访问修饰符 abstract 返回类型方法名(参数列表);//没有方法体

3)抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类()

4)抽象类,是考官比较爱问的知识点,在框架和设计模式使用较多

抽象类使用的注意事项和细节讨论

1)抽象类不能被实例化

2)抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法

3)一旦类包含了abstract方法,则这个类必须声明为abstract

4)abstract 只能修饰类和方法,不能修饰属性和其它的。

5)抽象类可以有任意成员【因为抽象类还是类】,比如:非抽象方法、构造器、静态属性等等

6)抽象方法不能有主体,即不能实现

7)如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类。

8)抽象方法不能使用private、final和 static来修饰,因为这些关键字都是和重写相违背的

注:static的本意是为了能够让类直接调用,但是没有方法体的方法显然没法调用,所以抽象方法不能使用static来修饰

模板模式

public class TestTemplate {
    public static void main(String[] args) {
        AA aa = new AA();
        aa.calculateTime();
        
        BB bb = new BB();
        bb.calculateTime();
    }
}
abstract public class Template {
    //抽象类-模板设计模式
    public abstract void job();//抽象方法
    public void calculateTime() {//实现方法,调用job方法
        //得到开始的时间
        long start = System.currentTimeMillis();
        job();//动态绑定机制
        //得的结束的时间
        long end = System.currentTimeMillis();
        System.out.println("AA执行时间" +(end - start));
    }
}
public class AA extends Template{
    @Override
	public void job() {//实现Template的抽象方法job
		long num = ;num: 1
		for (long i= 1; i <= 800000; i++) {
			num += i;
		}
	}
}


public class BB extends Template{
	public void job() {//这里也去,重写了Template的job方法
        long num = 0;
        for (long i = 1; i <=80000; i++) {
        	num *= i;
		}
	}
}

接口

基本介绍

接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。

interface 接口名{
    //属性
    //方法
}
class 类名 implements 接口{
    //自己属性;
    //自己方法;
    //必须实现的接口的抽象方法
}

小结

1.在Jdk7.0前接口里的所有方法都没有方法体,即都是抽象方法。

2.Jdk8.0后接口可以有静态方法,默认方法,也就是说接口中可以有方法的具体实现,但是需要使用default关键字修饰

//在jdk8后,可以有默认实现方法,需要使用default关键字修饰
default public void ok() {
	System.out.println("ok ...");
}
//在jdk8后,可以有静态方法
public static void cry() {
	System.out.println( "cry ....");
}

注意事项和绍节

1)接口不能被实例化

2)接口中所有的方法是 public方法,接口中抽象方法,可以不用abstract,因为方法默认的就为abstract

3)一个普通类实现接口,就必须将该接口的所有方法都实现。

4)抽象类实现接口,可以不用实现接口的方法。

5)一个类同时可以实现多个接口

interface IB {
	void hi();
}
interface IC {
	void say(;
}
class Pig implements IB, IC {
}

6)接口中的属性,只能是final的,而且是 public static final 修饰符。

比如:int a=1;实际上是public static final int a=1;(必须初始化)

7)接口中属性的访问形式:接口名.属性名

8)一个接口不能继承其它的类,但是可以继承多个别的接口

interface A extends B,C{}

9)接口的修饰符只能是public和默认,这点和类的修饰符是一样的。

接口vs继承

接口和继承解决的问题不同

继承的价值主要在于:解决代码的复用性和可维护性。

接口的价值主要在于:设计,设计好各种规范(方法),让其它类去实现这些方法。即更加的灵活

接口比继承更加灵活

接口比继承更加灵活,继承是满足is - a的关系,而接口只需满足 like - a的关系。

接口在一定程度上实现代码解耦

即:接口规范性+动态绑定机制

接口的多态特性

1)多态参数
在前面的Usb接口案例,Usb usb,既可以接收手机对象,又可以接收相机对象,就体现了接口多态(接口引用可以指向实现了接口的类的对象)

public class InterfacePolyParameter {
    public static void main(String[] args) {
        //接口的多态体现
        //接口类型的变量if01 可以指向实现了IF接口类的对象实例
        IF if01 =new Monster();
        if01 = new Car();
        //继承体现的多态
        AAA a = new BBB();
        a = new CCC();

    }
}
interface IF {}
class Monster implements IF{}
class Car implements IF{}

class AAA {}
class BBB extends AAA{}
class ccc extends AAA{}

2)多态数组

public class InterfacePolyArr {
    public static void main(String[] args) {
        //多态数组->接口类型数组
        Usb[] usbs = new Usb[2];
        usbs[o] = new Phone_();
        usbs[1] = new Camera_();
        for(int i = 0; i < usbs.length; i++) {
            usbs[i].work();//动态绑定..
            //和前面一样,我们仍然需要进行类型的向下转型
            if(usbs[i] instanceof Phone_) {//判断他的运行类型是
                ((Phone_) usbs[i]).call();
            }
        }
    }
}

interface Usb{
    void work();
}

class Phone_ implements Usb {
    public void call() {
        System.out.println("手机可以打电话。..");
    }
    @0verride
    public void work() {
        system.out.println("手机工作中...");
    }
}

class Camera_ implements Usb {
    @0verride
    public void work() {
        system.out.println("相机工作中...");
    }
}

3)接口存在多态传递

public class InterfacePolyPass {
    public static void main(String[] args) {
        //接口类型的变量可以指向,实现了该接口的类的对象实例
        IG ig = new Teacher();
        //如果IG 继承了IH接口,而Teacher类实现了IG接口
        //那么,实际上就相当于 Teacher类也实现了IH接口
        //这就是所谓的接口多态多态传递现象
        IH ih = new Teacher();

    }
}
interface IH {
    void hi();
}
interface IG extends IH{}
class Teacher implements IG {
    @0verride
    public void hi(){  
    }
}

四种内部类

一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。是我们类的第五大成员**[属性、方法、构造器、代码块、内部类]**,内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系

基本语法

class Outer{//外部类
    class Inner{//内部类
    }
}
class Other{//外部其他类
}

内部类的分类

定义在外部类局部位置上(比如方法内):

1)局部内部类(有类名)
2)匿名内部类(没有类名,重点)

定义在外部类的成员位置上:

1)成员内部类(没用static修饰)

2)静态内部类(使用static修饰)

局部内部类的使用

说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。

1.可以直接访问外部类的所有成员,包含私有的

2.不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final

3.作用域;仅仅在定义它的方法或代码块中。

4.局部内部类—访问---->外部类的成员[访问方式:直接访问]

5.外部类—访问---->局部内部类的成员

访问方式:创建对象,再访问(注意:必须在作用域内)

6.外部其他类—不能访问----->局部内部类(因为局部内部类地位是一个局部变量)

7.如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的E员,则可以使用(外部类名.this.成员)去访问
System.out.printIn("外部类的n2=”+外部类名.this.n2);

public class LocalInnerClass {
    public static void main(String[] args) {
        Outer02 outer02 = new Outer02();
        outer02.m1();
    }
}

class Outer02 {//外部类
    private int n1 = 100;

    private void m2() {
    }//私有方法

    public void m1() {
        //1。局部内部类是定义在外部类的局部位置,通常在方法
        //3.不能添加访问修饰符,但是可以使用final修饰
        //4.作用域:仅仅在定义它的方法或代码块中
        final class Inner02 {//局部内部类(本质仍然是一个类)
            //2.可以直接访问外部类的所有成员,包含私有的
            private int n1 = 800;

            public void f1() {
                //5.局部内部类可以直接访问外部类的成员,比如下面外部类n1 和 m2()
                //Outer02.this本质就是外部类的对象,即哪个对象调用了m1, Outer02.this就是哪个对象
                System.out.println("n1=" + n1 + "外部类的n1=" + Outer02.this.n1);
                m2();
            }
        }
        //6.外部类在方法中,可以创建Inner02对象,然后调用方法即可
        //7.如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,使用 外部类名.this.成员 去访问
        Inner02 inner02 = new Inner02();
        inner02.f1();
    }
    
}

记住:

(1)局部内部类定义在方法中/代码块

(2)作用域在方法体或者代码块中

(3)本质仍然是一个类

匿名内部类的使用(重要!!!)

说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名

(1)本质是类(2)内部类(3)该类没有名字(4)同时还是一个对象

1.匿名内部类的基本语法

new 类或接口(参数列表){
    类体
};

具体例子:

public class AnonymousInnerClass {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}

class Outer04 {//外部类
    private int n1 = 10;//属性
    public void method() {//方法
        //1.需求:想使用IA接口,并创建对象
        //2.传统方式,是写一个类,实现该接口,并创建对象
        //IA tiger = new Tiger();
        //tiger.cry();
        //3.需求是 Tiger/Dog 类只是使用一次,后面再不使用
        //4.可以使用匿名内部类来简化开发
        //5. tiger的编译类型? IA
        //6. tiger的运行类型? 就是匿名内部类 Outer04$1
        /*
            我们看底层 会分配类名 Outer04$1
            class outer04$ implements IA {
                @Override
                public void cry() {
                    System.out.println("老虎叫唤...");
                }
            }
		*/
        //7. jdk底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例,并且把地址返回给 tiger
        //8.匿名内部类使用一次,就不能再使用
        IA tiger = new IA() {
            @Override
            public void cry() {
                System.out.println("老虎叫唤...");
            }
        };
        System.out.println("tiger的运行类型=" + tiger.getClass());
        tiger.cry();


        //演示基于类的匿名内部类
        //分析
        //1. father编译类型 Father
        //2. father运行类型 Outer04$2
        //3.底层会创建匿名内部类
        /*
        	class Outer04$2 extends Father{
        		@Override
        		public void test() {
        			System.out.printLn("匿名内部类重写了test方法");
        		}
        	}
        */
        //4.同时也直接返回了匿名内部类 Outer04$2的对象
        //5.注意("jack")参数列表会传递给构造器
        Father father =new Father( "jack"){
            @Override
            public void test() {
                System.out.println("匿名内部类重写了test方法");
            }
        };
        System.out.println("father对象的运行类型=" + father.getClass());//Outer04$2
        father.test();

        //基于抽象类的匿名内部类
        Animal animal = new Animal(){
            @Override
            void eat() {
                System.out.println("小狗吃骨头...");
            }
        };
        animal.eat();
    }
}

interface IA {//接口
    public void cry();
}

//class Tiger implements IA {
//    @Override
//    public void cry() {
//        System.out.println("老虎叫唤...");
//    }
//}
//class Dog implements IA{
//    @Override
//    public void cry() {
//        System.out.println("小狗汪汪...");
//    }
//}


class Father {//类
    public Father(String name) {//构造器
        System.out.println("接收到name" + name);
    }
    public void test() {//方法

    }
}
abstract class Animal {//抽象类
    abstract void eat();
}

2.匿名内部类的语法比较奇特,请大家注意,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点,因此可以调用匿名内部类方法。

3.可以直接访问外部类的所有成员,包含私有的

4.不能添加访问修饰符,因为它的地位就是一个局部变量。

5.作用域:仅仅在定义它的方法或代码块中。

6.匿名内部类—访问---->外部类成员[访问方式:直接访问]

7.外部其他类—不能访问----->匿名内部类(因为匿名内部类地位是一个局部变量)

8.如果外部类和匿名内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

public class AnonymousInnerClassDetail {
    public static void main(String[] args) {
        Outer05 outer05 = new 0uter05();
        outer05.f1();
		//外部其他类---不能访问----->匿名内部类(因为匿名内部类地位是一个局部变量)
        System.out.println("main outer05 hashcode=" + outer05);
    }
}

class Outer05 {
    private int n1 = 99;
    public void f1() {
        //创建一个基于类的匿名内部类
        //不能添加访问修饰符,因为它的地位就是一个局部变量
        //作用域:仅仅在定义它的方法或代码块中
        Person p = new Person(){
            private int n1 = 88;
            @0verride
            public void hi() {
                //可以直接访回外部类的所有成员,包含私有的
                //默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
                System.out.println("匿名内部类重写了 hi方法 n1=" + n1 + "外部内的n1=" + Outer05.this.n1);
                //outer05.this就是调用f1的对象
                System.out.println("Outer05.this hashcode=" + Outer05.this.n1);

            }
        };
        p.hi();//动态绑定,运行类型是 Outer05$1
        
        //也可以直接调用,匿名内部类本身也是返回对象
        // class匿名内部类 extends Person{}
        new Person(){
            @Ovarride
            public void hi() {
                System.out.println("匿名内部类重写了 hi方法,哈哈...");
            }
            @Override
            public void ok(String str) {
                super.ok(str);
            }
        }.ok( "jack");//.hi();

    }
}

class Person {//类
    public void hi() {
        system.out.println("Person hi()");
    }
    public void ok(String str) {
        System.out.println("Person ok()" + str);
    }
}

匿名内部类的最佳实践

public class InnerClassExercise01 {
    public static void main(String[] args) {
        //当做实参直接传递,简洁高效
        f1(new,IL() {
            @0verride
            public void show() {
                System.out.println("这是一副名画~... ");
            }
        });
        //传统方法
        f1(new Picture());
    }
    //静态方法,形参是接口类型
    public static void f1(IL il) {
        il.show();
    }
}

//接口
interface IL {
    void show();
}
//类->实现IL => 编程领域(硬编码)
class Picture implements IL {
    @Override
    public void show() {
        System.out.println("这是一副名画...");
    }
}
public class InnerClassExercise02 {
    public static void main(String[] args) {
        /*
        1.有一个铃声接口Bell,里面有个ring方法。(右图)
        2.有一个手机类Cellphone,具有闹钟功能alarmClock,参数是Bell类型(右图)
        3.测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
        4.再传入另一个匿名内部类(对象),打印:小伙伴上课了
        */
        //老韩解读
        //1.传递的是实现了 Bell接口的匿名内部类 InnerClassExercise02$1
        //2.重写了ring
        //3.Bell bell = new Bell() {
        //    @Override
        //    public void ring() {
        //        System.out.println("懒猪起床了");
        //    }
        //};

        CellPhone cellPhone = new CellPhone();
        cellPhone.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("懒猪起床了");
            }
        });
        cellPhone.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("小伙伴上课了");
            }
        });
    }
}

interface Bell {//接口

    void ring();//法
}

class CellPhone {//类

    public void alarmClock(Bell bell) {//形参是Bell接口类型
        bell.ring();//动态绑定
    }
}

成员内部类

说明:成员内部类是定义在外部类的成员位置,并且没有static修饰。

1.可以直接访问外部类的所有成员,包含私有的

2.可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员。

3.作用域和外部类的其他成员一样,为整个类体, 比如前面案例,在外部类的成员方法中创建成员内部类对象再调用方法.

4.成员内部类—访问---->外部类(比如:属性)【访问方式:直接访问】(说明)

5.外部类—访问------>内部类(说明)访问方式:创建对象,再访问

6.外部其他类—访问---->成员内部类

7.如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

public class MemberInnerClass01 {
    public static void main(String[] args) {
        Outer08 outer08 = new Outer08();
        outer08.t1();

        //外部其他类,使用成员内部类的三种方式
        //第一种方式
        //outer08.new Inner08(); 相当于把 new Inner08()当做是outer08成员(这就是一个语法,不要特别的纠结。)
        Outer08.Inner08 inner08 = outer08.new Inner08();
        inner08.say();
        //第二方式在外部类中,编写一个方法,可以返回 Inner08对象
        Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
        inner08Instance.say();
        //第三种方式
        Outer08.Inner08 inner082 =new Outer08().new Inner08();
    }
}

class Outer08 {//外部类
    private int n1 = 10;
    public String name = "张三";

    private void hi() {
        System.out.println("hi()方法...");
    }

    //1.注意:成员内部类,是定义在外部内的成员位置上
    public class Inner08 {//成员内部类
        private double sal = 99.8;
        private int n1 = 66;
        public void say() {
            //可以直接访问外部类的所有成员,包含私有的
            //如果成员内部类的成员和外部类的成员重名,会遵守就近原则。可以通过 外部类名.this.属性 来访问外部类的成员
            System.out.println("n1 =" + n1 + " name = " + name + " 外部类的n1= " + Outer08.this.n1);
            hi();
        }
    }

    //方法,返回一个Inner08实例
    public Inner08 getInner08Instance() {
        return new Inner08();
    }

    //写方法
    public void t1() {
        //使用成员内部类
        //创建成员内部类的对象,然后使用相关的方法
        Inner08 inner08 = new Inner08();
        inner08.say();
        System.out.println(inner08.sal);
    }

}

静态内部类

说明:静态内部类是定义在外部类的成员位置,并且有static修饰

1.可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员

2.可以添加任意访问修饰符(public.protected、默认、private),因为它的地位就是一个成员。

3.作用域:同其他的成员,为整个类体

4.静态内部类—访问---->外部类(比如:静态属性)[访问方式:直接访问所有静态成员]

5.外部类—访问------>静态内部类访问方式:创建对象,再访问

6.外部其他类—访问----->静态内部类

7.如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问(因为是静态的,所以不用再用 外部类名.this.成员 )

public class Test {
    public static void main(String[] args) {
        Outer10 outer10 = new Outer10();
        outer10.m1();
        //外部其他类使用静态内部类
        //方式1
        //因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
        Outer10.Inner10 inner10 = new Outer10.Inner10();
        inner10.say();
        //方式二
        //编写一个方法,可以返回静态内部类的对象实例.
        Outer10.Inner10 inner101 = outer10.getInner10();
        System.out.println("===========");
        inner101.say();

        Outer10.Inner10 inner10_ = Outer10.getInner10_();
        System.out.println("*********");
        inner10_.say();


    }
}

class Outer10 {//外部类
    private int n1 = 10;
    public static String name = "张三";

    private static void cry(){}
    //Inner10就是静态内部类
    // 1.放在外部类的成员位置
    // 2.使用static修饰
    // 3.可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
    // 4.可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
    // 5.作用域:同其他的成员,为整个类体
    static class Inner10 {
        public static String name = "韩顺平教育";
        public void say() {
            //如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问
            System.out.println(name+" 外部类name= "+ Outer10.name);
            cry();
        }
    }
    public void m1(){//外部类---访问------>静态内部类访问方式:创建对象,再访问
        Inner10 inner10 = new Inner10();
        inner10.say();
    }
    public Inner10 getInner10(){
        return  new Inner10();
    }
    public static Inner10 getInner10_(){
        return  new Inner10();
    }
}

小结

(1)内部类有四种:①局部内部类② 匿名内部类③成员内部类④静态内部类

(2)重点还是掌握匿名内部类使用

new 类/接口(参数列表){
    //...
};

(3)成员内部类,静态内部类是放在外部类的成员位置,本质就是一个成员

(4)其他细节看笔记…

枚举

基本内容

1)枚举对应英文(enumeration,简写enum)

2)枚举是一组常量的集合。

3)可以这里理解:枚举属于一种特殊的类,里面只包含一组有限的特定的对象。

枚举的两种实现方式

自定义类实现枚举

1.不需要提供setXxx方法,因为枚举对象值通常为只读.

2.对枚举对象/属性使用final + static共同修饰,实现底层优化.

3.枚举对象名通常使用全部大写,常量的命名规范.

4.枚举对象根据需要,也可以有多个属性

public class Test {
    public static void main(String[] args) {
        System.out.println(Season.SPRING);
        System.out.println(Season.AUTUMN);
    }
}

//演示自定义枚举实现
class Season {//外部类
    private String name;
    private String desc;//描述
    public final static Season SPRING = new Season("春天","温暖");
    public final static Season WINTER = new Season("冬天","寒冷");
    public final static Season AUTUMN = new Season("秋天","凉爽");
    public final static Season SUMMER = new Season("夏天","炎热");
    //1.将构造器私有化,目的防止直接 new
    //2.去掉setXxx方法,防止属性被修改
    //3.在Season内部,直接创建固定的对象
    //4.优化,可以加入 final修饰符


    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }

    private Season(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }
}
使用enum关键字实现枚举
public class Test {
    public static void main(String[] args) {
        System.out.println(Season2.SPRING);
        System.out.println(Season2.AUTUMN);
    }
}

//演示使用enum关键字来实现枚举
enum Season2 {//外部类
    //    public final static Season SPRING = new Season("春天","温暖");
    //    public final static Season WINTER = new Season("冬天","寒冷");
    //    public final static Season AUTUMN = new Season("秋天","凉爽");
    //    public final static Season SUMMER = new Season("夏天","炎热");

    //如果使用了enum来实现枚举类
    // 1.使用关键字 enum替代class
    // 2.public static final Season SPRING = new Season("春天","温暖")
    //  直接使用SPRING("春天","温暖") 解读 常量名(实参列表)
    // 3.如果有多个常量(对象),使用,号间隔即可
    // 4.如果使用enum来实现枚举,要求将定义常量对象,写在前面
    //5。如果我们使用的是无参构造器,创建常量对象,则可以省略()

    SPRING("春天","温暖"),WINTER("冬天","寒冷"),AUTUMN("秋天","凉爽"),
    SUMMER("夏天","炎热"),What;
    private String name;
    private String desc;//描述
    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }

    private Season2() {//无参构造器
    }

    private Season2(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    @Override
    public String toString() {
        return "Season2{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}

enum关键字实现枚举注意事项

1.当我们使用enum关键字开发一个枚举类时,默认会继承Enum类。而且是一个final类(使用javap反编译来验证)

java 隔几秒执行几次后停止_后端_10

2传统的public static final Season2 SPRING = new Season2(“春天”,“温暖”);简化成 SPRING(“春天”,“温暖”),这里必须知道,它调用的是哪个构造器.

3.如果使用无参构造器创建枚举对象,则实参列表和小括号都可以省略

4.当有多个枚举对象时,使用","间隔,最后有一个分号结尾

5.枚举对象必须放在枚举类的行首

枚举的常用方法

1.toString:Enum类已经重写过了,返回的是当前对象名,子类可以重写该方法,用于返回对象的属性信息

2.name:返回当前对象名(常量名),子类中不能重写

3.ordinal:返回当前对象的位置号,默认从0开始

4.values:返回当前枚举类中所有的常量

5.valueof:将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则报异常!

6.compareTo:比较两个枚举常量,比较的就是编号!

package com.gx.test;

public class Test {
    public static void main(String[] args) {
        Season2 autumn = Season2.AUTUMN;
        //输出枚举对象的名字
        System.out.println(autumn.name());
        // ordinal()输出的是该枚举对象的次序/编号,从0开始编号
        //AUTUMN 枚举对象是第三个,因此输出2
        System.out.println(autumn.ordinal());
        //从反编译可以看出values方法,返回Season2[]
        // 含有定义的所有枚举对象
        System.out.println( "===遍历取出枚举对象(增强for)====");
        Season2[] valuse = autumn.values();
        for (Season2 season:valuse) {
            System.out.println(season);
        }

        //valueOf:将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则报异常
        // 执行流程
        // 1。根据你输入的 "AUTUMN" 到Season2的枚举对象去查找
        // 2.如果找到了,就返回,如果没有找到,就报错
        Season2 autumn1 = Season2.valueOf("AUTUMN ");
        System.out.println( "autumn1=" +autumn1);

        //compareTo:比较两个枚举常量,比较的就是编号
        // 1.就是把Season2.AUTUNN枚举对象的编号和Season2.SUMMER枚举对象的编号比较
        /*源码
        public final int compareTo(E o) {
            Enum<?> other = (Enum<?>)o;
            Enum<E> self = this;
            if (self.getClass() != other.getClass() && // optimization
                    self.getDeclaringClass() != other.getDeclaringClass())
                throw new ClassCastException();
            return self.ordinal - other.ordinal;
            //Season2.AUTUMN的编号[2] - Season2.SUMMER的编号[3] //等于-1
        }
        */
        System.out.println(Season2.AUTUMN.compareTo(Season2.SUMMER));

    }
}

//演示使用enum关键字来实现枚举
enum Season2{//外部类
    SPRING("春天","温暖"),
    SUMMER("夏天","炎热"),
    WINTER("冬天","寒冷"),
    AUTUMN("秋天","凉爽"),/*What*/;
    private String name;
    private String desc;//描述
    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }

    private Season2() {//无参构造器
    }

    private Season2(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    @Override
    public String toString() {
        return "Season2{" +
                "name='" + name + '\'' +
                ", desc='" + desc + '\'' +
                '}';
    }
}

enum的注意试想和细节讨论

1)使用enum关键字后,就不能再继承其它类了,因为enum会隐式继承Enum,而Java是单继承机制。

2)枚举类和普通类一样,可以实现接口,如下形式。

enum 类名 implements 接口1,接口2{}

注解(Annotation)

1)注解(Annotation)也被称为元数据(Metadata),用于修饰解释包、类、方法、属性、构造器、局部变量等数据信息。

2)和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。

3)在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替java EE旧版中所遗留的繁冗代码和XML配置等。

使用Annotation时要在其前面增加@符号,并把该 Annotation当成一个修饰符使用。用于修饰它支持的程序元素

三个基本的Annotation

1)@Override:限定某个方法,是重写父类方法,该注解只能用于方法

2)@Deprecated: 用于表示某个程序元素(类,方法等)已过时

3)@SuppressWarnings: 抑制编译器警告

补充说明: @interface的说明 interface不是interface,是注解类是jdk1.5之后加入的

@Override

1.@Override表示指定重写父类的方法(从编译层面验证),如果父类没有fly方法,则会报错

2.如果不写@Override注解,而父类仍有public void fly0)0,仍然构成重写

3.@Override只能修饰方法,不能修饰其它类,包,属性等等

4.查看@Override注解源码为@Target(ElementType.METHOD),说明只能修饰方法

5.@Target是修饰注解的注解,称为元注解

package com.gx.test;

public class Test {
    public static void main(String[] args) {
    }
}

class Father {
    public void fly() {
        System.out.println("Father fly...");
    }
}

class Son extends Father {//子类

    // 1.@Override 注解放在fly方法上,表示子类的fly方法时重写了父类的fly
    // 2.这里如果没有写 @Override 还是重写了父类fLy
    // 3.如果你写了@Override注解,编译器就会去检查该方法是否真的重写了父类的方法,如果的确重写了,则编译通过,如果没有构成重写,则编译错误
    // 4.@Override源码
    //  如果发现@interface表示一个注解类
        /*
            @Target(ElementType.METHOD)
            @Retention(RetentionPolicy.SOURCE)
            public @interface Override {
            }
        */
    @Override//说明
    public void fly() {
        System.out.println("Son fly....");
    }
}

@Deprecated

1.用于表示某个程序元素(类,方法等)已过时

2.可以修饰方法,类,字段,包,参数等等

3.@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD,PACKAGE, PARAMETER, TYPE})

4.@Deprecated的作用可以做到新旧版本的兼容和过渡

package com.gx.test;

public class Test {
    public static void main(String[] args) {
        A a = new A();
        a.hi();
        System.out.println(a.n1);
    }
}

// 1.@Deprecated 修饰某个元素,表示该元素已经过时
// 2.即不在推荐使用,但是仍然可以使用
// 3.@Documented源码
    /*
        @Documented
        @Retention(RetentionPolicy.RUNTIME)
        @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
        public @interface Deprecated {
            String since() default "";
            boolean forRemoval() default false;
        }
    */
// 4.可以修饰方法,类,字段,包,参数等等
// 5.@Deprecated 可以做版本升级过渡使用

@Deprecated
class A {
    @Deprecated
    public int n1 = 10;

    @Deprecated
    public void hi() {
    }
}

@SuppressWarnings

各种值的说明

1)unchecked是忽略没有检查的警告

2)rawtypes是忽略没有指定泛型的警告(传参时没有指定泛型的警告错误)

3)unused是忽略没有使用某个变量的警告错误

4)@SuppressWarnings可以修饰的程序元素为,查看@Target

5)生成@SupperssWarnings时,不用背,直接点击左侧的黄色提示,就可以选择(注意可以指定生成的位置)

package com.gx.test;

import java.util.ArrayList;
import java.util.List;

//@SuppressWarnings({"rawtypes","unchecked","unused"})
public class Test {
    //1.当我们不希望看到这些警告的时候,可以使用 SuppressWarnings 注解来抑制警告信息
    // 2。在{""}中,可以写入你希望抑制(不显示)警告信息
    //3。可以指定的警告类型有
//        all (抑制所有警告)
//        boxing (抑制装箱、拆箱操作时候的警告)
//        cast (抑制映射相关的警告)
//        dep-ann (抑制启用注释的警告)
//        deprecation (抑制过期方法警告)
//        fallthrough (抑制确在switch中缺失breaks的警告)
//        inally (抑制finally模块没有返回的警告)
//        hiding ()
//        incomplete-switch  (enum case)(忽略没有完整的switch语句)
//        nls (忽略非nls格式的字符)
//        null (忽略对null的操作)
//        rawtypes (使用generics时忽略没有指定相应的类型)
//        serial class (忽略在serializable类中没有声明serialVersionUID变量)
//        static-access (抑制不正确的静态访问方式警告)
//        synthetic-access (抑制子类没有按最优方法访问内部类的警告)
//        unchecked (抑制没有进行类型检查操作的警告)
//        unqualified-field-access (抑制没有权限访问的域的警告)
//        unused (抑制没被使用过的代码的警告)
    //4.关于SuppressWarnings作用范围是和你放置的位置相关
    //比如@SuppressWarnings放置在 main方法,那么抑制警告的范围就是 main
    // 通常我们可以放置具体的语句,方法,类.
    // @SuppressWarnings源码
    // (1)放置的位置就是 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE
    // (2)该注解类有数组String[] values()设置一个数组比如 {"rawtypes","unchecked","unused"}
        /*
            @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
            @Retention(RetentionPolicy.SOURCE)
            public @interface SuppressWarnings {
                String[] value();
            }
        */

    @SuppressWarnings({"rawtypes","unchecked","unused"})
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("jack");
        list.add("tom");
        list.add("mary");
        int i;
        System.out.println(list.get(1));
    }
    public void f1(){
        @SuppressWarnings("rawtypes")
        List list = new ArrayList();
        list.add("jack");
        list.add("tom");
        list.add("mary");
        @SuppressWarnings("unused")
        int i;
        System.out.println(list.get(1));
    }
}

元注解–JDK的Annotation(了解)

元注解的基本介绍

JDK的元 Annotation 用于修饰其他 Annotation

元注解:本身作用不大,讲这个原因希望同学们,看源码时,可以知道他是干什么

元注解的种类

(使用不多,了解,不用深入研究)

1)Retention//指定注解的作用范围,三种 SOURCE,CLASS,RUNTIME

2)Target//指定注解可以在哪些地方使用

3)Documented//指定该注解是否会在javadoc体现4) Inherited//子类会继承父类注解

@Retention

说明
只能用于修饰一个 Annotation定义,用于指定该Annotation可以保留多长时间,@Rentention包含一个 RetentionPolicy类型的成员变量,,使用@Rentention时必须为该value成员变量指定值:

@Retention的三种值

1)RetentionPolicy.SOURCE:编译器使用后,直接丢弃这种策略的注解

2)RetentionPolicy.CLASS:编译器将把注解记录在class文件中.当运行Java程序时,JVM不会保留注解。这是默认值

3)RetentionPolicy.RUNTIME:编译器将把注解记录在class文件中,当运行Java程序时,JVM会保留注解.程序可以通过反射获取该注解

@Target

基本说明:

用于修饰Annotation定义,用于指定被修饰的Annotation能用于修饰哪些程席完素.

@Taraet 也包含一个名为value 的成品变量

@Documented

基本说明:

@Documented:用于指定被该元 Annotation修饰的Annotation类将被javadoc工具提取成文档,即在生成文档时,可以看到该注解。

说明:定义为Documented的注解必须设置Retention值为RUNTIME。

@lnherited注解

被它修饰的Annotation将具有继承性.如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解

说明:实际应用中,使用较少,了解即可。

异常

基本概念

Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常)

执行过程中所发生的异常事件可分为两类

1)Error(错误):Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError[栈溢出]OOM(out ofmemory),Error是严重错误,程序会崩溃。

2)Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问,试图读取不存在的文件,网络连接中断等等.

3)Exception 分为两大类:

运行时异常[程序运行时,发生的异常]

编译时异常[编程时,编译器检查出的异常]

异常体系图(一部分)

java 隔几秒执行几次后停止_开发语言_11

小结

1.异常分为两大类,运行时异常和编译时异常.

2运行时异常,编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常

3.对于运行时异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响

4.编译时异常,是编译器要求必须处置的异常。

五大运行时异常

常见的运行时异常包括

1)NullPointerException 空指针异常

当应用程序试图在需要对象的地方使用null时,抛出该异常

String name = null;
System.out.println(name.length());

2)ArithmeticException 数学运算异常

当出现异常的运算条件时,抛出此异常。(例如除以0)

3)ArraylndexOutOfBoundsException 数组下标越界异常

用用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引

int [] arr = {1,2,3};
for (int i = 0; i <= arr.length; i++) {//<=则取了a[3]数组越界
    System.out.println(arr[i]);
}

4)ClassCastException 类型转换异常

当试图将对象强制转换为不是实例的子类时,抛出该异常。

public class Test {
    public static void main(String[] args) {
        A b = new B();//向上转型
        B b2 = (B) b;//向下转型
        C c2 = (C) b;///这里抛出ClassCastException
    }
}

class A {}
class B extends A { }
class C extends A { }

5)NumberFormatException 数字格式不正确异常门

当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常=>使用异常我们可以确保输入是满足条件数字

String name ="韩顺平教育";//将String转成int
int num = Integer.parseInt(name);//抛出NumberFormatException
System.out.println(num);//

编译异常

编译异常是指在编译期间,就必须处理的异常,否则代码不能通过编译。

常见的编译异常

SQLException//操作数据库时,查询表可能发生异常

IOException//操作文件时,发生的异常

FileNotFoundException//当操作一个不存在的文件时,发生异常

ClassNotFoundException //加载类,而该类不存在时,异常

EOFException//操作文件,到文件未尾,发生异常

lllegalArguementException//参数异常

异常处理

基本介绍

异常处理就是当异常发生时,对异常处理的方式。

异常处理的方式

1)try-catch-finally
程序员在代码中捕获发生的异常,自行处理

try {
    //代码//可能有异常
} catch (Exception e) {
    // 捕获到异常
    // 1.当异常发生时
    // 2.系统将异常封装成 Exception对象e,传递给catch
    // 3.得到异常对象后,程序员,自己处理
    // 4.注意,如果没有发生异常catch代码块不执行

} finally {
    // 1.不管try代码块是否有异常发生,始终要执行finally 
    // 2.所以,通常将释放资源的代码,放在finally
}

2)throws
将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM

throws处理机制图
1.try-catch-finally和throws二选一
2.如果程序员,没有显示是处理异常,默认throws

java 隔几秒执行几次后停止_java 隔几秒执行几次后停止_12

try-catch异常处理

1)Java提供try和catch块来处理异常。try块用于包含可能出错的代码。catch块用于处理try块中发生的异常。可以根据需要在程序中有多个数量的try…catch块。

2)基本语法

try {
//可疑代码
//将异常生成对应的异常对象,传递给catch块
}catch(异常){
//对异常的处理
}
//如果没有finally,语法是可以通过

try-catch异常处理细节

1)如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块.

2)如果异常没有发生,则顺序执行try的代码块,不会进入到catch.

3)如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等) 则使用如下代码- finally {}

4)可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(Exception在后,NullPointerException在前),如果发生异常,只会匹配一个catch,案例演示

try {
    //代码//可能有异常
} catch (NullPointerException e) {
    System.out.println("空指针异常=" + e.getMessage());
} catch (ArithmeticException e) {
    System.out.println("算术异常=" + e.getMessage());
} catch (Exception e) {
    System.out.println(e.getMessage());
}finally {
    
}

5)可以进行try-finally配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉。(应用场景:执行一段代码,不管是否发生异常,都必须执行某个业务逻辑)

小结

1)如果没有出现异常,则执行try块中所有语句,不执行catch块中语句,如果有finally,最后还需要执行finally里面的语句

2)如果出现异常,则try块中异常发生后,try块剩下的语句不再执行。将执行catch块中的语句,如果有finally,最后还需要执行finally里面的语句!

try-catch实践

package com.gx.test;

import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        //如果用户输入的不是一个整数,就提示他反复输入,直到输入一个整数为止思路
        // 1,创建Scanner对象
        // 2。使用无限循环,去接收一个输入
        // 3.然后将该输入的值,转成一个int
        // 4.如果在转换时,抛出异常,说明输入的内容不是一个可以转成int的内容
        // 5.如果没有抛出异常,则break该循环
        Scanner scanner = new Scanner(System.in);
        int num = 0;
        String inputStr = "";
        while (true) {
            System.out.println("请输入一个整毁: ");
            inputStr = scanner.next();
            try {
                num = Integer.parseInt(inputStr);//这里是可能抛出异常
                break;
            } catch (NumberFormatException e) {
                System.out.println("你输入的不是一个整数:");
            }
        }
        System.out.println("你输入的值是=" + num);
    }
}
package com.gx.test;

import java.util.Scanner;
//自创方法,不使用try-catch语法,代码更少,使用了Scanner中的hasNextInt()方法,但是其底层源代码仍旧是使用了try-catch语法且原理同上面的相同
public class Test {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.printf("请输入一个整毁:");
        while (!(scanner.hasNextInt())) {
            System.out.print("您输入的不是整型,请重新输入:");
            scanner.next();
        }
        int num = scanner.nextInt();
        System.out.println("你输入的值是=" + num);
    }
}

throws异常处理

基本介绍
1)如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。

2)在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类

public void f2() throws FileNotFoundException,NullPointerException , ArithmeticException {
    // 1,这里的异常是一个FileNotFoundException 编译异常
    // 2.使用前面讲过的 try-catch-finally
    // 3.使用throws ,抛出异常,让调用f2方法的调用者(方法)处理
    // 4. throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类
    // 5. throws关键字后也可以是异常列表,即可以抛出多个异常
    FileInputStream fis = new FileInputStream( "d : //aa.txt");
}

注意事项和细节讨论

1)对于编译异常,程序中必须处理,比如try-catch或者throws

2)对于运行时异常,程序中如果没有处理,默认就是throws的方式处理

3)子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型

class Father {//父类
    public void method() throws RuntimeException {
    }
}

class Son extends Father {//子类
    // 3,子类重写父类的方法时,对抛出异常的规定:子类重写的方法,
    //所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常类型的子类型
    @Override
    public void method() throws NullPointerException {
    }
}

4)在throws 过程中,如果有方法 try-catch,就相当于处理异常,就可以不必throws

public static void f1() {
        //这里大家思考问题调用f3()报错
        // 1.因为f3() 方法抛出的是一个编译异常
        // 2.即这时,就要去f1()必须处理这个编译异常
        // 3.在f1()中,要么try-catch-finally,或者继续throws这个编译异常
        f3();// 抛出异常
    }


public static void f3() throws FileNotFoundException {
    FileInputStream fis = new FileInputStream("d: //aa.txt");
}

public static void f4() {
    //老韩解读:
    // 1. 在f4()中调用方法f5()是OK
    // 2.原因是f5()抛出的是运行异常
    // 3. 而java中,并不要求程序员显示处理,因为有默认处理机制f5();
}

public static void f5() throws ArithmeticException {
}

自定义异常

基本介绍

当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中推述处理,这个时候可以自己设计异常类,用于描述该错误信息。

1)定义类:自定义异常类名(程序员自己写)继承Exception或RuntimeException

2)如果继承Exception,属于编译异常

3)如果继承RuntimeException,属于运行异常(一般来说,继承RuntimeException)

public class Test {
    public static void main(String[] args) {
        int age = 180;
        //要求范围在18 - 120之间,否则抛出一个自定义异常
        if (!(age >= 18 && age <= 120)) {
            //这里我们可以通过构造器,设置信息
            throw new AgeException("年龄需要在18~120之间");
        }
        System.out.println("你的年龄范围正确.");
    }

}
// 1.一般情况下,我们自定义异常是继承 RuntimeException
// 2.即把自定义异常做成运行时异常,好处时,我们可以使用默认的处理机制
// 3.即比较方便
class AgeException extends RuntimeException {
    public AgeException(String message) {//构造器
        super(message);
    }
}

throw与throws的区别

意义

位置

后面跟的东西

throws

异常处理的一种方式

方法声明处

异常类型

throw

手动生成异常对象的关键字

方法体中

异常对象

常用类

包装类

八种包装类

1.针对八种基本数据类型相应的引用类型—包装类

2.有了类的特点,就可以调用类中的方法。

基本数据类型

包装类

boolean

Boolean

char

Character

byte

Byte

short

Short

int

lnteger

long

Long

float

Float

double

Double

java 隔几秒执行几次后停止_开发语言_13

包装类与基本数据类型的转换

装箱与拆箱

public class Test {
    public static void main(String[] args) {
        //jdk5之前是手动装箱和拆箱
        int n1 = 180;
        Integer integer = new Integer(n1);
        Integer integer1 = Integer.valueOf(n1);
        //手动拆箱
        //Integer -> int
        int i = integer.intValue();

        //jdk5后,就可以自动装箱和自动拆箱
        int n2 = 200;
        // 自动装箱int->Integer
        Integer integer2 = n2;//底层使用的是Integer.valueOf(n2)//自动拆箱Integer->int
        int n3 = integer2;//底层仍然使用的是 intValue()方法
    }
}
public class Test {
    public static void main(String[] args) {
        Object obj1 = true ? new Integer(1) : new Double(2.0);//三元运算符【是一个整体】一真大师
        System.out.println(obj1);//什么?1.0
        
        Object obj2;
        if (true)
            obj2 = new Integer(1);
        else
            obj2 = new Double(2.0);
        System.out.println(obj2);//输出什么?1 分别计算
    }
}、
public class Test {
    public static void main(String[] args) {
        //包装类(Integer)->String
        Integer i = 100;//自动装箱
        // 方式1
        String str1 = i + "";
        //方式2
        String str2 = i.toString();
        //方式3
        String str3 = String.valueOf(i);

        // String ->包装类(Integer)
        String str4 = "123456";
        Integer i1 = Integer.parseInt(str4);//自动装箱
        Integer i2 = new Integer(str4);
    }
}
包装类方法

1)构造方法和XXX.valueOf()都可以把基本数据类型变成包装类或者把字符串变成包装类(Chracter除外)

2)XXValue()可以把包装类转换成基本类型

3)DarseXXX(方法(Character除外)可以把字符串变回基本类型

4)toString()方法、String类的valueOf()和+””方法可以把基本类型转换成字符串

public class Test {
    public static void main(String[] args) {
        System.out.println(Integer.MIN_VALUE);//返回最小值
        System.out.println(Integer.MAX_VALUE);//返回最大值

        System.out.println(Character.isDigit('a'));//判断是不是数字
        System.out.println(Character.isLetter('a'));//判断是不是字母
        System.out.println(Character.isUpperCase('a'));//判断是不是大写
        System.out.println(Character.isLowerCase('a'));//判断是不是小写
        
        System.out.println(Character.isWhitespace('a'));//判断是不是空格
        System.out.println(Character.toUpperCase('a'));//转成大写
        System.out.println(Character.toLowerCase('A'));//转成小写
    }
}

源码例题:

public class Test {
    public static void main(String[] args) {
        Integer i = new Integer(1);Integer j = new Integer(1);
        System.out.println(i == j);//False

        //所以,这里主要是看范围-128~127就是直接返回
        Integer m = 1;//底层Integer.valueOf(1);->阅读源码
        Integer n = 1;//底层 Integer.valueOf(1);
        System.out.println(m == n); //True
        Integer.valueOf(1);
        //所以,这里主要是看范围-128~127就是直接返回
        //否则,就new Integer(ox);
        Integer x = 128;//底层
        Integer y = 128;
        System.out.println(x == y);//False

        /*Integer.valueOf(1)源码:
        //1.如果i 在 IntegerCache.low(-128)~IntegerCache.high(127),就直接从数组返回
        //2.如果不在-128~127,就直接,new
            public static Integer valueOf(int i) {
                if (i >= Integer.IntegerCache.low && i <= Integer.IntegerCache.high)//low=-128 high=127
                    return Integer.IntegerCache.cache[i + (-Integer.IntegerCache.low)];
                return new Integer(i);
            }
        */
    }
}
public class Test {
    public static void main(String[] args) {
        //有new肯定就是新的对象
        
        //示例一
        Integer i1 =new Integer( 127);
        Integer i2=new Integer( 127);
        System.out.println(i1==i2);//F

        // 示例二
        Integer i3=new Integer( 128 );
        Integer i4=new Integer( 128 );
        System.out.println(i3==i4);//F

        // 示例三
        Integer i5=127;//底层Integer.valueOf(127)
        Integer i6=127;//-128~127
        System.out.println(i5==i6); //T

        // 示例四
        Integer i7=128;
        Integer i8=128;
        System.out.println(i7==i8);//F

        // 示例五
        Integer i9=127; //Integer.valueOf(127)
        Integer i10=new Integer(127);
        System.out.println(i9==i10);//F

    }
}
public class Test {
    public static void main(String[] args) {
        //只有有基本数据类型,判断的是值是否相同
        //这是因为跟基本数据类型比较时,会自动拆箱

        //示例六
        Integer i11=127;
        int i12=127;
        System.out.println(i11==i12);

        //示例七
        Integer i13=128;
        int i14=128;
        System.out.println(i13==i14);
    }
}

String类

String类的理解与创建对象

1)String对象用于保存字符串,也就是一组字符序列

2)字符串常量对象是用双引号括起的字符序列。例如:“你好”、“12.97”、"boy"等

3)字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节。

4)String类较常用构造器(其它看手册):

String s1 = new String();
String s2 = new String(String original);
String s3 = new String(char[]a);
String s4 = new String(char[]a,int startIndex,int count);
String s5 = new String(byte[] b)//网络编程用得多

5)String类实现了接口 Serializable [String 可以串行化:可以在网络传输]
接口Comparable [String 对象可以比较大小]

java 隔几秒执行几次后停止_后端_14

6)String是final类,不能被其他的类继承

7)String有属性 private final char value[];用于存放字符串内容

8)一定要注意: value是一个final类型,不可以修改(需要功力):即value不能指向新的地址,但是单个字符内容是可以变化

final char[] value = { 'a', 'b','c'};
char[] v2 = { 't','o', 'm'};
value[0]= 'H';
//value = v2;不可以修改value地址
创建String对象的两种方式
String s = "hsp";//方式一:直接赋值
String s2 = new String("hsp");//方式二:调用构造器

1.方式一:先从常量池查看是否有"hsp”数据空间,如果有,直接指向;如果没有则重新创建,然后指向。S最终指向的是常量池的空间地址

2.方式二:先在堆中创建空间,里面维护了value属性,指向常量池的hsp空间。如果常量池没有"hsp",重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址。

3.两种方式的内存分布图

java 隔几秒执行几次后停止_后端_15

public class Test {
    public static void main(String[] args) {
        String a = "hsp"; //a指向常量池的“hsp"
        String b = new String("hsp");//b指向堆中对象
        System.out.println(a.equals(b));//T
        System.out.println(a == b);//F
        //b.intern()方法返回常量池地址
        System.out.println(a == b.intern()); //T
        System.out.println(b == b.intern());//F
//        知识点:
//        当调用intern方法时,如果池已经包含一个等于此 String对象的字符串(用equals(Object)方法确定),则返回池中的字符串。否则,将此String 对象添加到池中,并返回此 String对象的引用
//        老韩解读:(1) b.intern()方法最终返回的是常量池的地址(对象)﹒
    }
}

上课的例子,原理介绍图仅作参考

String str1 = "bdqn";
        String str2 = "bdqn" ;
        System.out.println(str1==str2);//ture
        System.out.println(str1.equals(str2));//ture
        String str3 = new String( "bdqn");
        System.out.println(str1==str3);//false
        System.out.println(str1.equals(str3));//ture
        String str4 = new String( "bdqn");
        System.out.println(str3==str4);//false
        System.out.println(str3.equals(str4));//ture

我们都知道,在运算符中“==”的结果比较的是地址,地址相同时为ture,不同为false

而字符串的equals()方法比较的是字符串的内容是否相同,相同时为ture,不同为false

然而在此例子当中当没有给String变量开辟空间时,如果其复制为常量,其地址时相同的(即st1与st2)

而当我们给String变量开辟空间后,哪怕其复制内容相同,但是地址也不同了。

其原理就是常量的地址时确定的,“=”只是进行一个指针的指向操作,并没有给其分配空间

其原理如下:

java 隔几秒执行几次后停止_java_16

String的特性

1)String是一个final类,代表不可变的字符序列

2)字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的.

String a = "hello"+"abc";
创建了几个对象?只有1个对象.
//String a = "hello"+"abc"; //==>优化等价 String a = "helloabc";
//分析:
//1.编译器不傻,做一个优化,判断创建的常量池对象,是否有引用指向
//2.String a = "hello"+"abc"; =》String a = "helloabc";
public class Test {
    public static void main(String[] args) {
        String a = "hello";//创建a对象
        String b = "abc ";//创建 b对象
        //老韩解读
        // 1.先创建一个StringBuilder sb = StringBuilder()
        // 2.执行sb.append("hello");
        // 3. sb.append("abc " );
        // 4. String c= sb.toString()
        // 最后其实是c指向堆中的对象(String) value[] -> 池中"helloabc"
        String c = a + b;
        String d = "helloabc";
        System.out.println(c == d);//false
        String e = "hello" + "abc";//直接看池,e指向常量池
        System.out.println(e == d);//true
    }
}

java 隔几秒执行几次后停止_后端_17

老韩小结:底层是StringBuilder sb = new StringBuilder(); sb.append(a);sb.append(b); sb是在堆中,并且append是在原来字符串的基础上追加的.

重要规则:

String c1 = “ab” + “cd”;常量相加,看的是池。

String c1 = a+b;变量相加,是在堆中

特性题

public class Test {
    String str = new String("hsp");
    final char[] ch = {'j', 'a', 'v', 'a'};

    public void change(String str, char ch[]) {
        str = "java";
        ch[0] = 'h';
    }

    public static void main(String[] args) {
        Test ex = new Test();
        ex.change(ex.str, ex.ch);
        System.out.print(ex.str + " and ");
        System.out.println(ex.ch);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S6RdfhTt-1636722245126)(http://www.gdx0326.top:20014/static/java笔记.assets/image-20211108164547521.png)]

String的常用方法

public int indexOf(int ch)

搜索第一个出现的字符ch,如果没有找到,返回-1

public int indexOf(String value)

搜索第一个出现的字符串value,如果没有找到,返回-1

public int lastIndexOf(int ch)

搜索最后一个出现的字符ch,如果没有找到,返回-1

public int lastIndexOf(String value)

搜索最后一个出现的字符串value,如果没有找到,返回-1

public String substring(int index)

提取从位置索引开始的字符串部分

public String substring(int beginindex,int endindex)

提取beginindex和endindex之间的字符串部分,[beginindex, endindex-1]

public String trim()

返回一个前后不含任何空格的调用字符串的副本

equalslgnoreCase()

忽略大小写的判断内容是否相等

charAt(int i)

获取i位置索引处的字符

public class Test {
    public static void main(String[] args) {
        // 1.toUpperCase转换成大写
        String s = "heLLo";
        System.out.println(s.toUpperCase());//HELLOl
        // 2.toLowerCase
        System.out.println(s.toLowerCase());//hello
        // 3.concat拼接字符串
        String s1 = "宝玉";
        s1 = s1.concat("林黛玉").concat("薛宝钗").concat("together");
        System.out.println(s1);//宝玉 林黛玉 薛宝钗 together
        // 4.replace替换字符串中的字符
        s1 = "宝玉 and 林黛玉林黛玉林黛玉";
        //在s1中,将所有的林黛玉替换成薛宝钗
        //解读:s1.replace()方法执行后,返回的结果才是替换过的
        // 注意对s1没有任何影响,这里是将返回结果重新赋值了
        s1 = s1.replace("林黛玉", "薛宝钗");
        System.out.println(s1);//宝玉 and 薛宝钗 薛宝钗 薛宝钗
        // 5.split分割字符串,对于某些分割字符,我们需要转义比如│\\等
        String poem = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";
        // 1.以","为标准对poem进行分割,、返回一个数组
        // 2.在对字符串进行分割时,如果有特殊字符,需要加入转义符/
        String[] split = poem.split(",");
//        poem = "E:\\aaa\\bbb";
//        split = poem.split("\\\\");
        for (int i = 0; i < split.length; i++) {
            System.out.println(split[i]);
        }
        // 6.toCharArray转换成字符数组
        s = "happy";
        char[] chs = s.toCharArray();
        for (int i = 0; i < chs.length; i++) {
            System.out.println(chs[i]);
        }
        //7.compareTo 比较两个字符串的大小,如果前者大,则返回正数,后者大,则返回负数,如果相等,返回0
        // (1)如果长度相同,并且每个字符也相同,就返回0
        // (2)如果长度相同或者不相同,但是在进行比较时,可以区分大小
        //  就返回if (c1 != c2) {
        //                return c1 - c2;
        //            }
        // (3)如果前面的部分都相同,就返回str1.len - str2.len
        String a = "jcck";
        String b = "jack";
        System.out.println(a.compareTo(b));//返回值是 'c' - 'a' = 2的值
        // 8.format格式字符串
        /*占位符有:
         * %S 字符串 %c 字符 %d 整型 %.2f 浮点型
         *
         */
        String name = "john";
        int age = 10;
        double score = 98.3 / 3;
        char gender = '男';
        String info = "我的姓名是:" + name + ",性别是" + age + ",成绩是" + score + "性别是" + gender + "。希望大家喜欢";
        System.out.println(info);
        // 1.%s , %d , %.2f %c称为占位符
        // 2.这些占位符由后面变量来替换
        // 3.%s 表示后面由字符串来替换
        // 4.%d是整数来替换
        // 5.%.2f 表示使用小数来替换,替换后,只会保留小数点两位,并且进行四舍五入的处理
        // 6.%c使用char类型来替换
        String formatStr = "我的姓名是%s 性别是%d 成绩是%.2f 性别是%c 希望大家喜欢";
        String info2 = String.format(formatStr, name, age, score, gender);
        System.out.println("info2" + info2);
    }
}

String类是保存字符串常量的。每次更新都需要重新开辟空间,效率较低,因此java设计者还提供了StringBuilder和StringBufer来增强String的功能,并提高效率。

String翻转题
public class Test {
    public static void main(String[] args) {
        //测试
        String str = "abcdef";
        System.out.println("===交换前===");
        try {
            System.out.println(str);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return;
        }
        str = reverse(str, 1, 58);
        System.out.println("===交换后===");
        System.out.println(str);

    }

    public static String reverse(String str, int start, int end) {
        if(!(str != null && start >= 0 && end > start && end < str.length())) {
            throw new RuntimeException("参数不正确");
        }
        char[] chars = str.toCharArray();
        char temp = ' ';
        for (int i = start, j = end; i < j; i++, j--) {
            temp = chars[i];
            chars[i] = chars[j];
            chars[j] = temp;
        }
        return new String(chars);
    }
}

StringBufer类

基本介绍

1)java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删。

2)很多方法与String相同,但StringBuffer是可变长度的。

3)StringBuffer是一个容器。

public class Test {
    public static void main(String[] args) {
        // 1.StringBuffer的直接父类是 AbstractStringBuilder
        // 2.StringBuffer实现了Serializable,即StringBuffer的对象可以串行化(序列化)
        // 3.在父类中 AbstractStringBuilder有属性 char[] value,不是final 该value 数组存放字符串内容,引出存放在堆中的
        // 4. StringBuffer是一个 final类,不能被继承
        // 5.因为StringBuffer字符内容是存在 char[] value,所以在变化(增加/删除)时不用每次都更换地址(即不是每次创建新对象),所以效率高于String
        StringBuffer stringBuffer = new StringBuffer();
    }
}
String Vs StringBuffer

1)String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低//private final char value[];

2)StringBuffer保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用更新地址,效率较高//char[] value;//这个放在堆.

StringBuffer构造器
public class Test {
    public static void main(String[] args) {

        //1.创建一个大小为16的 char[],用于存放字符内
        /*源码
            @HotSpotIntrinsicCandidate
            public StringBuffer() {
                super(16);
            }
        */
        StringBuffer stringBuffer = new StringBuffer();

        //2通过构造器指定char[]大小
        /*源码
            @HotSpotIntrinsicCandidate
            public StringBuffer(int capacity) {
                super(capacity);
            }
        */
        StringBuffer stringBuffer1 = new StringBuffer(100);

        //3.通过给一个String创建StringBuffer
        /*源码
            @HotSpotIntrinsicCandidate
            public StringBuffer(String str) {
                super(str);
            }

            AbstractStringBuilder(String str) {
                int length = str.length();
                int capacity = (length < Integer.MAX_VALUE - 16)
                        ? length + 16 : Integer.MAX_VALUE;
                final byte initCoder = str.coder();
                coder = initCoder;
                value = (initCoder == LATIN1)
                        ? new byte[capacity] : StringUTF16.newBytesFor(capacity);
                append(str);//将"hello"添加进去
            }
        */
        StringBuffer helld = new StringBuffer("hello");
    }
}
StringBuffer转换
public class Test {
    public static void main(String[] args) {
        //看String-->StringBuffer
        String str = "hello tom";
        //方式1 使用构造器
        // 注意:返回的才是StringBuffer对象,对str 本身没有影响
        StringBuffer stringBuffer = new StringBuffer(str);
        //方式2 使用的是append方法
        StringBuffer stringBuffer1 = new StringBuffer();
        stringBuffer1 = stringBuffer1.append(str);

        //看看 StringBuffer-->String
        StringBuffer stringBuffer3 = new StringBuffer();
        //方式1使用StringBuffer提供的toString方法
        String s = stringBuffer3.toString();
        //方式2:使用构造器来搞定
        String s1 = new String(stringBuffer3);

    }
}
StringBuffer方法

1)增append

2)delete(start,end)

3)改replace(start,end,string)//将start----end间的内容替换掉,不含end

4)查indexOf//查找子串在字符串第1次出现的索引,如果找不到返回-1

5)插insert

6)获取长度length

public class Test {
    public static void main(String[] args) {
        StringBuffer s = new StringBuffer("hello");
        //增
        s.append(',');// "hello, "
        s.append("张三丰");//"hello,张三丰"
        s.append("赵敏").append(100).append(true).append(10.5);
        ;//"hello,张三丰赵敏100true10.5
        System.out.println(s);
        //删
        /*
            删除索引为>=start &&<end 处的字符
            解读:删除11~14的字符
        */
        s.delete(11, 14);
        System.out.println(s);
        //改
        //使用周芷若替换索引9-11的字符[9,11]
        s.replace(9, 11, "周芷若");
        System.out.println(s);//"hello,张三丰周芷若true10.5"
        //查找指定的子中在字符串第一次出现的索引,如果找不到返回-1
        int indexOf = s.indexOf("张三丰");
        System.out.println(indexOf);//6
        //插
        // hello,张三丰周芷若true10.5
        //在索引为9的位置插入"赵敏",原来索引为9的内容自动后移
        s.insert(9, "赵敏");// hello,张三丰赵敏周芷若true10.5
        System.out.println(s);
        //长度
        System.out.println(s.length());//22
        System.out.println(s);
    }
}

StringBuilder

基本介绍

1)一个可变的字符序列。此类提供一个与StringBuffer兼容的API,但不保证同步(StringBuilder 不是线程安全)。该类被设计用作 StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer 要快。

2)在 StringBuilder上的主要操作是append和insert方法,可重载这些方法,以接受任意类型的数据。

StringBuilder的常用方法

StringBuilder和 StringBuffer均代表可变的字符序列,方法是一样的,所以使用和StringBuffer一样

public class Test {
    public static void main(String[] args) {
        // 1.StringBuilder继承AbstractStringBuilder 类
        // 2.实现了Serializable ,说明StringBuilder对象是可以串行化(对象可以网络传输,可以保存到文件)
        // 3.StringBuilder 是final类,不能被继承
        // 4.StringBuilder|对象字符序列仍然是存放在其父类AbstractStringBuilder的 char[] value;// 因此,字符序列是堆中
        // 5.StringBuilder的方法,没有做互斥的处理,即没有synchronized 关键字,因此在单线程的情况下使用StringBuilder
        StringBuilder stringBuilder = new StringBuilder();
    }
}

String、StringBuffer 和StringBuilder的比较

1)StringBuilder 和 StringBuffer非常类似,均代表可变的字符序列,而且方法也一样

2)String:不可变字符序列,效率低,但是复用率高。

3)StringBuffer:可变字符序列、效率较高(增删)、线程安全

4)StringBuilder:可变字符序列、效率最高、线程不安全

5)String使用注意说明:

string s=“a”;1/创建了一个字符串

s += “b”;//实际上原来的"a"字符串对象已经丢弃了,现在又产生了一个字符串s+“b”(也就是"ab”)。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能=>结论:如果我们对String 做大量修改,不要使用String

效率比较测试
public class Test {
    public static void main(String[] args) {
        long startTime = 0L;
        long endTime = 0L;
        StringBuffer buffer = new StringBuffer("");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 20000; i++) {//StringBuffer拼接20000次
            buffer.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuffer的执行时间:" + (endTime - startTime));//约4

        StringBuilder builder = new StringBuilder("");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 20000; i++) {//StringBuilder拼接20000次
            builder.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuilder的执行时间:" + (endTime - startTime));//约3


        String text = "";
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 20000; i++) {//String拼接20000
            text = text + i;
        }
        endTime = System.currentTimeMillis();
        System.out.println("String的执行时间:" + (endTime - startTime));//约226

    }
}

效率:StringBuilder > StringBuffer > String

选择方式的总结

使用的原则,结论:

1)如果字符串存在大量的修改操作,一般使用 StringBuffer 或StringBuilder

2)如果字符串存在大量的修改操作,并在单线程的情况,使用StringBuilder

3)如果字符串存在大量的修改操作,并在多线程的情况,使用 StringBuffer

4)如果我们字符串很少修改,被多个对象引用,使用String,比如配置信息等

StringBuilder的方法使用和 StringBuffer一样

Math类

基本介绍

Math类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。

1)abs绝对值

2)pow求幂

3)ceil向上取整

4)floor向下取整

5)round四舍五入

6)sqrt求开方

7)random求随机数//思考:
请写出获取a-b之间的一个随机整数,a,b均为整数?2-7

8)max求两个数的最大值

9)min求两个数的最小值

public class Test {
    public static void main(String[] args) {
        //看看Math常用的方法(静态方法)
        // 1.abs 绝对值
        int abs = Math.abs(8);
        System.out.println(abs);//8
        //2.pow求幂
        double pow = Math.pow(2, 4);
        System.out.println(pow);//16
        //3.ceil向上取整,返回>=该参数的最小整数(转成double)
        double ceil = Math.ceil(-3.0001);
        System.out.println(ceil);//-3
        //4.floor向下取整,返回<=该参数的最大整数(转成double)
        double floor = Math.floor(-4.999);
        System.out.println(floor);//-5
        //5.round 四舍五入 Math.floor(该参数+0.5)
        long round = Math.round(-5.001);
        System.out.println(round);
        //6.sqrt求开方
        double sqrt = Math.sqrt(9.0);
        System.out.println(sqrt);//3.0
        //7.random求随机数
        //random 返回的是 0<= x <1之间的一个随机小数
        //思考:请写出获取a-b之间的一个随机整数,a,b均为整数?比如a=2,b=7
        // 即返回一个数x 2 <= x < 7
        //Math.random() * (b-a)返回的就是 0<= 数 <= b-a
        //(int)(a)<= x <= (int)(a + Math.random() * (b-a +1))
        //(2)使用具体的数给小伙伴介绍 a = 2 b = 7
        //(int)(a + Math . random() * (b-a +1) ) = (int)( 2 + Math. random()*6)
        // Math.random()*6 返回的是 0 <= x < 6小数
        // 2 + Math.random()*6 返回的就是 2 <= x < 8 小数
        //(int)(2 + Math.random()*6) = 2 <= x <= 7
        // 3.公式就是(int)(a + Math.random() * (b-a +1))
        for (int i = 0; i < 10; i++) {
            int sum = (int) (2 + Math.random() * (7 - 2 + 1));
            System.out.println(sum);
        }
        //max , min返回最大值和最小值
        int min = Math.min(2, 9);
        int max = Math.max(45, 90);
        System.out.println("min=" + min);
        System.out.println("max=" + max);
    }
}

Arrays类

Arrays的常用方法

Arrays里面包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)。

1)toString返回数组的字符串形式y

2)sort 排序(自然排序和定制排序)

定制排序源码分析

java 隔几秒执行几次后停止_后端_18

import java.util.Arrays;
import java.util.Comparator;

public class Test {
    public static void main(String[] args) {
        Integer[] integer = {1, 2, 3};

        //直接使用Arrays.toString方法,显示数组
        System.out.println(Arrays.toString(integer));

        //演示sort方法的使用
        Integer arr[] = {1, -1, 7, 0, 89};
        //1.可以直接使用冒泡排序,也可以直接使用Arrays提供的sort方法排序
        //2.因为数组是引用类型,所以通过sort排序后,会直接影响到实参 arr
        //Arrays.sort(arr);//默认排序方法
        //3. sort重载的,也可以通过传入一个接口 Comparator 实现定制排序
        //4.调用定制排序时,传入两个参数(1)排序的数组arr (2)实现了Comparator接口的匿名内部类,要求实现compare方法
        //6.这里体现了接口编程的方式
        //源码分析
        //(1) Arrays.sort(arr, new Comparator<Integer>(){});
        //(2) 最终到了private static <T> void binarySort(T[] a, int lo, int hi, int start,
        //                                       Comparator<? super T> c) {
        //(3)执行到 binarySort方法的代码,会根据动态绑定机制c.compare()执行我们传入的匿名内部类的 compare方法
        //while (left < right) {
        //                int mid = (left + right) >>> 1;
        //                if (c.compare(pivot, a[mid]) < 0)
        //                    right = mid;
        //                else
        //                    left = mid + 1;
        //            }
        //(4)new Comparator<Integer>() {
        //            @Override
        //            public int compare(Integer o1, Integer o2) {
        //                return o2-o1;
        //            }
        //        }
        //(5) public int compare(Object o1,0bject o2)返回的值>0还是<0会影响整个排序结果
        //这就充分体现了接口编程+动态绑定+匿名内部类的综合使用
        //将来的底层框架和源码的使用方式,会非常常见
        Arrays.sort(arr, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
        System.out.println("排序后:" + Arrays.toString(arr));
    }
}
模拟定制排序
import java.util.Arrays;
import java.util.Comparator;

public class Test {
    public static void main(String[] args) {
        int[] arr = {1, -1, 8, 0, 20};
        //bubble01(arr);
        bubble02(arr, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;//return o2-o1;
            }
        });
        System.out.println("==排序后的情况==");
        System.out.println(Arrays.toString(arr));
    }


    //使用冒泡完成排序
    public static void bubble01(int[] arr) {
        int temp = 0;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                //从小到大
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

    //结合冒泡+定制
    public static void bubble02(int[] arr, Comparator<Integer> c) {
        int temp = 0;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                //从小到大
                //数组排序由 c.compare(arr[j],arr[j +1])返回的值决定
                if (c.compare(arr[j], arr[j + 1]) > 0) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

}
其他常见方法

3)binarySearch 通过二分搜索法进行查找,要求必须排好序

4)copyOf 数组元素的复制

5)fill 数组元素的填充

6)equals 比较两个数组元素内容是否完全一致

7)asList将一组值,转换成list

import java.util.Arrays;
import java.util.List;

public class Test {
    public static void main(String[] args) {
        Integer arr[] = {1, 2, 9, 123, 567};
        // binarySearch 通过二分搜索法进行查找,要求必须排好
        // 1.使用binarySearch二叉查找
        // 2.要求该数组是有序的。如果该数组是无序的,不能使用binarySearch
        // 3.如果数组中不存在该元素,就返回return -(low + 1);
        int index = Arrays.binarySearch(arr, 9);
        System.out.println("index=" + index);

        // copy0f数组元素的复制
        // 1.从 arr数组中,拷贝 arr.length 个元素到newArr数组中
        // 2.如果铂贝的长度 >arr.length 就在新数组的后面增加 null
        // 3.如果拷贝长度 <0 就抛出异常NegativeArraySizeException
        // 4.该方法的底层使用的是System.arraycopy();
        Integer[] newArr = Arrays.copyOf(arr, arr.length);
        System.out.println("==拷贝执行完毕后==");
        System.out.println(Arrays.toString(newArr));

        //fill 数组元素的填充
        //1.使用99去填充num数组,可以理解成是替换原理的元素
        Integer[] num = new Integer[]{9, 3, 2};
        System.out.println("==num数组填充后==");
        Arrays.fill(num, 99);
        System.out.println(Arrays.toString(num));

        //equals比较两个数组元素内容是否完全一致
        Integer[] arr2 = {1, 2, 90, 123};
        //1.如果arr 和 arr2数组的元素一样,则方法true;
        //2.如果不是完全一样,就返回false
        boolean equals = Arrays.equals(arr, arr2);
        System.out.println("equals=" + equals);

        //asList将一组值,转换成list
        // 1.asList方法,会将〔2,3,4,5,6,1)数据转成一个List集
        // 2.返回的 asList 编译类型 List(接口)
        // 3.asList 运行类型 java.util.Arrays$ArrayList,即是Arrays类的静态内部类
        //private static class ArrayList<E> extends AbstractList<E>
        //        implements RandomAccess, java.io.Serializable
        List asList = Arrays.asList(2, 3, 4, 5, 6, 1);
        System.out.println("asList=" + asList);
        System.out.println("asList的运行类型" + asList.getClass());

    }
}

System类

常见方法

1)exit 退出当前程序

2)arraycopy :复制数组元素,比较适合底层调用,一般使用Arrays.copyOf完成复制数组.

3)currentTimeMillens:返回当前时间距离1970-1-1的毫秒数

4)gc:运行垃圾回收机制System.gc();

import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        //exit退出当前程序
        System.out.println("ok1");
        // 1.exit(0)表示程序退出
        // 2.0表示一个状态,正常的状态
//        System.exit(0);
        System.out.println("ok2");

        //arraycopy :复制数组元素,比较适合底层调用,一般使用Arrays.copyOf完成复制数组.
        int[] src = {1, 2, 3};
        int[] dest = new int[3];//dest当前是{0,0,0}
        //1主要是搞清楚这五个参数的含义
        //2.
        // Params:
        // src:原数组 (src – the source array.)
        // srcPos:从原数组哪位置开始拷贝 (srcPos – starting position in the source array.)
        // dest:目标数组,即把源数组的数据拷贝到哪个数组(dest – the destination array.)
        // destPos:把源数组的数据拷贝到目标数组的哪个索引(destPos – starting position in the destination data.)
        // length:从源数组拷贝多少个数据到目标数组(length – the number of array elements to be copied.)
        System.arraycopy(src, 0, dest, 0, src.length);
        //int[] src={1,2,3};
        System.out.println("dest" + Arrays.toString(dest));//123

        //currentTimeMillens:返回当前时间距离1970-1-1的毫秒数
        System.out.println(System.currentTimeMillis());
    }
}

Biglnteger类和BigDecimal类

基本介绍

应用场景:
1)Biglnteger适合保存比较大的整型

public class Test {
    public static void main(String[] args) {

        //当我们编程中,需要处理很大的整数,long不够用
        //可以使用BigInteger的类来搞定
//        long l = 237887989797979998785788l;
//        System.out.println("l=" + l);
        BigInteger bigInteger = new BigInteger("237887989797979998785788");
        BigInteger bigInteger1 = new BigInteger("1002124244");
        System.out.println(bigInteger);
        // 1.在对BigInteger进行加减乘除的时候,需要使用对应的方法,不能直接进行 + – * /
        // 2.可以创建一个要操作的BigInteger然后进行相应操作
        BigInteger add = bigInteger.add(bigInteger1);
        System.out.println(add);//加
        BigInteger subtract = bigInteger.subtract(bigInteger1);
        System.out.println(subtract);//减
        BigInteger multiply = bigInteger.multiply(bigInteger1);
        System.out.println(multiply);//乘
        BigInteger divide = bigInteger.divide(bigInteger1);
        System.out.println(divide);//除
    }
}

2)BigDecimal适合保存精度更高的浮点型(小数)

import java.math.BigDecimal;

public class Test {
    public static void main(String[] args) {
        //当我们需要保存一个精度很高的数时,double 不够用
        //可以是 BigDecimal
//        double d = 1999.11111111111999999999999977788d;
//        System.out.println(d);
        BigDecimal bigDecimal = new BigDecimal("1999.11111111111999999999999977788");
        BigDecimal bigDecimal1 = new BigDecimal("1.1");
        System.out.println(bigDecimal);
        // 1.如果对 BigDecimal进行运算,比如加减乘除,需要使用对应的方法
        // 2.创建一个需要操作的 BigDecimal然后调用相应的方法即可

        System.out.println(bigDecimal.add(bigDecimal1));
        System.out.println(bigDecimal.subtract(bigDecimal1));
        System.out.println(bigDecimal.multiply(bigDecimal1));
        //System.out.println(bigDecimal.divide(bigDecimal1));//可能抛出异常ArithmeticException
        //在调用divide 方法时,指定精度即可,BigDecimal.ROUND_CEILIN
        //如果有无限循环小数,就会保留分子的精度
        System.out.println(bigDecimal.divide(bigDecimal1,BigDecimal.ROUND_CEILING));
    }
}

日期类

第一代日期类Date

1)Date:精确到毫秒,代表特定的瞬间

2)SimpleDateFormat:格式和解析日期的类SimpleDateFormat格式化和解析日期的具体类。它允许进行格式化(日期->文本)、解析(文本->日期)和规范化.

java 隔几秒执行几次后停止_后端_19

public class Test {
    public static void main(String[] args) {

        // 1.获取当前系统时间
        // 2.这里的Date类是在java.util包
        // 3.默认输出的日期格式是国外的方式,因此通常需要对格式进行转换
        Date d1 = new Date();
        System.out.println("当前日期=" + d1);

        Date d2 = new Date(9234567);//通过指定毫秒数得到时间
        System.out.println("d2" + d2);
        System.out.println(d1.getTime());//获取某个时间对应的毫秒数

        // 1。创建SimpleDateFormat对象,可以指定相应的格式
        // 2.这里的格式使用的字母是规定好,不能乱写
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日hh:mm:ss E");
        String format = sdf.format(d1); // format:将日期转换成指定格式的字符串
        System.out.println(format);
        //1。可以把一个格式化的String转成对应的Date
        //2.得到Date仍然在输出时,还是按照国外的形式,如果希望指定格式输出,需要转换
        //3.在把String -> Date ,使用的 sdf 格式需要和你给的String的格式一样,否则会抛出转换异
        String s = "1996年01月01日 10:20:30 星期一";
        try {
            Date parse = sdf.parse(s);
            System.out.println(parse);
        } catch (ParseException e) {
            e.printStackTrace();
        }

    }
}
第二代日期类Calendar

1)第二代日期类,主要就是Calendar类(日历)。

public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>{}

2)Calendar类是一个抽象类,它为特定瞬间与一组诸如YEAR、MONTH、DAY_OF MONTH、HOUR等日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。

import java.util.Calendar;

public class Test {
    public static void main(String[] args) {
        // 1.Calendar是一个抽象类,并且构造器是private
        // 2.可以通过getInstance()来获取实例
        // 3.提供大量的方法和字段提供给程序员
        // 4.Calendar没有提供对应的格式化的类,因此需要程序员自己组合来输出(灵活)
        //5,如果我们需要按照24小时进制来获取时间,Calendar.HOUR ==改成=> Calendar.HOUR_OF_DAY
        // Calendar
        Calendar c = Calendar.getInstance();//创建日历类对象//比较简单,自由
        System.out.println(c);

        //获取日历对象的某个日历字段
        System.out.println("年:" + c.get(Calendar.YEAR));
        //这里为什么要+1,因为Calendar返回月时候,是按照0开始编号
        System.out.println("月:" + (c.get(Calendar.MONTH) + 1));
        System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH));
        System.out.println("小时:" + c.get(Calendar.HOUR));
        System.out.println("分钟:" + c.get(Calendar.MINUTE));
        System.out.println("秒:" + c.get(Calendar.SECOND));
        //Calender 没有专门的格式化方法,所以需要程序员自己来组合显示
        System.out.println(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" + c.get(Calendar.DAY_OF_MONTH)
                + " " + c.get(Calendar.HOUR_OF_DAY) + ":" + c.get(Calendar.MINUTE) + ":" + c.get(Calendar.SECOND));
    }
}
第三代日期类LocalDateTime

前面两代日期类的不足分析
JDK 1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了。

而Calendar也存在问题是:
1)可变性:像日期和时间这样的类应该是不可变的。

2)偏移性:Date中的年份是从1900开始的,而月份都从0开始。

3)格式化:格式化只对Date有用,Calendar则不行。

4)此外,它们也不是线程安全的;

5)不能处理闰秒等(每隔2天,多出1s).

LocalDateTime常见方法

1)LocalDate(日期/年月日)、LocalTime(时间/时分秒)、LocalDateTime(日期时间/年月日时分秒) JDK8加入

LocalDate只包含日期,可以获取日期字段

localTime只包含时间,可以获取时间字段

LocalDateTime包含日期+时间,可以获取日期和时间字段

2)DateTimeFormatter格式日期类类似于SimpleDateFormat

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Test {
    public static void main(String[] args) {
        //第三代日期
        //1.使用now()返回表示当前日期时间的对象
        LocalDateTime ldt = LocalDateTime.now();//LocalDate.now();//LocalTime.now()
        System.out.println(ldt);
        System.out.println("年=" + ldt.getYear());
        System.out.println("月=" + ldt.getMonthValue());
        System.out.println("日=" + ldt.getDayOfMonth());
        System.out.println("时=" + ldt.getHour());
        System.out.println("分=" + ldt.getMinute());
        System.out.println("秒=" + ldt.getSecond());
        //2.使用DateTimeFormatter对象来进行格式化//创建DateTimeFormatter对象
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH小时mm分钟ss秒");
        String format = dateTimeFormatter.format(ldt);
        System.out.println(format);
    }
}

3)Instant时间戳类似于Date

提供了一系列和Date类转换的方式

import java.time.Instant;
import java.util.Date;

public class Test {
    public static void main(String[] args) {
        //1.通过静态方法now()获取表示当前时间戳的对象
        Instant now = Instant.now();
        System.out.println(now);
        //2.通过 from可以把Instant转成Date
        Date date = Date.from(now);
        //3.通过date的toInstant()可以把 date 转成Instant对象
        Instant instant = date.toInstant();
    }
}

4)第三代日期类更多方法·

LocalDateTime类

MonthDay类:检查重复事件

是否是闰年

增加日期的某个部分

使用plus方法测试增加时间的某个部分

使用minus方法测试查看一年前和一年后的日期

其他的方法,使用的时候,自己查看API使用即可

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Test {
    public static void main(String[] args) {
        //第三代日期
        //1.使用now()返回表示当前日期时间的对象
        LocalDateTime ldt = LocalDateTime.now();
        //2.使用DateTimeFormatter对象来进行格式化//创建DateTimeFormatter对象
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH小时mm分钟ss秒");
        //String format = dateTimeFormatter.format(ldt);
        
        //提供plus 和minus方法可以对当前时间进行加或者减
        //看看890天后,是什么时候把年月日-时分秒
        LocalDateTime localDateTime = ldt.plusDays(890);
        System.out.println("890天以后是"+dateTimeFormatter.format(localDateTime));

        //看看在 3456分钟前是什么时候,把年月日-时分秒输出
        LocalDateTime localDateTime2 = ldt.minusMinutes(3456);
        System.out.println("3456分钟前日期=" + dateTimeFormatter.format(localDateTime2));

    }
}