I'm building a very simple library in Java, which will be packaged in a single Jar. It should only expose one class: World. The World class uses the subclasses of the Block class, which is in the same package (com.yannbane.a), and doesn't provide a lot of functionality itself, but needs to be extended. I planned to create another package, com.yannbane.a.blocks, which would have all the block types (subclasses).
The directory/package structure should, therefor, look like this:
com/
yannbane/
a/
World.java
Block.java
blocks/
Brick.java
Stone.java
However, in order for the subclasses of Block to actually extend the Block class, I needed to make the Block class public. This destroys my goal of having the Jar file only expose a single class, World. I also need to make the subclasses public so the World could use them.
How can I retain this package and directory structure but still have my Jar only expose the World class, not other classes?
If this is a matter of encapsulation, and all you want to expose to the world is the "World" class, then it does not matter if the unexposed classes are located in the same package or if they are inner classes in the same package.
At any rate, they will not be accessible to the users of your API. I believe encapsulation is more important here than the "logical" organization that you want to give your files. Because if you locate all your classes in the same package, then you will not have these problems and you will achieve the level of encapsulation that you are seeking. Perhaps what Java is telling you is that these classes are so inherently related that you should place them all in the same package.
Make the classes public but their constructors protected.
You still technically expose the classes - other packages are aware of them - but no other packages can instantiate those objects.
Even though the Block subclasses are in a different package from Block (com.yannbane.a and com.yannbane.blocks) they will be able to invoke the protected parent constructor, because protected members are accessible from the same package or from an inheriting object.
Related
My Java library is made of a few sub-packages (com.example.lib.api, com.example.lib.imp, com.example.lib.util,...).
The classes in api use classes A and B from imp. The classes in imp use class C in util.
I am forced to make A, B and C public, but I don't want them to be exposed to users of my library. Not hiding anything, my library is open source, but minimal APIs are simpler to understand.
Is there a way around it?
In Java 9 you will be able to control which packages are exported from a JAR. This way you can make them public, but not available to anyone else.
For now you can't control this. You either put everything in one package or rely on the documentation to make it clear they should not be used. e.g. jdk.internal assumes no one should use these except the JDK.
You cannot use a private class in any other package . Instead the class can be made public and the methods and variables can be made protected . So in this case the classes can be extended where they need and the contents in the class can be accessed only by the sub classes which extended it.
I have a question about a sneaky way to gain access to package-access members that occurred to me. Specifically, I want to extend a class - let's call it com.acme.Foo - to add some functionality. This is pure addition: all current methods of Foo would be supported just by delegating to the superclass's method. However, there is no accessible constructor of Foo, so I can't extend the class and my implementation won't pass the "isA" test for being a Foo. There is no interface that expresses Foo-ness that I can use instead of inheritance.
This is where the sneaky thought occurred to me: Foo has a package-access constructor, so why not just create a package com.acme in my source folder and create an InheritableFoo class in that package:
package com.acme;
public class InheritableFoo extends Foo {
public InheritableFoo() {
super();
}
}
Now I can implement my extension to Foo by extending InheritableFoo, since that DOES have an accessible constructor.
This feels all wrong, and somehow unethical: I'm not respecting the decision the original programmer made when he or she decided to not expose a constructor for Foo. But it could be the case that they simply adopted the "deny everything until there's a reason for it" approach. Either way, is there anything fundamentally wrong with this idea? Am I going to cause myself problems in the future if I go this route, and if so, why?
You are correct regarding the fact that you can "sneak" in a class of your own into another package and get access to package restricted elements.
This will however only as long as the author of com.acme.foo distribute his code as source or an unsealed package. Should the author of this package distribute it as a sealed jar (which is quite common I believe) your approach will no longer work.
From Sealing Packages within a JAR File
Packages within JAR files can be optionally sealed, which means that
all classes defined in that package must be archived in the same JAR
file.
How do I change my mistakenly c#-ish design to work with sensible access protection in java?
Here is my super class
abstract class Parent {
protected parentVariable;
protected parentMethod() {
//These methods and variables contain internal workings of my sub-classes
//to avoid repetition
// I don't want classes elsewhere in the package (that don't inherit from class) to see these.
}
}
I have sub classes that have shared internal working, which I've stuck it in the super class. It's still hidden to the other classes and usable by sub classes. Wait, no: this isn't c#, this is java.
Protected(c#) != Protected(java) ≈≈ Internal(C#).
c# protected = Access is limited to the containing class or types derived from the containing class.
java protected = Access is limited to the current package
Everything in the package can see access these. That's far too permissive for these internal workings.
How do I solve this? Do I have to bring the shared code down to the sub-classes and use "private" at the cost of code repetition? Was my use of parent classes bad design in the first place? Do I have to squirrel these inheritance trees away in new packages?
There is no access modifier that allows visibility to subclasses but not to classes of the same package.
But that's not such a big problem because classes in a given package are supposed to be "friend", cooperate, and be released all at the same time.
Even if they see some fields and methods that they shouldn't use, the other classes of the package are not part of any external API that you have no control on, and the protected methods are not accessible to the external code.
So, just document that these methods and fields shouldn't be used so that you or your coworkers don't mistakenly use them. Or put this class in its own package if you're really concerned about same-package visibility.
What's the reason of making top-level class non-public in Java?
Let's say we have Foo.java, there could be
class Foo {
}
or
public class Foo {
}
I understand that there will be some class - visibility issues with the former example (probably it won't be visible from other packages). But anyway, are there any reasons why someone may want to do as in the first code sample?
UPD: What cons I see in the former solution: nobody cares that it's non-public. That class can be simply extended by some other public class in the same package later, then, non-public part of the class may bring you visibility/access issues.
Here is an example.
No one needs to know about existence of our ConcreteDocument.
DocumentIF.java
public interface DocumentIF {
}
ConcreteDocument.java
class ConcreteDocument implements DocumentIF {
}
DocumentFactory.java
public class DocumentFactory {
public DocumentIF createDocument() {
return new ConcreteDocument();
}
}
Typically, you make a class package-private because you don't want the class to be used outside the package. When a top-level class isn't public, it's private to the package.
Say you have a package with a number of classes that must communicate the same sort of data with one another. But this data structure is an implementation detail and so you don't want it being used by user code. Making the transfer class package private maintains this sort of package level encapsulation.
I understand that there will be some class - visibility issues with the former example (probably it won't be visible from other packages).
That seems to me to be reason enough to use it if you want to keep the class private to that one package.
Just noticed another use! It seems you can only have one public top-level class per code file, but any number of non-public top-level classes. Haven't verified it personally, but if true that could be quite useful to prevent cluttering your project folder and to group classes with related functionality that aren't needed outside of the package.
Classes without a public or protected modifier are only visible inside the package they reside. If you think of components and interfaces there is a reason for leaving out the public modifier. Let's say you have a public class MyCompontent that internally uses other classes, but does not want to publish those to the outside world (users of the component) it makes sense to leave out the visibility modifier.
It is considered good design to keep the visibility of a class to the most minimum required. The reasons that I can think of:
The class can easily change in the future without causing breakages in external packages as the external packages do not have access to the class. In this regard it might be even better to start off a class by making it a private inner class.
The class being package visible cannot be extended by classes in external packages. This again makes it easier for this class to change without causing breaking changes in external packages. If this class was not meant to be extended then it would be even better to make this final.
A public visible class becomes a part of the exported API of your library. If you are a library designer, it is better to keep your exported API as small as possible because you do not want to confuse your consumer with un-necessary classes/details. Item 1 would again hold good in this case.
The book "Effective Java" by Josh Bloch is an excellent reference for Idiomatic Java code and design.
I plan to extend a JSF renderer. The package name is oracle.adfinternal.view.faces.renderkit.rich
Should the extended class be in the same package structure:
oracle.adfinternal.view.faces.renderkit.rich
or even oracle.adfinternal.view.faces.renderkit.rich.[subpackage]
or can/should I put it into my own package? com.company.renderkits.
I suppose package-private variables might be interfered with if I put this into my own package name?
Any thoughts?
In general, you should put your extended classes in your own package.
The package-private access level should be used by closely connected classes, possibly written by the same developer, who knows all the implementation details. This is not the case if you extend a class with some functionality.
All that said, there are a few occasions where you need to place your class in the package of the superclass as a workaround, but remember, this is an ugly hack, and try hard to avoid it.
You should put the class into your own package. There shouldn't be any compilation/access problems. The superclass already sees what it needs to see.
I suppose package-private variables might be interfered with if I put this into my own package name?
This is true, but normally the extending class shouldn't worry about this. The to-be-extended class would have used the protected modifier for this otherwise.
You should not add things to other entities (companies, person) packages. They could make a class with the same name (and same package of course) at a later date. They could also choose to seal their JAR files as well which would prevent you from adding classes to their packages.
The purpose of packages is to give each entity their own unique namepsace in which to create types.
In your case I would name the package something like: com.foobar.oracle.adfinternal.view.faces.renderkit.rich where "com.foobar" is the reverse domain name of your entity (if you don't have one pick something that is unique).