Java入坑之抽象类、设计模式与接口

news2025/1/13 6:14:14

目录

一、抽象类

1.1定义

1.2特点

1.3使用场景

1.4抽象方法

1.5抽象类的实现

1.6开-闭原则

1.7匿名类

二、设计模式(了解)

2.1定义

2.2分类

2.3模板设计模式

2.4单例模式

三、接口

3.1定义

3.2语法格式

3.3接口实现

3.4接口类型变量

3.5接口封装

3.6默认方法(Default Methods)

3.7静态方法(Static Methods)

3.8总结

3.9抽象类和接口的异同 

3.10接口回调

3.11接口作为参数

3.12面向接口编程

四、内部类和匿名类

4.1内部类

4.1.1内部类种类

4.1.2成员内部类

4.1.3静态内部类

4.1.4匿名内部类

4.1.5局部内部类

4.2函数式编程


一、抽象类

1.1定义

Java中的抽象类是一种特殊的类,不能被实例化,只能被继承。抽象类通常用于定义一个基类,用于被其它类继承,从而实现代码的复用和扩展。

抽象类把多种事物(类),也就是多个类的共性的内容抽取出来,可以只表示相同的相关功能,而不给出具体的实现。

1.2特点

抽象类在Java中有以下特点:

1.不能被实例化:抽象类只能被继承,不能直接创建实例对象

2.可以包含抽象方法:抽象类可以包含抽象方法,抽象方法没有具体实现,需要在子类中实现。

3.可以包含非抽象方法:抽象类也可以包含非抽象方法,非抽象方法有具体实现,可以在抽象类中直接调用。

4.可以包含静态方法:抽象类可以包含静态方法,静态方法可以在抽象类中直接调用。

5.可以包含静态变量和实例变量:抽象类可以包含静态变量和实例变量。

6.可以实现接口:抽象类可以实现接口,并且在实现接口的同时,可以定义一些共用的方法和属性,且无需实现接口的所有的抽象方法,未实现的抽象方法可以由子类实现

7.子类必须实现抽象方法:如果一个类继承了抽象类,那么它必须实现所有抽象方法,否则该子类也必须被声明为抽象类。

注意:抽象类的子类也可以是抽象类,子类是抽象类时不必实现抽象超类的所有抽象方法。

1.3使用场景

期望相关类共享公共代码以及约束(包含抽象类方法的模板)

期望相关类具有各自特有的属性行为

1.4抽象方法

用关键字abstract修饰的方法称为abstract方法(抽象方法)

对于抽象方法只可以进行定义,不可以实现,就是好只有方法头,并没有方法

例如:abstract  double  getArea( );

抽象方法不允许使用static、final,private修饰

1.5抽象类的实现

当一个非抽象类继承一个抽象类的时候,就必须实现抽象类中的所有的抽象方法

abstract class A{
    int a;
    abstract void p();
    abstract void p1();
}
class B extends A {
    int b;
    void p() {

    }
    // 编译错误,因为没有将A中的抽象方法全部实现。
}
abstract class A{
    int a;
    abstract void p();
    abstract void p1();
}
abstract class B extends A {
    int b;
    void p() {

    }
	// 不需要将p和p1全部实现。
}
class C extends B {
    void p1() {
        
    }
    // B没有实现的抽象方法p1被C实现
}

当一个类时抽象类继承一个抽象类的时候,可以实现一部分抽象类的方法,没有实现的抽象方法直接被继承。

abstract class A{
    int a;
    abstract void p();
    abstract void p1();
}
abstract class B extends A {
    int b;
    void p() {

    }
	// 不需要将p和p1全部实现。
}
class C extends B {
    void p1() {
        
    }
    // B没有实现的抽象方法p1被C实现
}

1.6开-闭原则

开闭原则(Open-Closed Principle,OCP)是指一个软件实体(类、模块、方法等)应该对扩展开放,对修改关闭。这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。

简单来说,开闭原则就是要求我们在设计软件时,应该尽量通过扩展来实现变化,而不是通过修改已有的代码来实现变化。这样可以提高软件的可维护性和可扩展性。

例如,假设我们设计了一个图形类,它可以绘制矩形和圆形。如果我们想要添加一个新的图形,比如三角形,那么按照开闭原则,我们应该通过扩展图形类(在不修改原有图形类的基础上,通过添加新的代码来实现新的需求。这可以通过继承、组合或者接口等方式来实现)来实现这个需求,而不是直接修改图形类的源代码。

遵守开闭原则可以使软件更容易维护和扩展。当需求发生变化时,我们只需要添加新的代码,而不需要修改原有的代码。这样就可以降低出错的风险,并且使软件更容易适应变化。

1.7匿名类

匿名类(也称为匿名内部类)是一种特殊的内部类,它没有名称。它通常用于创建一个只需要使用一次的类,比如在实现接口或继承抽象类时。适合于仅声明使用一次的不会被复用的类

匿名类的语法如下:

new SuperType(construction_parameters) {
   // 类的成员
   // 方法实现
}

其中,SuperType 是匿名类的超类或接口,construction_parameters 是超类或接口的构造函数参数。花括号中的代码块就是匿名类的定义,其中可以定义类的成员和实现方法。

public class Student {
   public void readBook(String bookName) {
      System.out.println("正在阅读:" + bookName);
   }
   
   public static void main(String[] args) {
      Student loudReader = new Student() {
         public void readBook(String bookName) {
            System.out.println("正在大声朗读:" + bookName);
         }
      };
      
      Student quietReader = new Student() {
         public void readBook(String bookName) {
            System.out.println("正在静静地阅读:" + bookName);
         }
      };
      
      Student audiobookListener = new Student() {
         public void readBook(String bookName) {
            System.out.println("正在听有声书:" + bookName);
         }
      };
      
      loudReader.readBook("Java编程思想");
      quietReader.readBook("算法导论");
      audiobookListener.readBook("红楼梦");
      
      Student anonymous = new Student() {
         public void readBook(String bookName) {
            System.out.println("正在用匿名内部类阅读:" + bookName);
         }
      };
      
      anonymous.readBook("设计模式");
   }
}

在这个例子中,我们首先定义了三个匿名类,分别代表了一个喜欢大声朗读的学生、一个喜欢默读的学生、一个喜欢听书的学生。然后,我们又创建了一个匿名内部类,它也继承自 Student 类,并且重写了 readBook() 方法,但是我们没有给这个匿名内部类起名字,直接在代码中使用了它。例如

Student anonymous = new Student() {
   public void readBook(String bookName) {
      System.out.println("正在用匿名内部类阅读:" + bookName);
   }
};

在这里,我们没有给这个匿名内部类命名,而是直接通过 new Student() 创建了一个 Student 子类对象,并在花括号中重写了其 readBook() 方法。这个匿名内部类可以看作是 Student 子类的一个实例,它的类名和对象名都是匿名的,只能通过 anonymous 引用来访问它。

二、设计模式(了解)

2.1定义

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

2.2分类

Java中一般认为有23种设计模式,它们分为三大类:创建型模式(5种)、结构型模式(7种)和行为型模式(11种)

  • 创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。
  • 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
  • 行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

2.3模板设计模式

模板方法模式是一种常用的设计.模式,它定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

abstract class Game {
   abstract void initialize();
   abstract void startPlay();
   abstract void endPlay();

   //模板
   public final void play(){

      //初始化游戏
      initialize();

      //开始游戏
      startPlay();

      //结束游戏
      endPlay();
   }
}

class Cricket extends Game {

   @Override
   void endPlay() {
      System.out.println("Cricket Game Finished!");
   }

   @Override
   void initialize() {
      System.out.println("Cricket Game Initialized! Start playing.");
   }

   @Override
   void startPlay() {
      System.out.println("Cricket Game Started. Enjoy the game!");
   }
}

class Football extends Game {

   @Override
   void endPlay() {
      System.out.println("Football Game Finished!");
   }

   @Override
   void initialize() {
      System.out.println("Football Game Initialized! Start playing.");
   }

   @Override
   void startPlay() {
      System.out.println("Football Game Started. Enjoy the game!");
   }
}

public class TemplatePatternDemo {
   
    public static void main(String[] args) {

       Game game = new Cricket();
       game.play();
       System.out.println();
       game = new Football();
       game.play();      
    }
}

在这个示例中,我们定义了一个抽象类Game,它包含了三个抽象方法initialize()startPlay()endPlay(),以及一个具体的模板方法play()play()方法定义了游戏的基本流程,它首先调用initialize()方法初始化游戏,然后调用startPlay()方法开始游戏,最后调用endPlay()方法结束游戏。

我们还定义了两个具体的子类CricketFootball,它们分别实现了Game类中的三个抽象方法。在主函数中,我们创建了一个Cricket对象和一个Football对象,并分别调用它们的play()方法来运行游戏。

模板模式优点:
1.封装不变部分,扩展可变部分。
2.提取公共代码,便于维护。
3.行为由父类控制,子类实现。


模板模式缺点:
每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

2.4单例模式

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

懒汉式实现方式

public class Singleton {
    private static Singleton instance;
    private Singleton (){}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

这是一个懒汉式单例模式的实现,它在第一次调用getInstance()方法时才会创建实例。但是这种实现方式并不支持多线程,因为它没有加锁synchronized,所以在多线程环境下可能会创建多个实例

饿汉式

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton (){}
    public static Singleton getInstance() {
        return instance;
    }
}

饿汉式单例模式是一种常用的单例模式实现方式。它在类加载时就初始化实例,因此具有很好的线程安全性。这种实现方式的优点是没有加锁,执行效率会提高。但缺点是类加载时就初始化,可能会浪费内存。

三、接口

3.1定义

在Java中,接口(interface)是一种抽象类型,它是抽象方法的集合。接口通常用来定义对象的行为。一个类可以实现一个或多个接口,从而继承接口中定义的抽象方法。

接口中的所有方法都是抽象的,也就是说它们没有具体的实现。因此,一个类实现了一个接口,就必须提供接口中所有方法的具体实现。

狭义上,interface是Java一种与类相似的类型;广义上,interface是互交的规范约束

  1. 接口中没有构造方法,也就不能通过new来构建对象,只能像抽象类一样去标示数据类型。

  2. 接口也具有继承性;

3.2语法格式

Java接口为引用类型,包含:常量/方法签名/默认方法/静态方法等

一个接口可以扩展继承自任意数量的接口*

[public] interface 接口名 [extends 父接口名]    {
    [public] [static] [final] 数据类型 常量名=常量值;    	     //常量声明
    [public] [abstract] 返回类型 方法名(参数列表);        //抽象方法声明
}
interface MyInterface {
    // 常量
    int CONSTANT = 1;

    // 抽象方法
    void abstractMethod();

    // 默认方法
    default void defaultMethod() {
        System.out.println("This is a default method.");
    }

    // 静态方法
    static void staticMethod() {
        System.out.println("This is a static method.");
    }
}

3.3接口实现

在Java中,一个类可以通过implements关键字来实现一个或多个接口,当一个类实现多个接口时,它必须提供所有接口中定义的抽象方法的具体实现。下面是一个简单的示例:

interface MyInterface1 {
    void myMethod1();
}

interface MyInterface2 {
    void myMethod2();
}

class MyClass implements MyInterface1, MyInterface2 {
    public void myMethod1() {
        System.out.println("This is a method from the first interface.");
    }

    public void myMethod2() {
        System.out.println("This is a method from the second interface.");
    }
}

在这个示例中,MyClass类实现了MyInterface1MyInterface2两个接口。因此,它必须提供myMethod1()myMethod2()两个方法的具体实现。

3.4接口类型变量

定义了一个接口,就是定义了一个可以引用的类型,像类一样,在任何需要的地方作为类型使用

在Java中,接口类型的变量可以引用实现了该接口的类的实例。这种特性使得我们可以在运行时动态地改变接口类型变量所引用的对象。下面是一个简单的示例:

interface MyInterface {
    void myMethod();
}

class MyClass1 implements MyInterface {
    public void myMethod() {
        System.out.println("This is a method from the first class.");
    }
}

class MyClass2 implements MyInterface {
    public void myMethod() {
        System.out.println("This is a method from the second class.");
    }
}

public class Main {
    public static void main(String[] args) {
        MyInterface myVar = new MyClass1();
        myVar.myMethod(); // 输出 "This is a method from the first class."

        myVar = new MyClass2();
        myVar.myMethod(); // 输出 "This is a method from the second class."
    }
}

在这个示例中,myVar是一个接口类型的变量。它首先被赋值为MyClass1的实例,然后又被赋值为MyClass2的实例。因此,当我们调用myVar.myMethod()方法时,它会根据myVar所引用的对象来执行不同的方法。

3.5接口封装

接口是一种封装抽象方法的方式。它允许我们将对象的行为与其实现分离,从而提高了代码的可维护性和可扩展性。

当我们使用接口来定义对象的行为时,我们可以在不修改原有代码的情况下,通过创建新的类来实现接口,从而为对象添加新的行为。这种特性使得我们可以在运行时动态地改变对象的行为。

32aade912e5740698d8a67b55044745b.png

3.6默认方法(Default Methods)

在Java 8中,接口可以包含默认方法(Default Methods)。默认方法是一种具有默认实现的方法,它可以被实现接口的类直接使用或覆盖。 

interface MyInterface {
    default void myMethod() {
        System.out.println("This is a default method.");
    }
}

class MyClass1 implements MyInterface {
    // 不覆盖默认方法
}

class MyClass2 implements MyInterface {
    // 覆盖默认方法
    public void myMethod() {
        System.out.println("This is an overridden method.");
    }
}

public class Main {
    public static void main(String[] args) {
        MyClass1 myVar1 = new MyClass1();
        myVar1.myMethod(); // 输出 "This is a default method."

        MyClass2 myVar2 = new MyClass2();
        myVar2.myMethod(); // 输出 "This is an overridden method."
    }
}

在这个示例中,MyInterface接口定义了一个默认方法myMethod()MyClass1类实现了这个接口,但没有覆盖默认方法。因此,当我们调用myVar1.myMethod()时,它会执行接口中定义的默认方法。而MyClass2类实现了这个接口,并覆盖了默认方法。因此,当我们调用myVar2.myMethod()时,它会执行类中定义的方法。

3.7静态方法(Static Methods)

在Java 8中,接口可以包含静态方法(Static Methods)。静态方法是一种与接口类型关联的方法,它不依赖于接口的实例。静态方法使用static关键字来定义,可以通过接口名称直接调用。

interface MyInterface {
    static void myMethod() {
        System.out.println("This is a static method.");
    }
}

public class Main {
    public static void main(String[] args) {
        MyInterface.myMethod(); // 输出 "This is a static method."
    }
}

在这个示例中,MyInterface接口定义了一个静态方法myMethod()。我们可以通过接口名称直接调用这个方法,而不需要创建接口的实例。

a11ef73705fb46469788641ffc49d88d.png

3.8总结

1b28687f8e1c49cc97dc459c629e06e7.png

3.9抽象类和接口的异同 

抽象类和接口都是Java中用来定义抽象类型的机制。它们都可以包含抽象方法,但也有一些重要的区别。

  • 定义方式不同:抽象类使用abstract关键字定义,而接口使用interface关键字定义。
  • 实现方式不同:一个类可以继承一个抽象类,但可以实现多个接口。
  • 方法实现不同:抽象类可以包含具体方法的实现,而接口中的所有方法都必须是抽象的(在Java 8中,接口可以包含默认方法和静态方法)。
  • 成员变量不同:抽象类可以包含任何类型的成员变量,而接口中只能包含静态常量。

抽象类和接口在使用时,抽象类更像 一个模板,接口一般作为标准或表示一种能力

3.10接口回调

接口回调就是一种允许一个对象将自己己的引用传递给另一个对象,从而使得另一个对象可以在适当的时候调用该对象的方法的机制。

接口回调通常用于在不同类之间进行通信。例如,假设我们有两个类AB,并且希望在类B中的某个方法被调用时,通知类A。我们可以定义一个回调接口,然后让类A实现这个接口。然后,我们可以将类A的实例作为回调对象传递给类B。当类B中的方法被调用时,它可以调用回调接口中定义的方法,从而通知类A

下面是一个简单的接口回调示例,它展示了如何在不同类之间使用接口回调来进行通信:

interface MyCallback {
    void myMethod();
}

class MyClassA implements MyCallback {
    public void myMethod() {
        System.out.println("This is a callback method from class A.");
    }
}

class MyClassB {
    private MyCallback callback;

    public MyClassB(MyCallback callback) {
        this.callback = callback;
    }

    public void doSomething() {
        System.out.println("Doing something in class B...");
        callback.myMethod();
    }
}

public class Main {
    public static void main(String[] args) {
        MyClassA myVarA = new MyClassA();
        MyClassB myVarB = new MyClassB(myVarA);
        myVarB.doSomething(); // 输出 "Doing something in class B..." 和 "This is a callback method from class A."
    }
}

在这个示例中,MyCallback接口定义了一个回调方法myMethod()MyClassA类实现了这个接口,并提供了myMethod()方法的具体实现。

MyClassB类包含一个MyCallback类型的成员变量,它在构造函数中初始化。当doSomething()方法被调用时,它会调用回调方法。

在主方法中,我们创建了一个MyClassA实例和一个MyClassB实例,并将MyClassA实例作为回调对象传递给MyClassB实例。因此,当我们调用myVarB.doSomething()时,它会触发回调,并执行MyClassA类中定义的回调方法。

3.11接口作为参数

在Java中,接口可以作为方法的参数。这样做的好处是可以很方便地封装起来,供调用者使用。参数为接口类型可以实现代码解耦。对调用者而言,无需关心内部构造逻辑,只要实现调用相关方法实现自己的下部逻辑即可,做到开箱即用的效果

interface Speak {
    void speak(String message);
}

class Person {
    private Speak speakBehavior;

    public Person(Speak speakBehavior) {
        this.speakBehavior = speakBehavior;
    }

    public void performSpeak(String message) {
        speakBehavior.speak(message);
    }
}

class LoudSpeak implements Speak {
    public void speak(String message) {
        System.out.println("LOUDLY: " + message);
    }
}

class QuietSpeak implements Speak {
    public void speak(String message) {
        System.out.println("quietly: " + message);
    }
}

public class Main {
    public static void main(String[] args) {
        Person person1 = new Person(new LoudSpeak());
        person1.performSpeak("Hello!");

        Person person2 = new Person(new QuietSpeak());
        person2.performSpeak("Hello!");
    }
}

在这个例子中,Speak 接口定义了一个 speak 方法。LoudSpeak 和 QuietSpeak 类实现了 Speak 接口,并重写了 speak 方法。Person 类有一个构造函数,它接受一个 Speak 类型的参数。在 main 方法中,我们创建了两个 Person 对象,分别传入了不同的 Speak 实现类作为参数。当我们调用 performSpeak 方法时,每个对象都会根据传入的 Speak 实现类来执行不同的行为

3.12面向接口编程

894452a8e0404924b96e6c5c2635d07e.jpg

7178 编程题 编程语言:Java

題目內容:

编写一个USB接口程序,模拟计算机启动过程和关闭过程启动过程中要加载鼠标、键盘、麦克风等USB设备,具体要求如下:

(1)定义一个接口USB,包含两个抽象方法turnOn()he turnOff(),分别用于表示USB设备的启动和关闭

(2)编写鼠标Mouse、键盘KeyBoard、麦克风Mic类,实现接口中的turnOn()、turnOff()方法,方法中显示“XX设备启动了”或“XX设备关闭了”即可

(3)编写计算机类Computer,要求有一个表示计算机上USB插槽数量的数组;添加USB设备的方法add(USB usb),功能为遍历所有插槽,如果有空闲的就添加一个USB设备

模拟开机启动USB设备的powerOn()方法,功能为遍历所有USB接口,如果连接了USB设备,则启动USB设备,然后显示“计算机开机成功”

模拟关机关闭USB设备的powerOff()方法,功能为遍历所有USB接口,如果连接了USB设备,则关闭USB设备,然后显示“计算机关机成功”

(4)编写测试类,要求建立计算机对象,建立鼠标、键盘、麦克风对象,并添加到计算机中,启动计算机,关闭计算机

输入输出说明:

无输入;

输出:

鼠标启动了

键盘启动了

麦克启动了

计算机开机成功

鼠标关闭了

键盘关闭了

麦克关闭了

计算机关机成功

import java.util.*;

interface USB {//定义接口
	void turnOn();
	void turnOff();
}

class Mouse implements USB {
	
	final String name="鼠标";

	public String getName() {
		return this.name;
	}
	
	public void turnOn() {
		System.out.printf("%s启动了\n",getName());
	}

	public void turnOff() {
		System.out.printf("%s关闭了\n",getName());
		
	}

}

class KeyBoard implements USB {
	
	final String name="键盘";

	public String getName() {
		return this.name;
	}
	
	public void turnOn() {
		System.out.printf("%s启动了\n",getName());
	}

	public void turnOff() {
		System.out.printf("%s关闭了\n",getName());
		
	}

}

class Mic implements USB {
	
	final String name="麦克";

	public String getName() {
		return this.name;
	}
	
	public void turnOn() {
		System.out.printf("%s启动了\n",getName());
	}

	public void turnOff() {
		System.out.printf("%s关闭了\n",getName());
		
	}

}

class Computer {
	
	USB usb[]=new USB[10];//定义USB接口数组
	int number;
	
	public void add(USB u) {
		usb[++number]=u;
	}
	
	public void powerOn() {
		for(USB u:usb) {
			if(u!=null)u.turnOn();
		}
		System.out.printf("计算机开机成功\n");
	}
	
	public void powerOff() {
		for(USB u:usb) {
			if(u!=null)u.turnOff();
		}
		System.out.printf("计算机关机成功\n");
	}
	
}

public class Main {

	public static void main(String[] args) {
		Computer c=new Computer();
		c.add(new Mouse());
		c.add(new KeyBoard());
		c.add(new Mic());
		c.powerOn();
		c.powerOff();
	}
	
}

四、内部类和匿名类

4.1内部类

3bbb71271cbe46aba70fff3e1de356ec.jpg

使用内部类原因是:每个内部类都能独立地继承一个类或实现某些接口,外部类的实现继承关系对内部类没有影响,弥补java不支持多继承的问题。

4.1.1内部类种类

1.成员内部类

2.静态内部类

3.匿名内部类

4.局部内部类

4.1.2成员内部类

成员内部类是定义在外部类的成员位置上的类。它可以访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰。它可以使用 private 或 protected 来修饰,如果你不希望内部类被外部类访问可以使用 private 修饰符

可以访问外部类所有的属性和方法。但是外部类要访问成员内部类的属性和方法,必须要先实例化成员内部类。 成员内部类里面不能包含静态的属性和方法

class OuterClass {
    private int x = 10;

    class InnerClass {
        public int getX() {
            return x;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        OuterClass.InnerClass inner = outer.new InnerClass();
        System.out.println(inner.getX());
    }
}

4.1.3静态内部类

静态内部类是指使用 static 修饰的内部类。它与非静态内部类的区别在于,静态内部类不需要依赖外部类的实例就可以被创建。静态内部类中可以定义静态成员和实例成员。它可以直接访问外部类的静态成员,但如果要访问外部类的实例成员,则需要通过外部类的实例去访问

只能访问外部类的静态成员变量和方法

class OuterClass {
    private static int x = 10;

    static class InnerClass {
        public int getX() {
            return x;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        OuterClass.InnerClass inner = new OuterClass.InnerClass();
        System.out.println(inner.getX());
    }
}

在 main 方法中,我们使用 new OuterClass.InnerClass() 来创建一个 InnerClass 对象 inner。最后,我们调用 inner.getX() 方法来获取外部类的私有静态成员变量 x 的值。

外部类如何调用静态内部类中的属性和方法

外部类可以通过创建静态内部类实例的方法来调用静态内部类的非静态属性和方法

class OuterClass {
    static class InnerClass {
        public int x = 10;

        public void printX() {
            System.out.println(x);
        }
    }

    public void accessInner() {
        InnerClass inner = new InnerClass();
        System.out.println(inner.x);
        inner.printX();
    }
}

public class Main {
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        outer.accessInner();
    }
}

外部类可以直接通过“ 外部类.内部类.属性(方法)” 的方式直接调用静态内部类中的静态属性和方法

4.1.4匿名内部类

当一个内部类需要继承或者实现接口时,而且只使用一次的时候,可以考虑使用匿名内部类。

和继承有关的匿名类

class MyClass {
    public void printMessage() {
        System.out.println("Hello from MyClass!");
    }
}

public class Main {
    public static void main(String[] args) {
        MyClass myObject = new MyClass() {
            @Override
            public void printMessage() {
                System.out.println("Hello from anonymous class!");
            }
        };
        myObject.printMessage();
    }
}

在这个例子中,MyClass 是一个类,它有一个方法 printMessage()。在 main 方法中,我们创建了一个 MyClass 的匿名子类,并重写了 printMessage() 方法。然后我们创建了一个该匿名子类的对象 myObject,并调用了它的 printMessage() 方法。

当我们运行这段代码时,会输出 “Hello from anonymous class!”,这表明我们成功地使用匿名类继承了 MyClass 并重写了它的 printMessage() 方法。

和接口有关的匿名类

interface HelloWorld {
    public void greet();
    public void greetSomeone(String someone);
}

public class EnglishGreeting {
    public void sayHello() {
        HelloWorld englishGreeting = new HelloWorld() {
            public void greet() {
                greetSomeone("world");
            }
            public void greetSomeone(String someone) {
                System.out.println("Hello " + someone);
            }
        };
        englishGreeting.greet();
    }
}

在这个例子中,我们创建了一个匿名类,它实现了 HelloWorld 接口。我们在 sayHello 方法中创建了一个 englishGreeting 对象,它是 HelloWorld 类型的。然后我们调用了 englishGreeting.greet() 方法,它会调用匿名类中重写的 greet 方法。

4.1.5局部内部类

局部内部类就是定义在代码块内的一个内部类。比如在方法里面定义一个内部类,就是局部内部类,用于解决代码块中的问题

作用范围:它所在的代码块里,不被代码块外的程序使用。

不能被public ,protected,private以及static修饰,但是可以被final修饰。 只能使用代码块内final修饰的参数

它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内

4.2函数式编程

只有一个方法的接口叫做函数式接口,可以使用lambda表达式简化,是函数式编程的基础

可以用@FunctionalInterface注解标识函数式接口
函数式编程:是一种编程的思想、一种方法

Lambda表达式语法

(arg1, arg2) -> expression
(arg1, arg2) -> {body}

箭头,函数参数列表与表达式/函数主体的分隔符
Lambda表达式可包含0或多个参数
参数列表,当参数为空时,需声明空括号;当只有一个参数时,可省略括号;参数类型可省略,编译器自动完成类型推导。当然也可以加上参数类型。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/436023.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

cyberdefenders------------Insider

cyberdefenders------------Insider 防守更聪明,而不是更难 0x01 前言 ​ CyberDefenders 是一个蓝队培训平台,专注于网络安全的防御方面,以学习、验证和提升网络防御技能。使用cyberdefenders的题目来学习恶意流量取证,题目来…

GBDT算法原理及实战

1.什么是GBDT算法 GBDT(Gradient Boosting Decision Tree),全名叫梯度提升决策树,是一种迭代的决策树算法,又叫 MART(Multiple Additive Regression Tree),它通过构造一组弱的学习器(树),并把多棵决策树的结果累加起来…

手把手教你实现控制数组某一个属性之和不能超过某一个数值变量

大家好啊,最近有个小任务,就是我表格多选后,某一项关于栏目数量之和不能超过其他变量 先看图: 代码就是: 这里有一个点就是我需要累加数量之和,其实遍历循环累加也可以 我这里用的是reduce方法 0代表设置…

机器学习实战:Python基于LDA线性判别模型进行分类预测(五)

文章目录 1 前言1.1 线性判别模型的介绍1.2 线性判别模型的应用 2 demo数据演示2.1 导入函数2.2 训练模型2.3 预测模型 3 LDA手写数字数据演示3.1 导入函数3.2 导入数据3.3 输出图像3.4 建立模型3.5 预测模型 4 讨论 1 前言 1.1 线性判别模型的介绍 线性判别模型(…

vue2使用sync修饰符父子组件的值双向绑定

1、使用场景 当我需要对一个 prop 进行“双向绑定的时候,通常用在封装弹窗组件的时候来进行使用,当然也会有其他的使用场景,只要涉及到父子组件之间需要传参的都可以使用,尽量不要使用watch监听来进行修改值,也不要尝试…

GCC编译器的使用

源文件需要经过编译才能生成可执行文件。GCC是一款强大的程序编译软件,能够在多个平台中使用。 1. GCC编译过程 主要分为四个过程:预处理、编译、汇编、链接。 1.1 预处理 主要处理源代码文件中以#开头的预编译指令。 处理规则有: &…

怎么使用midjourney?9个步骤教你学会AI创作

人工智能生成艺术作品的时代已经来临,互联网上到处都是试图创造完美提示的用户,以引导人工智能创造出正确的图像——有时甚至是错误的图像。听起来很有趣?Midjourney 是一种更常见的 AI 工具,人们用它只用几句话就能创造出梦幻般的…

【Linux系统编程】15.fcntl、lseek、truncate

目录 fcntl lseek 参数fd 参数offset 参数whence 返回值 应用场景 测试代码1 测试结果 测试代码2 测试结果 查看文件方式 truncate 参数path 参数length 测试代码3 测试结果 fcntl 获取文件属性、修改文件属性。 int flgsfcntl(fd,F_GETFL); //获取 flgs|…

微服务架构是什么?

一、微服务 1、什么是微服务? 微服务架构(通常简称为微服务)是指开发应用所用的一种架构形式。通过微服务,可将大型应用分解成多个独立的组件,其中每个组件都有各自的责任领域。在处理一个用户请求时,基于…

DOM事件流

DOM事件流 1. 常用事件绑定方式1.1 对象属性绑定1.2 addEventListener()绑定1.3 两种方式区别 2. 事件流2.1 概念2.2 事件顺序2.2.1 捕获阶段2.2.2 目标阶段2.2.3 冒泡阶段 3. 阻止事件冒泡3.1 event.stopPropagation()3.2 stopPropagation与stopImmediatePropagation区别 4. 事…

“科技助力财富增值 京华四季伴您一生”,北银理财深化线下线上客户交流互动

2023年4月12日,北银理财有限责任公司(以下简称“北银理财”)携手东方财富网启动北银理财财富号,首次采用线上直播及线下主题演讲相结合的方式,在上海举办以“科技助力财富增值,京华四季伴您一生”为主题的机…

6、springboot快速使用

文章目录 1、最佳实践1.1、引入场景依赖1.2、查看自动配置了哪些(选做)1.3、是否需要修改配置1、修改配置2、自定义加入或者替换组件3、自定义器 XXXXXCustomizer 2、开发小技巧2.1、Lombok1、引入坐标2、在IDEA中安装lombok插件(新版默认安装…

趣说数据结构 —— 前言

趣说数据结构 —— 前言 一次偶然的机会,翻到当初自己读大学的时候教材,看着自己当初的勾勾画画,一时感触良多。 很值得一提的是,我在封面后第一页,写着自己的专业和名字的地方下面,写着几行这样的字&…

leetcode刷题(6)

各位朋友们大家好,今天是我的leetcode刷题系列的第六篇。这篇文章将与队列方面的知识相关,因为这些知识用C语言实现较为复杂,所以我们就只使用Java来实现。 文章目录 设计循环队列题目要求用例输入提示做题思路代码实现 用栈实现队列题目要求…

Vue2-黑马(七)

目录: (1)router-路由嵌套 (2)router-路由跳转 (3)router-导航菜单 (1)router-路由嵌套 我们有这样的需求,我们已经显示了主页,但是主页里面有&…

SpringBoot数据库换源

文章目录 前言一. baomidou提供换源注解 DS二. 手动数据源切换三. AOP自动换源 前言 笔者知道有三种方式: baomidou提供的DS自定义AOP自动换源实现AbstractRoutingDataSource手动换源 一. baomidou提供换源注解 DS 注意 1.不能使用事务,否则数据源不会切换&…

云原生入门

云原生入门. 云原生是一种设计和构建应用程序的方法,它充分利用了云计算的优势,如弹性、可扩展性、自动化和敏捷性。云原生应用程序不仅可以在云中运行,而且是为云而生的,它们采用了一些新式的技术和架构模式,使得应用…

零基础入门python好学么

python对于零基础的小伙伴算是非常友好的了~ python以简单易学著称~ Python简洁,高效的特点,大大提升了程序员的编码速度,极大的提高了程序员的办公效率,比如用其他编程语言5、6行代码才能整明白的,用Python可能1-2行就…

不应使用Excel进行项目资源规划的 7 个原因

项目资源规划早期仅限于基本分配和调度。因此,企业使用自制工具或excel表来执行这一简单功能。然而,随着技术和业务流程的发展,资源规划变得复杂,并包括其他组成部分,如预测和容量规划,优化等。 由于传统…

1.BootstrapTable组件

1.先在页面声明一个表格对象 <table id"table" class"table table-striped"></table> 2.生成表格JS代码如下 var url /log/;var columns [{checkbox: true,visible: true //是否显示复选框},{field: id,title: 序号,width…