Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/wordpress/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 不可变类的示例_Java_Immutability - Fatal编程技术网

Java 不可变类的示例

Java 不可变类的示例,java,immutability,Java,Immutability,我已经知道不可变类的定义,但是我需要一些例子 构建后无法更改不可变类。因此,例如,Java字符串是不可变的 要使类不可变,必须使其final和所有字段private和final。例如,以下类是不可变的: public final class Person { private final String name; private final int age; private final Collection<String> friends;

我已经知道不可变类的定义,但是我需要一些例子

构建后无法更改不可变类。因此,例如,Java
字符串是不可变的

要使类不可变,必须使其
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);
     }
}
公共最终课程人员{
私有最终字符串名;
私人最终年龄;
私人最终收藏朋友;
公众人物(字符串名称、整数、收藏朋友){
this.name=名称;
这个。年龄=年龄;
this.friends=新阵列列表(friends);
}
公共字符串getName(){
返回此.name;
}
公共整数getAge(){
返回这个年龄;
}
公共集合getFriends(){
返回集合。不可修改集合(this.friends);
}
}
我在代码示例中添加了一个方法,展示了如何处理集合,这一点很重要


在可能的情况下,您应该使类不可变,因为这样您就不必担心线程安全之类的问题。

String
是不可变类的一个很好的“现实世界”示例。您可以将其与可变
StringBuilder
类进行对比


大多数用于反射的Java类都是不可变的。还有一些是“几乎不可变的”:例如,实现
Accessible
的类只有一个
setAccessible
方法,可以更改
Accessible
实例的状态


我相信标准类库中还有很多内容。

Sun(Oracle)文档中有一个关于如何创建不可变对象的优秀清单

  • 不要提供“setter”方法—修改字段或字段引用的对象的方法
  • 将所有字段设置为最终字段和私有字段
  • 不允许子类重写方法。最简单的方法是将类声明为final。一种更复杂的方法是使构造函数私有,并在工厂方法中构造实例
  • 如果实例字段包括对可变对象的引用,则不允许更改这些对象:
    • 不要提供修改可变对象的方法
    • 不要共享对可变对象的引用。永远不要存储对传递给构造函数的外部可变对象的引用;如有必要,创建副本并存储对副本的引用。类似地,在必要时创建内部可变对象的副本,以避免在方法中返回原始对象
  • 发件人:


    该站点还提供了在并发上下文中使用它的示例,但在编写库时,不变性也很有用。它确保库的调用者只能更改我们允许他们更改的内容。

    标准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.StackTraceeElement(用于生成异常stacktraces)
    • 大多数枚举类是不可变的,但这实际上取决于具体情况。(不要实现可变枚举,这有时会把你搞砸。)我认为至少标准API中的所有枚举类实际上都是不可变的

    • java.math.BigInteger和java.math.BigDecimal(至少这些类的对象本身、子类可能引入可变性,尽管这不是一个好主意)

    • java.io.File。请注意,这表示VM外部的对象(本地系统上的文件),该对象可能存在也可能不存在,并且具有一些修改和查询此外部对象状态的方法。但是文件对象本身保持不变。(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不太确定)
    • Cursor-表示鼠标光标的位图(这里也有一些子类可能是可变的或取决于外部因素)

    • java.util.Locale—表示特定的地理、政治或文化区域

    • java.util.UUID—尽可能多的全局唯一标识符
    • 虽然大多数集合都是可变的,但java.util.collections类中有一些包装器方法,它们返回集合的不可修改视图。如果您向它们传递一个在任何地方都不知道的集合,那么这些集合实际上是不可变的集合。另外,
      Collections.singletonMap()
      singletonList
      singleton
      返回不可变的单元素集合,也有不可变的空集合

    • java.net.URL和java.net.URI-表示资源(在internet或其他地方)

    • java.net.inet4地址和java.net.inet6地址,java.net.InetSocketAddress
    • java.security.Permission的大多数子类(表示某些操作所需的权限或赋予某些代码的权限),但不包括java.security.PermissionCollection和子类
    • 除了
      DateTimeException
      之外,
      java.time
      的所有类都是不可变的。的子包的大多数类
       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());
      
      }
      
      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's 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's state has changed.
          **/ 
          public ImmutableReader turnPage() {
              return new ImmutableReader(this.readersBook, page + 1);
          }
      }
      
      private final List<String> fruitnames;
      
      public Fruit(List<String> fruitnames) {
          this.fruitnames = new ArrayList<>(fruitnames);
      }
      
      public List<String> getFruitnames() {
           return new ArrayList<>(fruitnames);
      }
      
      @Override
      public int hashCode() {
          return getFruitnames() != null ? getFruitnames().hashCode(): 0;
      }
      
      public static void main(String args[]){
      
          List<String> fruitList = new ArrayList<>();
          fruitList.add("Apple");
          fruitList.add("Banana");
          //Immutable Object 1
          Fruit fruit1 = new Fruit(fruitList);
          //fruitHash is-689428840
          int fruitHash = fruit1.hashCode();
      
          System.out.println("fruitHash is" +fruitHash);
          //This value will not be added anymore as the state has already been defined and
          //now it cant change the state.
          fruitList.add("straberry");
          //fruitHash1 is-689428840
          int fruitHash1 = fruit1.hashCode();
      
      
          System.out.println("fruitHash1 is" +fruitHash1);
      }