I know this is pointless: I just find it funny and I want to inquire more about the mechanics of what happens when you create a class that inherits itself, resulting in a stack overflow crash. It's amazing that Java allows you to make such a construct to begin with.
I am just guessing, but is the JVM putting itself into an infinite loop trying to resolve the class before instancing it, or is it actually instancing multiple copies of the class endlessly?
I should have been more specific; I am using an inner class to derive from enclosing class.
public class Outside {
private int outsideValue;
public class Inside extends Outside {
private int insideValue;
public Inside(int val) {
insideValue = val;
}
}
public Outside() {
Inside o = new Inside(0);
}
}
public class Main {
public static void main(String args[]) {
Outside o = new Outside();
}
}
Remember that, since Inside extends Outside, it has an implicit call to super() which is the constructor of Outside (which in turn calls the constructor of Inside) and so it goes around.
The code you posted is conceptually not different from the following program:
class A {
B b = new B();
}
class B extends A {
}
public class Test {
public static void main(String[] args) {
new A(); // Create an A...
// ... which creates a B
// ... which extends A thus implicitly creates an A
// ... which creates a B
// ...
}
}
In its final form this problem has nothing to do with cyclic inheritance and inner classes. It's just an infinite recursion caused by unbound recursive constructor call. The same effect can be shown by the following simple example:
public class A {
public A() {
new A();
}
}
Note that this code is perfectly valid, since Java doesn't apply any restrictions on recursive calls.
In your case it's slightly more complicated due to inheritance, but if you recall that constructor of subclass implicitly call a constructor of superclass, it should be clear that these calls form infinite recursion.
Try in an IDE like eclipse, it wont allow you to do so. ie gives an error like this.
Cycle detected: the type Test cannot extend/implement itself or one of its own member types
The example you posted could get problematic if we change it a bit more:
public class Outside {
public class Inside extends Outside {
public Inside(int val) {
}
}
private Inside i;
public Outside() {
i = new Inside();
}
}
But this is not really related to the fact that Inside is an inner class of Outside, it could have happened with separate top-level-classes identically.
The java compiler is not going to enter into an infinite loop when trying to enter a cyclic inheritance chain. After all, every inheritance chain is a eventually finite graph (and, computationally speaking, with a very small number of nodes and edges.) More precisely, the inheritance graph from subclass A to (eventual) superclass Z must be a line (not the other way around, though), and the compiler can easily determine if it is a line or not.
It does not take much for a program to determine if such a small graph is cyclic or not, or if it is a line or not, which is what the compiler does. So the compiler does not go into an infinite loop, and the JVM never runs out of stack space since 1) neither the compiler runs on the JVM, nor 2) the JVM get to executes (since nothing gets to compile and the compiler never invokes under such conditions the JVM anyways.)
I'm not aware of any languages that permit such cyclic inheritance graphs (but I've been doing nothing but Java for 11 years, so my memory of anything other than Java is mushy.) I cannot see, furthermore, the use of such a construct (in modeling or real life). Might be theoretically interesting, though.
edit
Ok, I ran your code and indeed it causes an stack overflow. You were right. I'm gonna have to sit and really study this to understand why the compiler allows such a construct.
Nice find!!!!
Extending oneself generates an error of cyclic inheritance (which java doesn't allow). Your code sample does compile and is valid.
Due to Vladimir Ivanov's persistence, I will fix my edit.
Your code throws a StackOverflowError because of the following.
Inside o = new Inside(0);
Since Inside extends Outside, Inside first calls the super() method implicitly (since you've not called it yourself). Outside() constructor initializes Inside o and the cycle runs again, until the stack is full and it overflow (there's too many Inside and Outside inside the heap stack).
Hope this helps especially Vladimir Ivanov.
You can get the answer by:
Class.forName("MyClass");
This way it gets resolved but not instantiated. So you can chack if resolution itself causes the crash.
I guess it depends on the JVM you use.
When I try to compile :
class A extends A {
}
I get :
$ javac A.java
A.java:1: cyclic inheritance involving A
class A extends A {
^
1 error
So Java don't let you do this kind of thing. For information, java version "1.6.0_24"
Related
Using Java. The below is a single program that contains 2 methods that are called in another Class program that has the main (which proves that non-static methods require objects to be created first). HasAStaticMethod has an orange SonarLint error. Why doesn't the class NotStatic have an error, too?
public final class Test {
private Test () {
}
}
class HasAStaticMethod {
//private HasAStaticMethod(){}
public static void myPrint(String s) {
System.out.println(s);
}
}
class NotStatic {
public void myPrint(String s) {
System.out.println(s);
}
}```
Why does only the class with the static method have the error: “Add a private constructor to hide the implicit public one.”?
Creating an instance of HasStaticMethod would be a programmer mistake since it can serve (almost) no useful purpose ... as well as a harmful one (see below).
Declaring a private constructor will cause that programmer mistake (i.e. mistakenly instantiating HasStaticMethod) to be flagged as a compilation error.
This is a good thing.
Why doesn't the class NotStatic have an error, too?
Because you need an instance of NoStatic in order for call NoStatic.myPrint. So you need a non-private constructor to make the instance. A default constructor will do ... because that will be public.
NoStatic.myPrint(); // compilation error
new NoStatic().myPrint(); // OK
You don't need an instance in the HasStaticMethod case. The correct way to use it is:
HasStaticMethod.myPrint(); // OK
You could write this:
new HasStaticMethod().myPrint(); // compiles ... but bad
... but it doesn't do what the reader (most likely) thinks it does. The instantiation of the class is pointless, and calling a static method via an instance reference is downright misleading. That is the reasoning behind the IDE hint: to stop the programmer (who is using your HasStaticMethod class) from accidentally or deliberately writing that kind of nonsense.
I think you may be thinking about this from the wrong perspective1. The goal is to write Java code that 1) works and 2) can be read and maintained by someone else. To that end, it is good thing when the IDE / Sonar warns us we are doing something that is liable to lead to problems. (And indeed, this is why we use tools like Sonar.)
Now you are free to twiddle with the Sonar settings to turn off this warning if you don't like it. Or stop using Sonar altogether. (But check with your coworkers and manager first, because they might have some opinions on that course of action.)
But my advice is to just add the private constructor and declare the utility class as final ... as Sonar suggests. It is (IMO) a good thing to do.
1 - This should not be about "freedom of expression" or "personal choice". This is not poetry ...
I'm sure you all know the behaviour I mean - code such as:
Thread thread = new Thread();
int activeCount = thread.activeCount();
provokes a compiler warning. Why isn't it an error?
EDIT:
To be clear: question has nothing to do with Threads. I realise Thread examples are often given when discussing this because of the potential to really mess things up with them. But really the problem is that such usage is always nonsense and you can't (competently) write such a call and mean it. Any example of this type of method call would be barmy. Here's another:
String hello = "hello";
String number123AsString = hello.valueOf(123);
Which makes it look as if each String instance comes with a "String valueOf(int i)" method.
Basically I believe the Java designers made a mistake when they designed the language, and it's too late to fix it due to the compatibility issues involved. Yes, it can lead to very misleading code. Yes, you should avoid it. Yes, you should make sure your IDE is configured to treat it as an error, IMO. Should you ever design a language yourself, bear it in mind as an example of the kind of thing to avoid :)
Just to respond to DJClayworth's point, here's what's allowed in C#:
public class Foo
{
public static void Bar()
{
}
}
public class Abc
{
public void Test()
{
// Static methods in the same class and base classes
// (and outer classes) are available, with no
// qualification
Def();
// Static methods in other classes are available via
// the class name
Foo.Bar();
Abc abc = new Abc();
// This would *not* be legal. It being legal has no benefit,
// and just allows misleading code
// abc.Def();
}
public static void Def()
{
}
}
Why do I think it's misleading? Because if I look at code someVariable.SomeMethod() I expect it to use the value of someVariable. If SomeMethod() is a static method, that expectation is invalid; the code is tricking me. How can that possibly be a good thing?
Bizarrely enough, Java won't let you use a potentially uninitialized variable to call a static method, despite the fact that the only information it's going to use is the declared type of the variable. It's an inconsistent and unhelpful mess. Why allow it?
EDIT: This edit is a response to Clayton's answer, which claims it allows inheritance for static methods. It doesn't. Static methods just aren't polymorphic. Here's a short but complete program to demonstrate that:
class Base
{
static void foo()
{
System.out.println("Base.foo()");
}
}
class Derived extends Base
{
static void foo()
{
System.out.println("Derived.foo()");
}
}
public class Test
{
public static void main(String[] args)
{
Base b = new Derived();
b.foo(); // Prints "Base.foo()"
b = null;
b.foo(); // Still prints "Base.foo()"
}
}
As you can see, the execution-time value of b is completely ignored.
Why should it be an error? The instance has access to all the static methods. The static methods can't change the state of the instance (trying to is a compile error).
The problem with the well-known example that you give is very specific to threads, not static method calls. It looks as though you're getting the activeCount() for the thread referred to by thread, but you're really getting the count for the calling thread. This is a logical error that you as a programmer are making. Issuing a warning is the appropriate thing for the compiler to do in this case. It's up to you to heed the warning and fix your code.
EDIT: I realize that the syntax of the language is what's allowing you to write misleading code, but remember that the compiler and its warnings are part of the language too. The language allows you to do something that the compiler considers dubious, but it gives you the warning to make sure you're aware that it could cause problems.
They cannot make it an error anymore, because of all the code that is already out there.
I am with you on that it should be an error.
Maybe there should be an option/profile for the compiler to upgrade some warnings to errors.
Update: When they introduced the assert keyword in 1.4, which has similar potential compatibility issues with old code, they made it available only if you explicitly set the source mode to "1.4". I suppose one could make a it an error in a new source mode "java 7". But I doubt they would do it, considering that all the hassle it would cause. As others have pointed out, it is not strictly necessary to prevent you from writing confusing code. And language changes to Java should be limited to the strictly necessary at this point.
Short answer - the language allows it, so its not an error.
The really important thing, from the compiler's perspective, is that it be able to resolve symbols. In the case of a static method, it needs to know what class to look in for it -- since it's not associated with any particular object. Java's designers obviously decided that since they could determine the class of an object, they could also resolve the class of any static method for that object from any instance of the object. They choose to allow this -- swayed, perhaps, by #TofuBeer's observation -- to give the programmer some convenience. Other language designers have made different choices. I probably would have fallen into the latter camp, but it's not that big of a deal to me. I probably would allow the usage that #TofuBeer mentions, but having allowed it my position on not allowing access from an instance variable is less tenable.
Likely for the same logical that makes this not an error:
public class X
{
public static void foo()
{
}
public void bar()
{
foo(); // no need to do X.foo();
}
}
It isn't an error because it's part of the spec, but you're obviously asking about the rationale, which we can all guess at.
My guess is that the source of this is actually to allow a method in a class to invoke a static method in the same class without the hassle. Since calling x() is legal (even without the self class name), calling this.x() should be legal as well, and therefore calling via any object was made legal as well.
This also helps encourage users to turn private functions into static if they don't change the state.
Besides, compilers generally try to avoid declaring errors when there is no way that this could lead to a direct error. Since a static method does not change the state or care about the invoking object, it does not cause an actual error (just confusion) to allow this. A warning suffices.
The purpose of the instance variable reference is only to supply the type which encloses the static. If you look at the byte code invoking a static via instance.staticMethod or EnclosingClass.staticMethod produces the same invoke static method bytecode. No reference to the instance appears.
The answer as too why it's in there, well it just is. As long as you use the class. and not via an instance you will help avoid confusion in the future.
Probably you can change it in your IDE (in Eclipse Preferences -> Java -> Compiler -> Errors/Warnings)
There's not option for it. In java (like many other lang.) you can have access to all static members of a class through its class name or instance object of that class. That would be up to you and your case and software solution which one you should use that gives you more readability.
It's pretty old topic but still up-to-date and surprisingly bringing higher impact nowadays. As Jon mentioned, it might be just a mistake Java's designers made at the very beginning. But I wouldn't imagine before it can have impact on security.
Many coders know Apache Velocity, flexible and powerful template engine. It's so powerful that it allows to feed template with a set of named objects - stricly considered as objects from programming language (Java originally). Those objects can be accessed from within template like in programming language so for example Java's String instance can be used with all its public fields, properties and methods
$input.isEmpty()
where input is a String, runs directly through JVM and returns true or false to Velocity parser's output). So far so good.
But in Java all objects inherit from Object so our end-users can also put this to the template
$input.getClass()
to get an instance of String Class.
And with this reference they can also call a static method forName(String) on this
$input.getClass().forName("java.io.FileDescriptor")
use any class name and use it to whatever web server's account can do (deface, steal DB content, inspect config files, ...)
This exploit is somehow (in specific context) described here: https://github.com/veracode-research/solr-injection#7-cve-2019-17558-rce-via-velocity-template-by-_s00py
It wouldn't be possible if calling static methods from reference to the instance of class was prohibited.
I'm not saying that a particular programming framework is better than the other one or so but I just want to put a comparison. There's a port of Apache Velocity for .NET. In C# it's not possible to call static methods just from instance's reference what makes exploit like this useless:
$input.GetType().GetType("System.IO.FileStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
I just consider this:
instanceVar.staticMethod();
to be shorthand for this:
instanceVar.getClass().staticMethod();
If you always had to do this:
SomeClass.staticMethod();
then you wouldn't be able to leverage inheritance for static methods.
That is, by calling the static method via the instance you don't need to know what concrete class the instance is at compile time, only that it implements staticMethod() somewhere along the inheritance chain.
EDIT: This answer is wrong. See comments for details.
public class Basics {
Basics b = new Basics();
int instanceVariable = 0;
public void behavior() {
System.out.println("Print Something");
}
b.behavior(); // Why this line, b.behavior doesn't work?
public static void main(String[] args){
Basics b = new Basics(); /* Why are we allowed to create an
* object of same name again within
* the same class */
b.behavior(); // This line works
}
}
In the above class, I am able to create object . But I can't call b.behavior outside any class, but I am able to do that within a method. Why is that so? What is the difference?
public class Basics1 extends Basics{
Basics b = new Basics();
Basics1 b1 = new Basics1();
b = b1.instanceVariable; // I don't see error in this line, but previous line shows //error.
b1.instanceVariable // This line doesn't work
}
Why is b1.instanceVariable not working, instanceVariable is the base class instance variable.
You need to understand that a class is a "type definition", not a code block or sequence of statements.
You cannot just write arbitrary statements in a type definition.
Even so, "b1.instanceVariable" is not a statement. "b1.instanceVariable" doesn't mean anything in statement context.
A class defines variables and methods. b.behavior(); is a statement that cannot be on its own like that.
All code needs to be in methods, in field declarations (such as Basics b = new Basics(); in your example) or in "initializer blocks" (which are run as part of constructors or during class initialization).
This is just a syntax rule.
In other languages, you can have this kind of "raw code", to achieve various effects. What do you want to achieve?
run during compilation (like in Perl): Cannot be done in Java
run during constructor: use an init block
run during class loading: use a static init block
run when the program starts: put it in static void main
run during method invokation: put it in that method
Write code anywhere and expect it to execute is a form of procedural programming. In this form , you tend to loose context and soon the code becomes a spaghetti code --> methods getting called anywhere , anytime.
With OOP, you are trained to create objects with well defined methods which have a defined context. Just think, when would you like to get the b.behavior(); being called : Before initializing a class, after initializing the class, after execution of main or when the object is destroyed?
Interestingly, Java has defined syntaxes for each of the states.. You can wrap your code in { System.out.println("Hello World "); } and it will execute when the class is instantiate...Also you can use static { System.out.println("Hello World "); } and this will execute when class is loaded. But again, this is part of telling the JVM when to do it - an agreed upon syntax.. But without any marker around your code, when would you actually expect to run?
So I have a problem that looks something similar to this:
package com.blah.A_package;
public class A
{
public void f() {
g();
}
protected void g() {
System.out.println("superclass g()");
}
}
package com.blah.B_package;
public class B extends com.blah.A_package.A
{
protected void g() {
System.out.println("subclass g()");
}
}
public static void main(String[] args)
{
A scratch = new A();
scratch.f();
}
When run, it prints out "subclass g()" instead of the expected "superclass g()".
We're actually creating objects of both the superclass and the subclass (this is through reflection on a jar), sticking them in a map, and then pulling them out as we need them, but we have verified by printing out the object.getClass().getName() and seeing that we are in fact working with the superclass instantiation.
Anyway, when we run the application, for some reason it's using the subclass copy of the method rather than the superclasses, despite the object being an instantiation of the superclass (ie, it shouldn't even know about the subclasses methods). Is this a known thing that myself and my coworkers aren't aware of? We're completely stumped on why this would ever be happening.
In short, the only thing that can be causing this is that the runtime object is an instance of B, but you declared it as A. As the method is invoked, your program will start to look in the runtime class of the object it is invoked on, then work its way up the inheritance tree.
On a side note, you are missing constructors, your class B extends a package and your methods don't have return types. That is completely invalid Java.
One thing that can cause that confusion is having a subclass of B with the same name as its superclass (A) but on a different package with a similar name of the package of the A superclass.
Apart from that, it looks like an analysis error. Retrace your steps. Some ideas: delete class B or make it uninstantiatable, then reintroduce it and test it all again.
I'm sure you all know the behaviour I mean - code such as:
Thread thread = new Thread();
int activeCount = thread.activeCount();
provokes a compiler warning. Why isn't it an error?
EDIT:
To be clear: question has nothing to do with Threads. I realise Thread examples are often given when discussing this because of the potential to really mess things up with them. But really the problem is that such usage is always nonsense and you can't (competently) write such a call and mean it. Any example of this type of method call would be barmy. Here's another:
String hello = "hello";
String number123AsString = hello.valueOf(123);
Which makes it look as if each String instance comes with a "String valueOf(int i)" method.
Basically I believe the Java designers made a mistake when they designed the language, and it's too late to fix it due to the compatibility issues involved. Yes, it can lead to very misleading code. Yes, you should avoid it. Yes, you should make sure your IDE is configured to treat it as an error, IMO. Should you ever design a language yourself, bear it in mind as an example of the kind of thing to avoid :)
Just to respond to DJClayworth's point, here's what's allowed in C#:
public class Foo
{
public static void Bar()
{
}
}
public class Abc
{
public void Test()
{
// Static methods in the same class and base classes
// (and outer classes) are available, with no
// qualification
Def();
// Static methods in other classes are available via
// the class name
Foo.Bar();
Abc abc = new Abc();
// This would *not* be legal. It being legal has no benefit,
// and just allows misleading code
// abc.Def();
}
public static void Def()
{
}
}
Why do I think it's misleading? Because if I look at code someVariable.SomeMethod() I expect it to use the value of someVariable. If SomeMethod() is a static method, that expectation is invalid; the code is tricking me. How can that possibly be a good thing?
Bizarrely enough, Java won't let you use a potentially uninitialized variable to call a static method, despite the fact that the only information it's going to use is the declared type of the variable. It's an inconsistent and unhelpful mess. Why allow it?
EDIT: This edit is a response to Clayton's answer, which claims it allows inheritance for static methods. It doesn't. Static methods just aren't polymorphic. Here's a short but complete program to demonstrate that:
class Base
{
static void foo()
{
System.out.println("Base.foo()");
}
}
class Derived extends Base
{
static void foo()
{
System.out.println("Derived.foo()");
}
}
public class Test
{
public static void main(String[] args)
{
Base b = new Derived();
b.foo(); // Prints "Base.foo()"
b = null;
b.foo(); // Still prints "Base.foo()"
}
}
As you can see, the execution-time value of b is completely ignored.
Why should it be an error? The instance has access to all the static methods. The static methods can't change the state of the instance (trying to is a compile error).
The problem with the well-known example that you give is very specific to threads, not static method calls. It looks as though you're getting the activeCount() for the thread referred to by thread, but you're really getting the count for the calling thread. This is a logical error that you as a programmer are making. Issuing a warning is the appropriate thing for the compiler to do in this case. It's up to you to heed the warning and fix your code.
EDIT: I realize that the syntax of the language is what's allowing you to write misleading code, but remember that the compiler and its warnings are part of the language too. The language allows you to do something that the compiler considers dubious, but it gives you the warning to make sure you're aware that it could cause problems.
They cannot make it an error anymore, because of all the code that is already out there.
I am with you on that it should be an error.
Maybe there should be an option/profile for the compiler to upgrade some warnings to errors.
Update: When they introduced the assert keyword in 1.4, which has similar potential compatibility issues with old code, they made it available only if you explicitly set the source mode to "1.4". I suppose one could make a it an error in a new source mode "java 7". But I doubt they would do it, considering that all the hassle it would cause. As others have pointed out, it is not strictly necessary to prevent you from writing confusing code. And language changes to Java should be limited to the strictly necessary at this point.
Short answer - the language allows it, so its not an error.
The really important thing, from the compiler's perspective, is that it be able to resolve symbols. In the case of a static method, it needs to know what class to look in for it -- since it's not associated with any particular object. Java's designers obviously decided that since they could determine the class of an object, they could also resolve the class of any static method for that object from any instance of the object. They choose to allow this -- swayed, perhaps, by #TofuBeer's observation -- to give the programmer some convenience. Other language designers have made different choices. I probably would have fallen into the latter camp, but it's not that big of a deal to me. I probably would allow the usage that #TofuBeer mentions, but having allowed it my position on not allowing access from an instance variable is less tenable.
Likely for the same logical that makes this not an error:
public class X
{
public static void foo()
{
}
public void bar()
{
foo(); // no need to do X.foo();
}
}
It isn't an error because it's part of the spec, but you're obviously asking about the rationale, which we can all guess at.
My guess is that the source of this is actually to allow a method in a class to invoke a static method in the same class without the hassle. Since calling x() is legal (even without the self class name), calling this.x() should be legal as well, and therefore calling via any object was made legal as well.
This also helps encourage users to turn private functions into static if they don't change the state.
Besides, compilers generally try to avoid declaring errors when there is no way that this could lead to a direct error. Since a static method does not change the state or care about the invoking object, it does not cause an actual error (just confusion) to allow this. A warning suffices.
The purpose of the instance variable reference is only to supply the type which encloses the static. If you look at the byte code invoking a static via instance.staticMethod or EnclosingClass.staticMethod produces the same invoke static method bytecode. No reference to the instance appears.
The answer as too why it's in there, well it just is. As long as you use the class. and not via an instance you will help avoid confusion in the future.
Probably you can change it in your IDE (in Eclipse Preferences -> Java -> Compiler -> Errors/Warnings)
There's not option for it. In java (like many other lang.) you can have access to all static members of a class through its class name or instance object of that class. That would be up to you and your case and software solution which one you should use that gives you more readability.
It's pretty old topic but still up-to-date and surprisingly bringing higher impact nowadays. As Jon mentioned, it might be just a mistake Java's designers made at the very beginning. But I wouldn't imagine before it can have impact on security.
Many coders know Apache Velocity, flexible and powerful template engine. It's so powerful that it allows to feed template with a set of named objects - stricly considered as objects from programming language (Java originally). Those objects can be accessed from within template like in programming language so for example Java's String instance can be used with all its public fields, properties and methods
$input.isEmpty()
where input is a String, runs directly through JVM and returns true or false to Velocity parser's output). So far so good.
But in Java all objects inherit from Object so our end-users can also put this to the template
$input.getClass()
to get an instance of String Class.
And with this reference they can also call a static method forName(String) on this
$input.getClass().forName("java.io.FileDescriptor")
use any class name and use it to whatever web server's account can do (deface, steal DB content, inspect config files, ...)
This exploit is somehow (in specific context) described here: https://github.com/veracode-research/solr-injection#7-cve-2019-17558-rce-via-velocity-template-by-_s00py
It wouldn't be possible if calling static methods from reference to the instance of class was prohibited.
I'm not saying that a particular programming framework is better than the other one or so but I just want to put a comparison. There's a port of Apache Velocity for .NET. In C# it's not possible to call static methods just from instance's reference what makes exploit like this useless:
$input.GetType().GetType("System.IO.FileStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
I just consider this:
instanceVar.staticMethod();
to be shorthand for this:
instanceVar.getClass().staticMethod();
If you always had to do this:
SomeClass.staticMethod();
then you wouldn't be able to leverage inheritance for static methods.
That is, by calling the static method via the instance you don't need to know what concrete class the instance is at compile time, only that it implements staticMethod() somewhere along the inheritance chain.
EDIT: This answer is wrong. See comments for details.