Java `final` method: what does it promise?

2019-01-04 07:39发布

In a Java class a method can be defined to be final, to mark that this method may not be overridden:

public class Thingy {
    public Thingy() { ... }
    public int operationA() {...}
    /** this method does @return That and is final. */
    public final int getThat() { ...}
}

That's clear, and it may be of some use to protect against accidental overriding, or maybe performance — but that's not my question.

My question is: From an OOP point of view I understood that, by defining a method final the class designer promises this method will always work as described, or implied. But often this may be outside the influence of the class author, if what the method is doing is more complicated then just delivering a property.

The syntactic constraint is clear to me, but what is the implication in the OOP sense? Is final used correctly in this sense by most class authors?

What kind of "contract" does a final method promise?

标签: java oop final
5条回答
不美不萌又怎样
2楼-- · 2019-01-04 08:18

What kind of "contract" does a final method promise?

Look at it the other way, any non final method makes the implicit guarantee that you can override it with your own implementation and the class will still work as expected. When you can't guarantee that your class supports overwriting a method you should make it final.

查看更多
太酷不给撩
3楼-- · 2019-01-04 08:18

No, it's not outside the influence of the class author. You can't override it in your derived class, therefore it will do what the base class author intended.

http://download.oracle.com/javase/tutorial/java/IandI/final.html

Worth noting is the part where it suggests that methods called from constructors should be final.

查看更多
冷血范
4楼-- · 2019-01-04 08:22

I'm not sure you can make any assertions about the use of "final" and how that impacts the overall design contract of the software. You are guaranteed that no developer can override this method and void its contract that way. But on the other hand, the final method may rely on class or instance variables whose values are set by subclasses, and can call other class methods that are overridden. So final is at most a very weak guarantee.

查看更多
【Aperson】
5楼-- · 2019-01-04 08:30

First of all, you can mark non-abstract classes final as well as fields and methods. This way whole class can't be subclassed. So, behavior of class will be fixed.

I agree that marking methods final don't guarantee that their behavior will be the same in subclasses if these methods are calling non-final methods. If behavior is indeed need to be fixed, this has to be achieved by convention and careful design. And don't forget to notion this in javadoc!(java documentation)

Last but not the least, final keyword has very important role in Java Memory Model (JMM). It's guaranteed by JMM that to achieve visibility of final fields you don't need proper synchronization. E.g.:

class A implements Runnable {
  final String caption = "Some caption";                           

  void run() {
    // no need to synchronize here to see proper value of final field..
    System.out.println(caption);
  }
}  
查看更多
祖国的老花朵
6楼-- · 2019-01-04 08:33

As mentioned, final is used with a Java method to mark that the method can't be overridden (for object scope) or hidden (for static). This allows the original developer to create functionality that cannot be changed by subclasses, and that is all the guarantee it provides.

This means that if the method relies on other customizable components like non-public fields/methods the functionality of the final method may still be customizable. This is good though as (with polymorphism) it allows for partial customization.

There are a number of reasons to prevent something from being customizable, including:

  • Performance -- Some compilers can analyse and optimise the operation, especially the one without side-effects.

  • Obtain encapsulated data -- look at immutable Objects where their attributes are set at the construction time and should never be changed. Or a calculated value derived from those attributes. A good example is the Java String class.

  • Reliability and Contract -- Objects are composed of primitives (int, char, double, etc.) and/or other Objects. Not all operations applicable to those components should be applicable or even logical when they are used in the bigger Object. Methods with the final modifier can be used to ensure that. The Counter class is a good example.


public class Counter {
    private int counter = 0;

    public final int count() {
        return counter++;
    }

    public final int reset() {
        return (counter = 0);
    }
}

If the public final int count() method is not final, we can do something like this:

Counter c = new Counter() {   
    public int count() {
        super.count();   
        return super.count();   
    } 
}

c.count(); // now count 2

Or something like this:

Counter c = new Counter() {
    public int count() {
        int lastCount = 0;
        for (int i = super.count(); --i >= 0; ) {
            lastCount = super.count();
        }

        return lastCount;
    }
}

c.count(); // Now double count
查看更多
登录 后发表回答