问题
This follows from my unsuccessful attempt to find an answer to this question from 2014.
It's not clear to me whether there might in fact be some techniques in Groovy to use closures, specifically, to hide information. All I can say is that if information on such techniques is out there it is a perfect illustration, precisely, of "information-hiding": I cannot find it!
But failing that I think my understanding now is that absolutely zero attempt to hide information (or pretend to, as in Java - bearing in mind reflection techniques) is ever made. This appears to be by design, but also due to the requirements of Groovy's dynamic nature. It seems, for example, that @CompileStatic
, mentioned in the referenced question, is more about type-checking than anything else.
But in Python, for example, there is a convention (I assume still used) to make "fields which are meant to be considered private" begin with a double underscore. I've never heard anyone talking about this in connection with Groovy.
Aren't information-hiding and encapsulation, or at least conventions to encourage disciplined use of the "intimate state" of objects, good things? Any Groovy experts care to comment?
later
daggett has given an answer which is interesting in some ways, but not really what I had in mind. Consider this:
class Main {
static main( args ) {
def sm = new SecurityManager()
System.setSecurityManager( sm )
println new Bob().doSomethingProtected()
}
}
class Bob {
public doSomethingPublic() {
"public"
}
private doSomethingPrivate() {
"private"
}
protected doSomethingProtected() {
"protected"
}
}
... whichever one of these Bob
methods is called it will pass with the SecurityManager
not set, but fail with it set. It also doesn't matter which package it's in. Nor does it matter whether Bob
is in a subpackage (for example), with @PackageScope
: it is only if Main.main
is given @CompileStatic
that this will help (see referenced question).
I'm also not clear about precisely what you can do with a SecurityManager
set in this way: is it possible to enforce private
or protected
(or package-private) in some way? At the moment I just don't know and will have to investigate.
As for the other suggestion, it's intriguing, but doesn't in fact deny "visibility" as suggested. You'd also need to include the following method in class A
:
def getI() {
throw new Exception()
}
After that, yes, visibility is denied to every other class, whether in the same package or not, and also these "private" elements are not even visible to other objects of the same class (! - unlike Java). In that sense it does indeed deliver a very Draconian privacy. But to me it's also a bit of a hack. I'm not quite clear about this GroovyObjectSupport
class or what it does, and will have to investigate it. Finally, there is little point in actually giving these fields the private
modifier. As I said, the ONLY function of private
in Groovy is to deny visibility of these fields to subclasses of daggett's class A
here.
Having only a stark choice between a super-Draconian and hackish "private", or "unrestrictedly public", clearly represents a considerable "impoverishment" of choice of visibility compared to Java, where you have not only protected
but also package-private (subject, yes yes yes, of course, to use of reflection...), and where private
fields are visible to other objects of the same class.
回答1:
SecurityManager
don't run following code from
GroovyConsole
. only from groovy command line.
def sm = new SecurityManager()
System.setSecurityManager(sm)
//without previous lines the following code will run successfully
println new ByteArrayOutputStream().buf
this will throw the following exception
Caught: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessDeclaredMembers")
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:109)
at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:131)
Caused by: java.lang.ExceptionInInitializerError
at groovy.ui.GroovyMain.run(GroovyMain.java:397)
at groovy.ui.GroovyMain.process(GroovyMain.java:370)
at groovy.ui.GroovyMain.processArgs(GroovyMain.java:129)
at groovy.ui.GroovyMain.main(GroovyMain.java:109)
... 6 more
Caused by: java.security.AccessControlException: access denied ("java.util.logging.LoggingPermission" "control")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
at java.security.AccessController.checkPermission(AccessController.java:884)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.util.logging.LogManager.checkPermission(LogManager.java:1586)
at java.util.logging.Logger.checkPermission(Logger.java:422)
at java.util.logging.Logger.setUseParentHandlers(Logger.java:1799)
at org.codehaus.groovy.runtime.StackTraceUtils.<clinit>(StackTraceUtils.java:57)
... 10 more
control access with getProperty
& setProperty
class A extends GroovyObjectSupport{
private int i=555
private int j=666
def f(){
println "i=$i j=$j"
}
Object getProperty(String name){
if(name in ['i'])throw new Exception("Access to property `$name` is denied")
return super.getProperty(name)
}
}
def a=new A()
a.f()
println "a.j = ${a.j}"
println "a.i = ${a.i}"
this will allow access to member j
but not to the member i
outside of class.
output:
i=555 j=666
a.j = 666
Exception thrown
java.lang.Exception: Access to property `i` is denied
...
来源:https://stackoverflow.com/questions/50825335/information-hiding-in-groovy-using-closures-naming-conventions