I have come into a situation where I want to conditionally load and resolve a class.
Loading it is as easy as getting a handle to the correct ClassLoader and calling the loadClass method. after calling the loadClass method, I get a valid handle to the class I wanted to load. However, the target class' static intializers are not getting invoked because the class is not being resolved until later. Unfortunately, the classes static initializers register important callbacks. An example of this is shown below.
public class ClassA
{
public static void main(String[] args) throws Throwable
{
Class<?> classB = ClassA.class.getClassLoader().loadClass("ClassB");
System.out.println(classB.getName());
}
}
public class ClassB
{
static
{
System.out.println("Class B initializer.");
}
}
The output of running ClassA in this example is of course:ClassB
I have found a temporary workaround which is (in my opinion) a bit of a hack
and that is to call an unimportant static function in ClassB which forces the the class to be resolved. This method is shown below.
public class ClassA
{
public static void main(String[] args) throws Throwable
{
Class<?> classB = ClassA.class.getClassLoader().loadClass("ClassB");
classB.getMethod("something").invoke(null);
System.out.println(classB.getName());
}
}
public class ClassB
{
static
{
System.out.println("Class B initializer.");
}
public static void something(){}
}
The output from this method is (as expected):
Class B Initializer.
ClassB
This method has many problems with it such as I have to depend on the class having a public static function, and worry about any side effects of calling that function. Is there a more legitimate way to force classes to resolve?
You can use Class.forName(..) to have your class initialized and get a reference to its Class object.
Class<?> classB = Class.forName("ClassB");
The javadoc states
A call to forName("X") causes the class named X to be initialized.
Related:
What purpose does Class.forName() serve if you don't use the return value?
Related
I have below scenario :
class C {
static void m1() {}
}
interface I {
default void m1() {}
}
//this will give compilation error : inherited method from C cannot hide public abstract method in I
class Main extends C implements I {
}
Below are my questions:
I am aware that instance method will override the default methods but what if static methods in class have same signature as default method in Interface?
If static method m1() in class C would be public then compilation error will be :
static method m1() conflicts with abstract method in I.
so when the access modifier was default it was trying to hide and when it is public it is conflicting. why is this difference? what is the concept behind it?
Ultimately that boils down to the fact that when you have something like this:
class Me {
public static void go() {
System.out.println("going");
}
}
These both would be allowed:
Me.go();
Me meAgain = new Me();
meAgain.go(); // with a warning here
Intersting is that this would work too for example:
Me meAgain = null;
meAgain.go();
Personally I still see this as design flaw that could not be retracted due to compatibility - but I wish the compiler would not allow me to access the static method from an instance.
Your first question is not related to java-8 per-se, it has been like this before java-8:
interface ITest {
public void go();
}
class Test implements ITest {
public static void go() { // fails to compile
}
}
default methods just follow the same rule here. Why this happens is actually detailed quite a lot on stack overflow - but the underlying idea is that potentially this would cause confusion on which method to call (imagine ITest would be a class that Test would extends and you do ITest test = new Test(); test.go(); -> which method are you calling?)
I think that for the same reasons this is not allowed also (which is basically your second question, otherwise you would have a static and non-static method with the same signatures)
static class Me {
static void go() {
}
void go() {
}
}
It's interesting that this is sort of fixed (I guess that they realized it would be really bad to do the same mistake again) in method references:
static class Mapper {
static int increment(int x) {
return x + 1;
}
int decrement(int x) {
return x - 1;
}
}
Mapper m = new Mapper();
IntStream.of(1, 2, 3).map(m::increment); // will not compile
IntStream.of(1, 2, 3).map(m::decrement); // will compile
Answering your 1st question:
Both the "static method in class" and the "default method in interface" are available to the class Main, and hence if they have the same signature, it will create ambiguity.
For example:
class C{
static void m1(){System.out.println("m1 from C");}
}
public class Main extends C{
public static void main(String[] args) {
Main main=new Main();
main.m1();
}
}
Output: m1 from C
Similarly,
interface I{
default void m1(){System.out.println("m1 from I");}
}
public class Main implements I{
public static void main(String[] args) {
Main main=new Main();
main.m1();
}
}
Output: m1 from I
As you can see, both these can be accessed similarly. So this is also the reason for conflict when you implement I and extend C.
Answering your second question:
If your classed and interfaces are in the same package, the default and public access modifier should work similarly.
Also, m1() in C is static which cannot be overridden, and hence it cannot be considered as implementation of m1() in I and so the compilation issue.
Hope that helps!
I will answer your first question since the second is already answered
I am aware that instance method will override the default methods but
what if static methods in class have same signature as default method
in Interface?
I am assuming you are using JDK 1.8 and hence the confusion. default modifier in an interface method is not talking about its access specifications. Instead it mentions that the interface itself need to implement this method. Access specification for the method is still public. Starting from JDK8 , interfaces allow you specify methods with default modifer to allow to extend interfaces in a backward compatible way.
In your interface you had to give default void m1() {} for the compilation to be successfull. Normally we simply define them in an abstract way like void m1(); in an interface You had to implement the method because you specified the method as default. Hope you understand.
Because class methods in java can also be called using instance variables, this construct will lead to ambiguities:
Main m = new Main();
m.m1();
It is unclear if the last statement should call the class method C.m1() or the instance method I.m1().
Why is it not allowed to call the static method through the class reference returned by .class ? But instead if static method is called directly using class name it works fine. Like in example below. Are they not equal ?
package typeinfo;
class Base {
public static void method1() {
System.out.println("Inside static method1");
}
public void method2() {
System.out.println("Inside method2");
}
}
public class Sample {
public static void main(String[] args) {
Class<Base> b = Base.class;
// Works fine
Base.method1();
// Gives compilation error: cannot find symbol
// Is below statement not equal to Base.method1() ?
b.method1();
}
}
.class returns an instance of class java.lang.Class - and no, Class<Base> is not the same as Base.
Class java.lang.Class is mainly used when you use the Reflection API.
b is of type Class, so it has the methods of the Class type, and not the methods of your Base class.
You can use instances of Class to invoke methods of the classes they refer to via reflection.
Base is class name. Base.method() is java syntax for invoking a static method on class Base.
Base.class is a reference to an object of type Class, describing the class Base. Base.class.method1() does not work of course, because class Class does not have a method method1.
You can call methods of underlying class if you have to, using reflection. Consider:
Base.class.getMethod("method1").invoke(null);
I'm aware that in static methods you can't use the keyword "this".
Now, I also know that if I want to call a method from that class that I'm currently in, I can use the class name,
Example: Main.someStaticMethod();
Now, if I want to use that class (the same as in the example above) in a parameter, how would I do that?
Main.someStaticMethodWithParam(Main);
That Doesn't work since the IDE thinks main is a parameter and thus just comes up with the error: Undefined variable.
You should pass an instance of the class to your static method:
public class Main {
private int x;
public static <T> void printClassName(Class<T> clazz) {
System.out.println(clazz.getName());
}
public static void main() {
printClassName(Main.class);
}
}
Prints (assuming the class is not inside a package):
Main
I naturally can have classes inside any class, so in my main method. I also can access to its methods and its attributes.
But this code isn't working. I know main to be static, so is it something like:
The main method runs and is it the one constructing any class, even the one who contains it.
Then, main should start, construct the class who contains it, and then any class or method inside.
package holamundo;
public class HolaMundo {
public class AnotherClass {
// Class body
}
public void method () {
// Code
}
public static void main(String[] args) {
AnotherClass a = new AnotherClass();
method();
}
So doing:
package holamundo;
public class HolaMundo {
public static class AnotherClass {
// Class body
}
public static void method () {
// Code
}
public static void main(String[] args) {
AnotherClass a = new AnotherClass();
method();
}
We could say main is running first, among the AnotherClass and method definitions?
I tried writing this up with my own words, but the SCJP 6 book does it way better, so here it goes:
A static nested class is simply a class that's a static member of the
enclosing class
Perhaps to better understand, here's some code:
public class HolaMundo {
public static class AnotherClass {
public void hello(){
System.out.println("Hello");
}
public static void hola(){
System.out.println("Hola");
}
}
public static void main(String[] args) {
HolaMundo.AnotherClass.hola();
HolaMundo.AnotherClass holaAnother = new HolaMundo.AnotherClass();
holaAnother.hello();
}
}
Note that the above code in the main() method will continue to work if you remove the occurrences of HolaMundo..
If you're confused, here's more from the book:
The class itself isn't really "static"; there's no such thing as a
static class. The static modifier in this case says that the nested
class is a static member of the outer class. That means it can be
accessed, as with other static members, without having an instance of
the outer class.
A static method (like main()), doesn't belong (and also cannot access) to any particular instance of any class.
This means that a static method can create new instances of any class it has access to, even if it happens to be an instance of the class that declared said method in the first place.
Now, since in this case, main(), AnotherClass and method() are all static members of HolaMundo, then yes, this means that they all "run together".
More specifically, they are loaded when the class is first loaded by the JVM (aka at Class Loading time).
In Java, non-static nested classes have an implicit reference to an instance of the container class and so cannot be utilized in static contexts (like the main method) since there is no instance to reference.
I have a Java problem with nested classes.
My first class structure looked like this:
public class TopClass {
public void mainMethod() {
// uses the different "method" methods from
// NestedClass-implementing nested classes
}
private interface NestedClass {
public void method();
}
private class NestedClass1 {
public void method() {
}
}
private class NestedClass2 {
public void method(){
}
}
}
But now I want these method() methods to be static because they should be principally.
I cannot make them static without having them in a static class, but that's no problem, I made the classes static, they should be anyway.
It looks like this right now:
public class TopClass {
public void mainMethod() {
// uses the different "method" methods from
// NestedClass-implementing nested classes
}
private static interface NestedClass {
public void method();
}
private static class NestedClass1 {
public static void method() {
}
}
private static class NestedClass2 {
public static void method(){
}
}
}
But then the trouble begins. A static method does not inherit correctly from a non-static interface method, as I get this message This static method cannot hide the instance method from TopClass.NestedClass in Eclipse.
When I make the interface method static, it gives me this error: Illegal modifier for the interface method method; only public & abstract are permitted
So I thought of an abstract class, and tried this:
public class TopClass {
public void mainMethod() {
// uses the different "method" methods from
// NestedClass-implementing nested classes
}
private static abstract class NestedClass {
public static abstract void method();
}
private static class NestedClass1 {
public static void method() {
}
}
private static class NestedClass2 {
public static void method(){
}
}
}
But again, seemingly abstract methods cannot be declared static: The abstract method method in type NestedClass can only set a visibility modifier, one of public or protected.
Leaving the static away (in the abstract class method), errors this on the method methods in the NestedClass1 & 2: This static method cannot hide the instance method from TopClass.NestedClass.
Isn't there any way to declare some kind of superstructure for covering static methods?
EDIT:
The problem I actually try to solve it the lack of possibility of Java for storing references to methods. So instead I have those classes everyone with just one method, but to store them in a List f.e. they must be able to be "caught" by a superstructure.
I got the hint to try anonymous classes or enums, gonna try that now.
Interfaces and statics don't go together. At all. There is no Java support for creating / imposing patterns on static methods.
A static method declaration must always be followed by a definition. It cannot be implemented by subclasses.
I think you're just not approaching your problem right. Try a different approach!
Make NestedClass an interface NestedInterface and store your different implementations as anonymous classes implementing this interface:
public static final NestedInterface firstNested = new NestedInterface() {
#Override
public void method() {
// ...
}
};
Make NestedClass an enumeration NestedEnum and store your different implementations as enumeration values implementing an abstract method from the enumeration. This only works if you have a fixed number of implementations you which to choose from and you do not want to accept NestedClass implementations from outside sources.
public enum NestedEnum {
FIRST {
#Override
public void method() {
// ...
}
};
public abstract void method();
}
EDIT: In reply to your comment:
The classes itself are static as well..
static in the context of a nested class means that this class can be instantiated without an instance of the containing class.
A regular nested class such as in your first example can be instantiated through TopClass.this.new NestedClass1(). Normally you'd simply write new NestedClass1() from within the constructor or an instance method of TopClass, but in this verbose form you can clearly see the dependence on TopClass.this. This can also be seen from any method of NestedClass1, as you have access to the containing class with TopClass.this.
A static nested class such as in your second example can be instantiated through new TopClass.NestedClass1(). Once again, you could just write new NestedClass1() but the verbose form clearly shows that the construction only depends on TopClass and is not associated with an instance of TopClass. You could even create an instance from an outside class using the same snippet new TopClass.NestedClass1() without ever creating a TopClass instance.
I suggest you take a look at this question on inner classes and static nested classes.
The fact the your interface/abstract class is nested is irrelevant to the problem.
You just can't. There is no way in Java to enforce some class to implement static methods. Just cry and surrender and use instance methods.
static abstract is a contradiction. Static methods are not like other languages' class methods. When you make a static method it goes on a single class, it doesn't get inherited by or have its implementation deferred to subclasses.
You don't explain why you want these methods to be static. If you want these methods to be defined by subclasses then they shouldn't be.