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

目录

一、抽象类

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或多个参数
参数列表,当参数为空时,需声明空括号;当只有一个参数时,可省略括号;参数类型可省略,编译器自动完成类型推导。当然也可以加上参数类型。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烟雨平生9527

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值