一、接口的新特性
1、JDK8 版本的接口新特性
(1)允许在接口中定义非抽象方法,但是需要使用关键字 default 修饰,这些方法就是默认方法
作用:解决接口升级的问题
接口中默认方法的定义格式:
格式:public default 返回值类型 方法名(参数列表) {}
示例:public default void show() {}
在实现类中调用接口的默认方法:
格式:接口名.super.方法名();
注意事项:
public可以省略,省略后仍是public权限,default不能省
实现类中可以重写默认方法,在实现类中需要去掉default关键字
若一个实现类实现了多个接口,多个接口有相同的默认方法,则实现类必须重写该默认方法
(2)允许在接口中定义静态方法
格式与类中的静态方法格式相同
注意事项:
public可以省略,static不能省略
接口中的静态方法只能通过接口名进行调用,不允许实现类通过对象进行调用
2、JDK9 版本的接口新特性
允许在接口中定义私有方法(可以是静态的)
便于接口中的非抽象方法进行调用
由于静态方法只能调用静态方法,所以私有方法可以是静态的
二、代码块
在Java类下,使用 { } 括起来的代码被称为代码块
1、局部代码块
位置:方法中定义
作用:限定变量的生命周期,及早释放,提高内存利用率
2、构造代码块
位置:类中方法外定义
特点:每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行
作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
3、静态代码块
位置:类中方法外定义
特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
作用:在类加载的时候做一些数据初始化的操作
public class BlockDemo {
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student(1);
}
}
class Student {
static String school;
static { // 静态代码块
school = "mySchool";
System.out.println("静态代码块...");
}
{ // 构造代码块
System.out.println("构造代码块...");
}
Student() {
System.out.println("Student类的空参构造");
}
Student(int n) {
System.out.println("Student类的带参构造");
}
}
输出:
静态代码块...
构造代码块...
Student类的空参构造
构造代码块...
Student类的带参构造
三、内部类
1、成员内部类
内部类就是定义在一个类里面的类
内部类中,访问外部类成员:直接访问,包括私有(若有重名,用外部类名.this.成员)
外部类中,访问内部类成员:需要创建对象访问
格式:外部类名.内部类名 对象名 = new 外部类对象().new 内部类对象();
public class InnerDemo {
public static void main(String[] args) {
Outer.Inner obj1 = new Outer().new Inner();
obj1.getN();
//obj1.getM(); 报错
obj1.getOuterMember();
obj1.getOuterN();
Outer obj2 = new Outer();
obj2.getInnerMember();
}
}
class Outer {
private int m = 1;
private int n = 10;
public void getM() {
System.out.println("Outer getM: m = " + m);
}
public void getInnerMember() {
System.out.println("Outer getInnerMember");
Inner inner = new Inner();
inner.getN();
}
class Inner {
public int n = 2;
public void getN() {
System.out.println("Inner getN: n = " + n);
}
public void getOuterMember() {
System.out.println("Inner getOuterMember");
getM();
m = 3;
getM();
}
public void getOuterN() {
System.out.println("Inner getOuterN Outer.n = " + Outer.this.n);
}
}
}
输出:
Inner getN: n = 2
Inner getOuterMember
Outer getM: m = 1
Outer getM: m = 3
Inner getOuterN Outer.n = 10
Outer getInnerMember
Inner getN: n = 2
2、静态内部类
有 static 修饰的成员内部类
格式:外部类名.内部类名 对象名 = new 外部类名.内部类对象();
范例:Outer.Inner in = new Outer.Inner();
注意:静态只能访问静态
在静态内部类中如果要访问外部类的非静态成员,需要创建外部类对象
3、局部内部类(不常用)
放在方法、代码块、构造器等执行体中的类
4、匿名内部类
概述:匿名内部类本质上是一个特殊的局部内部类(定义在方法内部)
前提:需要存在一个接口或类
格式:new 类名 / 接口名 () {}
new 类名表示继承这个类,new 接口名表示实现这个接口
匿名内部类可以使代码更加简洁,定义一个类的同时对其进行实例化
Tips:方法的形参是接口类型,应该传入这个接口的实现类对象
匿名内部类可以作为方法的实际参数进行传输
如果接口里的抽象方法较少,建议采用匿名内部类
如果接口里的抽象方法较多,建议传入实现类的对象
public class AnonClassDemo {
public static void main(String[] args) {
// 法一:采用匿名内部类
useInter(new Inter() {
@Override
public void show() {
System.out.println("匿名内部类");
}
});
// 法二:传入实现类的对象
Inter i = new InterImpl();
// 或者 InterImpl i = new InterImpl();
useInter(i);
}
public static void useInter(Inter i) {
i.show();
}
}
interface Inter {
void show();
}
class InterImpl implements Inter {
@Override
public void show() {
System.out.println("实现类");
}
}
输出:
匿名内部类
实现类
四、Lambda表达式
1、简介
Lambda表达式是 JDK8 开始后的一种新语法形式。
作用:简化匿名内部类的代码写法
快捷键:将光标移动到匿名内部类处,按 alt + enter,可以直接化简成 Lambda 表达式
(匿名内部类被重写方法的形参列表) -> {
被重写方法的方法体代码
}
useInter(() -> {
System.out.println("Lambda表达式");
})
Lambda 表达式只能简化函数式接口的匿名内部类的写法形式
函数式接口:接口中有且仅有一个抽象方法
通常在接口上加上一个 @FunctionalInterface 注解,标记该接口必须是满足函数式接口
2、Lambda表达式的省略写法
参数类型可以省略不写。
如果只有一个参数,参数类型可以省略,同时 () 也可以省略
如果Lambda表达式的方法体代码只有一行代码
可以省略大括号不写,同时要省略分号
此时,如果这行代码是return语句,必须省略return不写,同时也必须省略 ";" 不写
3、Lambda表达式和匿名内部类的区别
使用限制不同
匿名内部类 : 可以操作类, 接口
Lambda表达式 : 只能操作函数式接口
实现原理不同
匿名内部类:编译之后,产生一个单独的.class字节码文件
Lambda表达式:编译之后,没有一个单独的.class字节码文件
Tips:import java.util.* 表示导入 uitl 包里的所有的类(*是通配符)
五、窗体、组件、事件
1、窗体 JFrame
import javax.swing.*;
public class FrameDemo {
public static void main(String[] args) {
// 创建窗体对象
JFrame frame = new JFrame();
// 设置窗体标题
frame.setTitle("Frame Demo");
// 设置关闭模式,关闭窗体后停止Java程序
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 设置宽和高
frame.setSize(500, 500);
// 设置窗体可见,这一步放在最后
frame.setVisible(true);
}
}
2、组件
(1) JButton 按钮组件
添加组件:
窗体对象.setLayout(null); 取消默认布局
创建组件对象
组件对象.setBounds(x,y,width,height); 设置摆放位置
窗体对象.getContentPane().add(组件对象);
(2)JLabel 图片或文本组件
JLabel(String text) 使用指定的文本创建一个 JLabel 对象
JLabel(Icon image) 创建一个具有指定图像的 JLabel 对象
如果多个组件摆放在同一个位置,后添加的组件,会被压在底层
在写路径时,\ 要写成 \\
frame.setLayout(null);
JButton button = new JButton("Click Me");
button.setBounds(30, 30, 100, 30);
frame.add(button);
JLabel label = new JLabel("Hello World");
label.setBounds(30, 60, 100, 30);
frame.add(label);
JLabel png = new JLabel(new ImageIcon("D:\\..."));
png.setBounds(30, 90, 810, 875);
frame.add(png);
3、事件
ActionListener : 动作监听器 (鼠标点击, 空格按下)
KeyListener : 键盘监听器
焦点:程序的注意力集中在某一个组件上
一个按钮组件被创建后,焦点默认集中在按钮上
// 为按钮添加动作监听
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Clicked");
}
});
// 取消按钮的焦点
button.setFocusable(false);
// 添加键盘监听
frame.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
// 只能监听一部分按键
}
@Override
public void keyPressed(KeyEvent e) {
System.out.println("Key pressed: " + e.getKeyCode());
}
@Override
public void keyReleased(KeyEvent e) {
System.out.println("Key released: " + e.getKeyCode());
}
});
六、设计模式
1、概念
一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结
使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性
2、两个常用的设计模式
(1)适配器设计模式:解决接口与接口实现类之间的矛盾
接口实现类可能不需要实现接口中的所有抽象方法
实现步骤:
编写一个 xxxAdapter 类, 实现对应接口
重写内部所有抽象方法, 但方法都是空实现
让自己的类去继承适配器类, 重写自己需要的方法即可
为了避免其他类创建适配器类的对象, 使用 abstract 进行修饰
(2)模板设计模式:把抽象类整体就可以看做成一个模板
把模板中不能决定的东西定义成抽象方法
让使用模板的类(继承抽象类的类)去重写抽象方法实现需求
模板已经定义了通用结构,使用者只需要关心自己需要实现的功能即可