Java SE
2020-08-19 17:05:40 38 举报
AI智能生成
Java 基础最详笔记整理
作者其他创作
大纲/内容
Java SE
运算符与表达式
算术运算符
+
String类型,字符拼接
-
/
%
++
放在变量前
先自增在使用
放在变量后
先使用在自增
中间变量缓存机制
在java中,执行自增运算时,会为每一个自增操作分配一个临时变量,如果是前缀加(++i),就会“先自加1后赋值(给临时变量)”;如果是后缀加(i++),就会“先赋值(给临时变量)后自加1”。
运算最终使用的,并不是变量本身,而是被赋了值的临时变量。
--
关系运算符
==
!=
返回boolean值
逻辑运算符
&
与
&&
短路与
都要满足
|
或
||
短路或
!
非
最终返回值Boolean
赋值运算符
=
+=,-=,*=,/=,%=\t编译时会将右边的数据类型转换为左边的数据类型,然后再参与运算
三目运算符
位运算符
按位与 &
参与运算的数以补码的方式出现
通常用来对某些为清0或者保留某些位
按位或 |
只要对应的两个二进制位有一个为1时,结果就为1
求反运算 ~
左移
<<
二进制位全部左移,高位丢弃,低位补0
可能出现数据溢出
右移
>>
二进制位全部右移
右移时,符号位随同移动
正数,最高位补0
负数,符号位为1
>>>
无符号右移
忽略符号,空位都以0补齐
负数位移是 精度丢失
数据类型
基本数据类型
整型
byte
1字节
-128~127 -2^7~2^7
short
2字节
-2^15~2^15
int
4字节
整形默认
-2^31~2^31
long
8字节
-2^63~2^63
浮点型
float
单精度浮点
32位
使用:后面加F或f,如:3.2F
double
双精度浮点
浮点型默认
64位
存在问题
舍入误差
精度丢失
浮点数的存储方式
?
boolean
值
true
false
与其让数据类型不兼容,不存在相互转换
误区
容易误认为:true是1,false是0
char
2 字节
字符型
本质是保存在内存中的Unicode编码,保存的是16位无符号的整数
\\u 开头
后跟16进制
几个常用字符对应的Unicode编码
a: 97
A: 65
0: 48
取值范围:0~65535
数据类型的转换
自动转换(隐式转换)
小类型转为大类型
转换顺序
byte -> short -> int -> long -> float -> double
char 可以转换为 int,如:int = '中';
强制转换(显示转换)
大转小
存在数据溢出
不同数据类型的运算
两个不同数据类型的变量运算,首先,范围小的类型转为范围大的类型,运算结果和范围大的保持一致
byte,short,char 三种类型参与运算时,一律先转为int在计算
运算过程中避免数据溢出
引用数据类型
String
String 是不可变对象,本质是字符数组
数组不可变性
==
在引用类型中表示等号两边是否是同一个引用
字符串拼接
大量字符串拼接,效率低,会创建很多对象
对象的创建方式
类比数组的创建方式
= new String(); & = new String(\"a\");
存放在堆
= \"字符串\";
放在常量池
JDK 1.7 之前 在方法区
JDk 1.7 之后 放在堆
保存的对象是唯一存在的。
创建String直接量对象,先看改值是否存在,存在直接饮用,不存在则开辟空间用于存放
直接量
API结构
本身是 final
final对象的不可变性
extends
Object
implements
Serializable
序列化
Comparable<String>
CharSequence
常用方法
length
返回字符串长度
indexOf(int ch)
返回指定字符在这个字符串第一次出现的索引
subString
int beginIndex
从beginIndex开始,返回一个新的字符串
int beginIndex,int endIndex
返回一个从begin到end的子串
trim
去除字符串两边的空格
valueOf
根据指定参数类型返回相应类型的字符串表现形式
charAt
返回指定所引出的char值
回文算法
toUpperCase
全部转为大写
toLowerCase
小写
startWith
String prefix
判断是否以指定的字符串开始
测试此字符串从指定索引开始的子字符串是否以指定前缀开始
toCharArray
将此字符串转换为一个新的字符数组
StringBuilder
提供一个可变的数组
字符串的修改在数组中进行
不涉及对象的改变
字符序列是无线的
Java 中的字符串拼接是利用StringBuilder实现的
构造方法
无参
构造一个不带任何字符的字符串生成器
初始容量为:16字符
有参
构造方法中单数决定了初始容量以及初始化内容
参数为String
构造一个字符串生成器,并初始化为字符串内容
如:StringBuilder sb = new StringBuilder(\"abd\");
线程不安全,效率高
StringBuffer
与StringBuilder基本相同
线程安全
方法是被synchronized修饰,都是线程安全的方法
日期
Date
创建当前日期
getTime
获取时间(弃用)
Calendar
子类对象GregorianCalendar
getInstance
j静态方法
根据你所在时区,获取一个子类对象
get
getTimeInMillis
setTime
set
获取时间分量
YEAR
MONTH
DATE
DAY_OF_WEEK
SimpleDateFormat
日期类型转换
将指定字符串的日期表示转换为日期对象
format
Date --> String
parse
String --> Date
Java 中所有类的父类
方法
toString
结构:类名@散列码
散列码用于表示对象的地址
toString的重写
Java 提供的API几乎都是重写了toString方法
建议每个类都重写toString方便调试
equals
等同于 ==
两边都是基本类型,直接比较
两边都是引用类型,判断是否为同样引用
若还需要判断对象内容,需要重写
如:判断Person 是否为同一个
通常建议重写
hashCode
返回对象的哈希值
为了提高哈希表的性能
在同一次java应用程序执行期间,在对同一个对象多次调用hashcode方法时,必须返回相同的整数,前提是比较时equals信息没有被修改
若equals返回值为true,hashcode方法返回值一定相等
hashcode返回的值不是唯一的
若根据equals方法判定两个对象不相等,那么对象调用的hashcode方法不一定要求不同的整数结果,为不相等的对象生成不同整数结果可以提高哈希表的性能
wait
导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。
包装类
抽象类Number
Byte
Short
Integer
intValue
放回一个int类型值
返回一个Integer类型的值
对于-128~127范围内的数字进行缓存,该方法多次调用返回的是一个对象
parseInt
将字符串参数作为有符号的十进制整数进行解析
Long
Float
Double
parseDouble
放回一个新的double值,该值被初始化为用指定String表示的值,这与Double类的valueOf方法一样
Boolean
Character
自动拆箱与自动装箱
Java 5.0 以后提供了autoBoxing功能
依靠编译期预处理
集合
Collection
本身是个接口
Iterable 子接口
add
插入元素
addAll
contains
判断是否包含元素
isEmpty
判断集合是否为空
size
返回集合元素个数
toArray
集合转为数组
remove
clear
移除集合中所有元素
List
无序,可重复
Collection 子接口
ArrayList
动态数组
声明时没有确定数组容量
新建的是空数组
源码
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
添加元素时,才会分配空间
默认容量为 10
每次以 1.5 倍扩容
源码: int newCapacity = oldCapacity + (oldCapacity >> 1);
元素通过下标直接访问
线性表顺序结构
访问性能优于LinkedList
内存地址连续,便于查找
结构修改性能劣与LInkedList
内存地址不连续,修改时该指针即可
LinkedList
链表
采用双向链表的形式
结构修改性能优于ArrayList
访问性能劣于ArrayList
队列和栈的实现
Queue接口
子主题
循环遍历
普通for循环
效率低
可以使用下角标
增强for循环
for (Integer integer : List) { }
Stream
JDK 1.8 新特性
效率高
list.forEach(e -> System.out.print(e));
迭代器
get(int index)
获取指定下标对应的元素
将给定元素插入给定的位置,并将原位置的元素放回
添加元素
删除给定元素,并返回被删除的元素
数组转化为集合
Arrays.asList
返回的集合不能增删元素,否则会报错
对元素的修改会影响原数组的数组
Set
不可重复
HashSet
无序的,且顺序动态
HashMap实例支持
底层有HashMap实现
public HashSet() { map = new HashMap<>(); }
TreeSet
按照元素自然顺序进行排序
基于 TreeMap的NavigableSet实现
没有下标
equals方法放回为true时,不能重复添加
迭代
Map
用于保存具有映射关系的数据
key值唯一存在
HashMap
Map中的key的hashCode值经过散列算法,得到散列下标,不同的hashCode值得到的散列下标不能相同,否则会生成链表
降低了查询性能
为了降低链表出现的概率,需要对equals和hashCode进行重写
查询性能较好
内存结构
JDK1.8 之前
数组 + 链表
JDK 1.8
数组 + 链表 + 红黑树
当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间
创建时,未指定大小 默认为:16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
最大容量:1 << 30
static final int MAXIMUM_CAPACITY = 1 << 30;
装载因子
默认为:0.75f
static final float DEFAULT_LOAD_FACTOR = 0.75f;
当 HashMap 中元素数量超过 容量装载因子时,进行resize()操作
阙值
默认为:8
static final int TREEIFY_THRESHOLD = 8;
用来定义在哈希冲突的情况下,转变为红黑树的阈值
hash冲突
解决办法
1.开放定址法(线性探测再散列,二次探测再散列,伪随机探测再散列)
2.再哈希法
3.链地址法
4.建立一个公共溢出区
TreeMap
二叉树实现
散列存储
索引存储
LinkedHashMap
有序的Map
使用Map的Hash表和链表实现,可以预知迭代顺序
维护一个双向循环链表
此链表定义了迭代顺序,通常时存放元素的顺序
取出顺序与存放顺序一致
提供的方法
get(K)
根据Key获取Value
containsKey
判断某个key在Map中存在
hashcode
返回该引用的哈希值
Map的迭代
keySet
得到Map中的所有key的set集合
根据key拿到value
entrySet
得到Map中所有元素的Set集合
getKey
getValue
Iterator
接口
hasNext
Next
迭代过程中要删除元素,只能用iter的remove方法,不能用集合的remove方法。否则会报并发操作异常
文件
File
implement
Comparable
createNewFile
新建文件
没有该文件
创建成功 返回 true
已有该文件
返回false,创建失败
isFile
判断File对象是不是文件
判断文件内容长度
字节表示
exists
判断文件或目录是否存在
delete
删除该路径下的File对象
idDrectory
判断是否为文件夹
针对目录操作的方法
mkdir
新建目录
mkdirs
新建多级目录
删除目录
必须保证当前目录为空
listFile
列出路径下的所有子目录
获取功能的方法
getName
获取文件名
getAbsolutePath
获取绝对路径
getpath
获取相对路径
endWith
传入文件后缀名参数,判断文件名的后缀名是否相符
编码
定义: 将字符数据拆分为byte的过程叫编码
互联网和文件都是使用byte[8]来传输
字符数据在互联网(文件)传输时,必须拆分为byte进行传输
常见编码
ISO
不支持中文
GBK
1~2字节变长编码
英语:1 字节
中文:2 字节
UTF-8
1~4字节变长
英文:1字节
中文:不定
RandomAccessFile
Java 提供一个可以对文件随机访问的操作
该类的读写操作基于指针
IO流
按流向区分
输入流
InputStream
读入数据
接口,输入流的父类
输出流
OutStream
写出数据
输出流的父类
按读写单位区分
字节流
读写单位是字节
字符流
读写单位是字符
其他区分
节点流
低级流
处理流
高级流
节点流基础上的封装,添加了其他优化功能
具体流形式
文件流
FileInputStream
打开一个到实际文件的链接,创建一个FileInputStream,该文件通过文件系统中的File对象指定
FileOuputStream
创建一个向指定File 对象表示的文件中写入数据的文件输出流
FileOutputStream
write(int b)
write(byte [] b
close
若写入数据的文件不存在,输出流会自动创建
read()
read(byte [] b)
属于节点流
存在编码问题
缓冲流
BufferInputStream
内部维护缓冲区(byte数组),读取的内容填满缓冲区后才会一次性读入
BufferOutputStream
内部维护缓冲区,需要写出的内容填满缓冲区后才会一次性写出
数据处理流
实例化需要传入字节流作为参数
flush
清空缓冲区
对象流
ObjectInputStream
ObjectOutputStream
对象的序列化和反序列化
对象是存放在内存中的,如果我们需要将其存入硬盘或者是网络传输,则需要将其对象拆分为字节序列,这个过程叫做对象的序列化。反向流程称为反序列
对象要实现序列化与反序列化需要实现Serializable接口
Serializable接口只是一个标志接口,实现不需要重写任何方法和属性
SerialVersionUID
版本号决定了一个对象是否能反序列化成功
序列化和反序列化的版本不兼容时,会报版本不兼容异常
transient关键字
当一个属性被transient修饰时,该属性在进行序列化时会被忽略
当一个对象可以被序列化时,他的属性如果也是一个对象的话,那么该对象必须是可以被序列化的
应用
对象持久化到磁盘
对象的网络传输
读写单位是字符(char)
封装了字符的编码算法
在用字符读写数据时一定涉及到字符数据和字节数据的相互转换
字符只能操作文件数据,不能操作其他数据
字符流的底层依旧是字节流,本身属于处理流
Reader
字符输入了的父类
InputStreamReader
参数
相关节点
指定字符集
默认
关闭流
read
读取单个字符
将字符读入数组中的一部分
Writer
字符输出流的父类
OutputStreamWriter
使用该流,可以设置字符集,并按照指定的字符集将字符转换为相应字节后输出
相关节点流
刷新缓冲
writer
写入
缓冲字符流
内部维护了一个缓冲区,读写效率高
BufferedReader
提供了按行读取的方法
提供了自动刷新功能
readLine
读取一行数据
不断读取,直到读取到换行符
PrintWriter
BufferedWriter的封装类
内部自动调用BufferedWriter
提供自动刷新功能
(File/Strig file)
关闭流,先刷新
print
println
异常
传统异常
异常结构
Throwable
Java中所有异常和错误的Super类
Exception
文件损坏,设备错误,网络故障,用户非法输入等
分类
检测异常
在编译期编译器验证,强制执行处理或声明规则,否则不予通过
throws
抛出异常
子类抛出异常必须为父类抛出异常的一部分或父类抛出异常的子类异常
在定义方法时,在方法申明后面通过throws抛出,该方法不进行处理
thow
在方法体抛出的异常
若在方法体内抛出异常,程序执行到这步直接抛出,不在执行
try
需要进行处理的代码块
catch
catch可以指定多个,用于捕获不同的异常
建议最后一个捕获Exception
非检测异常
不遵循声明或处理规则,编译器不会检查是否解决了这样一个异常
RuntimeException属于非检测异常
IllegalArgumentException
NumberFormatException
数据类型转换异常
NullPointException
空指针
IndexOutOfBoundsException
索引超出范围
ClassCastException
当试图将对象强制转换为不是实例的子类时,抛出该异常
自定义异常
继承Exception/RuntimeException
自定义类中重写构造方法
Error
由运行环境问题造成的不可解决的问题
线程
线程和进程
进程
一个运行起来的程序称为一个进程
系统会为每个进程分配独立的空间
同一个进程中多个线程会共享进程的资源
一个线程是进程的一个执行流
当进程运行后,会立刻申请一个主线程或者首要线程
main方法就是一个主线程
同一个线程中,如果有多个任务(线程)同时执行,就称为线程的并发执行
并发并不是真正的同时执行
通过获得某一个时间片运行线程,多个线程之间快速的来回切换达到并发
线程的并发处理
CPU给每个线程动态的分配时间段来执行,这个时间段叫时间片
线程的生命周期
新建--NEW
新建一个线程
就绪--WAITING
此线程具备了时间片外的所有资源
运行--RUNNABLE
获取分配的时间片后开始运行
阻塞--BLOCKED
由运行状态被阻塞,暂停运行
死亡--TERMINATED
线程结束
线程的创建和使用
Java中的线程调度
Java中的线程调度是抢占式的
线程的创建
继承Thread类
重写run方法
任务和对象绑定,耦合度高
实现Runable接口
实现run方法
将任务作为参数出入Thread对象
任务和对象不绑定,耦合度低,利于调度
匿名内部类
资源加载一次的时候
线程的使用
start
将此线程加入任务调度
进入就绪状态
获取当前线程对象
Thread.currentThread()
sleep
线程休眠
使线程进入阻塞状态一段时间
不会释放锁
yield
线程礼让
是当前的线程让出让此CPU时间片,进入就绪状态
时间片不一定分配给需要的线程
join
协调多个线程的同步运行
同步和异步
同步
当个线程执行有先后顺序
异步
当个线程间执行没有先后顺序,各自独立运行
多个线程设计本身是异步运行的
根据业务逻辑的需要同步运行时需要的方法
getId
返回线程的唯一标识
获取线程名
命名线程
setName
构造线程时传参
isLive
判断线程是否处于活动状态
getPriority
返回线程的优先级
线程优先级
现成的切换由线程的调度控制,我们无法干涉,但是我们可以通过修改线程优先级来最大程度的改善其获得时间片的概率
线程的优先级分为10级,其中10最高
线程中的三个常量分别表示最高、最低和默认
MAX_PRIORITY
10
MIN_PRIORITY
1
NORM_PRIORITY
5
setPriority
设置线程优先级
守护线程(Daemon)又称后台线程
当进程中的前台线程结束时,无论守护线程是否在运行,都会立即结束
GC(垃圾回收器)是一个守护线程
setDaemon
参数为true时,该线程将被设置为一个后台线程
isDaemon
测试线程是否为守护线程
isInterrrupted
测试线程是否已经中断
线程同步
多个线程并发访问同一个资源可能出现安全问题,为了解决该问题,我们需要将异步执行改为同步执行
synchronize
锁机制
Java 提供了一个内置的锁机制来支持原子性
代用代码获得锁
结束调用释放锁
同步锁
同步方法
给调用方法的对象加锁
静态方法通过synchronize修饰后,该方法具有一定的同步效果
synchronize修饰静态方法时,添加锁的对象是一个Class对象,即当前类.class
同步代码块
synchronized
(同步监视器--锁对象的引用)
{ 代码块 }
多个需要同步的线程在访问该同步块时,看到的应该是同一个锁对象的引用。否则达不到效果
通常使用将来要调用该代码块的方法,this
有效缩小同步范围能够在保证安全的情况下提高并发执行效率
synchronize的互斥性
synchronized修饰多段代码或多个方法,但是他们的同步监视器对象是同一个时,这些代码间是互斥的。调用这些方法的多个线程不能同时执行,必须等待
我们可以通过synchronized来使非线程安全的API转为线程安全的
ArrayList、linkedList、HashSet都是非线程安全的,我们可以通过Collections.synchronizedXXX方法将它们转化为线程安全的
线程池
主要作用
控制线程数量(避免因为大量线程而导致的系统崩溃)
重用线程(避免频繁创建销毁线程)
原理
创建若干对象,他们的集合称为线程池
服务器接收请求后,现将任务交给线程池
线程池从线程池中取出一个闲置的线程为其服务,服务完毕,不关闭线程,而是重新还到线程池中
一个线程可以同时接纳多个任务
线程池的实现
创建线程池对象
Executor类
newFixedThreadPool(int nThreads);
创建固定大小的线程池
FixedThreadPool
线程数固定的线程池
CacheThreadPool
线程数根据任务动态调整线程池
SingleThreadExecutor
进单线程执行的线程池
返回ExecutorService接口的实例
将任务交给线程池
ExecutorService
execute(Runnable command)
线程池的关闭
shutdown
关闭线程池,执行以前提交的任务
不接受新任务
shutdownNow
关闭线程池,中断现在正在执行的任务,不再执行等待中的任务,并将等待中的任务作为集合返回
面向对象
封装
将对象的行为和数据封装为一个整体,并尽可能的隐藏对象的内部细节
行为公开化
属性私有化
类与对象
类
属性(变量)
成员变量/实例变量
定义在方法外部,类的内部
初始化时间
创建对象时,现在堆中开辟内存,此时成员变量默认初始化
属于对象的属性
初始值
基本类型,整型
0
浮点
0.0
\\u0000
引用类型
null
局部变量
定义在方法内
使用前必须初始化
生命周期
变量声明到方法结束
将一段具有特定功能的代码块封装,以便多次调用,提高代码复用率
结构
修饰符
访问控制修饰符
public
公共
protected
本类,同胞类即父子类
本类即同胞类
private
私有
通常用来修饰类的成员
成员变量
构造器
也可以修饰类
外部类只允许是public和默认
修饰内部类的时候参考类的成员
返回值类型
有返回值,必须先声明
没有返回void
方法名
驼峰命名法
参数列表
形参
实参
可变参数
...
参数名
方法体
返回一个当前类的对象
方法名与类一致
没有返回值
super
构造方法首行默认为super();
super.
类型
无惨构造
Java 默认提供
有参构造
一个类只能有一个无惨构造器,但是可以有多个有参构造器
概念
类是一类实例属性及行为的抽象
代码块
加载资源,作用类似构造器
static
static修饰的属性属于类的属性
不存放在堆中,存储在方法区
全类只有一份
使用
通过类名直接调用
修饰
static修饰的方法中不能使用关键字super,this
static修饰的方法不能调用非static方法
不能调用this,super关键字
修饰代码块
静态代码块
属于类的代码块
在类加载的期间执行,只执行一次
可用于在软件中加载静态资源
即初始化静态属性
修饰变量
final
修饰属性
不可被更改
常量
修饰方法
不可被重写
修饰类
不可被继承
static final
在编译期被替换
内部类
可以对外部类的所有成员进行访问
内部类中又有一个隐式的引用指向外部类对象
只服务于他所在的外部类
如果在一个程序中需要创建一个类对象(通常用于实现接口或者继承某个类),而且当该对象创建后,这个类就没有意义了,那么这个类就不必命名,称为匿名内部类
可以实现接口,继承内部类
匿名内部类的继承可以是普通类
常见方法
作为参数
如果一个方法的参数类型是接口或抽象类,将来传递参数时一定是一个子类或者实现类对象。而且只在这个位置使用,使用后失去意义
对象
类的实例
创建和使用
创建
new
反射
Class
newInstance
使用无惨的构造器创建对象
Constructor
调用有参的和私有的构造方法
clone
原型模式
访问行为
访问属性
Java 的内存管理
堆-heap
保存new出来的对象
当对象不被任何引用指向时,会被GC自动回收
和对象保持一致
Java GC机制
内存泄露
内存溢出
栈-stack
保存局部变量
执行方法时,java内存会为这个方法在栈中开辟一个空间,用于存放该方法中的所有变量,称为栈帧
栈帧及局部变量的声明周期
随着方法的执行结束,这个方法在栈中的栈帧也会随之销毁
方法区
方法区用来存放类的信息,java程序运行时,首先通过类装载器载入类文件的字节码信息,经过解析后将其装入方法区,类的各种信息(包括方法)都在方法区中存储
程序的整体执行过程
编译阶段
.class文件
执行阶段
加载.class文件至方法区
类的所有信息
执行程序
若执行方法,首先去方法区找到这个方法,然后执行
局部对象在栈中
对象在堆中
继承
java 中通过extends实现父子类继承
父类(超类)
将多个类之间共有的特性抽象出来封装成父类
子类(派生类)
子类继承父类的属性和方法,同时可以定义自己的属性和方法
JAVA 的继承特点
单继承
继承具有传递性
不继承的成员
可以共享
可以通过super() 共享父类的构造方法
super() 默认为构造器的第一行
私有属性及方法
静态成员
抽象 abstract
抽象方法
只声明,不实现
没有方法体
一个类中有抽象方法,那么一定是抽象类,反之抽象类不一定有抽象方法
抽象类
基于父类
为子类提供公共的类型
封装子类的重复内容
定义抽象方法
不可被实例化
有构造方法
不可与final修饰同一个类
若子类不是一个抽象类,那么继承抽象类,必须重现其抽象方法
接口 interface
一种特殊的抽象类
所有属性都是常量
所有方法都是抽象方法
接口的实现
需要重写其中的抽象方法
lambda表达式
可以多实现
多继承多实现
接口的继承可以是多继承
多态
行为多态
方法的重载与重写
重载
方法名相同,参数列表不同
遵循编译期绑定
重写
重写规则
方法的签名必须保持一致
方法的签名
返回类型要么保持一致,要么子类放回值类型是父类返回值类型的子类
修饰符要么保持一致,要么子类修饰符范围 > 父类修饰符范围
重载和重写完全没有关系
属性多态
一个类型的引用在指向不同的对象的时候有不同的实现
子类的向上造型
父类引用指向子类对象
自动转
父类向下造型
子类引用指向父类对象
强制转换
强制转型
前提是该类型指向的对象确实是该子类类型,不是该类型不可转换
可以通过强制转换将变量转换为某种接口类型,前提是引用指向的对象确实实现了该接口
instanceOf
类型判断
判断引用类型所指向的对象是否属于该类型
请点个赞❤ 鼓励创作
0 条评论
回复 删除
下一页