Может ли статика быть сложной для меня?

Java задняя часть

static — это ключевое слово, часто используемое в нашей повседневной жизни, а также очень важное ключевое слово в Java. static может изменять переменные, методы, создавать статические блоки кода, статические пакеты импорта и т. д. Давайте поговорим об этом ключе подробнее. мы начинаем с основ, с основного использования, а затем анализируем его принципы, оптимизацию и так далее.

Знакомство со статическим ключевым словом

статическая переменная модификатора

staticПонятие, представленное ключевым словом,全局的、静态的, украшенная им переменная называется静态变量.

public class TestStatic {
    
    static int i = 10; // 定义了一个静态变量 i 
}

Статические переменные также известны как переменные класса, а статические переменные принадлежат классу. Что это обозначает? Фактически это означает, что ключевое слово static может быть определено только в классе{}, но не определен ни в одном методе.

То же самое верно, даже если ключевое слово static удалено из метода.

static принадлежит классу, и класс напрямую вызывает статическую измененную переменную, ему не нужно вручную создавать экземпляр класса для вызова

public class TestStatic {

    static int i = 10;

    public static void main(String[] args) {
        System.out.println(TestStatic.i);
    }
}

Здесь вам нужно понять концепцию нескольких переменных

  • Определяется в конструкторах, блоках кода, методахПеременные называются переменными экземпляра, и существует столько копий переменных экземпляра, сколько экземпляров.
  • Определяется в методах, конструкторах, блоках кодаПеременные называются локальными переменными;
  • Определяется в параметрах методаПеременные называются параметрами.

Ссылка для деталей

статический декорированный метод

static может изменять методы, а методы, измененные static, вызываются静态方法, по сути, заключается в добавлении определения методаstaticключевые слова изменяются, например, следующим образом

static void sayHello(){}

"Java Programming Thought" имеет классическое описание на странице P86.

Статический метод — это метод без this, а нестатический метод нельзя вызывать внутри статического и наоборот. А вызывать статические методы можно только через сам класс без создания каких-либо объектов, что собственно и является основной целью статических методов.

Одним из очень важных слов является то, чтоСтатический метод - это метод без этого, то есть вы можете получить доступ к статическим методам без создания объекта. Посмотрите на следующий фрагмент кода

В приведенном выше примере, посколькуstaticMethodЭто статический метод, поэтому его можно вызывать, используя имя класса.имя переменной.

Итак, если вы хотите вызвать метод без создания объекта, вы можете сделать метод статическим. Обычно самый статичный метод, который мы видим, является основным методом.Что касается того, почему основной метод должен быть статическим, теперь должно быть ясно. Поскольку программа не создает никаких объектов при выполнении основного метода, доступ к нему возможен только через имя класса.

Примечания о статических декорированных методах

  • Во-первых, чаще всего используется первая точка, без создания объектов, напрямую类名.变量名доступный;
  • Нестатический метод нельзя вызывать внутри статического модифицированного метода;

  • Статический статический метод можно вызывать внутри нестатического метода.

статически оформленный блок кода

Ключевое слово static может использоваться для изменения блоков кода. Существует два типа блоков кода.{}кодовый блок; одинstatic {}Статические блоки кода. Блок кода, украшенный статическими элементами, называется статическим блоком кода. Статические блоки кода можно размещать в любом месте класса. В классе может быть несколько статических блоков. Когда класс загружается впервые, он будет выполняться в порядке блоков статического кода. Каждый статический измененный блок кода может выполняться только раз. . Мы встретимся и поговорим о порядке загрузки блоков кода. Ниже приведен пример статического блока кода.

статические блоки кода могут использоваться дляпорядок выполнения оптимизатора, из-за его характеристик: он будет выполняться только один раз при загрузке класса.

static используется как статический внутренний класс

Сценариев использования внутренних классов немного, но есть и более полезные внутренние классы. Прежде чем понять статические внутренние классы, давайте взглянем на классификацию внутренних классов.

  • нормальный внутренний класс
  • локальный внутренний класс
  • статический внутренний класс
  • анонимный внутренний класс

静态内部类Это внутренний класс, дополненный статическими.Статический внутренний класс может содержать статические или нестатические члены, но статические члены не могут быть объявлены в нестатических внутренних классах.

Статические внутренние классы имеют много функций.Поскольку создание экземпляров нестатических внутренних классов требует ссылок на объекты внешнего класса, создание нестатических объектов внутреннего класса должно полагаться на экземпляры внешнего класса, в то время как создание экземпляров статических внутренних классов нужно полагаться только на внешний класс.

А поскольку объект нестатического внутреннего класса содержит ссылку на объект внешнего класса, нестатический внутренний класс может получить доступ к нестатическим членам внешнего класса, в то время как статический внутренний класс может получить доступ только к статическим членам внешнего класса. класс;

  • Внутренний класс должен быть отделен от объекта внешнего класса для создания экземпляра.
  • Избегайте переполнения памяти при использовании внутренних классов
public class ClassDemo {
  
    private int a = 10;
    private static int b = 20;

    static class StaticClass{
        public static int c = 30;
        public int d = 40;
      
        public static void print(){
            //下面代码会报错,静态内部类不能访问外部类实例成员
            //System.out.println(a);
     
            //静态内部类只可以访问外部类类成员
            System.out.println("b = "+b);
            
        }
      
        public void print01(){
            //静态内部内所处的类中的方法,调用静态内部类的实例方法,属于外部类中调用静态内部类的实例方法
            StaticClass sc = new StaticClass();
            sc.print();
        }   
    }
}

статический пакет

Я не знаю, замечали ли вы это явление, например, вы использовалиjava.utilПри использовании внутреннего класса инструментов вам необходимо импортировать пакет java.util, чтобы использовать его внутренний класс инструментов, как показано ниже.

Но есть и другой способ управления пакетом — использовать静态导包, статический импорт должен использоватьimport staticИспользуется для импорта статических методов или статических переменных в класс или пакет.

import static java.lang.Integer.*;

public class StaticTest {

    public static void main(String[] args) {
        System.out.println(MAX_VALUE);
        System.out.println(toHexString(111));
    }
}

статические расширенные знания

После того, как мы разберемся с использованием ключевого слова static, давайте взглянем на более подробное использование static, то есть от поверхностного к глубокому, не торопитесь и достаточно прелюдий~

О классе, к которому принадлежит static

Свойства и методы, модифицированные static, принадлежат классу и не будут принадлежать какому-либо объекту, они вызываются точно так же.类名.属性名/方法名, тогда как переменные экземпляра и локальные переменные принадлежат конкретным экземплярам объекта.

Место хранения статических измененных переменных

Во-первых, давайте познакомимся с различными областями хранения JVM.

  • 虚拟机栈: Стек виртуальной машины Java — это частная область данных потока.Жизненный цикл стека виртуальной машины Java такой же, как и у потока, а стек виртуальной машины также является местом хранения локальных переменных. Во время выполнения метода создается стек виртуальной машины栈帧(stack frame).

  • 本地方法栈: локальный стек методов также является частной областью данных потока, а область, где хранится локальный стек методов, в основном используется в Java.nativeОбласть, в которой хранятся методы, украшенные ключевыми словами

  • 程序计数器: Счетчик программ также является областью личных данных нити.Эта часть области используется для хранения адреса инструкции нити и используется для оценки функций ветвления, цикла, перехода, исключения, переключения нити и восстановления поток, которые все завершаются счетчиком программ.

  • 方法区: область методов — это область памяти, совместно используемая каждым потоком, которая используется для хранения таких данных, как информация о классе, константы, статические переменные и код, скомпилированный компилятором реального времени, загруженным виртуальной машиной, то естьСтатические декорированные переменные хранятся в области методов.

  • : куча — это область данных, разделяемая потоками. Куча — это самая большая область хранения в JVM. Все экземпляры объектов, включаяпеременные экземпляра находятся в кучеСделайте соответствующее распределение.

Жизненный цикл статических переменных

Жизненный цикл статической переменной такой же, как и у класса: она создается при загрузке класса и уничтожается при уничтожении класса, обычные переменные-члены имеют такой же жизненный цикл, как и у той, которой они принадлежат.

статическая сериализация

Мы знаем, что целью сериализации являетсяПреобразование объекта Java в последовательность байтов. Объект преобразуется в упорядоченный поток байтов, чтобы его можно было передать по сети или сохранить в локальном файле.

Переменные, объявленные как статические и переходные типы, не могут быть сериализованы, потому что статически измененные переменные хранятся в области методов, и будет сериализована только куча памяти. иtransientРоль ключевого слова заключается в предотвращении сериализации объекта.

порядок загрузки классов

Мы упоминали о концепции порядка загрузки классов ранее.Статические модифицированные переменные и статические блоки кода инициализируются перед использованием.Порядок инициализации классов следующий:

Загрузить статическое поле родительского класса -> статический блок кода родительского класса -> статическое поле дочернего класса -> статический блок кода дочернего класса -> переменная-член родительского класса (нестатическая поле)

-> нестатический блок кода родительского класса -> конструктор родительского класса -> переменная-член дочернего класса -> переменная-член дочернего класса -> нестатический блок кода дочернего класса -> конструктор дочернего класса

static часто используется для печати журнала

В процессе разработки мы часто используемstaticКлючевое слово печатается в виде журнала, следующая строка кода, которую вы должны часто видеть

private static final Logger LOGGER = LogFactory.getLoggger(StaticTest.class);

Однако удаление static и final может распечатать журналы.

private final Logger LOGGER = LogFactory.getLoggger(StaticTest.class);
private Logger LOGGER = LogFactory.getLoggger(StaticTest.class);

Но есть проблема с таким способом печати логов

Для каждого экземпляра объекта StaticTest будет LOGGER. Если будет создано 1000 объектов StaticTest, будет добавлено 1000 объектов Logger, что приведет к пустой трате ресурсов. Поэтому объект Logger обычно объявляется как статическая переменная. Таким образом, Это может уменьшить оккупацию ресурсов памяти.

static часто используется как одноэлементный шаблон

Поскольку шаблон singleton означает, что для разных классов существует только одна его копия, поэтому static может точно соответствовать шаблону singleton.

Ниже приведен сценарий, в котором классическая блокировка с двойной проверкой реализует одноэлементный режим.

public class Singleton {
  
    private static volatile Singleton singleton;
 
    private Singleton() {}
 
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

Чтобы дать краткое описание приведенного выше кода

использоватьstaticЧтобы убедиться, что одноэлементные переменные являются статическими, используйтеvolatileГарантированная видимость одноэлементных переменных с использованием закрытого конструктора гарантирует, что экземпляр Singleton не может быть создан с помощью new .

использоватьSingleton.getInstance()Чтобы получить одноэлементный объект, будет вынесено первое решение. Если одноэлементный объект пуст, объект класса Singletion будет заблокирован. Вот некоторые друзья, которые могут не знать, почему им нужно судить дважды. Вот объяснение.

Если поток t1 выполняется до singleton == null и определяет, что объект имеет значение null, то поток дает право на выполнение t2, t2 определяет, что объект имеет значение null, блокирует объект класса Singleton и выполняет следующий процесс оценки и создания экземпляра. . Если второе суждение не вынесено, то t1 также будет создан после первого суждения, и в это время все равно будет создано несколько объектов.

Является ли конструктор класса статическим

Я полагаю, что большинство мелких партнеров не рассматривали этот вопрос, в мысли о программировании на Java есть такая фраза.Хотя конструктор класса не украшен статическими элементами, на самом деле это статический метод., но фактического объяснения не дается, но на этот вопрос можно ответить со следующих аспектов

  • Самое простое и легкое для запоминания правило для статики — отсутствие этой ссылки. В конструкторе класса есть неявная привязка this, потому что конструктор привязан к классу, с этой точки зрения конструктор не статичен.
  • С точки зрения методов класса, поскольку类.方法名К нему можно получить доступ без необходимости создания нового объекта, поэтому с этой точки зрения конструктор не статичен.
  • С точки зрения инструкций JVM рассмотрим пример
public class StaticTest {

    public StaticTest(){}

    public static void test(){

    }

    public static void main(String[] args) {
        StaticTest.test();
        StaticTest staticTest = new StaticTest();
    }
}

Давайте используем javap -c для генерации байт-кода StaticTest и посмотрим

public class test.StaticTest {
  public test.StaticTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void test();
    Code:
       0: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2                  // Method test:()V
       3: new           #3                  // class test/StaticTest
       6: dup
       7: invokespecial #4                  // Method "<init>":()V
      10: astore_1
      11: return
}

Мы обнаружили, что при вызове статических методов мы используемinvokestaticинструкция, новый объект вызываетinvokespecialинструкции, а в спецификации JVMdocs.Oracle.com/JavaColor/spec…Говоря о

С этой точки зрения,invokestaticДирективы — это директивы, которые специально используются для выполнения статических методов;invokespecialэто инструкция, специально используемая для выполнения методов экземпляра; в этом смысле конструкторы также не являются статическими.