Подтвердить что ты не робот

Примеры непреложных классов

Я уже знаю определение неизменяемых классов, но мне нужно несколько примеров.

4b9b3361

Ответ 1

Некоторые известные неизменные классы в стандартном API:

  • java.lang.String(уже упоминалось)
  • Классы-оболочки для примитивных типов: java.lang.Integer, java.lang.Byte, java.lang.Character, java.lang.Short, java.lang.Boolean, java.lang.Long, java.lang.Double, java.lang.Float
  • java.lang.StackTraceElement(используется при построении стеков исключений)
  • Большинство классов перечисления неизменяемы, но это фактически зависит от конкретного случая. (Не реализуйте изменчивые перечисления, это немного повредит вам.) Я думаю, что по крайней мере все классы enum в стандартном API фактически неизменяемы.

  • java.math.BigInteger и java.math.BigDecimal(по крайней мере, объекты самих этих классов, подклассы могут вводить изменчивость, хотя это не очень хорошая идея)

  • java.io.File. Обратите внимание, что это представляет объект, внешний по отношению к виртуальной машине (файл в локальной системе), который может или не может существовать, и имеет некоторые методы, изменяющие и запрашивающие состояние этого внешнего объекта. Но сам объект File остается неизменным. (Все остальные классы в java.io изменяемы.)

  • java.awt.Font - представляет шрифт для рисования текста на экране (могут быть некоторые изменяемые подклассы, но это, конечно, не будет полезно)

  • java.awt.BasicStroke - вспомогательный объект для рисования линий в графических контекстах
  • java.awt.Color - (по крайней мере, объекты этого класса, некоторые подклассы могут быть изменчивыми или в зависимости от некоторых внешних факторов (например, системных цветов)) и большинства других реализаций java.awt.Paint
    • java.awt.GradientPaint,
    • java.awt.LinearGradientPaint
    • java.awt.RadialGradientPaint,
    • (Я не уверен в java.awt.TexturePaint)
  • java.awt.Cursor - представление растрового изображения для курсора мыши (здесь тоже некоторые подклассы могут изменяться или в зависимости от внешних факторов)

  • java.util.Locale - представляющий конкретный географический, политический или культурный регион.

  • java.util.UUID - максимально возможный глобальный уникальный идентификатор
  • в то время как большинство коллекций изменяемы, в классе java.util.Collections есть некоторые методы-обертки, которые возвращают немодифицируемый вид коллекции. Если вы передадите им коллекцию, не известную нигде, это на самом деле неизменные коллекции. Кроме того, Collections.singletonMap(), .singletonList, .singleton возвращают неизменяемые одноэлементные коллекции, а также неизменяемые пустые.

  • java.net.URL и java.net.URI - представление ресурса (в Интернете или где-то еще)

  • java.net.Inet4Address и java.net.Inet6Address, java.net.InetSocketAddress
  • большинство подклассов java.security.Permission(представляющие разрешения, необходимые для некоторого действия или данные для некоторого кода), но не java.security.PermissionCollection и подклассы.

Можно сказать, что примитивные типы тоже неизменяемы - вы не можете изменить значение 42, не так ли?


- класс AccessControlContext неизменяемый класс

AccessControlContext не имеет каких-либо мутирующих методов. И его состояние состоит из списка ProtectionDomains (который является неизменным классом) и DomainCombiner. DomainCombiner - это интерфейс, поэтому в принципе реализация может делать что-то другое при каждом вызове.

На самом деле, а также поведение ProtectionDomain может зависеть от текущей политики в силе -. Спорно ли называть такой объект неизменяемой

и AccessController?

Нет объектов типа AccessController, так как это конечный класс без доступного конструктора. Все методы статичны. Можно сказать, что AccessController не является ни изменяемым, ни неизменным, или и тем, и другим.

То же самое относится ко всем другим классам, которые не могут иметь объекты (экземпляры), наиболее известные:

  • java.lang.Void
  • java.lang.System(но это имеет некоторое изменяемое статическое состояние - in, out, err)
  • java.lang.Math(это тоже - генератор случайных чисел)
  • java.lang.reflect.Array
  • java.util.Collections
  • java.util.Arrays

Ответ 2

Неизменяемые классы не могут быть изменены после строительства. Так, например, Java String неизменен.

Чтобы сделать класс неизменным, вы должны сделать его final и все поля private и final. Например, следующий класс является неизменным:

public final class Person {

     private final String name;
     private final int age;
     private final Collection<String> friends;

     public Person(String name, int age, Collection<String> friends) {
         this.name = name;
         this.age = age;
         this.friends = new ArrayList(friends);
     }

     public String getName() { 
         return this.name;
     }

     public int getAge() {
         return this.age;
     }

     public Collection<String> getFriends() {
         return Collections.unmodifiableCollection(this.friends);
     }
}

Я добавил в методе в примере кода, показывающем, как обрабатывать коллекции, важный момент.

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

Ответ 3

Важно помнить, что объявление класса как окончательного не означает, что оно является "неизменным", это в основном означает, что этот класс не может быть расширен (или специализирован).

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

Ответ 4

Чтобы создать неизменяемый класс, вам необходимо выполнить следующие шаги:

  • Объявить класс окончательным, чтобы он не расширялся.
  • Сделать все поля закрытыми, чтобы прямой доступ не разрешался.
  • Не предоставлять методы настройки для переменных
  • Сделать все изменяемые поля окончательными, чтобы можно было присвоить его значение только один раз.
  • Инициализировать все поля через конструктор, выполняющий глубокую копию.
  • Выполнение клонирования объектов в методах getter для возврата копии а не возвращать фактическую ссылку на объект.

Ниже приведен пример .

Мы также можем использовать Builder Pattern для легкого создания неизменяемых классов, пример можно найти здесь.

Ответ 5

LocalDate, LocalTime и LocalDateTime (начиная с версии 1.8) также неизменяемы. На самом деле, этот вопрос находится на экзамене OCAJSE8 (1Z0-808), и именно поэтому я решил рассматривать его как не просто комментарий.

Все примитивные классы-оболочки (например, Логические, Символ, Байт, Короткие, Целое > , Длинные, Float и Двойной) являются неизменяемыми.

Деньги и Валюта API (для Java9) также должны быть неизменными.

Кстати, список с поддержкой массива (созданный Arrays.asList(myArray)) являются структурно неизменными.

Кроме того, существуют некоторые граничные случаи, такие как java.util.Optional (показано на экзамене OCP, 1Z0-809), что является неизменным, если содержащийся элемент сам по себе является неизменным.

Ответ 6

String - хороший пример "реального мира" неизменяемого класса. И вы можете сравнить его с изменяемым классом StringBuilder.


Большинство классов Java, используемых для отражения, неизменяемы. И некоторые из них "почти неизменяемы": например, классы, реализующие Accessible, имеют только метод setAccessible, который изменяет состояние экземпляра Accessible.


Я уверен, что в стандартных библиотеках классов есть еще много.

Ответ 7

Документация Sun (Oracle) имеет отличный контрольный список о том, как создать неизменяемый объект.

  • Не предоставляйте методы setter - методы, которые изменяют поля или объекты, на которые ссылаются поля.
  • Сделать все поля окончательными и частными.
  • Не позволяйте подклассам переопределять методы. Самый простой способ сделать это - объявить класс окончательным. Более сложный подход состоит в том, чтобы сделать конструктор частным и построить экземпляры в factory методах.
  • Если поля экземпляра включают ссылки на изменяемые объекты, не разрешайте изменять эти объекты:
    • Не предоставляйте методы, изменяющие изменяемые объекты.
    • Не используйте ссылки на изменяемые объекты. Никогда не храните ссылки на внешние, изменяемые объекты, переданные конструктору; при необходимости, создавать копии и хранить ссылки на копии. Аналогичным образом создайте копии своих внутренних изменяемых объектов, если это необходимо, чтобы избежать возврата оригиналов в ваши методы.

От: http://download.oracle.com/javase/tutorial/essential/concurrency/imstrat.html

На сайте также приведены примеры его использования в контексте concurrency, но неизменность также полезна при написании библиотек. Он гарантирует, что абоненты библиотеки могут изменять только то, что мы им разрешаем.

Ответ 8

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

Переменные объекты - это объекты, состояние которых может быть изменено после построения .example- StringBuffer После изменения значения измененной ячейки памяти изменено.  Пример ниже -

 public static void immutableOperation(){
    String str=new String("String is immutable class in Java object value cann't alter once created...");
    System.out.println(str);
    str.replaceAll("String", "StringBuffer");
    System.out.println(str);
    str.concat("Concating value ");
    System.out.println(str + "HashCode Value  " + str.hashCode());
    str=str.concat("Concating value ");
    System.out.println(str + "HashCode Val  " + str.hashCode());

}

public static void mutableOperation(){
    StringBuffer str=new StringBuffer("StringBuffer is mutable class in Java object value can  alter once created...");
    System.out.println(str + "HashCode Val - " + str.hashCode());
    str.replace(0, 12, "String");
    System.out.println(str + "HashCode Val - " + str.hashCode());

}

Ответ 9

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

Mutable class

class MutableBook {
    private String title;

    public String getTitle(){
        return this.title;
    }

    public void setTitle(String title){
        this.title = title;
    }
}

И неизменяемая реализация с использованием изменяемого экземпляра книги.

public class ImmutableReader {
    private final MutableBook readersBook;
    private final int page;

    public ImmutableReader(MutableBook book) {
        this(book, 0);
    }

    private ImmutableReader(MutableBook book, int page){
        this.page = page;

        // Make copy to ensure this books state won't change.
        MutableBook bookCopy = new MutableBook();
        bookCopy.setTitle(book.getTitle());
        this.readersBook = bookCopy;
    }


    public MutableBook getBook() {
        // Do not return the book, but a new copy. Do not want the readers
        // book to change it state if developer changes book after this call.
        MutableBook bookCopy = new MutableBook();
        bookCopy.setTitle(this.readersBook.getTitle());
        return bookCopy;
    }

    public int getPage() {
        // primitives are already immutable.
        return page;
    }

    /**
    * Must return reader instance since it state has changed.
    **/ 
    public ImmutableReader turnPage() {
        return new ImmutableReader(this.readersBook, page + 1);
    }
}

Для того, чтобы ваш класс был действительно неизменным, он должен соответствовать следующей сиремии:

  • Все члены класса объявлены окончательными.
  • Все переменные, используемые в классе на уровне класса, должны быть созданы при построении класса.
  • Никакая переменная класса не может иметь метод setter.
    • Это подразумевается из первого утверждения, но хочу дать понять, что вы не можете изменить состояние класса.
  • Все дочерние объекты также должны быть неизменными или их состояние никогда не изменяется в неизменяемом классе.
    • Если у вас есть класс с изменяемыми свойствами, вы должны заблокировать его. Объявите его приватным и убедитесь, что вы его никогда не изменяете.

Чтобы узнать немного больше, взгляните на мой пост в блоге: http://keaplogik.blogspot.com/2015/07/java-immutable-classes-simplified.html

Ответ 10

Простой неизменный класс:

public final class ImmutableStudent {

    private final int id;
    private final String name;

    public ImmutableStudent(int id, String name) {
        this.name = name;
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

Неизменяемый класс с изменяемыми полями:

package com.programmer.gate.beans;

public final class ImmutableStudent {

    private final int id;
    private final String name;
    private final Age age;

    public ImmutableStudent(int id, String name, Age age) {
        this.name = name;
        this.id = id;
        Age cloneAge = new Age();
        cloneAge.setDay(age.getDay());
        cloneAge.setMonth(age.getMonth());
        cloneAge.setYear(age.getYear());
        this.age = cloneAge;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public Age getAge() {
       Age cloneAge = new Age();
       cloneAge.setDay(this.age.getDay());
       cloneAge.setMonth(this.age.getMonth());
       cloneAge.setYear(this.age.getYear());

       return cloneAge;
    }
}

Ссылка: Как создать неизменяемый класс в java