I have long java class and method names
LONGGGGGGGGGGGGGGGClass.longggggggggggggggggggggggggMethod();
I want to alias it to
g.m(); in another class
can this be done?
No.
Wrap it in a method with a name you like better.
For one thing, you should rarely be typing the class name. You might have something like this:
import DamnLongPackageNameThatIDontLikeTyping;
class MyCoolClass()
{
DamnLongClassNameThatIDontLikeTyping dlc=new DamnLongClassNameThatIDontLikeTyping();
dlc.this();
dlc.that();
dlc.tOther();
dlc.damnLongAnnoyingMethodNameStillHasToBeTypedEveryTime();
}
Okay, so that's not great, but you shouldn't be typing the entire class name very often, just when you first declare it; and the package import makes it so you don't have to type: DamnLongPackageNameThatIDontLikeTyping.DamnLongClassNameThatIDontLikeTyping every time.
Still, that can be annoying to type. Enter the editor. If you aren't using Eclipse, Netbeans or IntelliJ then you really need to stop reading right now and go install it--load up your project. I'll wait....
Seriously. Go get it. The rest of this won't be any fun without it.
Now, the really neat thing is that to get what I typed above, you just do this:
class MyCoolClass()
{
DLC<ctrl-space>
After typing that, your file will look like this:
import DamnLongPackageNameThatIDontLikeTyping;
class MyCoolClass()
{
DamnLongClassNameThatIDontLikeTyping<your cursor here>
Note that you didn't type damn long ANYTHING, just DLC It figured out what class you wanted to import, added an import for it and stuck the class in there. (You may have to choose from a list of classes if there is more than one match).
On top of that, once you have an object named dlc instantiated you can type:
dlc.<ctrl-space> and get a list of methods in that class. NEVER AGAIN TYPE A METHOD NAME. If there are a kagillion methods in your class, don't scroll over them, type: dlc.dLAM<ctrl-space> to get dlc.damnLongAnnoyingMethodNameStillHasToBeTypedEveryTime();
Never type a long method name again.
No long method names, no long class names, no long package names. Yet you get extremely readable methods, packages and classes. This is why java programmers tend to use these long names, we also try to remember that we are coding for the next guy and don't want him to have to run all over our code trying to figure out what:
g.m(); refers to -- forcing them to remember that in this class it means GreatClass.motion, but in the next class it means Grey.modifyColor -- that would be really cruel.
Java being statically typed places a LOT of power into the editor. It can do things that you can't even dream of doing with dynamically typed languages, and you should play to the strength of your language to be an effective programmer -- not try to fit each language into some style you learned from using another language.
Note that this works for static methods as well...
DLC<ctrl-space>.dLM<ctrl-space> would be replaced by a call to DamnLongClass.damnLongMethod(), and it would even include the parens for you in 9 keystrokes.
The Java language provides no aliasing mechanism.
However, you could ease your "pain" somewhat by some combination of the following:
For static methods, you can use static imports to avoid having the long class name.
You could declare your own convenience class with a short name and short method names, and implement the static methods to delegate to the real methods like:
public static void shortName(...) {
VeryLongClassName.veryLongMethodName(...);
}
For regular methods, you could implement a Wrapper class, or a subclass with more convenient method names. However, both have downsides from the maintenance and (depending on your JVM) performance perspectives.
In Java 8 and later, you could potentially take a method reference, assign it to a named variable, and use that to make your calls.
But lets step back:
If the real problem is that you are just fed up with typing long names, a solution is to use a modern IDE that supports completion of names as you type them. See #BillK's answer for example.
If the real problem is that you are fed up with the long names taking to much space, a solution is to use a wider screen / longer lines. Most monitors are big enough to display 120 character (or more) wide source code with no eye strain.
If neither of the above is the answer, consider just refactoring the offending code to use sensible (i.e. shorter) class and method names. Once again, a modern IDE can handle this kind of refactoring quickly and safely.
On the last point, I would consider that the overly long class names and method names are bad style. IMO, you are justified in taking the time to fix them yourself, or suggesting that they be fixed, especially if they constitute a "public" API for some library or module.
To those who would argue that long identifiers are good style because they convey more information, the counter argument is that they don't actually improve readability. But if you say that they do improve readability, then it follows that using aliases instead of the long identifiers would be reducing readability!
Actually there is a way to get 1/2 of what you're after.
Looking at your example:
LONGGGGGGGGGGGGGGGClass.longggggggggggggggggggggggggMethod();
It appears that longggggggggggggggggggggggggMethod is static. (If it weren't, you'd be prefixing it with a variable name, which you control the size of.)
You can use Java's static import feature to 'alias' or import the static methods of the LONGGGGGGGGGGGGGGGClass into your own class' namespace. Instead of the above code, you would only have to write this:
longggggggggggggggggggggggggMethod();
You can use inheritance or encapsulation to wrap the original class.
class g extends LONGCLASS
{
void a() { super.loooonnng(); }
}
or
class g
{
private LONGCLASS lc;
void a() { lc.loooonnng(); }
}
Not supported in Java.
There is an enhancement ticket (7166917) for adding aliases for imports which would be helpful. The idea is this :
import a.very.lng.pckage.* as shortpckg
import my.pckage.IsAVeryLongClassName as MyShort
public class Shorten
{
public static final Shorten m = new Shorten();
public int a(params)
{
return some_method_with_long_name(params);
}
public void b()
{
// whatever static code you want
}
}
In your main code then:
import static mypackage.Shorten.m;
...
int res = m.a(params);
m.b();
...
This way you effectively alias any static stuff you want, while avoiding warnings.
I only ran a simple test but I defined an inner class variable. I'm not an expert nor do I know the consequences of doing this but I obtained positive results.
package a.b;
public class Library {
public static String str;
}
Now write a class to access the static variables from Library
package a.b;
public class Access {
public class Short extends Library {}
Short.str;
}
Related
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.
I created classes like below in the same package test. It was just to test whether java really allows it. And it does but then it comes in to problems.
package test;
public class E {
}
package test;
public class T {
}
package test;
import test.E;
import test.T;
public class K<E, T> {
E e;
T t;
public K(E e, T t) {
this.e = e;
this.t = t;
}
public static void main(String[] args) {
K k = new K<E, T>(new E(), new T());
}
}
Above code give multiple compilation problems
Multiple markers at this line
- Cannot make a static reference to the non-static type E
- Cannot make a static reference to the non-static type T
- Cannot make a static reference to the non-static type T
- Cannot make a static reference to the non-static type E
- K is a raw type. References to generic type K<E,T> should be
parameterized
It clearly shows compiler is confused between E and class E same for T.
So workaround is define it real types using package.
K k = new K<test.E, test.T>(new test.E(), new test.T());
Now if there all these classes are in default package there is no way to solve this compilation issue.
So Question is should java allow declaration of such classes in default package?
It clearly shows compiler is confused between E and class E same for T.
I think you've got that wrong. I think that if you read the relevant parts of the JLS carefully (I'll look them up later) you will find that they clearly state what E and T should resolve to in the various contexts. I would be very surprised if the compiler is getting the resolution wrong; i.e. not implementing the JLS.
In reality, the confusion is in the mind of the person who wrote the code ...
The problem here is that the rules about what takes precedence over what are probably not what you (and typical programmers) expect. But they are like they are for a good reason.
Normally this doesn't matter, but if you ignore the normal Java naming conventions and use one-letter names for classes, then you might get burnt.
So Question is should java allow declaration of such classes in default package?
Alternatively, should "you" be ignoring the Java class naming conventions?
Frankly, there are a lot of ways that a programmer can hurt themselves if they ignore the style guidelines / recommendations. But if you try to protect the programmer too much, you actually hurt him/her by making it impossible to implement stuff where you need to push the envelope. The best policy is (IMO) to not treat programmers as children. If they really want to juggle with sharp knives ... let them.
This is very nice research.
But, you are still allowed to create a class with name String, Java never complained against using same class name. To differentiate whether you use your String class (or) Java provided String class, you need to append the package (full name).
As Matt Ball said, default packages are shouldn't be used.
Backward compatibility could be another reason why Generic Types not defined as "reserve words"
Whether allow same class name (or) not, I think that is what packages are for. As long as there is a way to differentiate which class we are referring to, I think it is perfectly fine to allow same name.
You can get really confused if you want to. I am not sure its up to the compiler to prevent you from writing confusing code but I do think the compiler should try to be clear in its error messages.
public class T<T> {
public T() {
}
public static <T> T T() {
T T = null;
return T; // which T is this?
}
}
Considering you can write
public class String<Object>{}
Disalowing class with same name as how YOU named type parameter or forbiding you to name type parameter as any existing class would be insane (Class with conflicting name can be from another jar created in future, so any name of type parameter can be same as name of some class, and vice versa)
I have an existing class into which I want to add a method. But I want the method to be called only from a specific method from a specific class. Is there any way that I can prevent that call from other classes/methods?
For example, I have an existing class A
public final class A
{
//other stuff available for all classes/methods
//I want to add a method that does its job only if called from a specific method of a class, for example:
public void method()
{
//proceed if called from Class B.anotherMethod() else throw Exception
}
}
One way of doing this is getting the StackTrace inside the method() and then confirming the parent method?
What I am looking for is a solution that is more clean and advisable solution like a pattern or something.
To be honest, you have painted yourself into a corner here.
If classes A and B are not related and not members of the same package, then visibility won't solve the problem. (And even if it did, reflection can be used to subvert the visibility rules.)
Static code analysis won't solve the problem if the code can use reflection to call the method.
Passing and checking B.this as an extra parameter to A.method(...) doesn't help because some other class C could pass a B instance.
This leaves only the stacktrace approach1... or giving up and relying on the good sense of the programmer2 not to call methods that they shouldn't.
The ideal solution is to revisit the design and/or coding decisions that got you into this mess.
1 - See other answers for examples that use annotations, a security manager, etc to conceal the stacktrace stuff from the application programmer. But note that under the hood you are adding probably hundreds, possibly thousands of instructions overhead per method call.
2 - Do not underestimate the programmer's good sense. Most programmers, when they see advice not to call some method, are likely to follow that advice.
The right way to do this would be a SecurityManager.
Define a permission which all code which wants to call A.method() has to have, and then make sure only B and A have that permission (this also means that no class has AllPermission).
In A, you check this with System.getSecurityManager().checkPermission(new BMethodPermission()), and in B you call the method inside of AccessController.doPrivileged(...).
Of course, this requires that a security manager is installed (and it uses suitable policies) - if it isn't, all code is trusted and everyone can call everything (if necessary, with Reflection).
You might consider using an interface. If you're passing in the calling class, you can confirm that the class is of the appropriate type.
Alternatively, if you're using Java, you can use "default" or "package" level access (e.g. void method() vs. public void method()). This will allow your method to be called by any class inside the package and does not require that you pass the class to the method.
The only way to check for sure at run time is to take a stack trace. Even if its private you can access the method via reflections.
A simpler way to do this would be to check usages in your IDE. (provided its not called via reflections)
As others have mentioned, using the stack trace is one way to implement the functionality that you are looking for. Generally, if one needs to "block" callers from a public method, it could be a sign of poor design. As a rule of thumb, use access modifiers that restrict the scope as much as possible. However, making a method package-private or protected is not always an option. Sometimes, one may want to group some classes in a separate package. In that case, the default (package-private) access is too restrictive, and it usually does not make sense to subclass, so protected is not helpful either.
If restricting calling to certain classes is desired, you can create a method like:
public static void checkPermission(Class... expectedCallerClasses) {
StackTraceElement callerTrace = Thread.currentThread().getStackTrace()[3];
for (Class expectedClass : expectedCallerClasses) {
if (callerTrace.getClassName().equals(expectedClass.getName())) {
return;
}
}
throw new RuntimeException("Bad caller.");
}
Using it is very simple: just specify what class(es) can call the method. For example,
public void stop() {
checkPermission(ShutdownHandler.class);
running = false;
}
So, if the stop method gets called by a class other than ShutdownHandler, checkPermission will throw an IllegalStateException.
You may wonder why checkPermission is hard-coded to use the fourth element of the stack trace. This is because Thread#getStackTrace() makes the most recently called method the first element. So,
getStackTrace()[0] would be the call to getStackTrace itself.
getStackTrace()[1] would be the call to checkPermission.
getStackTrace()[2] would be the call to stop.
getStackTrace()[3] would be the method that called stop. This is what we are interested in.
You mentioned that you want methods to be called from a specific class and method, but checkPermission only checks for class names. Adding the functionality to check for method names requires only a few modifications, so I'm going to leave that as an exercise.
Make proper use of protected
The standard way to do this in java is to put Class B and Class A in the same package (maybe a subpackage of your current application) and use the default visibility.
The default java visibility is "package-private" which means everything in that package can see your method, but nothing outside that package can access it.
See Also:
Is there a way to simulate the C++ 'friend' concept in Java?
Assuming that you only need to apply this restriction to classes within your project, static analysis could work for you - for example an ArchUnit test:
package net.openid.conformance.archunit;
import com.google.gson.JsonElement;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.AccessTarget;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchRule;
import net.openid.conformance.testmodule.OIDFJSON;
import org.junit.Test;
import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target;
import static com.tngtech.archunit.core.domain.JavaClass.Predicates.assignableTo;
import static com.tngtech.archunit.core.domain.properties.HasName.Predicates.*;
import static com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With.owner;
import static com.tngtech.archunit.lang.conditions.ArchPredicates.are;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
public class PreventGetAs {
#Test
public void doNotCallJsonElementGetAs() {
JavaClasses importedClasses = new ClassFileImporter().importPackages("net.openid.conformance");
JavaClasses allExceptOIDFJSON = importedClasses.that(DescribedPredicate.not(nameContaining("OIDFJSON")));
ArchRule rule = noClasses().should().callMethodWhere(
target(nameMatching("getAs[^J].*")) // ignores getAsJsonObject/getAsJsonPrimitive/etc which are fine
.and(target(owner(assignableTo(JsonElement.class)))
)).because("the getAs methods perform implicit conversions that might not be desirable - use OIDFJSON wrapper instead");
rule.check(allExceptOIDFJSON);
}
}
You can do it by using annotations and reflection. I will report a similar case, i.e. the case where you can let the method being called only by specific methods from extenal classes. Suppose that the class that must be "protected" by a whatsoever invocation of the its public methods is Invoked, while Invoker is the class tha has a method enabled to invoke one or more methods from Invoked. Then, you can do something like reported in the following.
public class Invoked{
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public static #interface CanInvoke{}
public void methodToBeInvoked() {
boolean canExecute=false;
try {
//get the caller class
StackTraceElement element = (new Throwable()).getStackTrace()[1];
String className = element.getClassName();
Class<?> callerClass = Class.forName(className);
//check if caller method is annotated
for (Method m : callerClass.getDeclaredMethods()) {
if (m.getName().equals(methodName)) {
if(Objects.nonNull(m.getAnnotation(EnabledToMakeOperationRemoved.class))){
canExecute = true;
break;
}
}
}
} catch (SecurityException | ClassNotFoundException ex e) {
//In my case does nothing
}
if(canExecute){
//do something
}
else{
//throw exception
}
}
}
and the Invoker class is
public class Invoker{
private Invoked i;
#Invoked.CanInvoke
public void methodInvoker(){
i.methodToBeInvoked();
}
}
Note that the method that is enabled to invoke is annotated with the CanInvoke annotation.
The case that you requested is similar. You annotate the classes/method that cannot call the public method and then you set to true the canExecute variable only if the method/class is not annotated.
You can use a tool like Macker and add it to your build process to check some rules are respected, like
<?xml version="1.0"?>
<macker>
<ruleset name="Simple example">
<access-rule>
<deny>
<from class="**Print*" />
<to class="java.**" />
</deny>
</access-rule>
</ruleset>
</macker>
It will NOT prevent you from writing wrong code but if you use Maven or another build system it can raise an error during your build process.
This tools work at a "class" level not at a "method" level but I do not see the point of preventing the call of only one method from a certain class ...
I realise your use case states 'specific method in specific class', but I don't think you can reliably solve this at design time (and I can't think of a use case where this would have to be enforced anyway).
The following example creates an easy design time solution for restricting the access of a class' method to a particular class. It can, however, be easily extended to multiple allowed classes.
It is achieved by defining a public inner class with a private constructor that acts as a key to the method at hand. In the following example the class Bar has a method that should only be called from an instance of the Foo class.
Class Foo:
public class Foo
{
public Foo()
{
Bar bar = new Bar();
bar.method(new FooPrivateKey());
}
public class FooPrivateKey
{
private FooPrivateKey()
{ }
}
}
Class Bar:
public class Bar
{
public Bar()
{
}
public void method(FooPrivateKey fooPrivateKey)
{
if(fooPrivateKey == null)
{ throw new IllegalArgumentException("This method should only be called from the Foo class.");}
//Do originally intended work.
}
}
I don't think this is by any means safe for things like reflection or even things like FooPrivateKey.class.newInstance(), but this will at least warn the programmer a little more obtrusively than a simple comment or documentation, while you don't have to look in to more complicated things like what was suggested by people like Roberto Trunfio and Ronan Quillevere (which are perfectly viable answers as well, just too complicated for most situations in my opinion).
I hope this is sufficient for your use case.
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.
For example:
public void doSomething() {
final double MIN_INTEREST = 0.0;
// ...
}
Personally, I would rather see these substitution constants declared statically at the class level.
I suppose I'm looking for an "industry viewpoint" on the matter.
I would think that you should only put them at the class level if they are used by multiple methods. If it is only used in that method then that looks fine to me.
My starting position is that every variable or constant should be declared/initialized as close to its first use as possible/practical (i.e. don't break a logical block of code in half, just to declare a few lines closer), and scoped as tightly as possible. -- Unless you can give me a damn good reason why it should be different.
For example, a method scoped final won't be visible in the public API. Sometimes this bit of information could be quite useful to the users of your class, and should be moved up.
In the example you gave in the question, I would say that MIN_INTEREST is probably one of those pieces of information that a user would like to get their hands on, and it should be scoped to the class, not the method. (Although, there is no context to the example code, and my assumption could be completely wrong.)
Technically, there is no such thing as a "method scoped constant" in Java. What you are referring to is simply a final local variable; it is created an destroyed with each method invocation.
http://www.java-tips.org/java-se-tips/java.lang/how-do-i-declare-a-constant-in-java.html
I've used this method scoped constants myself but every so often a colleague will down mod it during code reviews. Again, these colleagues are not into reading/writing open source but they are used to enterprise software.
I tell them that it does NOT make sense to use a class level constant if it is used within a single method but I've found more than 1 colleague insisting that it be moved UP.
I usually comply since I'm not so rigid unless it affects readability and/or performance.
Information hiding and modularity are key principles, and narrow scoping is better information hiding. If the constant is only needed by the method, the hiding is good. If and when the constant is useful elsewhere, bring it out to a broader scope, but only as broadly as needed.
You are probably concerned because this is a constant, and therefore, it may seem to belong to some global properties table. Maybe it does. Maybe it doesn't. Your concern is valid, but there is no one best place for all constants.
I have a different take on this: IMHO its better to place them at file/class scope especially if you are working in teams for this reason: say you start with a small piece of code...
public void doSomething() {
final double MIN_INTEREST = 0.0;
// ...
}
and other members of you team expand the class with whole bunch of methods and now the class is a wonderful 500 lines/50 methods giant class. Imagine the experience of an engineer who is trying to adding a new method with a constant, they will have to 1 scan the whole class looking for constants that match their need, 2 move the constant to class scope hoping that there are no conflicts with existing code and 3 also add their method.
If you instead add all constants at file/class scope to begin with, engineers have a 1 single place to look for existing constants and, 2 derive some constants from others where it makes sense. (for example if you have a constant for pi you may also want to define a new constant with a value of pi/2).
The reason why you can define a final variable at a class level or method (local) level it's because you can override the global static constant inside the (local) method.
Example:
public class Test {
final double MIN_INTEREST = 0.0;
/**
* #param args
*/
public static void main(String[] args) {
Test test = new Test();
test.doSomethingLocal();
test.doSomethingGlobal();
}
public void doSomethingGlobal() {
System.out.println("Global-> " + MIN_INTEREST);
}
public void doSomethingLocal() {
final double MIN_INTEREST = 0.1;
System.out.println("Local-> " + MIN_INTEREST);
}
}
The output will be:
Local-> 0.1
Global-> 0.0
So your question doesn't make any sense.