内部类
内部类是
Java
独有的一种语法结构,即在一个类的内部定义另一个类,此时,内部类就成为外部类
中的成员,访问权限遵循类成员的访问权限机制,可以是
public
、
protected、缺省和private
内部类可以很方便地访问外部类中的其它成员。它能帮我实现一些特殊的需要:
内部类可以很方便地访问外部类中的其它成员。它能帮我实现一些特殊的需要:
1.
完善多重继承
2. 形成闭包
什么时候使用内部类
:
当一个事物的内部
,
还有一个部分需要完整的结构去描述
,
而这个内部的完整结构又只为外部事物提供服务
,
那么整个内部的完成结构最好使用内部类
------
一个事物内部还有一个独立的事物
外部类的成员变量和内部类的成员变量以及内部类的局部变量重名时
,
怎么区分
?
System
.
out
.
println
(
name
);
//
内部类的局部变量
System
.
out
.
println
(
this
.
name
);
//
内部类的成员变量
System
.
out
.
println
(
Student
.
this
.
name
);
//外部类的成员变量
接口类型作为方法参数传递和返回
1.
接口作为方法参数
,
传递实参时
,
传递的是实现类对象
2.
接口作为返回值类型返回
,实际返回的是实现类对象
抽象类作为方法参数和返回值
1.
抽象类作为方法参数传递
,
传递实参时
,
传递的是其子类对象
2.
抽象类作为方法返回值类型返回时
,实际返回的是其子类对象
普通类做方法参数和返回值
普通类作为方法参数传递
,
传递的是对象
普通类作为方法返回值返回
,返回的是对象
匿名内部类
(
重点
)
所谓的匿名内部类
,可以理解为没有显式声明出类名的内部类
我们如果想实现接口
,
简单使用一次抽象方法
,
我们就需要创建一个实现类
,
实现这个接口
,
重写抽
象方法
,
还要
new
实现类对象
,
所以我们在想如果就单纯的想使用一次接口中的方法
,
我们能不能不这么麻烦呢
?
可以
1
.
创建实现类
,
实现接口
2
.
重写方法
3
.
创建实现类对象
4
.
调用方法
如果就想单纯的使用一下接口中的方法
,
我们就没必要经过以上四步了
,
我们可以四合一
格式
:
new
接口
/
抽象类
(){
重写方法
}.
重写的方法
();
=================================
类名 对象名
=
new
接口
/
抽象类
(){
重写方法
}
对象名
.
重写的方法
();
匿名内部类的好处:减少代码
匿名内部类的本质
1.
创建了一个类
,
这个类没有名字
,
局部内部类
2.
这个类实现了一个接口或继承了一个类
3.
创建了这个没有名字的类的对象
Lambda
表达式
(
重点
)
在
JDK8
中
Java
引入了动态语言或函数式语言中的
lambda
表达式
Lambda
表达式主要是替换了原有匿名内部类的写法,也就是简化了匿名内部类的写法。
lambda表达式本质上是一段匿名内部类,也可以是一段可以传递的代码
lambda
语法结构如下:
()
->
{}
各部分解释
:
() :
重写方法的参数位置
->
:
将参数传递到方法体中
{} :
重写方法的方法体
Lambda表达式使用前提
Lambda表达式使用前提
必须是函数式接口做方法参数传递
啥叫函数式接口
:
有且只有一个抽象方法的接口
,
用
@FunctionalInterface
去检测
Lambda 表达式省略规则
Lambda 表达式省略规则
L
ambda
表达式怎么写
a
.
观察是否是函数式接口做方法参数传递
b
.
如果是
,
考虑使用
Lambda
表达式
c
.
调用方法
,
以匿名内部类的形式传递实参
d
.
从
new
接口开始到重写方法的方法名结束
,
选中
,
删除
,
别忘记再删除一个右半个大括号
e
.
在重写方法的参数后面
,
方法体的大括号前面加上
->
省略规则 :
省略规则 :
a
.
重写方法的参数类型可以省略
b
.
如果重写方法只有一个参数
,
所在的小括号可以省略
c
.
如果方法体中只有一句话
,
那么所在的大括号以及分号可以省略
d
.
如果方法体中只有一句话并且带
return
的
,
那么所在的大括号
,
分号以及return 可以省略
示例
-
不需要参数
,
返回值为
5
: ()
->
5
-
接收一个参数
(
数字类型
),
返回其
2
倍的值:
x
->
2
*
x
-
接受
2
个参数
(
数字
),
并返回他们的差值:
(
x
,
y
)
->
x – y
-
接收
2
个
int
型整数
,
返回他们的和:
(
int
x
,
int
y
)
->
x
+
y
异常
概述
:
代码出现了不正常的现象
;
在
java
中
,
异常都是一个一个的类
异常处理方式
(
重点
)
格式
:
在方法参数和方法体之间位置上写
throws
异常
意义
:
处理异常
将异常往上抛
异常处理方式一
_throws
多个异常
1.
格式
:
throws
异常
1
,
异常
2
2.
注意
:
如果
throws
的多个异常之间有子父类继承关系
,
我们可以直接
throws
父类异常
如果不知道多个异常之间是否有子父类继承关系
,
我们可以直接
throws Exception
异常处理方式二
_try...catch
格式
:
try
{
可能出现异常的代码
}
catch
(
异常 对象名
){
处理异常的代码
->
将来开发会将异常信息保存到日志文件中
}
异常处理方式二
_
多个
catch
try
{
可能出现异常的代码
}
catch
(
异常 对象名
){
处理异常的代码
->
将来开发会将异常信息保存到日志文件中
}
catch
(
异常 对象名
){
处理异常的代码
->
将来开发会将异常信息保存到日志文件中
}
catch
(
异常 对象名
){
处理异常的代码
->
将来开发会将异常信息保存到日志文件中
}
catch
(
异常 对象名
){
处理异常的代码
->
将来开发会将异常信息保存到日志文件中
}...
注意
:
如果
catch
的多个异常之间有子父类继承关系
,
我们可以直接
catch
父类异常
如果不知道多个异常之间是否有子父类继承关系
,
我们也可以直接
catch Exception
finally 关键字
finally 关键字
概述
:
代表的是不管是否触发了异常
,
都会执行的代码块
特殊情况
:
如果之前执行了
System
.
exit
(
0
)
终止当前正在执行的
java
虚拟机
使用
:
都是配合
try
...
catch
使用
try
{
可能出现异常的代码
}
catch
(
异常 对象名
){
处理异常的代码
->
将来开发会将异常信息保存到日志文件中
}
finally
{
不管是否有异常
,
都会执行的代码
}
finally
的使用场景
:
1.
关闭资源
2.
原因
:
对象如果没有用了
,GC(
垃圾回收器
)
回收
,
用来回收堆内存中的垃圾
,
释放内存
,
但是有一
些对象
GC
回收不了
,
比如
:
连接对象
(Connection),IO
流对象
,Socket
对象
,
这些对象
GC
回收不了
,
就需
要我们自己手动回收
,
手动关闭
将来不能回收的对象
new
完之后
,
后续操作不管是否操作成功
,
是否有异常
,
我们都需要手动
关闭
,
此时我们就可以将关闭资源的代码放到
finally
中
抛异常时注意的事项
1.
如果父类中的方法抛了异常
,
那么子类重写之后要不要抛
?
可抛可不抛
2.
如果父类中的方法没有抛异常
,
那么子类重写之后要不要抛
?
不要抛
try_catch
和
throws的使用时机
1.
如果处理异常之后
,
还想让后续的代码正常执行
,
我们使用
try
...
catch
2.
如果方法之间是递进关系
(
调用
),
我们可以先
throws
,
但是到了最后需要用
try
...
catch做一个统一的异 常处理
1.
编译时期异常是必须要处理的
,
不处理爆红
,
没法往下写
a.throws
b.try...catch
2.
运行时期异常我们一般不处理
,
一旦出现运行时期异常
,
肯定是代码写的有问题
,
我们直接修改
代码细节就行啦
Object
类
概述
:
所有类的根类
(
父类
),
所有的类都会直接或者间接继承
Object类
Object 中的 toString
Object 中的 toString
Object
中的
toString
方法
:
返回该对象的字符串表示形式
public
String
toString
() {
return
getClass
().
getName
()
+
"@"
+
Integer
.
toHexString
(
hashCode
());
}
注意
:
a
.
如果没有重写
Object
中的
toString
方法
,
直接输出对象名会默认调用
Object
中的
toString
方法
,
直接
输出地址值
b
.
如果重写了
Object
中的
toString
方法
,
再输出地址值
,
重写没有意义
,
所以重写完
toString
之后
,
应该
返回对象的内容
总结
:
如果直接输出对象名不想输出地址值
,
就重写
Object
中的
toString
方法
Object
中的equals
概述
:
比较两个对象的地址值是否相等
public
boolean
equals
(
Object
obj
) {
return
(
this
==
obj
);
}
==
针对于基本数据类型来说
,
比较的是值
==
针对于引用数据类型来说
,
比较的是地址值
注意
:
a
.
如果没有重写
Object
中的
equals
方法
,
那么就会调用
Object
中的
equals
方法
,
比较对象的地址值
b
.
如果重写了
Object
中的
equals
方法
,
那么就会调用重写后的
equals
方法
,
应该比较对象的内容
经典接口
我们知道基本数据类型的数据(除
boolean
类型外)需要比较大小的话,之间使用比较运算符即
可,但是引用数据类型是不能直接使用比较运算符来比较大小的。那么,如何解决这个问题呢?
Java
给所有引用数据类型的大小比较,指定了一个标准接口,就是
java.lang.Comparable接口:
package
java
.
lang
;
public interface
Comparable
{
int
compareTo
(
Object
obj
);
}
那么我们想要使得我们某个类的对象可以比较大小,怎么做呢?步骤:
第一步:哪个类的对象要比较大小,哪个类就实现
java.lang.Comparable
接口,并重写方法
方法体就是你要如何比较当前对象和指定的另一个对象的大小
第二步:对象比较大小时,通过对象调用
compareTo
方法,根据方法的返回值决定谁大谁小。
this
对象(调用
compareTo
方法的对象)减 指定对象(传入
compareTo()
的参数对象)大于
0,
返回正整数
this
对象(调用
compareTo
方法的对象)减 指定对象(传入
compareTo()
的参数对象)小于
0
返回负整数
this
对象(调用
compareTo
方法的对象)减 指定对象(传入
compareTo()
的参数对象)等于
0
返回零
java.util.Comparator
java.util.Comparator
(
1
)如果一个类,没有实现
Comparable
接口,而这个类你又不方便修改(例如:一些第三方的
类,你只有
.class
文件,没有源文件),那么这样类的对象也要比较大小怎么办?
(
2
)如果一个类,实现了
Comparable
接口,也指定了两个对象的比较大小的规则,但是此时此刻
我不想按照它预定义的方法比较大小,但是我又不能随意修改,因为会影响其他地方的使用,怎么办?
JDK
在设计类库之初,也考虑到这种情况了,所以又增加了一个
java.util.Comparator
接口。
那么我们想要比较某个类的两个对象的大小,怎么做呢?步骤:
第一步:编写一个类,我们称之为比较器类型,实现
java.util.Comparator
接口,并重写方法
方法体就是你要如何指定的两个对象的大小
第二步:比较大小时,通过比较器类型的对象调用
compare()
方法,将要比较大小的两个对象作为
compare
方法的实参传入,根据方法的返回值决定谁大谁小。
o1
对象减
o2
大于
0
返回正整数
o1
对象减
o2
小于
0
返回负整数
o1
对象减
o2
等于
0
返回零