Какие модификаторы доступа существуют в Java?

Ответ

В Java существует четыре основных модификатора доступа, которые определяют видимость классов, методов и полей. Упорядочены от самого строгого к самому открытому:

  1. private: Элемент доступен только внутри класса, в котором он объявлен. Это максимальный уровень инкапсуляции.
  2. default (package-private): Элемент доступен только внутри своего пакета. Используется, когда модификатор доступа не указан явно.
  3. protected: Элемент доступен внутри своего пакета, а также классам-наследникам (subclasses), даже если они находятся в других пакетах.
  4. public: Элемент доступен из любого другого класса.
Сводная таблица видимости: Модификатор Класс Пакет Подкласс (другой пакет) Весь мир
private Да Нет Нет Нет
default Да Да Нет Нет
protected Да Да Да Нет
public Да Да Да Да

Пример в коде:

package com.example;

public class AccessModifiersDemo {
    private String secret = "Только для этого класса";
    String packagePrivate = "Для классов пакета com.example"; // default
    protected String forSubclasses = "Для пакета и наследников";
    public String api = "Для всех";

    private void privateMethod() {}
    public void publicMethod() {
        // Внутри класса доступно всё
        System.out.println(secret);
    }
}

// Класс в другом пакете
package com.other;
import com.example.AccessModifiersDemo;

class OtherPackageClass extends AccessModifiersDemo {
    void test() {
        // System.out.println(secret); // Ошибка: private
        // System.out.println(packagePrivate); // Ошибка: default
        System.out.println(forSubclasses); // OK: protected (наследник)
        System.out.println(api); // OK: public
    }
}

Примечание для C#: В C# используются схожие модификаторы public, protected, private, а также internal (аналог Java default) и protected internal (объединение protected и internal).

Ответ 18+ 🔞

А, ну это про наши любимые модификаторы доступа в Java, да? Ёпта, классика, как "Муму" Тургенева, только проще, блядь. Сейчас разжуём, как бабка семечки.

Смотри, есть у нас четыре таких охранника, которые решают, кто и куда может совать свой нос. Идут они, как водка по градусам — от самой жёсткой до той, что всех на уши ставит.

Первый, private — это как твой личный дневник в запертом ящике. Только сам класс, в котором это объявлено, может туда лазить. Никакой сосед по пакету, никакой сын-наследник — нихуя. Максимальная закрытость, инкапсуляция в её, блядь, чистейшем виде. Секретики свои храни.

Второй, default (он же package-private). Во, это интересно! Его даже писать не надо, просто ни хуя не ставишь. Доступ — только для своих, для членов одного пакета. Как в коммуналке: все, кто живёт в квартире com.example, могут брать твою соль, но сосед из com.other — уже нет. Семейное, так сказать.

Третий, protected. А вот это уже хитрая жопа. Он как default, но с бонусом для родни. То есть доступ даётся и всему пакету, и ещё всем детям-наследникам, даже если они уехали жить в другой пакет. Типа, "семья — это святое, где бы ты ни был".

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

А вот тебе табличка, чтобы в голове не еблось:

Модификатор Сам класс Свой пакет Наследник (чужой пакет) Весь мир
private Да Нет Нет Нет
default Да Да Нет Нет
protected Да Да Да Нет
public Да Да Да Да

Ну и кусочек кода, чтобы было понятнее, где что торчит:

package com.example;

public class AccessModifiersDemo {
    private String secret = "Только для этого класса";
    String packagePrivate = "Для классов пакета com.example"; // default
    protected String forSubclasses = "Для пакета и наследников";
    public String api = "Для всех";

    private void privateMethod() {}
    public void publicMethod() {
        // Внутри класса доступно всё
        System.out.println(secret);
    }
}

// Класс в другом пакете
package com.other;
import com.example.AccessModifiersDemo;

class OtherPackageClass extends AccessModifiersDemo {
    void test() {
        // System.out.println(secret); // Ошибка: private — нихуя не получишь
        // System.out.println(packagePrivate); // Ошибка: default — ты не из нашего пакета
        System.out.println(forSubclasses); // OK: protected — ты же сын, проходи
        System.out.println(api); // OK: public — welcome, блядь
    }
}

И да, для тех, кто из мира C# подъехал: у вас там почти так же, только internal — это наш default, а protected internal — это такая помесь, чтоб её. В общем, суть одна, просто вывеска другая.