java基础笔记(工具)

一、final 的使用场景

final 关键字主要用于定义常量、限制继承以及防止方法重写,其具体应用场景包括:

  1. 修饰变量

    • 常量:将变量声明为 final 后,该变量一旦初始化后就不能再改变。常见用法是定义全局常量,例如:
      public static final int MAX_CONNECTIONS = 100;
      
    • 局部变量:在方法中,将局部变量声明为 final 可以确保其值在赋值之后不再改变,有助于编写更安全和易于维护的代码。
  2. 修饰方法

    • 防止重写:在方法声明中使用 final 可以防止该方法被子类重写,从而保持父类的原有行为。例如:
      public final void process() {
          // 处理逻辑
      }
      
      这种做法在设计不希望被修改的核心算法时非常有用,确保逻辑不被子类干扰。
  3. 修饰类

    • 防止继承:当一个类被声明为 final 时,表示该类不能被继承。这通常用于安全设计或者为了防止类行为被扩展。例如:
      public final class String {
          // String 类为 final,保证其不可变性和安全性
      }
      
  4. 方法参数和匿名内部类

    • 方法参数:有时我们希望方法参数在方法内部不可变,可以用 final 修饰参数。
    • 匿名内部类:在匿名内部类中,方法外的局部变量如果被内部类使用,必须声明为 final(在 Java 8 及以后版本中,要求“事实上的 final”,即变量值不变即可)。

二、static 的使用场景

static 关键字主要用于定义类级别的成员,它可以使成员在所有实例之间共享,而不依赖于具体的对象。主要使用场景包括:

  1. 修饰变量

    • 类变量:使用 static 修饰的变量属于类而不是某个实例,所有实例共享同一个变量。例如,用于计数、缓存数据、配置参数等:
      public class Counter {
          public static int count = 0;
          
          public Counter() {
              count++;
          }
      }
      
  2. 修饰方法

    • 静态方法:静态方法可以在不创建对象实例的情况下调用,常用于工具类、帮助方法或与实例状态无关的操作。例如:
      public class MathUtils {
          public static int add(int a, int b) {
              return a + b;
          }
      }
      // 调用时直接使用类名: MathUtils.add(2, 3);
      
    • 静态方法内不能直接访问非静态成员,因为它们不依赖于具体对象。
  3. 静态块(Static Block)

    • 类级别初始化:静态块用于在类加载时进行一次性初始化操作,如加载配置、初始化静态资源等。静态块在类加载时自动执行,只执行一次:
      public class Config {
          public static Map<String, String> settings;
          
          static {
              settings = new HashMap<>();
              settings.put("url", "http://example.com");
              // 执行其他初始化操作
          }
      }
      
  4. 静态内部类

    • 嵌套类:将内部类声明为 static 后,该内部类不再依赖于外部类的实例。这在设计工具类、辅助类或者当内部类的实例不需要引用外部类时非常有用:
      public class OuterClass {
          public static class NestedStaticClass {
              public void display() {
                  System.out.println("Static nested class");
              }
          }
      }
      // 使用时: OuterClass.NestedStaticClass nested = new OuterClass.NestedStaticClass();
      
  5. 静态导入

    • 简化调用:通过 import static 语句,可以直接使用类中的静态成员而无需类名修饰,例如:
      import static java.lang.Math.PI;
      import static java.lang.Math.cos;
      
      public class Circle {
          public double calculateCircumference(double radius) {
              return 2 * PI * radius;
          }
          
          public double calculateCos(double angle) {
              return cos(angle);
          }
      }
      

总结

  • final 用于:

    • 定义常量,确保变量一经初始化后不再改变;
    • 防止方法被重写,保证关键逻辑不被修改;
    • 防止类被继承,确保类的行为和安全性。
  • static 用于:

    • 定义类变量和类方法,使其在所有实例间共享,适用于工具类和全局数据;
    • 类级别初始化(静态块),在类加载时完成初始化操作;
    • 定义静态内部类,避免对外部类实例的依赖;
    • 简化静态成员的使用(静态导入)。

在 Java 中,protected 关键字用于修饰类的成员(变量、方法、构造器等),它的访问权限介于 publicdefault(包级私有)之间。下面详细说明 protected 的作用和使用场景:


在 Java 中,将 staticfinal 一起使用主要用于定义常量。下面详细说明它们一起使用的意义、作用及常见场景:


1. 含义解析

  • static
    表示该成员属于类本身,而不是某个实例。无论创建多少个对象,static 成员只有一份拷贝。

  • final
    表示该变量一旦赋值后就不能再更改(对于基本类型,是不可变的;对于引用类型,则意味着引用不再变化)。

staticfinal 一起使用时,就定义了一个全局常量,该常量在整个应用中都是共享且不可改变的。


2. 使用场景

定义常量

  • 数值常量、字符串常量
    例如:
    public class Constants {
        public static final int MAX_CONNECTIONS = 100;
        public static final String APP_NAME = "MyApplication";
    }
    
    这种方式定义的常量可以直接通过类名访问:
    int max = Constants.MAX_CONNECTIONS;
    String name = Constants.APP_NAME;
    

编译期优化

  • 当常量是基本类型或 String,且赋值为编译时可确定的表达式时,编译器会将它们内联到使用处,从而提高性能。例如:
    public static final double PI = 3.141592653589793;
    
    在其他类中引用 PI 时,编译器可能会直接将数值 3.141592653589793 写入字节码中。

配置和全局设置

  • 对于一些需要全局统一管理的配置参数,可以用 static final 定义,保证程序运行过程中该参数不可变,避免因修改引起的不确定行为。

3. 注意事项

  1. 不可变性

    • 使用 static final 定义的变量在初始化之后不可修改,确保了全局常量的稳定性。
    • 对于引用类型,虽然引用地址不可改变,但引用的对象本身的状态如果可变,则可能会引起问题,因此最好使用不可变对象(例如:String 或不可变集合)。
  2. 访问修饰符的选择

    • 常量通常定义为 public static final,以便在全局范围内访问。
    • 如果只在内部使用,则可以定义为 private static final
  3. 命名约定

    • 常量的命名通常全部使用大写字母,单词之间用下划线分隔,如:MAX_CONNECTIONSDEFAULT_TIMEOUT

4. 总结

staticfinal 关键字一起使用的主要目的在于定义常量,这些常量具有以下特点:

  • 全局共享:属于类,不依赖对象实例;
  • 不可变性:一旦初始化后不能更改,保证数据的稳定性;
  • 编译期优化:可以在编译期间直接内联,提高效率。

这种方式在 Java 开发中十分常见,尤其适用于定义应用中不变的配置信息、常量值等场景。

一、访问权限说明

  1. 同一包内

    • protected 修饰的成员在同一包内是可以被直接访问的,就像包级私有(默认访问权限)一样。
  2. 不同包中的子类

    • 如果一个类在其他包中继承了包含 protected 成员的父类,那么子类可以直接访问父类中被 protected 修饰的成员,即使这些子类不在同一个包中。
  3. 不同包中的非子类

    • 对于不在同一包中且不是子类的其他类,即使知道该成员所在的类,也无法直接访问 protected 成员。
  4. 与其他修饰符的比较

    • public:任何地方都可以访问。
    • private:只能在本类中访问。
    • 默认(无修饰符):仅在同一包内访问。
    • protected:允许同一包内访问,并且允许跨包访问,但前提是跨包的类必须继承自该类。

二、使用场景

  1. 封装与继承

    • 当你希望一个成员对继承该类的子类开放,但不希望对所有类开放时,protected 是一个很好的选择。例如,某个核心方法希望子类可以重写或直接使用,但不希望其他类直接调用此方法。
  2. 跨包继承场景

    • 当你的项目中不同包之间存在继承关系,并希望子类可以访问父类的一些重要成员时,可以将这些成员声明为 protected

三、示例代码

下面通过一个简单的例子展示 protected 的使用:

// 位于包 com.example.base 下的父类
package com.example.base;

public class BaseClass {
    // protected 成员
    protected String message = "Hello from BaseClass";

    // protected 方法
    protected void showMessage() {
        System.out.println(message);
    }
}

// 位于包 com.example.sub 下的子类
package com.example.sub;

import com.example.base.BaseClass;

public class SubClass extends BaseClass {
    public void display() {
        // 可以直接访问父类的 protected 成员
        System.out.println("SubClass accessing: " + message);
        // 可以调用父类的 protected 方法
        showMessage();
    }
}

// 位于包 com.example.other 下的非子类
package com.example.other;

import com.example.base.BaseClass;

public class OtherClass {
    public void test() {
        BaseClass base = new BaseClass();
        // 编译错误:无法访问 protected 成员,因为 OtherClass 既不在同一个包,也不是子类
        // System.out.println(base.message);
        // base.showMessage();
    }
}

在这个例子中:

  • SubClass:作为 BaseClass 的子类,可以直接访问 protected 成员 message 以及调用 showMessage() 方法,即使它不在同一个包中。
  • OtherClass:不是 BaseClass 的子类,也不在同一个包中,因此不能直接访问 protected 成员。

四、总结

  • protected 关键字提供了一种适中的访问控制方式,使得类的成员对同包中的其他类开放,同时也对继承自该类的子类开放(无论子类所在包)。
  • 在设计类结构时,使用 protected 可以在保持封装性的同时,允许子类扩展或重用父类的部分功能,是面向对象编程中常用的访问控制修饰符之一。
    在 Java 中,使用 private 关键字声明的变量只能在声明该变量的类内部访问,子类不能直接访问父类中的 private 变量。如果子类需要访问或修改这些变量,可以通过以下几种方式实现:
  1. 提供公共的或受保护的访问方法(getter/setter)
    在父类中为 private 变量提供 publicprotected 的访问方法,从而允许子类通过方法调用来访问这些变量。例如:

    public class Parent {
        private int data;
    
        // 提供受保护的访问方法
        protected int getData() {
            return data;
        }
    
        protected void setData(int data) {
            this.data = data;
        }
    }
    
    public class Child extends Parent {
        public void display() {
            // 通过父类提供的访问方法来访问 private 变量
            System.out.println("Data: " + getData());
        }
    }
    
  2. 将变量声明为 protected
    如果希望子类直接访问该变量,可以将变量的访问级别从 private 改为 protected。这样,除了父类本身,同一包内的其他类以及子类都可以直接访问该变量:

    public class Parent {
        // 改为 protected 后,子类可以直接访问
        protected int data;
    }
    
    public class Child extends Parent {
        public void display() {
            // 子类可以直接访问父类的 protected 变量
            System.out.println("Data: " + data);
        }
    }
    

总结来说,private 声明的变量不能被子类直接访问。如果需要让子类能够访问或修改这些变量,可以考虑使用 getter/setter 方法,或者将变量的访问权限改为 protected

你可能感兴趣的:(JAVA,java,笔记,开发语言)