18

Compiling

import java.util.concurrent.Callable;

class Ideone
{
    Callable<?> x = super::clone;
}

using Oracle JDK gives:

Main.java:6: error: incompatible types: invalid method reference
    Callable<?> x = super::clone;
                    ^
    clone() has protected access in Object

which makes no sense as a class should be able to access its parent's protected methods. This expression works fine in Eclipse's compiler.

Also, () -> super.clone() compiles fine....

Is this a bug?

billc.cn
  • 7,187
  • 3
  • 39
  • 79
  • 2
    Does `this::clone` work? – thecoop Oct 13 '15 at 16:21
  • I can reproduce this with JDK 1.8.0_51 and Eclipse Mars 4.5.0. Seems like an Eclipse bug. – Tunaki Oct 13 '15 at 16:22
  • Works fine JDK 1.8.0_60 and Eclipse Mars – Flown Oct 13 '15 at 16:26
  • 3
    @thecoop: `this.clone` or generally `this::protectedMethod` works whereas any `super::protectedMethod` fails when the declaring class is inside a different package. – Holger Oct 13 '15 at 16:29
  • Possibly related: A JDK bug, but it's about fixing the JLS documentation: [6.6.2: Handle method references in protected access rules](https://bugs.openjdk.java.net/browse/JDK-8032830). – rgettman Oct 13 '15 at 16:49
  • @Flown I've just downloaded JDK 8u60 (build 1.8.0_60-b27) and it still gives the same error... – billc.cn Oct 13 '15 at 16:54
  • @billc.cn Tried it again and you're right there is a compilation error. Wonder why it has compiled the first time. – Flown Oct 13 '15 at 17:07
  • @rgettman The bug is interesting. It asserts that `super::Identifier` can always be used and doc does not need to be updated, but as far as I can see, none of the bullet points in [JLS 6.6.2](https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6.2) matches this, esp. `super` is neither a `ExpressionName` nor a `Primary` expression. – billc.cn Oct 13 '15 at 17:12
  • 2
    @billc.cn I read 6.6.2 very simply: access to a protected member is permitted only within the body of a subclass. **In addition**, the three bullet points apply under the conditions named inside them. Those bullet points are there to prevent access to a protected member in a sibling class, and `super` does not belong there. So it falls within the introductory sentence, and is therefore allowed without any of the three limitations applying. – RealSkeptic Oct 13 '15 at 19:42

1 Answers1

7

super is not actually an expression, and there's no static type to talk about. super.foo() has the same access as this.foo(); it's just that, the method invocation is translated differently in byte code, as "super invoke", as opposed to "normal invoke".

JLS is not very clear on this; e.g. in section of protected access, the super.protectedMember form is not mentioned; but obviously that form should be discussed in JLS; and it should be accessible. (The section does suggest that X::m and X.m should be treated the same w.r.t. access right)

In the section of method reference, the wording is also vague; nevertheless, super::clone should be accessible the same ways as super.clone() is accessible.

A bug report has been created: JDK-8139836: “Can't use super::x method reference when x is protected”. Its current status is that it will be fixed in Java 9.

Holger
  • 285,553
  • 42
  • 434
  • 765
ZhongYu
  • 19,446
  • 5
  • 33
  • 61
  • (Please see my [comment](#comment54031785_33107500).) 6.6.2.1 is written in very precise language, so I'd say it's not vague on the case: the case is literally undefined. However, since this form is required to implement a useful `clone()`, I can hardly believe it's been missing in the spec for so long. – billc.cn Oct 13 '15 at 17:28
  • 1
    well... would you say that the unqualified `clone()` form is also undefined? maybe it's well understood that it's equivalent to `this.clone()`. Similarly, maybe, `super.clone()` is well understood, among the target audience of JLS, to be equivalent in many ways to `this.clone()` at compile time. – ZhongYu Oct 13 '15 at 17:31
  • 1
    I think, it’s safe to assume that if the additions do not apply, “Access is permitted only within the body of a subclass S of C” is the only restriction. But it’s not entirely correct to say “`super.foo()` has the same access as `this.foo()`” as the current class could override `foo()` with a different (less restricting) access. – Holger Oct 14 '15 at 10:26
  • 1
    @Holger - well, we are not talking about general accessibility of `foo`. we are talking about whether `this.foo()` is accessible, a yes-no question. (which is always yes) – ZhongYu Oct 14 '15 at 12:42
  • 1
    It’s clear that your intended statement is correct as `foo()` can only be overridden if it is accessible. Still, “has the same access” is a misleading wording. – Holger Oct 14 '15 at 13:04