Java面向对象高级

一、JDK8 和 JDK9 接口新特性

1. JDK8 接口新特性

a. 允许在接口中定义非抽象方法,但是需要使用关键字 default 修饰,这些方法就是默认方法

作用: 解决接口升级的问题;需要在接口中添加新的方法时可以不用修改所有的实现类。

接口中默认方法的定义格式:

  • 格式:public default 返回值类型 方法名(参数列表) { }
  • 范例:public default void show( ) { }

注意事项:

  • 默认方法不是抽象方法,所以不强制被重写(但是可以被重写,重写的时候去掉 default 关键字)
  • public 可以省略,default 不能省略
  • 如果实现了多个接口,多个接口中存在相同的方法声明,子类就必须对该方法进行重写

b. 允许在接口中定义 static 静态方法

接口中静态方法的定义格式:

  • 格式:public static 返回值类型 方法名(参数列表) { }
  • 范例:public static void show( ) { }

注意事项:

  • 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
  • public 可以省略,static 不能省略

2. JDK9 接口新特性

接口中允许定义 private 私有方法

接口中私有方法的定义格式:

  • 格式1:private 返回值类型 方法名(参数列表) { }
  • 范例1:private void show( ) { }
  • 格式2:private static 返回值类型 方法名(参数列表) { }
  • 范例2:private static void method( ) { }

例如:

interface Inter {
    public default void start() {
        System.out.println("start...");
        System.out.println("日志记录");
    }

    public default void end() {
        System.out.println("end...");
        System.out.println("日志记录");
    }
}

该接口的两个默认方法中存在逻辑相同的代码,可以将其抽取出来作为接口的私有方法:

interface Inter {
    public default void start() {
        System.out.println("start...");
        log();
    }

    public default void end() {
        System.out.println("end...");
        log();
    }

    private void log() {
        System.out.println("日志记录");
    }
}

作用:提升复用性,减少冗余代码

二、代码块

使用 { } 括起来的代码被称为代码块

  • 局部代码块
    位置:方法中定义
    作用:限定变量的生命周期,及早释放,提高内存利用率
  • 构造代码块
    位置:类中方法外定义
    特点:每次构造方法执行的时候,都会执行该代码块中的代码,并且在构造方法执行前执行
    作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
  • 静态代码块
    位置:类中方法外定义
    特点:需要通过 static 关键字修饰,随着类的加载而加载,并且只执行一次
    作用:在类加载的时候做一些数据初始化的操作
  • 同步代码块

三、内部类

1. 成员内部类

成员内部类就是定义在一个类里面的类:

class Outer {
	//内部类
    class Inner {    
    }
}

创建对象的格式:

  • 格式:外部类名.内部类名 对象名 = new 外部类对象( ).new 内部类对象( );
  • 范例:Outer.Inner oi = new Outer( ).new Inner( );

内部类成员访问:

  • 内部类中,访问外部类成员:直接访问,包括私有类型成员
  • 外部类中,访问内部类成员:需要先创建内部类对象再访问

例如:

public class Outer {
    Inner i = new Inner();
    
    private void method() {//私有类型方法内部类仍可以直接访问
        System.out.println("method...");
        System.out.println(i.num);//外部类中访问内部类成员--->先创建对象再访问
    }
    class Inner {
        int num = 10;

        public void show() {
            System.out.println("show...");
            method();//内部类中访问外部类成员--->直接访问
        }
    }
}

测试类:

public class InnerDemo {
    public static void main(String[] args) {
        Outer.Inner oi = new Outer().new Inner();
        System.out.println(oi.num);
        oi.show();
    }
}

运行结果为:

10
show...
method...
10

注意:在成员内部类中访问所在外部类对象,格式:外部类名.this

class Outer {
    int num = 10;

    class Inner {
        int num = 20;

        public void show() {
            int num = 30;
            System.out.println(num); //30
            System.out.println(this.num); //20
            System.out.println(Outer.this.num); //10
        }
    }
}

2. 静态内部类

有 static 修饰的成员内部类:

class Outer {
    static class Inner {
    }
}

静态内部类创建对象的格式:

  • 格式:外部类名.内部类名 对象名 = new 外部类名.内部类对象( );
  • 范例:Outer.Inner oi = new Outer.Inner( );

例如:

class OuterClass {

    static class InnerClass {
        public void show() {
            System.out.println("show...");
        }
    }
}

测试类:

public class StaticInnerDemo {
    public static void main(String[] args) {
        OuterClass.InnerClass oi = new OuterClass.InnerClass();
        oi.show();//运行结果为show...
    }
}

如果 show 方法是静态方法,则可以通过类名一级一级调用:

public class StaticInnerDemo {
    public static void main(String[] args) {
        OuterClass.InnerClass.show();
    }
}

class OuterClass {

    static class InnerClass {
        public static void show() {
            System.out.println("show...");
        }
    }
}

注意:静态只能访问静态

3. 局部内部类

放在方法、代码块、构造器等执行体中,用处不是很大,在这边就不再叙述了。

4. 匿名内部类

概述: 匿名内部类本质上是一个特殊的局部内部类(定义在方法内部)。

前提: 需要存在一个接口或类

格式:

  • new 类名( ) { }:代表继承这个类
  • new 接口名( ) { }:代表实现这个接口

作用: 匿名内部类可以使代码更加简洁,定义一个类的同时对其进行实例化。

使用总结: 匿名内部类可以作为方法的实际参数进行传输。

如果一个方法的形参是接口类型,应该传入的是该接口的实现类对象:

  • 若该接口的抽象方法只有1个或很少,则可以通过匿名内部类来作为参数进行传输:
public class AnonClassDemo {
    public static void main(String[] args) {
    	//通过匿名内部类进行参数传输
        useInter(new Inter() {
            @Override
            public void show() {
                System.out.println("show...");
            }
        });
    }
    //方法的形参是接口类型
    public static void useInter(Inter i) {
        i.show();
    }
}
//接口的抽象方法只有1个
interface Inter {
    void show();
}
  • 若该接口的抽象方法较多,则可以通过实现类来进行参数传递:
public class AnonClassDemo {
    public static void main(String[] args) {
        useInter(new InterImpl());//相当于 Inter i = new InterImpl();
    }

    public static void useInter(Inter i) {
        i.show1();
        i.show2();
        i.show3();
    }
}

interface Inter {
    void show1();
    void show2();
    void show3();
}
//实现类重写所有的抽象方法
class InterImpl implements Inter {
    @Override
    public void show1() {
        System.out.println("show1...");
    }

    @Override
    public void show2() {
        System.out.println("show2...");
    }

    @Override
    public void show3() {
        System.out.println("show3...");
    }
}

四、Lambda 表达式

1. Lambda 概述

  • Lambda 表达式是 JDK8 开始后的一种新语法形式
  • 作用:简化匿名内部类的代码写法
  • Lambda 表达式的简化格式:
    ()-> { }
    (匿名内部类被重写方法的形参列表)-> {被重写方法的方法体代码}
  • Lambda 表达式只能简化函数式接口的匿名内部类的写法形式
  • 什么是函数式接口
    首先必须是接口、其次接口中有且仅有一个抽象方法的形式
    通常我们会在接口上加上一个@FunctionalInterface 注解,标记该接口必须是满足函数式接口

以上述匿名内部类的代码为例进行 Lambda 表达式的简化:

public class LambdaDemo01 {
    public static void main(String[] args) {
        useInter(() ->{
            System.out.println("show...");
        });
    }

    public static void useInter(Inter i) {
        i.show();
    }
}

interface Inter {
    void show();
}

2. Lambda 表达式的省略写法

  • 参数类型可以省略不写。
  • 如果只有一个参数,参数类型可以省略,同时()也可以省略。
  • 如果 Lambda 表达式的方法体代码只有一行代码
    可以省略大括号不写,同时要省略分号
    此时,如果这行代码是 return 语句,必须省略 return 不写,同时也必须省略 " ; "不写

3. Lambda 表达式和匿名内部类的区别

使用限制不同

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

实现原理不同

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

五、窗体、组件、事件

1. 窗体对象 JFrame

import javax.swing.*;

public class FrameTest {
    public static void main(String[] args) {
        //创建窗体对象
        JFrame frame = new JFrame();

        //设置宽和高
        frame.setSize(514,595);

        //设置关闭模式
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        //设置窗体标题
        frame.setTitle("窗体");

        //设置窗体可见,一般位于代码的最后
        frame.setVisible(true);
    }
}

2. 按钮组件 JButton

import javax.swing.*;
/*
    JButton构造方法:
        1. public JButton():创建一个空白的按钮
        2. public JButton(String text):创建一个带文本的按钮

  注意:窗体默认给组件布局设置为充满窗体,如果取消了窗体的默认布局,就需要手动指定组件的摆放位置
 */
public class ButtonTest {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(500,500);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        //取消窗体默认布局
        frame.setLayout(null);

        //1. 创建按钮对象
        JButton btn = new JButton("点我呀~");
        //2. 手动指定组件摆放位置
        btn.setBounds(50,50,100,100);
        //3. 将按钮添加到窗体的 [面板对象] 中
        frame.getContentPane().add(btn);

        frame.setVisible(true);
    }
}

3. JLabel 组件展示文本和图片

import javax.swing.*;
/*
    JLabel构造方法:
        1. JLabel(String text) 使用指定的文本创建一个 JLabel 对象
        2. JLabel(Icon image) 创建一个具有指定图像的 JLabel 对象
 */
public class LabelTest {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(800,500);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLayout(null);

        //创建一个 JLabel 对象用于展示文本
        JLabel jl1 = new JLabel("你好!");
        jl1.setBounds(50,50,100,100);
        frame.getContentPane().add(jl1);
        
        创建一个 JLabel 对象用于展示图片
        JLabel jl2 = new JLabel(new ImageIcon("E:\\image\\1.jpeg"));//图片路径
        jl2.setBounds(150,50,500,281);
        frame.getContentPane().add(jl2);

        frame.setVisible(true);
    }
}

4. 事件监听

动作监听器:ActionListener

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/*
    动作事件:ActionListener

    通过  1.鼠标点击 2.空格按键  触发
 */

public class ActionListenerTest {
    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("按钮");
        btn.setBounds(0,0,100,100);
        frame.getContentPane().add(btn);

        /*
            给该按钮组件创建一个动作事件
            该添加方法的形参是一个接口,所以使用匿名内部类来进行参数传递
         */
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("我被点了!!!");
            }
        });

        frame.setVisible(true);
    }
}

键盘监听器:KeyListener

import javax.swing.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

/*
    键盘事件:KeyListener

    敲击键盘任意键位触发
 */

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

        frame.addKeyListener(new KeyListener() {

            //只能监听到键盘的一部分按键,该方法不常用
            @Override
            public void keyTyped(KeyEvent e) {

            }

            //按下某个键时调用此方法
            @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 {
                    System.out.println("下移动业务代码");
                }
            }

            //释放某个键时调用此方法
            @Override
            public void keyReleased(KeyEvent e) {

            }
        });

        frame.setVisible(true);

    }
}

事件冲突

焦点:程序的注意力集中在了某一个组件上

import javax.swing.*;

public class Tips {
    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("按钮");
        btn.setBounds(0,0,100,100);
        frame.getContentPane().add(btn);
        
        //取消焦点
        btn.setFocusable(false);

        frame.setVisible(true);
    }
}

六、设计模式

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

1. 适配器设计模式

  • 解决接口与接口实现类之间的矛盾问题
  • 实现步骤:
    1、编写一个 xxxAdapter 类,实现对应接口
    2、重写内部所有抽象方法,但方法都是空实现
    3、让自己的类去继承适配器类,重写自己需要的方法即可
    4、为了避免其他类创建适配器类的对象,使用 abstract 进行修饰

例如:

public class Test {
    public static void main(String[] args) {
        useAnimal u = new useAnimal();
        u.eat();
        u.drink();
    }
}

interface Animal {
    void eat();
    void drink();
    void sleep();
    void play();
}

//适配器类实现接口
abstract class AnimalAdapter implements Animal {
    @Override
    public void eat() {

    }

    @Override
    public void drink() {

    }

    @Override
    public void sleep() {

    }

    @Override
    public void play() {

    }
}

//重写自己需要的方法
class useAnimal extends AnimalAdapter {
    @Override
    public void eat() {
        System.out.println("eat...");
    }

    @Override
    public void drink() {
        System.out.println("drink...");
    }
}

2. 模板设计模式

  • 模板设计模式:把抽象类整体就可以看作成一个模板,模板中不能决定的东西定义成抽象方法,让使用模板的类(基础抽象类的类)去重写抽象方法实现需求
  • 小结:模板设计模式的优势,模板已经定义了通用结构,使用者只需要关心自己需要实现的功能即可
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值