3

在 C# 中存在一种称为属性的成员类型。这使您可以轻松简单地定义私有字段并提供简单或复杂的 getter 和 setter,同时通过不必定义整个方法来节省空间。Java 没有这样的东西,据我所知,普遍的共识是吸收它并为私有变量定义完整的 getter 和 setter 方法。

目前,我一直在玩弄以下课程:

public class Property<T> {

    private T value = null;

    public Property(){}
    public Property(T initialValue){
        value = initialValue;
    }

    public T get(){
        return value;
    }

    public void set(T newValue){
        value = newValue;
    }

}

通过这个实现,您可以定义只需要 getter 和 setter 的简单属性: final Property<String> name = new Property<>("Dog");

或者更高级的选项,例如 MSDN 为 C# 提供的选项:

...
public double seconds;

public final Property<Double> Hours = new Property<Double>(){
    @Override
    public Double get() {
        return seconds/3600;
    }

    @Override                                              
    public void set(Double newValue) {
        seconds = newValue * 3600;
    }
};
...

这种解决方案的优缺点是什么?

4

3 回答 3

2

优点很明显。我将指出一些使其优于 C# 的属性:

  1. 支持字段被隐藏起来,这样您就不会意外使用它而不是属性。(但缺点是如果你愿意,你不能轻易选择使用支持字段)
  2. 与 C# 的自动属性不同,您可以选择仅覆盖getorset方法,而不是两者,例如

    public Property<List<String>> MyList = new Property<List<String>>(){
        @Override
        public List<String> get() {
            if (value == null)
                value = new ArrayList<String>();
            return value;
        }
        // set still works
    };
    

但是也有缺点:

  1. 它不是 Java 语言或任何通用库的一部分,因此它可能会让阅读您的代码的人感到困惑(包括将来的您自己)。
  2. 您无法更改getset方法的可见性:如果Property<T>可以访问,则可以获取和设置值。
  3. 如果您不创建您的Property字段final,任何可以访问它的人都可以将其更改为他们自己的Property实现。这可能很有用,但大多数情况下会很痛苦。
  4. (这是与 C# 的属性共享的一个缺点)您不能更改传递给getandset方法的参数。例如,您不能Property<MyType>同时拥有 aset(MyType)和 aset(CompatibleType)方法(除非您扩展Property)。
  5. 普遍使用泛型意味着在运行时(感谢type erasure)您正在Object普遍使用。double如果您使用原语(例如使用vs ) ,这种装箱/拆箱可能会稍微降低性能(在大多数应用程序中不明显Property<Double>)。

顺便说一句,Scala是一种在 JVM 上运行的语言,它包含作为本机特性的属性,并与 Java 的属性版本(getter/setter)互操作。您可能想研究一下,因为基本上其他人已经为您破解了 Java 语言。=)

总而言之,我想说你不应该试图让 Java 具有属性。在罗马做到入乡随俗。如果您不喜欢罗马人的做法,请沿着街道 (Scala) 或全国各地 (C#) 移动。

于 2013-10-05T23:04:54.807 回答
1

所以完整的语法,比如 name,现在应该是:

theObject.name.set("new name");

关键是,您如何访问该名称对象?它是公共/受保护的那么它可以被覆盖。是私人的吗?那么无论如何你都不能在课堂外改变它。

您提出的解决方案仅在您已经有权访问该对象时才有效,此时您不需要该解决方案。

于 2013-10-05T22:13:58.483 回答
0

这个解决方案(你的匿名内部类)的优点是,如果你不需要在其他任何地方实现它,它可以让你不必为这种情况编写一个完整的额外类。

此解决方案的缺点是稍后您可能希望在其他地方实现它,然后您希望重构代码以将 Property<Double> 的实现提取到它自己的类中以避免重复自己。

我想说,如果你很确定你不会在其他任何地方需要这个实现(我猜你不会),那就继续使用匿名内部类的后续解决方案。这是一个很好的。

于 2013-10-05T23:44:42.140 回答