JAVA游戏项目之设计模式

举报
tea_year 发表于 2025/05/28 17:10:32 2025/05/28
【摘要】 问题解答项目演示一、本章目标1. 问题解答图片不显示,Brand类没有重写paint方法,有重写但是重写的是print(), 图片地址写错:this.image = ("imgs//"+name+".png");this.grayImage = ("imgs"+name+"_gray.png");灰色图片不显示,imgs后面没有 //。还有一种情况,代码是复制的,“刷子” 两个字重新...

问题解答项目演示

一、本章目标

1. 问题解答

  1. 图片不显示,Brand类没有重写paint方法,有重写但是重写的是print(), 图片地址写错:

    this.image     = ("imgs//"+name+".png");
    this.grayImage = ("imgs"+name+"_gray.png");

    灰色图片不显示,imgs后面没有 //。

    还有一种情况,代码是复制的,“刷子” 两个字重新写一遍即可。

  2. 不能获取Brand的名称或者获取的名称是null,但是getName方法可以调用,没有生产getter/setter方法,调用的就是父类的方法,

  3. 这最后一个图标跑到第一个位置怎么办?最后一个图标不显示?

image-20221215160452311.png

image-20221215160532045.png

解决办法,再初始化窗体的时候加上绝对布局这句话:

  public void init(){
      this.setTitle("云和数据版-羊了个羊");
      this.setSize(450,800);
      this.setLayout(null);//设置绝对布局
      this.setLocationRelativeTo(null);
      this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      this.setVisible(true);
  }
  1. 有的图片显示,有的图片不显示,怎么解决?

image-20221215161842158.png

同学说:“我又重新输入一遍可以了”, 图片名称、图片文件夹名称、必须要对应。编码问题,mac系统UTF-8,

windows系统的默认编码是GBK

image-20221216094723549.png

  1. Swing的问题,按钮不显示完整的文字?

image-20221215173751950.png


  btn01.setSize(80,25);//调整宽度大小
  1. 导入不同的包的问题,要明确自己到导入的是那个包的类,同一个类不同的包是不同的类型。Layer

  2. 快捷键: CTRL + ALT + L 代码格式化。

二、涉及知识点

1. final关键字的用法

2. 适配器设计模式

3. 模板方法设计模式

4. 匿名内部类

三、知识点讲解

1. final关键字的用法

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {}
//线程安全的字符串容器
public final class StringBuffer extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence{}
public final class StringBuilder extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
public final class System {}


final修饰类: 最终的,用来修饰一个类,表示此类不能被其它类所继承,提高安全性,提高程序的可读性。避免子类重写父类的方法从而改变父类的行为特征。

比如:String类、System类、StringBuffer类都是final修饰的类…

final class A{
}
class B extends A{ //错误,不能被继承。
}

final修饰属性:final 修饰的变量(成员变量或局部变量)称为常量。名称一般大写,且只能被赋值一次。

static final 用来修饰属性:全局常量。

代码演示:

(1)直接再声明时赋值

class A {
   private final String INFO = "嘻嘻"; //声明常量 const
   public void print() {     
     //INFO = "哈哈";
     //The final field A.INFO cannot be assigned
   } 
}

(2)通过构造方法赋值,但不能使用setter方法了,否则会报错

package cn.yunhe.demo;public class FinalSun {
    private final String name;
    private final int age;
    public FinalSun(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;//报错
    }
}
  • final修饰符可以修饰静态变量、成员变量和局部变量,分别表示静态常量、实例常量和局部常量。

public class Demo{
    public static final int MAX_VALUE = 23;  //静态常量
    public static final int MIN_VALUE = 10;  //静态常量
    private final Date birthday = new Date(); //成员常量
    public static final double PI = 3.14159265358979323846;
}
  • 静态常量一般以大写字母命名,单词之间以“_”符号分开。

  • 局部常量的案例

public class Sum {
    public static void main(String[] args) {
        byte num1 = 2,num2 = 3;
        byte num = num1 + num2;
        System.out.println(num);
    }
}

通过编译,我们会发现。在编译的过程中会报错。加上final关键字:

package cn.yunhe.demo;public class Sum {
    public static void main(String[] args) {
        final byte num1 = 2,num2 = 3;
        byte num = num1 + num2;
        System.out.println(num);
    }
}

正常执行,无论属性是基本类型还是引用类型,final所起的作用都是变量里面存放的“值”不能变。

因为 + 号会提升两个参数为整型的,再赋值给byte类型,所以报错。

final修饰方法: 表明此方法不能被子类重写。

class A {
   public final void print() {
     System.out.println("A");
   } 
}
class B extends A {
    public void print() { 
    // 错误,不能被重写。
    } 
}

注意:对于类和方法来说,不能同时使用abstract关键字和final关键字,因为互相矛盾。使用abstract关键字,则必须继承,使用final关键字,则不能继承,所以不能同时使用。

final修饰方法参数

如果变量是作为参数传入的,我们怎么保证它的值不会改变呢?这就用到了final的第二种用法,即在我们编写方法时,可以在参数前面添加final关键字,它表示在整个方法中,我们不会(实际上是不能)改变参数的值:

public class FinalTest {/* .10-5.. */public void finalFunc(final int i, final Value v) {
        // i = 5; 不能改变i的值
        // v = new Value(); 不能改变v的值
        v.num = 5; // 可以改变引用对象的值
    }
}
public class Test1 {    
    public int addOne(final int x) {
        //   return ++x;
        //Cannot assign a value to final variable 'x'
        return x + 1;
    }
}

final修饰引用变量

对于引用类型来说,变量不可变指的是当前地址值不可变,但是可以改变当前地址中的内容。

地址不能变,地址中的数据可以变。房子的编号不能改变,但是房子里租客是可以改变的。

class Other {
   public int i; 
}
public class Something {
    public static void main(String[] args) {
       Other o = new Other();
       new Something().addOne(o);
    }
    public void addOne(final Other o) {
       // o = new Other();
       o.i++;
     } 
}

final和finalize、finally的区别

1.简单区别:

final用于声明属性,方法和类,分别表示属性不可改变,方法不可覆盖,类不可继承。 finally是异常处理语句结构的一部分,表示总是执行的。 finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,供垃圾收集时的其他资源回收,例如关闭文件等。

2.中等区别: 虽然这几个单词在Java中都存在,但是并没太多关联: final:java中的关键字,修饰符。 A).如果一个类被声明为final,就意味着它不能再派生出新的子类,不能作为父类被继承。因此,一个类不能同时被声明为abstract抽象类的和final的类。 B).如果将变量或者方法声明为final,可以保证它们在使用中不被改变.   1)被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。   2)被声明final的方法只能使用,不能重载。 finally:java的一种异常处理机制。   finally是对Java异常处理模型的最佳补充。finally结构使代码总会执行,而不管无异常发生。使用finally可以维护对象的内部状态,并可以清理非内存资源。特别是在关闭数据库连接这方面,如果程序员把数据库连接的close()方法放到finally中,就会大大降低程序出错的几率。 finalize:Java中的一个方法名。 Java技术使用finalize()方法在垃圾收集器将对象从内存中清除出去前,做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没被引用时对这个对象调用的。它是在Object类中定义的,因此所的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。 3.详细区别: 这是一道再经典不过的面试题了,我们在各个公司的面试题中几乎都能看到它的身影。final、finally和finalize虽然长得像孪生兄弟一样,但是它们的含义和用法却是大相径庭。 final关键字我们首先来说说final。它可以用于以下四个地方: 1).定义变量,包括静态的和非静态的。 2).定义方法的参数。 3).定义方法。 4).定义类。 定义变量,包括静态的和非静态的。定义方法的参数 第一种情况: 如果final修饰的是一个基本类型,就表示这个变量被赋予的值是不可变的,即它是个常量; 如果final修饰的是一个对象,就表示这个变量被赋予的引用是不可变的 这里需要提醒大家注意的是,不可改变的只是这个变量所保存的引用,并不是这个引用所指向的对象。 第二种情况:final的含义与第一种情况相同。 实际上对于前两种情况,一种更贴切的表述final的含义的描述,那就是,如果一个变量或方法参数被final修饰,就表示它只能被赋值一次,但是JAVA虚拟机为变量设定的默认值不记作一次赋值。被final修饰的变量必须被初始化。初始化的方式以下几种: 1.在定义的时候初始化。 2.final变量可以在初始化块中初始化,不可以在静态初始化块中初始化。 3.静态final变量可以在定义时初始化,也可以在静态初始化块中初始化,不可以在初始化块中初始化。 4.final变量还可以在类的构造器中初始化,但是静态final变量不可以。 通过下面的代码可以验证以上的观点:

接下来我们一起回顾一下finally的用法。finally只能用在try/catch语句中并且附带着一个语句块,表示这段语句最终总是被执行。请看下面的代码:

public final class FinallyTest{
    public static void main(String[] args){
        try{
            throw new NullPointerException();
        }catch(NullPointerException e){
            System.out.println("程序抛出了异常");
        }finally{
            //这里总会被执行,不受break,return影响另如数据库连接的close()一般写在这里,
            //可以降低程序的出错几率
            System.out.println("执行了finally语句块");
        }
    }
}

运行结果说明了finally的作用:

1.程序抛出了异常

2.执行了finally语句块请大家注意,捕获程序抛出的异常之后,既不加处理,也不继续向上抛出异常,并不是良好的编程习惯,它掩盖了程序执行中发生的错误,这里只是方便演示,请不要学习。 那么,没一种情况使finally语句块得不到执行呢? return、continue、break这个可以打乱代码顺序执行语句的规律。那我们就来试试看,这个语句是否能影响finally语句块的执行:

public final class FinallyTest {
    //测试return语句
    //结果显示:编译器在编译return new ReturnClass();时,
    //将它分成了两个步骤new ReturnClass()和return,前一个创建对象语句是在finally语句块之前被执行的,
    //而后一个return语句是在finally语句块之后执行的,也就是说finally语句块是在程序退出方法之前被执行的
    public ReturnClass testReturn() {
        try {
            return new ReturnClass();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("执行了finally语句");
        }
        return null;
    }//测试continue语句
    public void testContinue(){
        for(int i=0; i<3; i++){
            try {
                System.out.println(i);
                if(i == 1){
                    System.out.println("con");
                }
            } catch(Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("执行了finally语句");
            }
        }
    }
    //测试break语句
    public void testBreak() {
        for (int i=0; i<3; i++) {
            try {
                System.out.println(i);
                if (i == 1) {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("执行了finally语句");
            }
        }
    }public static void main(String[] args) {
        FinallyTest ft = new FinallyTest();
        // 测试return语句
        ft.testReturn();
        System.out.println();
        // 测试continue语句
        ft.testContinue();
        System.out.println();
        // 测试break语句
        ft.testBreak();
    }
}class ReturnClass {
    public ReturnClass() {
        System.out.println("执行了return语句");
    }
}

很明显,return、continue和break都没能阻止finally语句块的执行。从输出的结果来看,return语句似乎在finally语句块之前执行了,事实真的如此吗?我们来想想看,return语句的作用是什么呢?是退出当前的方法,并将值或对象返回。如果 finally语句块是在return语句之后执行的,那么return语句被执行后就已经退出当前方法了,finally语句块又如何能被执行呢?因此,正确的执行顺序应该是这样的:编译器在编译return new ReturnClass();时,将它分成了两个步骤,new ReturnClass()和return,前一个创建对象的语句是在finally语句块之前被执行的,而后一个return语句是在finally语句块之后执行的,也就是说finally语句块是在程序退出方法之前被执行的。同样,finally语句块是在循环被跳过(continue和中断(break之前被执行的 finalize方法 最后,我们再来看看finalize,它是一个方法,属于java.lang.Object类,它的定义如下: protected void finalize()throws Throwable{}众所周知,finalize()方法是GC(garbagecollector)运行机制的一部分,在此我们只说说finalize()方法的作用是什么呢?finalize()方法是在GC清理它所从属的对象时被调用的,如果执行它的过程中抛出了无法捕获的异常(uncaughtexception,GC将终止对改对象的清理,并且该异常会被忽略;直到下一次GC开始清理这个对象时,它的finalize()会被再次调用。请看下面的示例:

public final class FinallyTest{
    //重写finalize()方法
    protected void finalize() throws Throwable{
         System.out.println("执行了finalize()方法");
    }
    public static void main(String[] args){
          FinallyTest ft = new FinallyTest();
          ft = null;
          System.gc();
    }
}

运行结果如下:• 执行了finalize()方法 程序调用了java.lang.System类的gc()方法,引起GC的执行,GC在清理ft对象时调用了它的finalize()方法,因此才了上面的输出结果。调用System.gc()等同于调用下面这行代码:Runtime.getRuntime().gc();调用它们的作用只是建议垃圾收集器(GC启动,清理无用的对象释放内存空间,但是GC的启动并不是一定的,这由JAVA虚拟机来决定。直到 JAVA虚拟机停止运行,些对象的finalize()可能都没被运行过,那么怎样保证所对象的这个方法在JAVA虚拟机停止运行之前一定被调用呢?答案是我们可以调用System类的另一个方法:

public static void runFinalizersOnExit(boolean value){
    //othercode
} 
//调用方式,但是这个方法被不建议使用。
System.runFinalizersOnExit(true);

给这个方法传入true就可以保证对象的finalize()方法在JAVA虚拟机停止运行前一定被运行了,不过遗憾的是这个方法是不安全的,它会导致有用的对象finalize()被误调用,因此已不被赞成使用了。由于finalize()属于Object类,因此所类都这个方法,Object的任意子类都可以重写(override该方法,在其中释放系统资源或者做其它的清理工作,如关闭输入输出流。通过以上知识的回顾,我想大家对于final、finally、finalize的用法区别已经很清楚了。

2. 适配器设计模式

设计模式(Design pattern) 是解决软件开发某些特定问题而提出的一些解决方案也可以理解成解决问题的一些思路。通过设计模式可以帮助我们增强代码的可重用性、可扩充性、 可维护性、灵活性好。我们使用设计模式最终的目的是实现代码的高内聚和低耦合。

729011-20230119115009536-714001969.png


设计模式:适配器设计模式

接口的概念:

package cn.yunhe.demo2;
//USB接口
public interface USB {
    public void usbConnect();
    public void usbStop();
}
package cn.yunhe.demo2;
//上网接口
public interface NetService {
    public void connect();
}
package cn.yunhe.demo2;
//拍照接口
public interface Photoable {
    public void takePhoto();
}
package cn.yunhe.demo2;
//接口表示的一种能力,规范,电视:USB接口,可以直接播放优盘的数据,网线接口,可以连接有线网络,WIFI, HDMI接口 可以连接电脑
//如果实现一个接口就要实现接口的所有方法
//手机类,继承一个父类实现多个接口
public class Phone  implements USB,NetService,Photoable {
    private String brand;
    private int price;
    public void sendMsg(){
        System.out.println("发送短信...");
    }
    public void call(){
        System.out.println("打电话...");
    }
    @Override
    public void usbConnect() {
        System.out.println("连接到优盘....");
    }
    @Override
    public void usbStop() {}
    @Override
    public void connect() {
        System.out.println("连接到互联网...");
    }
    @Override
    public void takePhoto() {}
}
package cn.yunhe.demo2;
//测试类
public class PhoneTest {
    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.call();
        phone.usbConnect();
        phone.connect();
        phone.takePhoto();
    }
}

适配器设计模式:

package cn.yunhe.demo;
class Voltage220V{
    public int output220v(){
        int src = 220;//源电压
        System.out.println("源电压 " + src  + "v");
        return src;
    }
}
interface IVoltage5V{
    int output5v();
}
//适配器类
class VoltageAdapter extends Voltage220V implements IVoltage5V {
​
    @Override
    public int output5v() {
        int src = output220v();
        int dst = src / 44;//变成5v
        return dst;
    }
}class Phone{
    public void charging(IVoltage5V iVoltage5V){
        if (iVoltage5V.output5v() == 5){
            System.out.println("电压 5v 可以充电~~~~~~");
        }else {
            System.out.println("电压不是5v,不可以充电");
        }
    }
}
public class Client {
    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.charging(new VoltageAdapter());
    }
}

Java事件处理机制和适配器全面解析

最重要的是理解事件源监视器处理事件的接口的概念。

1.事件源:是能够产生时间的对象都可以叫事件源,比如文本框,按钮,下拉列表之类的组件。

2.监视器:事件源要产生事件,必须要有什么东西去监视它,以便作出相应啊,那就是监视器,监视器的作用是对事件源进行监视,以便对发生的时间进行处理。

事件源通过相应的方法注册自己的监听器。比如addListener(监听器);

3.处理事件的接口:监视器负责处理事件源发生的事件,监视器是一个对象,为了处理事件源发生的事件,监视器这个对象会自动调用一个方法来处理事件。被调用的这个方法就是所说的处理事件的接口中的方法。

java规定监视器这个对象的类必须声明实现相应的接口, 即必须在类体重重写接口中的所有方法,当事件源发生事件事件时,监视器就会自动调用被类重写的接口方法。

处理事件示意图

2021120411073320.png

java常用的监听接口

2021120411073321.png

此外还有MouseMotionListener,MouseWheelListener,WindowFocusListener, WindowStateListener,监听接口。有时候监听接口中有很多抽象方法,在实现接口的时候,需要重写所有的方法,但是我们经常只会用到其中的一个或两个,这无疑是一种劳累,多余。于是就有了适配器类,出于简化的目的,每个还有多个方法的的监听器接口都配有一个适配器类,这个类实现了接口中的所有方法,但是每个方法没有做任何事情。

比如:FocusAdapter,KeyAdapter,MouseAdapter,MouseMotionAdapter, WindowAdapter.

这就提供另一种方法,就是继承适配器类,重写其中的需要使用的方法,不必重写全部的方法,简单方便。

class A extends WindowAdapter{
   pubilc void windowClosing(WinwEvent e){//重写WindowAdapter中的方法
        //处理时间代码
   }
}

Java事件适配器的作用

适配器其实从接口事件演变尔来的。相当于触发器,说简单点,它就是一些动作 。

例如说 鼠标的按下 点击 还有键盘 等等。 适配器 就是实现 接口事件的类 不过 ,不是真的实现 ,只是空实现 ,没有具体的方法体。 适配器主要是为了方便程序员操作 ,避免了代码的重复性。只要一个对象或者属性添加了这个适配器, 那么它就会监视这对象或属性 。例如说一个按纽。

按纽添加一个MouseAdapter适配器, 并重写里面的mouseClicked(MouseEvent e)方法。

public void mouseClicked(MouseEvent e) 
{
    System.out.println("你点击了鼠标");
} 

当你点击按纽时 后台就是打印 “你点击了鼠标”. 再说明白点 就相当你给按纽 添加了一个鼠标对象。 你通过 鼠标 就可以 产生对应的动作!

MouseAdapter实现了MouseListener,MouseWheelListener,MouseMotionListener接口,而方法都是为空,你可以重写mouseClicked(MouseEvent e) 方法从而响应鼠标按键在组件上单击事件,重写mouseDragged(MouseEvent e)方法从而响应鼠标按键在组件上按下并拖动事件等等。

3. 模板方法设计模式

模板方法简介 模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。 这种类型的设计模式属于行为型模式。定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。

模板模式,其主要的的思想就是做一个模板,提供给客户端进行调用。除去生活中我们经常用到的简历模板、合同模板等等,Java中也有很经典的模板使用,那就是Servlet,HttpService类提供了一个service()方法,这个方法调用七个do方法中的一个或几个,完成对客户端调用的响应。这些do方法需要由HttpServlet的具体则由子类提供。

模板模式主要由抽象模板(Abstract Template)角色和具体模板(Concrete Template)角色组成。

抽象模板(Abstract Template): 定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤;定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。 具体模板(Concrete Template): 实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤;每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。

4.匿名内部类

  1. ==如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,==

  2. ==那么这种情况下就可以省略掉该类的定义,而改为使用【匿名内部类】。==

匿名内部类就是内部类的简化写法,是一种特殊的局部内部类。

前提:存在一个类或者接口,这里的类可以是具体的类也可以是抽象类。

本质是:一个继承了该类或者实现该接口的子类匿名对象。

适合那种只需要创建一次对象的类。

Comparable:内部比较器 public class Student implements Comparable{}内部比较器只能有一个,一般采用最经常使用的比较规则。

Comparator:外部比较器 可指定多个 不需要Student实现该接口,而是定义专门的类、

总结:

1、匿名内部类可以实现一个接口,也可以继承一个类(可以是抽象类)。

2、匿名内部类只能实现一个接口,而不是多个。

3、必须实现所有方法,匿名内部类不能是抽象类。

4、匿名内部类不可能有构造方法,因为类是匿名的。

5、匿名内部类没有访问控制符。

6、如果想实现构造方法的一些初始化功能,可可以通过代码块实现。

7、如果要访问所在方法的局部变量,该变量需要使用final修饰。


内部类的作用

1、内部类提供了更小的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。

2、内部类可以访问外部类的私有属性,内部列被当成其外部类的成员。但外部类不能访问内部类的内部属性。

3、接口只解决了多重继承的部分问题,而内部类使得多重继承的解决方案变的更加完整。

4、用匿名内部类实现回调功能,我们通俗的讲解就是说在Java中,通常就是编写一个接口,然后你来实现这个接口,然后把这个接口

的一个对象作为参数的形式传到另一个程序中,然后通过接口调用你的方法,匿名内部列就可以很好地展现量这一种回调功能。


内部类使用场合

1、由于内部类提供了更好的封装性,并且可以很方便的访问外部类的属性,所以,在只为外部类提供服务的情况下可以优先考虑使用内部类。

2、使用内部类间接实现多继承:每个内部类都能独立地继承一个类或者实现某些接口,所以无论外部类是否已经继承了某个类或者实现了某些

接口,对于内部列都没有任何影响。

多线程的应用场景:

public class myfunction {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类");
            }
        }).start();
    }
}

综合案例:

  1. 接口:

public interface MyInterface {
    void method1(); // 抽象方法   省略了public abstract
    void method2();
}
  1. 实现类,如果用匿名内部类,则不需要写实现类:

public class MyInterfaceImpl implements MyInterface {  //实现类
    @Override
    public void method1() {
        System.out.println("实现类覆盖重写了方法!111");  // 覆盖重写
    }
    @Override
    public void method2() {
        System.out.println("实现类覆盖重写了方法!222");
    }
}
  1. 测试类:

package cn.yunhe.demo;
interface MyInterface {
    void method1(); // 抽象方法   省略了public abstract
    void method2();
}
class MyInterfaceImpl implements MyInterface {  //实现类
    @Override
    public void method1() {
        System.out.println("实现类覆盖重写了方法!111");  // 覆盖重写
    }
    @Override
    public void method2() {
        System.out.println("实现类覆盖重写了方法!222");
    }
}
public class TestInnerClass {
    public static void main(String[] args) {
        //用到了实现类,其中的方法如果要经常用到,则用这种方法
        MyInterface obj = new MyInterfaceImpl();
        obj.method1();
        // MyInterface obj = new MyInterface();//错误写法
        //使用匿名内部类,但不是匿名对象,对象名称是objA
        //这样写就不用写实现类,只用到一次
        MyInterface objA = new MyInterface() {
            @Override
            public void method1() {
                System.out.println("匿名内部类实现了方法!111-method1");
            }
​
            @Override
            public void method2() {
                System.out.println("匿名内部类实现了方法!111-method2");
            }
        };
        objA.method1();//匿名内部类,不匿名对象
        objA.method2();//匿名内部类,不匿名对象
        //使用了匿名内部类,而且省略了对象名称,也是匿名对象
        new MyInterface() {
​
            @Override
            public void method1() {
                System.out.println("匿名内部类实现了方法!222-method1");
            }
​
            @Override
            public void method2() {
                System.out.println("匿名内部类实现了方法!222-method2");
            }
        }.method1();
        //因为匿名对象无法调用第二次方法,所以需要再创建一个匿名内部类的匿名对象
        new MyInterface() {
            @Override
            public void method1() {
                System.out.println("匿名内部类实现了方法!333-method1");
            }
​
            @Override
            public void method2() {
                System.out.println("匿名内部类实现了方法!333-method2");
            }
        }.method2();
    }
}

再思考一下自动刷新线程的实现方式,就是匿名内部类。

四、代码实现

无,把前面四章的代码问题解决。

五、本章总结

  1. final关键字的用法

  2. final、finally、finalize 面试题,三者的区别

  3. 适配器设计模式

  4. 模板方法设计模式

  5. 匿名内部类

六、本章作业

  1. 完成final关键字案例的代码

  2. 完成final、finally、finalize 面试题的代码

  3. 完成适配器设计模式的代码

  4. 完成模板方法设计模式的代码

  5. 完成匿名内部类的代码

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。