2

I'm almost certain this question has been asked, but I'm not sure what to search for regarding it.

Anyway, I was was curious if it would be possible to create a class that extends ByteBuffer. I thought it would be impossible due to ByteBuffer having package-private constructors:

// package-private
ByteBuffer(int mark, int pos, int lim, int cap, byte[] hb, int offset) {
    super(mark, pos, lim, cap);
    this.hb = hb;
    this.offset = offset;
}

// Creates a new buffer with the given mark, position, limit, and capacity
//
ByteBuffer(int mark, int pos, int lim, int cap) { // package-private
    this(mark, pos, lim, cap, null, 0);
}

However, I found out if you create your class in a package that shares a name with its parent, then it compiles perfectly.

package java.nio;

public class Test extends ByteBuffer {
    Test(int mark, int pos, int lim, int cap, byte[] hb, int offset) {
        super(mark, pos, lim, cap, hb, offset);
    }

    @Override
    public ByteBuffer slice() {
        return null;
    }

    ...
}   

It compiles in Java 9 and Java 10 as well, but only when using --patch-module when compiling:

javac --patch-module java.base=. java/nio/Test.java

My question is: How (and why) does this compile?

Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • [Adding Classes To Modules With `--patch-module`](https://blog.codefx.org/java/five-command-line-options-to-hack-the-java-9-module-system/#Adding-Classes-To-Modules-With--patch-module) – Elliott Frisch Aug 07 '18 at 00:52
  • I'm a little confused by your wording. I think I know what you mean from your example, but I don't see how that's "[creating a] class in a package that shares a name with its parent". As far as I can tell, it's just "creating a class in a package". – John Bollinger Aug 07 '18 at 00:52
  • @JohnBollinger To clarify, creating a package with the same name as the parent's package. So I create a package `java.nio` locally (since `ByteBuffer` also resides in `java.nio`, but in a different location) – Jacob G. Aug 07 '18 at 00:54
  • @ElliottFrisch I would be happy with that, but this method also works with Java 8. – Jacob G. Aug 07 '18 at 00:55
  • 1
    Ok, so here's the problem with your wording, and also most of an answer: there is no "package with the same name". There is the package identified by a given name, period. Just one for each valid package name. – John Bollinger Aug 07 '18 at 00:56
  • @JohnBollinger So are you saying that if I name my package `java.nio`, then it will be compiled with the `java.nio` package built into the JDK? – Jacob G. Aug 07 '18 at 00:57
  • No. I am saying that you can declare classes you write to be in package `java.nio`, and that's the same package that also contains a bunch of classes shipped with the JDK. But that does not make your class part of the JDK, and very likely Java will refuse to load it, because the platform packages are *sealed*. – John Bollinger Aug 07 '18 at 01:01

1 Answers1

3

Are packages (that share a name) combined during compliation?

Not exactly. A package name uniquely identifies a package. There is only one for each name.

But the Java sources for the members of a package don't have to all reside in the same source tree or be compiled at the same time. The Java compiler will accept your classes' declaration of any valid package name, and accept your classes as being in the package they say they are in.

On the other hand, that does not mean you can use classes that you declare to be in a java.* or javax.* package in any given JVM. Standard JVMs will refuse to load classes belonging to those packages from any source external to the JVM. You can build such classes but you cannot use them. You can protect your own packages in much the same way, through a mechanism called "package sealing".

On the third hand, with unsealed packages, you can indeed load package members from multiple distinct sources.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157