Java 随笔记: 面向对象编程(三)

Java 类、方法、模式及关键字知识总结
本文围绕 Java 展开,介绍了类变量、类方法、main 方法、代码块等基础概念。阐述了单例设计模式、模板设计模式的实现与应用,还讲解了 final 关键字、抽象类、接口和内部类的特点与用法,为 Java 学习提供了全面的知识总结。

目录

1. 类变量

2. 类方法

3. main 方法

4. 代码块

5. 单例设计模式

6. final 关键字

8. 抽象类

9. 模板设计模式

10. 接口

11. 内部类


1. 类变量

在Java中,类变量也被称为静态变量,用关键字“static”声明。类变量属于整个类,而不是某个特定的实例对象。这意味着,类变量只有一份拷贝,被该类的所有实例对象所共享

类变量可以用于存储与类相关的数据,例如常量、配置参数等。它们在类加载时被初始化,并且在整个程序运行期间都存在。类变量可以直接通过类名来访问,而无需创建该类的实例对象。

可以通过以下方式定义和使用类变量:

  1. 在类内部,在方法之外声明一个静态变量。例如:

    public class MyClass {
        public static int myVariable;
    }
    

    在这个例子中,myVariable就是一个类变量。

  2. 通过类名直接访问类变量。例如:

    MyClass.myVariable = 10;
    

    这个例子中,将myVariable的值设置为10

类变量的一些特点如下:

  • 类变量在内存中只有一份拷贝,被该类的所有实例对象所共享。
  • 类变量可以在类的任何地方进行访问,包括类的方法、构造函数、静态代码块等。
  • 类变量的生命周期与类的生命周期相同,即在类加载时被初始化,直到程序退出或类被卸载时才会被销毁。
  • 类变量可以通过类名直接访问,也可以通过对象名访问,但建议使用类名直接访问,以便明确表达该变量是一个类变量。
  • 类变量可以被继承,并且可以被子类中的同名类变量所隐藏

需要注意的是,类变量的使用应该遵循合适的命名规范和访问权限。一般情况下,类变量应该使用私有访问权限,并提供公共的getter和setter方法来访问和修改该变量的值。这样可以封装类变量的实现细节,同时也能保证对类变量的访问具有一定的控制能力。

2. 类方法

在Java中,类方法是与类相关联的方法,而不是与类的实例相关联的方法。类方法可以通过类名直接调用,而不需要创建类的实例。类方法通常用来执行通用的操作,不依赖于特定的对象状态。

以下是一些关于Java中类方法的详细介绍:

  1. 声明类方法: 在Java中,通过在方法前面添加static关键字来声明类方法。静态方法属于类本身,而不属于类的实例。例如:

    public class MyClass {
        public static void myMethod() {
            // 方法体
        }
    }
    
  2. 调用类方法: 可以通过类名直接调用类方法,而不需要创建类的实例。例如:

    MyClass.myMethod();
    
  3. 类方法的特点:

    • 类方法可以访问类的静态变量,但不能访问实例变量
    • 类方法不能使用this关键字,因为this关键字代表当前对象实例,而类方法不依赖于对象实例。
    • 类方法可以调用其他类方法,包括其他类的静态方法。
    • 类方法可以被继承,子类可以重写父类的类方法。
  4. 例子:

    public class MathUtils {
        public static int add(int a, int b) {
            return a + b;
        }
        
        public static int subtract(int a, int b) {
            return a - b;
        }
    }
    

    可以通过类名直接调用MathUtils类的add和subtract方法:

    int result1 = MathUtils.add(5, 3);
    int result2 = MathUtils.subtract(10, 7);
    

类方法通常用于执行与整个类相关的通用操作,例如数学计算、工具类中的常用功能等。由于类方法不依赖于对象实例,可以直接通过类名调用,而无需创建类的实例。这种特性使得类方法非常适合用于定义那些不需要访问对象状态的操作。

3. main 方法

在Java中,main方法是一个特殊的方法,是程序的入口点每个Java程序都必须包含一个名为main的方法,以便能够运行程序

main方法的声明如下:

public static void main(String[] args) {
    // 程序代码
}

其中:

  • public 表示main方法是公共的,可以被其他类访问。
  • static 表示main方法是静态的,可以直接通过类名调用。
  • void 表示main方法不返回任何值。
  • main 是方法的名称,是Java程序的入口点。
  • String[] args 是main方法的参数,是一个字符串数组,可以在命令行中传递参数给程序。

关于main方法的一些重要事项

  1. main方法必须是public访问权限的,这是因为JVM需要通过反射机制来调用它。
  2. main方法必须是static静态的,这是因为在程序启动时,对象还没有被创建,只能直接调用静态方法
  3. main方法的返回类型是void,即无返回值。
  4. main方法的参数是一个字符串数组,可以接收命令行参数。字符串数组可以用来传递程序运行时的参数
  5. main方法是程序执行的起点,程序从main方法开始执行,一直到main方法结束

下面是一个简单的示例

public class Main {
    public static void main(String[] args) {
        // 打印命令行参数
        for (String arg : args) {
            System.out.println(arg);
        }
        
        // 调用其他方法
        printHello();
    }
    
    public static void printHello() {
        System.out.println("Hello, World!");
    }
}

在上面的示例中,main方法首先打印命令行参数,然后调用printHello方法打印"Hello, World!"。可以通过命令行传递参数给程序,例如:

java Main arg1 arg2

运行结果会打印出传递的参数:

arg1
arg2
Hello, World!

4. 代码块

在Java中,代码块是一段被花括号包围的代码,也被称为代码组或语句组。主要有三种类型的代码块:方法块、构造块和静态块。

  1. 方法块(普通块): 方法块是位于方法内的一段代码,用于执行特定任务。它可以在方法内的任何地方定义,并在方法被调用时被执行。方法块可以包括变量定义、条件判断、循环等语句。方法块的作用域仅限于所属方法,不可以被其他方法访问。

    示例代码如下:
    public class Example {
        public void method() {
            // 方法块开始
            {
                int x = 10;
                System.out.println(x);
            }
            // 方法块结束
        }
    }
    
  2. 构造块(实例块): 构造块是位于类中的一段代码,用于初始化实例变量或执行其他任务。它在对象创建时被执行,而且每次创建对象时都会执行一次。构造块可以在类中的任何地方定义,且在构造方法之前执行。构造块的作用域仅限于所属类,不可以被其他类访问。

    示例代码如下:
    public class Example {
        {
            // 构造块开始
            int x = 10;
            System.out.println(x);
        }
        
        public Example() {
            // 构造方法
        }
    }
    
  3. 静态块: 静态块是位于类中的一段代码,用于初始化静态变量或执行其他任务。它在类被加载时执行,且只执行一次。静态块可以在类中的任何地方定义,且在静态变量初始化之前执行。静态块的作用域仅限于所属类,不可以被其他类访问。

    示例代码如下:
    public class Example {
        static {
            // 静态块开始
            int x = 10;
            System.out.println(x);
        }
        
        public static void main(String[] args) {
            // 主方法
        }
    }
    

需要注意的是,方法块的作用域仅限于所属方法,构造块和静态块的作用域仅限于所属类。此外,方法块和构造块可以多次定义和执行,而静态块只执行一次

5. 单例设计模式

单例设计模式是一种创建型设计模式,用于保证一个类只有一个实例,并提供一个全局访问点来获取该实例。这种模式通常被用于需要对资源进行集中管理或避免频繁创建对象的情况

实现单例设计模式的关键是:

  1. 将类的构造方法私有化,防止外部通过new关键字创建实例。
  2. 在类内部创建一个私有的静态成员变量来保存唯一实例的引用。
  3. 提供一个公共的静态方法来获取该实例。

实现单例设计模式的方法有多种,下面介绍其中两种常用的方式:

  1. 饿汉式单例模式 在类加载时就创建实例对象,并将其保存在静态变量中。这种方式的优点是实现简单,线程安全,但缺点是会在类加载时就创建实例,可能会造成不必要的资源浪费。

    示例代码:
    public class Singleton {
        // 在类加载时就创建实例对象
        private static final Singleton instance = new Singleton();
        
        // 私有构造方法,防止外部创建实例
        private Singleton() {}
        
        // 提供静态方法来获取实例对象
        public static Singleton getInstance() {
            return instance;
        }
    }
    
  2. 懒汉式单例模式在获取实例对象时才创建实例。这种方式的优点是延迟了实例的创建,在需要时再进行创建,减少了资源的浪费。但缺点是在多线程环境下可能会出现线程安全问题,需要额外的处理。

    示例代码:
    public class Singleton {
        private static Singleton instance;
        
        // 私有构造方法,防止外部创建实例
        private Singleton() {}
        
        // 提供静态方法来获取实例对象
        public static Singleton getInstance() {
            if (instance == null) {
                // 在多线程环境下需要进行同步处理
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
    

使用单例模式时需要注意以下几点:

  • 单例实例需要是线程安全的,尤其在多线程环境下使用懒汉模式时要进行同步处理。
  • 单例实例需要是唯一的,不能通过其他方式创建实例。
  • 避免使用全局变量的方式实现单例模式,这会造成资源的浪费或无法正确管理资源。

单例设计模式在实际开发中广泛应用,例如数据库连接池、日志管理等场景

6. final 关键字

final关键字在Java中用于修饰类、方法和变量,具有不同的作用和用法

  1. 修饰类 :使用final修饰的类是不可继承的,即该类不能再有子类。这是为了防止其他类对该类进行扩展或修改。

    示例代码:
    final class FinalClass {
        // 类的内容
    }
    
  2. 修饰方法: 使用final修饰的方法是不可重写的,即子类不能对该方法进行覆盖。这是为了防止子类修改父类的实现逻辑。

    示例代码:
    class SuperClass {
        final void finalMethod() {
            // 方法的实现
        }
    }
    
    class SubClass extends SuperClass {
        // 编译错误,无法重写final方法
        // void finalMethod() {}
    }
    
  3. 修饰变量: 使用final修饰的变量是不可修改的,即该变量的值不能被改变。一旦被赋值后,就不能再次修改。该变量可以在声明时直接赋值,或在构造函数中进行赋值,但之后不可再修改。

    示例代码:
    class TestFinalVariable {
        final int number = 10;
        
        void modifyVariable() {
            // 编译错误,无法修改final变量
            // number = 20;
        }
    }
    

需要注意的是,final修饰的引用变量并不是不可变的,而是引用的对象不可变。即引用变量所指向的对象的状态是可以改变的,但引用变量本身不能再指向其他对象

示例代码:

class TestFinalReference {
    final StringBuilder stringBuilder = new StringBuilder("Hello");
    
    void modifyReference() {
        // 可以修改引用变量指向的对象的状态
        stringBuilder.append(" World");
        
        // 编译错误,无法修改final引用变量指向其他对象
        // stringBuilder = new StringBuilder("Hello");
    }
}

8. 抽象类

在Java中,抽象类是一种特殊的类,用于定义具有部分或全部抽象方法的类。抽象类不能被实例化,只能被继承,并且子类必须实现抽象类中的所有抽象方法才能创建对象。

下面详细介绍Java中的抽象类:

  1. 定义抽象类
    • 使用abstract关键字修饰类,表示该类是一个抽象类。
    • 可以包含普通成员变量、普通方法、静态成员变量和静态方法。
    • 可以包含抽象方法,抽象方法没有方法体,只有方法签名。
    • 代码示例:
      public abstract class AbstractClass {
          // 普通成员变量
          private int number;
          
          // 抽象方法
          public abstract void doSomething();
      
          // 普通方法
          public void printNumber() {
              System.out.println("Number: " + number);
          }
      }
      
  2. 继承抽象类
    • 一个普通的类可以继承抽象类,并且必须实现抽象类中的所有抽象方法
    • 如果不实现抽象方法,则该类也必须声明为抽象类
    • 代码示例:
      public class ConcreteClass extends AbstractClass {
          // 实现抽象方法
          public void doSomething() {
              // 方法的具体实现
          }
      }
      
  3. 使用抽象类
    • 由于抽象类不能被实例化,我们通常使用它的子类进行对象的创建和调用。
    • 抽象类可以作为变量的类型、方法的参数类型或返回值类型
    • 代码示例:
      public class Main {
          public static void main(String[] args) {
              // 使用抽象类的子类创建对象
              AbstractClass obj = new ConcreteClass();
              obj.doSomething();
              obj.printNumber();
          }
      }
      

特殊注意事项

  • 抽象类可以有构造方法,但不能直接实例化。子类的构造方法会隐式调用父类的构造方法。
  • 抽象类中的抽象方法必须在子类中被实现,否则子类也必须声明为抽象类。
  • 抽象类可以拥有普通方法的实现,子类可以直接继承或重写这些方法。
  • 抽象类可以拥有成员变量,可以被子类继承和访问。

抽象类的主要目的是作为其他类的父类,提供一种模板或蓝图,规定子类必须实现的方法,从而实现代码的重用和规范。它可以为子类提供一些通用的属性和行为,同时也可以使用多态的方式操作抽象类对象。

9. 模板设计模式

模版设计模式是一种行为设计模式,它定义了一个操作中的算法框架,将一些步骤的具体实现推迟到子类中。模版设计模式是基于继承的,通过抽象类或接口定义一个算法的骨架,具体的实现则由子类来完成。

以下是模版设计模式的详细介绍:

  1. 模版类
    • 模版类是一个抽象类或接口,定义了一个算法的骨架。
    • 模版类中包含一个或多个抽象方法,这些方法需要由子类实现。
    • 模版类中可以包含一些具体实现的方法,这些方法是固定的,并且在算法框架中不会改变。
    • 代码示例:
      public abstract class AbstractTemplate {
          // 固定实现的方法
          public void preProcess() {
              // 子类无法改变的操作
          }
          
          // 抽象方法,由子类实现
          public abstract void processData();
          
          // 固定实现的方法
          public void postProcess() {
              // 子类无法改变的操作
          }
          
          // 模版方法,定义算法的骨架,调用固定实现的方法和抽象方法
          public void execute() {
              preProcess();
              processData();
              postProcess();
          }
      }
      
  2. 具体实现类
    • 具体实现类继承或实现模版类,实现其中的抽象方法。
    • 具体实现类可以根据需要重写模版类中的固定实现的方法。
    • 代码示例:
      public class ConcreteTemplate extends AbstractTemplate {
          // 实现抽象方法
          public void processData() {
              // 子类实现的操作
          }
          
          // 重写固定实现的方法
          public void postProcess() {
              // 子类自定义的操作
          }
      }
      
  3. 使用模版类
    • 创建具体实现类的对象,调用模版类的方法来执行算法。
    • 在模版方法中,固定实现的方法会被全部执行,抽象方法的实现会根据具体实现类的不同而有所变化。
    • 代码示例:
      public class Main {
          public static void main(String[] args) {
              AbstractTemplate template = new ConcreteTemplate();
              template.execute();
          }
      }
      

模版设计模式的优点包括:

  • 提供了一种固定的算法框架,可以减少代码的重复。
  • 提供了一种简化算法实现的方式,将具体实现推迟到子类中。

模版设计模式的缺点包括:

  • 可能会导致子类之间的耦合性增加,因为模版类固定了一些方法的调用顺序和方式。
  • 由于使用了继承,可能会限制代码的灵活性。

模版设计模式在许多框架和库中都有广泛的应用,例如在Java中,常见的应用场景包括数据库操作、网络请求等。通过使用模版设计模式,可以提高代码的可维护性、可扩展性和复用性,同时也能够将变化和不变的部分分离,使代码更加易于理解和维护。

10. 接口

在Java中,接口是一种特殊的引用类型,它定义了一组方法的签名(即方法名、参数列表和返回类型),但没有具体的实现。接口提供了一种契约机制,用于定义类的行为和功能,并实现多态和代码复用

以下是Java中接口的详细介绍:

  1. 定义接口
    • 使用 interface 关键字来定义接口。
    • 接口中可以包含常量和抽象方法。
    • 接口中的方法默认为 public abstract,并且不能有具体的实现。
    • 接口中的常量默认为 public static final,并且只能是基本类型或字符串,不能被修改。
    • 示例代码:
      public interface MyInterface {
          // 常量
          int MY_CONSTANT = 10;
          
          // 抽象方法
          void myMethod();
      }
      
  2. 实现接口
    • 使用 implements 关键字来实现接口。
    • 类实现接口时,必须实现接口中的所有抽象方法。
    • 类可以实现多个接口,使用逗号分隔。
    • 示例代码:
      public class MyClass implements MyInterface {
          // 实现抽象方法
          public void myMethod() {
              // 方法的具体实现
          }
      }
      
  3. 接口的特点
    • 接口可以继承其他接口,使用 extends 关键字。
    • 接口之间可以形成继承关系,从而实现多态。
    • 一个类可以同时实现多个接口。
    • 示例代码:
      public interface AnotherInterface extends MyInterface {
          // 接口继承其他接口
          void anotherMethod();
      }
      
      public class MyClass implements AnotherInterface {
          // 实现抽象方法
          public void myMethod() {
              // 方法的具体实现
          }
          
          // 实现额外的方法
          public void anotherMethod() {
              // 方法的具体实现
          }
      }
      
  4. 接口的应用
    • 接口可以用于实现多态,通过接口引用不同的实现类来实现灵活的对象调用。
    • 接口可以用于定义回调方法,使得对象能够在特定情况下调用其他对象的方法。
    • 接口可以用于实现类之间的解耦,通过依赖接口而不是具体实现类,提高代码的灵活性和可扩展性。

接口在Java中被广泛应用于各种场景,特别是在面向对象的设计中,用于定义类之间的契约和约定。通过接口,可以提供统一的方法集合,使得不同的类能够实现相同的接口并具备相同的行为。接口的使用可以提高代码的可读性、重用性和可维护性。

11. 内部类

在Java中,内部类是定义在另一个类内部的类。内部类可以访问外部类的成员(包括私有成员),并且可以隐藏在外部类中,从而提供更好的封装性和代码组织性。Java中的内部类主要有以下几种类型:

  1. 成员内部类(Member Inner Class)
    • 成员内部类是定义在类内部且直接在类的成员位置上的类
    • 成员内部类可以使用外部类的成员变量和方法,并且可以访问外部类的私有成员
    • 成员内部类的实例必须依赖于外部类的实例,需要通过外部类的实例创建内部类的对象。
    • 示例代码:
      public class OuterClass {
          private int outerVariable;
          
          public void outerMethod() {
              // ...
          }
          
          public class InnerClass {
              private int innerVariable;
              
              public void innerMethod() {
                  // 可以访问外部类的成员
                  outerVariable = 10;
                  outerMethod();
                  
                  // ...
              }
          }
      }
      
  2. 静态内部类(Static Inner Class)
    • 静态内部类是定义在类内部但使用 static 修饰的类
    • 静态内部类与外部类的实例无关,可以直接访问外部类的静态成员,但无法访问外部类的非静态成员
    • 静态内部类可以在外部类的静态方法中直接创建对象,无需依赖于外部类的实例。
    • 示例代码:
      public class OuterClass {
          private static int outerStaticVariable;
          
          public static void outerStaticMethod() {
              // ...
          }
          
          public static class InnerClass {
              private int innerVariable;
              
              public void innerMethod() {
                  // 可以访问外部类的静态成员
                  outerStaticVariable = 10;
                  outerStaticMethod();
                  
                  // ...
              }
          }
      }
      
  3. 局部内部类(Local Inner Class)
    • 局部内部类是定义在方法内部的类,也可以在代码块内部定义
    • 局部内部类只能在定义它的方法或代码块中使用,对外部类和其他方法不可见
    • 局部内部类可以访问外部类和方法的成员,但只能访问 final 或事实上为 final 的局部变量。 
    • 示例代码:
      public class OuterClass {
          public void outerMethod() {
              final int localVar = 10; // 局部变量
              
              class LocalInnerClass {
                  public void innerMethod() {
                      // 可以访问外部类的成员
                      outerMethod();
                      
                      // 可以访问局部变量(注意需要为 final 或事实上为 final)
                      int sum = localVar + 20;
                      
                      // ...
                  }
              }
              
              // 在方法内部创建局部内部类的对象
              LocalInnerClass innerClass = new LocalInnerClass();
              innerClass.innerMethod();
          }
      }
      
  4. 匿名内部类(Anonymous Inner Class)
    • 匿名内部类是没有名字的内部类,直接在创建对象时定义并实现
    • 匿名内部类通常用于实现接口或继承抽象类,并重写其方法。
    • 匿名内部类可以访问外部类的成员,但只能访问 final 或事实上为 final 的局部变量
    • 示例代码:
      public class OuterClass {
          public void methodWithCallback() {
              Callback callback = new Callback() {
                  public void onCallback() {
                      // 匿名内部类重写接口方法
                      // ...
                  }
              };
              
              // 调用接口方法
              callback.onCallback();
          }
      }
      

事实上为 final 的局部变量指的是在代码中虽然没有明确使用 final 关键字来修饰该局部变量,但其实质上在编译时是不可被修改的。这种情况通常发生在以下两种情况下:

  1. 如果局部变量在声明后没有被重新赋值,即在整个作用域内保持不变。
  2. 局部变量被传递给局部内部类的方法中,而该方法中没有对局部变量进行修改。

这是因为局部内部类的对象可能会在方法执行完毕后仍然存在,而非 final 的局部变量可能会被修改或销毁,导致局部内部类访问的变量状态不确定

内部类在Java中被广泛应用于各种场景,例如:实现事件处理、实现回调机制、封装复杂的数据结构等。内部类提供了更好的封装性和代码组织性,可以在类内部定义一些逻辑相关的辅助类,使得代码更加清晰和可读。同时,内部类能够访问外部类的成员,并且可以实现多重继承或实现多个接口,从而增加了代码的灵活性和可复用性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值