面向对象(第三部分)

static关键字

  • 在Java中,static关键字用于声明静态成员,可以应用于变量、方法、代码块和嵌套类
  • 使用static关键字修饰的类成员均属于类本身,而不属于实例对象,故所修饰的成员只有1个不会因为实例的创建而增多
  • 静态成员不会因为类的实例的创建而增多,而是在类加载时分配内存,在整个程序运行期间都存在,直到程序结束才被销毁。这使得静态成员适合用于表示类级别的属性或方法,而不是特定于实例的属性或方法。
  • 静态变量(类变量):
    • 静态变量属于类,而不是实例。所有该类的实例共享同一个静态变量的副本。可以通过类名直接访问静态变量,无需实例化对象。
public class MyClass {
    public static int staticVar = 10;
}

  • 静态方法:
    • 静态方法属于类,而不是实例。静态方法可以直接通过类名调用,无需实例化对象。
public class MyClass {
    public static void staticMethod() {
        System.out.println("This is a static method.");
    }
}

  • 静态代码块:
    • 静态代码块用static关键字定义,在类加载时执行,用于初始化静态变量或执行其他静态操作。
public class MyClass {
    static {
        System.out.println("Static block is executed.");
    }
}

  • 静态内部类:
    • 在类内部使用static关键字定义的内部类是静态内部类。静态内部类不持有对外部类实例的引用。
public class OuterClass {
    static class StaticInnerClass {
        // Code for static inner class
    }
}

单例设计模式

设计模式

  • 创建型模式
    • 简单工厂模式、工厂方法模式、抽象工厂模式、创建者模式、原型模式、单例模式
  • 结构型模式
    • 外观模式、适配器模式、代理模式、装饰模式、桥接模式、组合模式、享元模式
  • 行为型模式
    • 模板方法模式、观察者模式、状态模式、策略模式、职责链模式、命令模式、访问者模式、调停者模式、备忘录模式、迭代器模式、解释器模式

实现单例模式

  • 单例设计模式用于确保一个类只有一个实例,并提供全局访问点。
  • 饿汉式单例模式
    • 在这种方式中,实例在类加载时就被创建,因此在多线程环境下也能保证单例的唯一性。
  public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {
        // 私有构造函数
    }

    public static Singleton getInstance() {
        return instance;
    }
}
  • 懒汉式单例模式
    • 懒汉式单例模式在第一次使用时才会创建实例,可以节省资源,但在多线程环境下需要考虑线程安全性。
  public class Singleton {
    private static Singleton instance;

    private Singleton() {
        // 私有构造函数
    }

    //使用synchronized关键字保证多线程安全
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

  • 这两种创建单例模式的方法,区别只是在于创造实际实例的时间,饿汉式在声明实例的时候便进行创建,而懒汉式是先声明,再在使用的时候进行创建

类的成员之四:代码块

  • 在Java类中,除了字段(属性)和方法之外,还可以包含代码块。
  • 代码块是一组语句,可以在类中定义,用于初始化实例变量或执行特定的操作。
  • 在Java中,有两种类型的代码块:静态代码块和实例代码块。
  • 静态代码块按照在类中出现的顺序执行,且仅执行一次(在类加载时)。
  • 实例代码块在每次创建对象时执行,执行顺序与它们在类中出现的顺序一致,优先于构造方法执行。
  • 可以在有多构造器时抽出相同代码,来使得代码更精简

静态代码块:

  • 静态代码块使用关键字 static 来声明,它在类加载时执行(类只加载一次),且只执行一次。静态代码块用于初始化静态变量或执行静态操作。静态代码块位于类中的任何位置,但在类加载时按照在类中出现的顺序执行。只能调用静态的结构(若调用非静态可能会因为非静态结构消亡而无法调用)
  • 主要用于对静态变量的赋值,防止静态变量被修改
public class MyClass {
    static {
        // 静态代码块
        System.out.println("Static block is executed.");
    }
}

实例代码块:

  • 实例代码块没有使用关键字 static,它在创建对象时执行,每次创建对象时都会执行一次。实例代码块用于初始化实例变量或执行实例操作。实例代码块位于类中,但不在任何方法内部。可以调用静态和非静态的结构
public class MyClass {
    {
        // 实例代码块
        System.out.println("Instance block is executed.");
    }
}

构造器和代码块区别

  • 构造器用于初始化对象,而代码块用于执行特定的代码逻辑。
  • 构造器在创建对象时被调用,代码块在类加载或对象创建时执行。
  • 构造器没有返回类型,而代码块也不需要返回类型。
  • 构造器的名称与类名相同,而代码块没有名称,只是一段被大括号包围的代码。

类中属性赋值的位置及过程

  • 默认初始化->显式初始化=代码块中初始化->构造器中初始化->通过对象进行赋值
  • 显式赋值:比较适合于每个对象的属性值相同的场景
  • 构造器中赋值:比较适合每个对象的属性值不同的场景

类内部成员加载顺序

  1. 父类的静态成员加载:
    • 首先加载父类的静态变量(静态字段)和静态初始化块,按照在父类中的顺序依次加载和执行。
  2. 子类的静态成员加载:
    • 接着加载子类的静态变量和静态初始化块,按照在子类中的顺序依次加载和执行。
  3. 父类的实例成员加载:
    • 父类的实例变量(非静态变量)和实例初始化块按照在父类中的顺序依次加载和执行。
  4. 父类的构造方法:
    • 父类的构造方法在子类实例化时被调用,用于初始化父类对象的实例变量。
  5. 子类的实例成员加载:
    • 子类的实例变量和实例初始化块按照在子类中的顺序依次加载和执行。
  6. 子类的构造方法:
    • 最后调用子类的构造方法,用于初始化子类对象的实例变量。
  • 总体来说,类加载时会按照父类优先的顺序依次加载父类的静态成员和实例成员,然后加载子类的静态成员和实例成员。这确保了继承关系中类成员的正确加载顺序。
class Parent {
    static {
        System.out.println("1. Parent static block");
    }

    {
        System.out.println("3. Parent instance block");
    }

    Parent() {
        System.out.println("4. Parent constructor");
    }
}

class Child extends Parent {
    static {
        System.out.println("2. Child static block");
    }

    {
        System.out.println("5. Child instance block");
    }

    Child() {
        System.out.println("6. Child constructor");
    }
}

public class Main {
    public static void main(String[] args) {
        new Child();
    }
}

final关键字

  • 在 Java 中,“final” 可以用来修饰类、方法和变量。
  • 当一个类被声明为 final 时,意味着它不能被继承;
  • 当一个方法被声明为 final 时,意味着它不能被子类重写;
  • 当一个变量被声明为 final 时,意味着它的值只能被赋值一次。

抽象类与抽象方法

  • 在Java中,抽象类是一种类,它不能被实例化,只能作为其他类的父类来使用。
  • 抽象类通常用于定义子类的通用结构和行为,而具体的实现则由子类来完成。
  • 在抽象类中可以包含抽象方法,这些方法只有声明而没有具体的实现,具体的实现由继承该抽象类的子类提供。
  • 要定义一个抽象类,可以使用关键字abstract来修饰类,而要定义一个抽象方法,可以使用关键字abstract来修饰方法。一个类中只要包含了一个抽象方法,那么这个类必须被声明为抽象类。
// 定义一个抽象类
abstract class Shape {
    // 定义一个抽象方法
    public abstract double calculateArea();
}

// 继承抽象类,并实现抽象方法
class Circle extends Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

public class Main {
    public static void main(String[] args) {
        Circle circle = new Circle(5);
        System.out.println("Circle Area: " + circle.calculateArea());
    }
}

模板方法设计模式

  • 在Java中,模板方法模式通常通过抽象类来实现
// 抽象类定义了算法的骨架
abstract class AbstractClass {
    // 模板方法定义了算法的步骤
    public void templateMethod() {
        step1();
        step2();
        step3();
    }

    // 抽象方法,由子类实现
    abstract void step1();
    abstract void step2();

    // 钩子方法,子类可以选择性地覆盖
    void step3() {
        System.out.println("Default implementation of step3");
    }
}

// 具体子类实现抽象类中的抽象方法
class ConcreteClass extends AbstractClass {
    @Override
    void step1() {
        System.out.println("Step 1");
    }

    @Override
    void step2() {
        System.out.println("Step 2");
    }

    // 可选地覆盖钩子方法
    @Override
    void step3() {
        System.out.println("Custom implementation of step3");
    }
}

public class Main {
    public static void main(String[] args) {
        AbstractClass abstractClass = new ConcreteClass();
        abstractClass.templateMethod();
    }
}

接口

  • 接口(Interface)是一种抽象类型,它定义了一组方法但没有实现这些方法的具体代码
  • 接口可以包含常量和方法的声明,但不能包含方法的实现。
  • 接口定义了一种契约,规定了实现该接口的类需要提供哪些方法。
  • 类可以实现一个或多个接口,实现接口的类必须提供接口中定义的所有方法。
  • 接口中的方法默认是公共的(public),因此实现接口的类中的方法也必须是公共的。
  • 接口可以被用来实现多态性,通过接口的引用可以指向实现该接口的任何类的对象。
interface MyInterface {
    //省略了public abstract的声明
    void method1();
    int method2(int x, int y);
}

class MyClass implements MyInterface {
    @Override
    public void method1() {
        // 方法1的具体实现
    }

    @Override
    public int method2(int x, int y) {
        // 方法2的具体实现
        return x + y;
    }
}
  • 接口可以看作是功能的描述,抽象类可以看作类的模板,类可以看作实例对象特征的集合

类的成员之五:内部类

  • 在Java中,一个类可以包含另一个类,这就是内部类。
  • 内部类分为成员内部类(Member Inner Class)、静态内部类(Static Inner Class)、局部内部类(Local Inner Class)和匿名内部类(Anonymous Inner Class)。
  • 成员内部类是定义在另一个类中的类,它是外部类的一个成员,可以访问外部类的所有成员,包括私有成员。
  • 成员内部类的实例依赖于外部类的实例,因此在创建成员内部类的实例之前,必须先创建外部类的实例。
public class OuterClass {
    private int outerField;

    public OuterClass(int outerField) {
        this.outerField = outerField;
    }

    // 成员内部类
    public class InnerClass {
        public void innerMethod() {
            System.out.println("Inner method called");
            System.out.println("Outer field accessed from inner class: " + outerField);
        }
    }

    public static void main(String[] args) {
        OuterClass outerObject = new OuterClass(10);
        OuterClass.InnerClass innerObject = outerObject.new InnerClass();
        innerObject.innerMethod();
    }
}

枚举类

  • 在Java中,枚举类(Enum)是一种特殊的数据类型,它允许你定义一个包含固定常量的集合。
  • 枚举类在Java中被用来表示一组固定的值,比如星期几、月份等。
  • 枚举类在Java中是通过关键字enum来定义的。
public class EnumExample {
    // 定义一个枚举类型 Color
    public enum Color {
        //将自己作为自己的内部类
        RED(255,0,0,"红色"), GREEN(0,255,0,"绿色"), BLUE(0,0,255,"蓝色");

        private final int r;
        private final int g;
        private final int b;
        private final int color;

        //定义了枚举类的元素组成
        Color(int r,int g,int b,String color){
            this.r=r;
            this.g=g;
            this.b=b;
            this.color=color
        }

        @Override
        public String toString(){
            return name()+"("+r+","+g+","+b+")"+"->"+color;
        }
    }

    public static void main(String[] args) {
        // 使用枚举常量
        Color c1 = Color.RED;
        Color c2 = Color.GREEN;

        // 输出枚举常量
        System.out.println("Color 1: " + c1); // 输出:Color 1: (255,0,0,"红色")
        System.out.println("Color 2: " + c2); // 输出:Color 2: (0,0,255,"蓝色")
    }
}

Annotation注解和单元测试

  • 在Java中,注解(Annotations)是一种元数据,它提供了关于程序代码的额外信息。
  • 注解可以用来为类、方法、变量、参数等元素添加元数据信息,这些信息可以被编译器、解释器或其他工具使用。
  • @Override:用于指示一个方法将覆盖父类中的方法。
  • @Deprecated:用于标记已过时的方法、类或字段。
  • @SuppressWarnings:用于禁止特定类型的警告信息。
  • @FunctionalInterface:用于指示接口是一个函数式接口。
  • @Retention:指定注解的保留策略,包括SOURCE、CLASS和RUNTIME。
  • @Target:指定注解可以应用的元素类型,如TYPE、METHOD、FIELD等。
  • @Documented:用于指示将注解信息包含在Javadoc文档中。

元注解

  • 元注解(meta-annotation)是用于注解其他注解的特殊类型的注解。
  • 元注解提供了关于注解本身的元数据信息,可以用来控制注解的行为和作用范围。
  • @Target:指定注解可以应用的程序元素类型,如类、方法、字段等。
  • @Retention:指定注解的保留策略,包括源代码级别、编译时级别和运行时级别。
  • @Documented:指定注解是否包含在Java文档中。
  • @Inherited:指定注解是否可以被子类继承。

自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CustomAnnotation {
    String value() default "This is a custom annotation";
}

public class MyClass {

    @CustomAnnotation("Custom Annotation Example")
    public void myMethod() {
        // Your method implementation here
    }
}

JUnit单元测试

  • 所在的类必须是public,非抽象的,包含唯一的无参构造器
  • @Test标记的方法本身必须是public,非抽象的,非静态的,void无返回值,()无参数的
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class MyMath {

    public int add(int a, int b) {
        return a + b;
    }

    @Test
    public void testAdd() {
        MyMath math = new MyMath();
        int result = math.add(3, 4);
        assertEquals(7, result);
    }
}


包装类

  • Java包装类(Wrapper Classes)是用来将基本数据类型转换为对象的类。
  • 在Java中,基本数据类型(如int、double、char等)是非对象,但有时候需要将它们当作对象来处理,这时就可以使用包装类。
  • 包装类提供了很多实用的方法来处理基本数据类型,以及使其具有对象的特性,比如可以在集合中存储基本数据类型的对象等。另外,自动装箱(Autoboxing)和拆箱(Unboxing)功能使得在基本数据类型和包装类之间的转换更加方便。
  • Boolean - 对应boolean
  • Byte - 对应byte
  • Short - 对应short
  • Integer - 对应int
  • Long - 对应long
  • Float - 对应float
  • Double - 对应double
  • Character - 对应char
public class WrapperExample {
    public static void main(String[] args) {
        // 使用包装类来实例化对象
        Integer num1 = new Integer(10);
        Integer num2 = 20; // 自动装箱

        // 调用包装类的方法
        System.out.println("num1 = " + num1.intValue());
        System.out.println("num2 = " + num2);

        // 将包装类转换为基本数据类型
        int sum = num1 + num2; // 自动拆箱
        System.out.println("Sum = " + sum);
    }
}
  • 25
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值