Java 什么是C++';s常量成员函数? C++中,我可以定义一个访问成员函数,它返回私有数据成员的值(或引用),这样调用方就不能以任何方式修改该私有数据成员。

Java 什么是C++';s常量成员函数? C++中,我可以定义一个访问成员函数,它返回私有数据成员的值(或引用),这样调用方就不能以任何方式修改该私有数据成员。,java,Java,有没有一种在Java中实现这一点的方法 如果是,怎么做 我知道final关键字,但当应用于方法时,它是: 防止重写/多态 在子类中使用该方法 使该方法可以内联。(见下文@Joachim Sauer的评论) 但它并没有限制该方法返回对数据成员的引用,以便调用方不能修改它 我是否忽略了一些显而易见的事情?你没有忽略任何事情。纯Java中没有这样做的方法。可能有一些库使用注释提供了其中的一些子集,但我现在还不知道 传回不可变数据引用的方法是使传回的类不可变、简单明了。有几个库函数可以帮助您在一些非常有

有没有一种在Java中实现这一点的方法

如果是,怎么做

我知道
final
关键字,但当应用于方法时,它是:

  • 防止重写/多态 在子类中使用该方法
  • 使该方法可以内联。(见下文@Joachim Sauer的评论)
  • 但它并没有限制该方法返回对数据成员的引用,以便调用方不能修改它


    我是否忽略了一些显而易见的事情?

    你没有忽略任何事情。纯Java中没有这样做的方法。可能有一些库使用注释提供了其中的一些子集,但我现在还不知道

    传回不可变数据引用的方法是使传回的类不可变、简单明了。有几个库函数可以帮助您在一些非常有限但常见的情况下生成某些数据的不可变视图。这里有一个例子:

    private List<String> internalData;
    
    public List<String> getSomeList() {
        return Collections.unmodifiableList(internalData);
    }
    
    私有列表内部数据;
    公共列表getSomeList(){
    返回集合。不可修改列表(internalData);
    }
    
    这在java中不存在
    final
    const
    具有不同的语义,但应用于基元类型的变量时除外。java解决方案通常涉及创建不可变类,其中对象在构造中初始化,并且不提供允许更改的访问器。例如,
    String
    Integer

    可以返回成员的副本,因此更改不会反映在私有引用点的对象中。当然,对于原语,这个问题并不存在


    不过,请注意内存使用情况!这可能不是所有情况下的正确解决方案。在这种情况下,另一个答案中建议的不可变对象可能是解决方法。

    我认为在Java中没有一种方法可以解决非原始对象的问题(您总是传递对此类对象的引用)。最接近的方法是返回对象的副本(使用克隆或类似的方法);但这不是非常地道的Java

    如果您只想授予对成员对象的“可见”部分的访问权限,那么您可以使用该可见部分创建一个接口,并返回该接口。例如:

    public interface Bar {
         public int getBing();
    }
    
    public class BarImpl implements Bar {
         private int bing;
         public int getBing() {
            return bing;
         }
         public void setBing(int bing) {
            this.bing = bing;
         }
    }
    
    public class Foo {
         private BarImpl bar;
    
         public Bar getNonModifiableBar() {
             return bar; // Caller won't be able to change the bing value, only read it.
         }
    }
    

    Java中没有与C
    const
    等价的“类型修饰符”(遗憾的是)

    最接近的方法是返回不可变对象或围绕可变对象的不可变包装器

    然而,不变性不是Java的语言特性,因此您必须依赖于库

    不可变对象的示例包括:

    • 原语包装器包括
      整数
      字符
    • String
    • 文件
    • URL

    常用的不可变包装器(即围绕防止突变的可变类型的包装器)是由返回的对象返回的包装器。

    防止修改取决于返回的对象。Java不提供对不可修改对象的声明式/编译时检查,除非该类型缺少mutator

    JDK中有一些支持:类似的方法将创建一个对象,如果客户端调用collection mutator方法,该对象将抛出运行时异常


    如果您真的有动机,可以通过定义只读接口(或类)来获得编译时检查,这些接口(或类)只能自己公开/实现访问器方法。请记住,如果客户端使用内省,并且对象提供了变种(不会引发UnsupportedOperationException),则仅声明方法返回只读接口不会阻止运行时修改。

    避免此问题的一种方法是不公开数据结构(另一个正在返回副本或不可变包装)

    e、 g.代替

    public List<String> getSomeList();
    

    当你这样做的时候:

    Object2 obj2 = obj1.getObj2();
    obj2 = new Object2();
    
    原始的私有成员(obj1.obj2)与以前一样(只是为了确保您理解了这个概念)。您可以省略obj2的setter,这样内部字段就不能取消更改

    如果希望Object2字段不可变,则需要应用相同的模式(私有字段,无setter)

    这是否回答了您的问题?

    您可以返回一个对象,或者返回一个私有实例变量的副本。这样,对象的内部状态就不会被修改,即:

    private MyMutableObject mutable = ...
    
    public MyMutableObject getMutableObject() {
       return new MyMutableObject(this.mutable);
    }
    `
    

    您的第#2项是错误的:内联不是由Java指定的,这种优化完全由JVM决定,JVM内联方法不需要
    final
    。@Joachim Sauer感谢您指出这一点。我感到困惑。下面的陈述正好相反。他错了吗?是的,它错了。Roseindia.net是一个它的质量通常很差。它的站点范围从轻微误导到完全错误。而
    静态final
    字段是用常量表达式初始化的(所谓的“编译时常量”)可以内联,Java中没有指定任何类型的方法内联。这是JVM在运行时的一种可能的运行时优化,但不能影响观察到的行为(使用
    final
    方法更容易,但也可以使用非
    final
    方法)@Joachim Sauer谢谢。+2我将编辑我的原始帖子以反映您的更正。由于我在网上发现了一些令人困惑的信息,我将不得不部分更正我自己:至少有内联方法。通常我的说法仍然是正确的:普通Java编译器不内联方法,但让矮子来决定为什么返回副本不是惯用的Java呢?对不起,我的意思是,对于访问器(臭名昭著的get/set方法),它是
    private MyMutableObject mutable = ...
    
    public MyMutableObject getMutableObject() {
       return new MyMutableObject(this.mutable);
    }
    `