12_代码块,内部类,Lambda表达式,窗体的使用,设计模式

JAVA SE 代码块,内部类,Lambda表达式,窗体的使用,设计模式

代码块

在Java类下,使用 { } 括起来的代码被称为代码块

分类:局部代码块 构造代码块 静态代码块 同步代码块[多态]

  • 局部代码块

​ 位置:方法中定义
​ 作用:限定变量的生命周期,及早释放,提高内存利用率

  • 构造代码块

​ 位置:类中方法外定义
​ 特点:每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行
​ 作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性

  • 静态代码块

​ 位置:类中方法外定义
​ 特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
​ 作用:在类加载的时候做一些数据初始化的操作;加载配置文件

1
2
3
4
5
6
class Student {
static String school;
static {
school = "ABC";
}
}

内部类

内部类:定义在一个类里面的类

创建对象的格式

外部类名.内部类名 对象名 = new 外部类对象().new 内部类对象();

1
Outer.Inner in = new Outer().new Inner();

成员访问细节 :

  • 内部类中, 访问外部类成员 : 直接访问, 包括私有
  • 外部类中, 访问内部类成员 : 需要创建对象访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class InnerTest {
public static void main(String[] args) {
MyOuter.MyInner a = new MyOuter().new MyInner();
a.show();
}
}

class MyOuter {
int num = 10;
class MyInner {
int num = 20;
public void show(){
int num = 30;
System.out.println(num); // 30 输出内部类方法中定义的
System.out.println(this.num); // 20 输出内部类成员变量
System.out.println(MyOuter.this.num); // 10 输出外部类成员变量,指定this是MyOuter本类的
}

}

}

静态内部类 : static 修饰的成员内部类

​ 创建对象格式 : 外部类名.内部类名 对象名 = new 外部类名.内部类对象();

注意事项 : 静态只能访问静态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class StaticInnerTest {
public static void main(String[] args) {
Outer.InnerClass.A(); //静态可以通过类名调用
}
}

class Outer {
int num1 = 10;
static int num2 = 20;

static class InnerClass {
public static void A(){
Outer o = new Outer(); //非静态成员,需要先创建对象,才能调用
System.out.println(o.num1);
System.out.println(num2);
}
}
}

局部内部类: 放在方法、代码块、构造器等执行体中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class LocalClassTest {
public static void main(String[] args) {
A a = new A();
a.show();
}
}

class A {
public void show(){
class B {
public void method(){
System.out.println("B");
}
}
B b = new B(); //要调用方法中的类,需要先在该方法中创建对象,使用内部类要用的方法,最后在主函数中通过调用外部类的该方法才能使用,很麻烦,一般不会使用
b.method();
}
}

匿名内部类

概述 : 匿名内部类本质上是一个特殊的局部内部类(定义在方法内部),匿名内部类可以使代码更加简洁,定义一个类的同时对其进行实例化
前提 : 需要存在一个接口或类
格式 :
new 类名\接口名 () { }

1
2
3
new 类名(){}  :  代表继承这个类
new 接口名(){} : 代表实现这个接口
结论 : 可以让代码变得更加简洁, 在定义类的时候对其进行实例化

问题: 方法的形参是接口类型, 我们该传入的是什么?
: —–>传入的是该接口的实现类对象 要实现的方法多时,就实例化一个接口,方法少时就用匿名内部类**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class AnonClass {
public static void main(String[] args) {
useInter(new InterImpl());
useInter(new Inter(){ //匿名内部类作实现类对象
@Override
public void show() { //实现接口的方法
System.out.println("匿名内部类");
}
});
}
public static void useInter(Inter i){ // Inter i = new InterImpl(); 要传入一个实现类对象
i.show();
}
}

interface Inter {
void show();
}

Lambda表达式

Lambda表达式 : JDK8开始后的一种新语法形式

作用 : 简化匿名内部类的代码写法。
格式 : () -> {}

1
2
(匿名内部类被重写方法的形参列表) -> {   被重写方法的方法体代码。}
注:-> 是语法形式,无实际含义

注意:Lambda 表达式只能简化函数式接口的匿名内部类的写法形式

函数式接口
  • 必须是接口,接口中有且仅有一个抽象方法的形式
  • 通常会在接口上加上一个@FunctionalInterface注解,标记该接口必须是满足函数式接口。
1
2
3
4
5
6
7
8
9
10
11
12
@FunctionalInterface
interface Inter {
void cx();
}

//使用
useInter(new Inter() {
@Override
public void cx() {
System.out.println("cx");
}
});

IDEA简化成Lambda快捷键:alt+回车

Lambda表达式的省略写法

  • 参数类型可以省略不写。
  • 如果只有一个参数,参数类型可以省略,同时 () 也可以省略。
  • 如果Lambda表达式的方法体代码只有一行代码
    可以省略大括号不写,同时要省略分号
    此时,如果这行代码是return语句,必须省略return不写,同时也必须省略 “;” 不写
1
2
3
4
5
6
7
8
9
10
interface Calculator {
int calc(int a, int b);
}

Calculator方法:
int result = calculator.calc(10, 20);
System.out.println(result);

Lambda表达实现:
Calculator((a, b) -> a - b);

匿名内部类&Lambda

  • 使用限制不同

匿名内部类 : 可以操作类, 接口
Lambda表达式 : 只能操作函数式接口

  • 实现原理不同

匿名内部类:编译之后,产生一个单独的.class字节码文件
Lambda表达式:编译之后,没有一个单独的.class字节码文件

1
2
3
4
5
6
7
8
9
10
11
use(new A() {
@Override
public void method() {
System.out.println("匿名内部类");
}
});

use(() -> {
System.out.println("Lambda");
});
});

窗体、组件、事件

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
// 创建窗体对象
JFrame frame = new JFrame();
// 设置窗体大小 单位:像素
frame.setSize(500, 800);
// 修改窗体的关闭模式
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// 设置窗体标题
frame.setTitle("窗体");
// 设置窗体可见
frame.setVisible(true);
}

组件的添加

  1. 窗体对象.setLayout(null); 取消默认布局

  2. 创建组件对象

  3. 组件对象.setBounds(x,y,width,height); 设置摆放位置

  4. 窗体对象.getContentPane().add(组件对象);

    如果相同位置,先来的会显示,优先级高,后设置的被覆盖;

    窗体中添加按钮组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
JButton构造方法 :
1. public JButton() : 创建一个空白的按钮
2. public JButton(String text) : 创建一个带文本的按钮
注: 如果取消窗体的默认布局, 需要手动指定组件的摆放位置

public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(500,500);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLayout(null); // 取消窗体默认布局

JButton btn = new JButton("Hello World"); // 1. 创建按钮对象
btn.setBounds(60,60,100,100); // 设置按钮位置 大小

frame.getContentPane().add(btn); // 2. 将按钮添加到窗体的面板对象中
frame.setVisible(true);
}
使用JLabel展示文本和图片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 JLabel构造方法 :
JLabel(String text) 使用指定的文本创建一个 JLabel 对象
JLabel(Icon image) 创建一个具有指定图像的 JLabel 对象

public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(500,500);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLayout(null);

JLabel jl = new JLabel("你好"); // JLabel展示文本
jl.setBounds(50,50,100,100);
frame.getContentPane().add(jl);

JLabel imgLabel = new JLabel(new ImageIcon("<图片位置>")); // JLabel展示图片
imgLabel.setBounds(50, 150, 100,100);
frame.getContentPane().add(imgLabel);

frame.setVisible(true);
}

监听器的使用

动作事件 : ActionListener
  • 鼠标点击

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    JButton btn = new JButton("按钮"); 	 //按钮点击事件
    btn.setBounds(0,0,100,100);
    frame.getContentPane().add(btn);

    btn.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
    System.out.println("按钮被点击了");
    }
    });
  • 空格按键

    通过打印e.getKeyCode()的值,快速获取需要的按键代码数值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    frame.addKeyListener(new KeyListener() {
    @Override
    public void keyTyped(KeyEvent e) {
    //无法监听:fn,ctrl,esc,上下左右 很少用
    }

    @Override
    public void keyPressed(KeyEvent e) { //点击事件
    int keyCode = e.getKeyCode();
    if(keyCode == 37) {
    System.out.println("左");
    }else if(keyCode == 38){
    System.out.println("上");
    }else if(keyCode == 39){
    System.out.println("右");
    }else if(keyCode == 40){
    System.out.println("下");
    }
    }

    //适配器模式
    frame.addKeyListener(new KeyAdapter() {
    @Override
    public void keyPressed(KeyEvent e) {
    System.out.println("键盘");
    } //只需要重写这一个方法
    });


    @Override
    public void keyReleased(KeyEvent e) { //松开事件
    }
    });
焦点: 程序的注意力集中在了某一个组件上

注: 按钮组件比较特殊, 在创建好之后, 程序的焦点, 默认就在按钮组件上

但按钮组件, 其实不需要占用程序的焦点,通过setFocusable(false); 取消焦点;

1
btn.setFocusable(false);

否则:监听点击按钮事件和键盘点击事件同时设置后,焦点在按钮上,操作键盘会显示按钮事件发生,自己的键盘事件无法使用。

设计模式

设计模式(Design pattern):一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
目的:使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。

适配器设计模式:解决接口与接口实现类之间的矛盾问题

实现步骤
  1. 编写一个 xxxAdapter 类, 实现对应接口
  2. 重写内部所有抽象方法, 但方法都是空实现
  3. 让自己的类去继承适配器类, 重写自己需要的方法即可
  4. 为了避免其他类创建适配器类的对象, 使用 abstract 进行修饰
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
interface Inter {
void A();
void B();
void C();
}

abstract class A_Adapter implements Inter {

@Override
public void A() {
}

@Override
public void B() {
}

@Override
public void C() {
}

}

class NeedC extends A_Adapter {
@Override
public void C() {
System.out.println("只需要重写所需的这个方法");
}
}

模板设计模式:把抽象类整体看做成一个模板,模板中不能决定的东西定义成抽象方法

让使用模板的类(继承抽象类的类)去重写抽象方法实现需求

目的:模板设计模式的优势,模板已经定义了通用结构,使用者只需要关心自己需要实现的功能即可

1
2
3
4
5
6
7
8
9
10
public abstract class Template {

public final void write() { //final修饰,防止子类修改
System.out.println("模板头部固定代码");
body();
System.out.println("模板尾部固定代码");
}

public abstract void body(); //中间设置为抽象方法,供子类实现
}
1
2
3
4
5
6
7
8
9
10
public class Happy extends Template {
@Override
public void body() {
System.out.println("模板中要实现的代码");
}
}

使用:
Happy happy = new Happy();
happy.write();

12_代码块,内部类,Lambda表达式,窗体的使用,设计模式
http://example.com/2023/02/14/JavaSE学习笔记-代码块,内部类,Lambda表达式,窗体的使用,设计模式/
作者
zhanghao
发布于
2023年2月14日
许可协议