6

I have an abstract class with an abstract method, the parameters for which I want to be final - that is, I do not want to allow implementations of the abstract class & method to reassign the parameter.

EDIT: The motivation for this is not immutability per se, which is more to do with the design of the objects. (In fact, in my use case, the parameter is collection which will be mutated in the implementation of the abstract method.) Rather, I want to communicate to anyone implementing my abstract class/method that these variables should not be reassigned. I know that I can communicate that via the java-doc, but I was looking for something more contractual - that they would have to follow, rather than just be guided to follow.

In a non-abstract method, I can do this using the final keyword - for example:

public class MyClazz {
  public void doSomething(final int finalParameter){
    finalParameter++; // compile error - cannot assign a value to final variable
  }
}

However, if I use the final keyword in an abstract method, this does not form part of the contract - that is, implementations of the abstract method do not require the final keyword, and the parameter can be reassigned:

public abstract class MyAbstractClazz {
  public abstract void doSomething(final int finalVariable);
}

public class MyExtendedClazz extends MyAbstractClazz {
  @Override
  public void doSomething(int finalVariable) { // does not require final keyword
    finalVariable++; // so the variable is modifiable
  }
}

As pointed out in answers to this SO Question, the final keyword does not form part of the method signature, which is why the implementation of the abstract class does not require it.

So, there are two questions:

  1. Why is the final keyword not part of the method signature? I understand that it isn't, but I want to know if there's a particular reason why it isn't.

  2. Given that the final keyword is not part of the method signature, is there an alternative way of making parameters in an abstract method unassignable?

Other research:

  • this SO question touches on the same issue, but doesn't either of my two questions. In fact, the second question is explicitly asked, but does not receive an answer.

  • lots of questions/blogs etc. on the final keyword refer to "the final word". However, with respect to this question, the relevant comment is as follows (which, while useful, doesn't address my two questions):

Note that final parameters are not considered part of the method signature, and are ignored by the compiler when resolving method calls. Parameters can be declared final (or not) with no influence on how the method is overriden.

Community
  • 1
  • 1
amaidment
  • 6,942
  • 5
  • 52
  • 88
  • But even if a method reassigns the variable handed to it, it has no consequences for the caller as the object reference is passed by value. Things turn a lot more evil if you change to object by modifying its state. – Matthias Jul 18 '13 at 09:45
  • What exactly are you trying to accomplish? Immutability? – Erik Pragt Jul 18 '13 at 09:46
  • @ErikPragt- amended question on the motivation. – amaidment Jul 18 '13 at 10:21

2 Answers2

11

I have an abstract class with an abstract method, the parameters for which I want to be final - that is, I do not want to allow implementations of the abstract class & method to reassign the parameter.

Why not? That's an implementation detail. It's unobservable to the calling code, so there's no reason why the abstract method should specify it. That's why it's not part of the method signature, either - just like synchronized isn't.

A method should implement its documented contract - but how it chooses to do so is up to it. The contract can't say anything useful about the finality of a parameter, as Java always uses pass-by-value.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Ok, thanks - that makes sense of why it's not part of the signature. I've edited my question with more on my motivation, but I expect that the best I can do is indicate the intended implementation in the documentation. – amaidment Jul 18 '13 at 10:23
  • @amaidment: I think you're missing the point - why would anyone care whether the method implementation changed the value of the parameter? That's *completely hidden* from the outside world. You say "these variables should not be reassigned" - why do you care how the method is implemented? If one implementation happens to be cleaner if it reassigns the parameter, why would you want to prevent that? – Jon Skeet Jul 18 '13 at 10:32
  • Those are good, helpful questions... the answer to all of which, I realise, is "I shouldn't.". – amaidment Jul 18 '13 at 10:35
  • @amaidment: Excellent :) – Jon Skeet Jul 18 '13 at 10:37
  • "Java always uses pass-by-value" if you accept that for objects, what is being passed, is a pointer to the object (that you don't have to do any magic to use). – Phil Jan 07 '14 at 05:03
  • @Phil: It's a reference, yes. The value of *any* variable or similar expression is a primitive value or a reference. It's *never* an object. – Jon Skeet Jan 07 '14 at 05:06
  • @Jon Skeet: No, not a reference. A pointer, passed by value. They aren't the same thing. http://javadude.com/articles/passbyvalue.htm – Phil Jan 07 '14 at 05:15
  • @Phil: No, it's a reference. That's the Java terminology. From section 4.3.1 of the JLS: "The reference values (often just references) are pointers to these objects, and a special null reference, which refers to no object." (Although I dislike using the word "pointer" as that suggests it's as simple as the actual memory location, when it doesn't have to be - it's just *a way* of navigating to the object in question. In a toy VM, a reference could be (say) a 16-bit index into an array of *real* pointers. "Reference" here isn't exactly the same in Java as in C++, but I'm using Java terminology. – Jon Skeet Jan 07 '14 at 05:18
  • @Phil: And in particular, while Scott (the author of the article you referred to) doesn't like the term "reference" that *is* the term used by Java (and C#, which incidentally has pointers *as well*, which still aren't the same as references). I disagree with Scott in his dislike of the term reference here, but whether it was well chosen or not it is the term used throughout the JLS. (Count the number of occurrences of the word "reference" as a noun vs "pointer"...) – Jon Skeet Jan 07 '14 at 05:21
  • The fact that sun got the terminology wrong is the entire point here. When you declare an object, you get a pointer (or pointer like thing) (which sun called a reference) to it. It behaves the same way as as what other languages (that preceded Java) call a pointer does. It does not behave the same way as what other languages (that preceded Java) call a reference does. As far as I know (and I could be wrong), earlier languages were consistent with what 'pointer' and 'reference' meant, and sun just went ahead and changed all that, just to screw with us all. :-) – Phil Jan 07 '14 at 05:25
  • @Phil: No, it doesn't behave the same way as a pointer does - not in all ways. In particular, there is no pointer arithmetic involved - it's just an opaque value which refers to an object (or is null). How it refers to it is an implementation detail. This distinction is important in C#, where there are pointers and references - see http://blogs.msdn.com/b/ericlippert/archive/2011/03/07/references-and-pointers-part-one.aspx. But regardless of whether you think Sun did the wrong thing, they clearly defined the terminology for Java, so when we're talking about Java *that's the terminology to use* – Jon Skeet Jan 07 '14 at 05:28
  • @Phil: It's one thing to introduce references to a C++ programmer by *comparing* them to pointers, but when the topic is entirely Java, your "correcting" my use of terminology to fit in with your preferred view of the world rather than the terminology used throughout the Java Language Specification (and by Java developers everywhere) is inappropriate, IMO. – Jon Skeet Jan 07 '14 at 05:29
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/44665/discussion-between-phil-and-jon-skeet) – Phil Jan 07 '14 at 05:29
4

Parameters are passed by value, if you call the method using certain variable, this variable wont get modified even if you reassign the parameter inside the method, that's why it doesn't make sense for final to be part of the contract.

morgano
  • 17,210
  • 10
  • 45
  • 56