Right now I'm implementing a method that has one parameter of the type Class and this method returns a boolean if the given class object requires an instance of it's enclosing class for it to be instantiated.
This method currently works as follows:
if (clazz.getEnclosingClass() == null) {
return false;
}
if (clazz.isAnonymousClass() || clazz.isMemberClass()) {
return !Modifier.isStatic(clazz.getModifiers());
}
if (clazz.getEnclosingConstructor() != null) {
return true;
}
final Method enclosingMethod = clazz.getEnclosingMethod();
if (enclosingMethod != null) {
return !Modifier.isStatic(enclosingMethod.getModifiers());
}
To explain why it is designed as such:
I need step 6 to determine whether the local class resides in either a Static Initializer Block or an Instance Initializer Block, so I'm done with the implementation for this function.
So here's where the reflection API falls a bit short. There's no method Class.getEnclosingInitializer()
or such, nor is there a class that represents an initializer in the reflection package.
Isn't an initializer block a member of a class? In the java 1.8 spec the Member interface only has the implementation classes Field, Executable (with subclasses Constructor and Method), and then there's MemberName that's out of the scope for most users of reflection.
I'm not really sure if the people behind the spec forgot about this situation and local classes actually should be static if declared in a static method/initializer (like anonymous classes). But it seems to me that it's lacking this last bit of consistency from this point of view.
So does anybody have an idea on how to ascertain in which type of initializer block the local class is declared?
I'm not really keen on digging through fields for a synthetic one of a type that equals it's enclosing class, or looping through it's constructors for something akin to that (sidenote: Parameter objects from Constructor.getParameters()
always return false on isImplicit()
and isSynthetic()
no matter what i try... that just seems wrong). So if I can avoid such solutions that would be great.
In Java we cannot declare static initializers or member interfaces in a local class (static members can be declared provided there are final and can be initialized at compile time).
Local classes are non-static because they have access to instance members of the enclosing block. Consequently, they cannot contain most kinds of static declarations.
A Static Initialization Block in Java is a block that runs before the main( ) method in Java. Java does not care if this block is written after the main( ) method or before the main( ) method, it will be executed before the main method( ) regardless.
In order to perform any operations while assigning values to an instance data member, an initializer block is used. In simpler terms, the initializer block is used to declare/initialize the common part of various constructors of a class. It runs every time whenever the object is created.
An interesting puzzle, but I'm afraid it has no solution that satisfies your requirements. Once the source files are compiled into bytecode, the details about class enclosing scope is lost. Remember that JVM is not only for Java language, while the described problem is mostly language-specific.
I need step 6 to determine whether the local class resides in either a Static Initializer Block or an Instance Initializer Block
No such information is available in run-time. Class file has EnclosingMethod
attribute for local or anonymous classes (JVMS §4.7.7). However, there is no way to distinguish between enclosing instance initializer and static initializer. The spec explicitly says that
«method_index must be zero if the current class was immediately enclosed in source code by an instance initializer, static initializer, instance variable initializer, or class variable initializer».
Consider these two cases:
class Outer {
{
// Local class inside instance initializer
class Local {}
}
}
vs.
class Outer {
static {
// Local class inside static initializer
class Local {
final Outer this$0;
Local(Outer outer) {
this$0 = outer;
}
}
}
}
They are compiled to almost the same class file. The only difference is that field this$0
has SYNTHETIC
flag in the first case, but not in the second. But checking this flag is exactly what you want to avoid. (Why?)
local classes actually should be static if declared in a static method/initializer (like anonymous classes)
I would argue that neither local nor anonymous classes should ever be static. Furthermore, Java Language Specification requires them to be non-static:
So, it's clearly a spec violation that getModifiers()
sometimes returns STATIC
for an anonymous class. There is a bug JDK-8034044 that has been fixed in upcoming JDK 9. And that breaks step 2 of your algorithm.
Okay, what to do then? It depends on what you actually mean by
if the given class object requires an instance of it's enclosing class for it to be instantiated
I would say, the above definition implies that all constructors of a class have an extra argument of enclosing class type. In this case there is indeed no way to instantiate a class without an instance of the enclosing class.
However, if you really wish to distinguish between initializer and static initializer, your only chance (as I've shown above) is to look for a field with SYNTHETIC
flag.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With