I'm making a game where players have to write their own class to control the on-screen units. However, I want to prevent them from using static variables inside the player class so that their units have to communicate information via a communication system I have developed (i.e transmitting 1s and 0s) rather than just accessing the static "unitsTargeted" variable or whatever else it might be. Can I prevent them from using static modifiers somehow?
That depends. If you have no control over the source code or the run environment, then you cannot stop them from compiling what they want nor from having that executed.
If you have control over the build (ie: the source gets sent to a system you controlled and you control the compilation), then you could build a custom compiler.
If you control the run environment in some fashion, you could inspect the supplied class to see what it contains. You could use some byte-code tool, or better yet just use reflection API and check if any of the members are static. Once you use reflection to get a list of members, iterate over them and check their isStatic. If the class contains any static members, you could reject it.
In your case, since you are uploading classes to a server from clients, you could check it simply by using Java's reflection API. If the clients are submitting source code, then you will need to compile it first, though I assume you do that anyway before you use it.
Here is a test case I just ran:
package test.tmp;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
public class StaticChecker
{
public static void main(String[] args)
{
for(Class c : new Class[]{StaticChecker.class, ClassWithStatics.class, ClassWithoutStatics.class})
{
System.out.println("For " + c + "...");
boolean hasStatic = hasStaticMembers(c);
System.out.println("\tIt contains static members: " + hasStatic);
if(hasStatic)
{
System.out.println("\tThe static members are:");
for(String s : checkStaticMembers(c))
System.out.println("\t\t" + s);
}
}
}
public static boolean hasStaticMembers(Class c)
{
return checkStaticMembers(c).size() > 0;
}
public static List<String> checkStaticMembers(Class c)
{
List<String> staticMemberNames = new ArrayList<String>();
for(Field field : c.getDeclaredFields())
if(Modifier.isStatic(field.getModifiers()))
staticMemberNames.add(field.toString());
for(Method method : c.getDeclaredMethods())
if(Modifier.isStatic(method.getModifiers()))
staticMemberNames.add(method.toString());
return staticMemberNames;
}
}
class ClassWithStatics
{
public static int N = 3;
private static String S = "?";
private int n;
void f() { System.out.println("f()"); }
static void g() { System.out.println("g()"); }
public static void h() { System.out.println("h()"); }
}
class ClassWithoutStatics
{
int a;
String b;
void f() { System.out.println("f()"); }
}
When I run the above test, I get the following output:
For class test.tmp.StaticChecker...
It contains static members: true
The static members are:
public static void test.tmp.StaticChecker.main(java.lang.String[])
public static java.util.List test.tmp.StaticChecker.checkStaticMembers(java.lang.Class)
public static boolean test.tmp.StaticChecker.hasStaticMembers(java.lang.Class)
For class test.tmp.ClassWithStatics...
It contains static members: true
The static members are:
public static int test.tmp.ClassWithStatics.N
private static java.lang.String test.tmp.ClassWithStatics.S
static void test.tmp.ClassWithStatics.g()
public static void test.tmp.ClassWithStatics.h()
For class test.tmp.ClassWithoutStatics...
It contains static members: false
Please note that what you are doing can be dangerous and you should be very careful to limit what code executed server-side can do. All someone needs to do to ruin your day is submit a class which deletes files or installs unwanted files or any other nefarious action.
Do not to use static variable in your program, or if you really need one, make it ThreadLocal and keep it on a thread which is not accessible from the user classes.
If you want your program to be relatively safe you should also build some kind of class validator which will make sure those classes use only allowed classes, a very short white list of allowed classes.
You can use ASM to make such validator.
Related
I want to know how to use multiple classes in one file in java. I typed this code but it is showing compilation errors.
class test {
int a, b, c;
void getdata(int x, int y) {
a = x;
b = y;
}
void add() {
c = a + b;
System.out.println("Addition = " + c);
}
}
public class P8 {
public static void main(String[] args) {
test obj = new test();
test.getdata(200, 100);
test.add();
}
}
You can only have one public top-level class per file. So, remove the public from all but one (or all) of the classes.
However, there are some surprising problems that can happen if you have multiple classes in a file. Basically, you can get into trouble by (accidentally or otherwise) defining multiple classes with the same name in the same package.
If you're just a beginner, it might be hard to imagine what I'm going on about. The simple rule to avoid the problems is: one class per file, and call the file the same thing as the class it declares.
The compilation errors in the classes you showed us have nothing to do with having two classes in the file.
public static void main(String[] args) {
test obj = new test();
test.getdata(200, 100); // error here
test.add(); // error here
}
When I compile your code using javac the error messages are:
$ javac P8.java
P8.java:21: error: non-static method getdata(int,int) cannot be referenced from a static context
test.getdata(200, 100);
^
P8.java:22: error: non-static method add() cannot be referenced from a static context
test.add();
^
2 errors
The problem is that test is a class name, not the name of a variable. As a result you are trying to invoke instance methods as if they were static methods.
But to my mind, this is a classic "I've shot myself in the foot Mum" moment.
You have broken one of the most widely observed rules of Java style.
Java class names should always start with an uppercase letter.
You have named your class test rather than Test. So when you wrote
test.getdata(200, 100);
test looks like a variable name, and that looks like a call of an instance method. But it isn't.
My bet is that this is part of what caused you to misconstrue the error message as being related (somehow) to having two classes in a file.
There is another stylistic howler in you code. You have called a method getdata but it actually behaves as a (sort of) setter for the Test class. If your code wasn't so small that it fits on a single page, that would be really misleading.
And finally, I agree with people who advise you not to put multiple top level classes into a single source file. It is legal code, but unnecessary. And style guides typically recommend against doing it.
i hope it will help you....
i just changed test.getdata() to obj.getdata()
and test.add() to obj.add() ..... check it out..
class test {
int a,b,c;
void getdata(int x, int y) {
a=x;
b=y;
}
void add() {
c=a+b;
System.out.println("Addition = "+c);
}
}
public class P8 {
public static void main(String[] args) {
test obj = new test();
obj.getdata(200,100);
obj.add();
}
}
you can not call test.getdata()..
and test.add()... as its not static methods
You can use at most one public class per one java file (COMPILATION UNIT) and unlimited number of separate package-private classes.
Compilation unit must named as public class is.
You also can have in your public class the unlimited number of inner classes and static nested classes.
Inner classes have an intenal pointer to the enclosing class so they have access to its members as well as local vars. They can be anonymuous.
Static nested classes is just like regular pubic class but is defined within enclosing class
Here's a very basic example of how to nest classes within classes. For this example, let's say that my file is named Test.java
public class Test {
public Test() {
}
class Person {
public Person() {
}
}
}
You should really take a look at how constructors work, because that may be one of your problems. Can't tell what else without more info, unfortunately.
{
// you have to call the method by the object which you are created. then it will run without error.
Test obj = new Test();
obj.getdata(20, 10);
obj.add();`
}
You have to nest your classes in each other, although it is not recommended.
public class P8 {//Currently inside P8 class
class test {//Declaring while inside P8
private int a, b, c;//Private vars in a nested class
void getdata(int x, int y) {
a = x;
b = y;
}
void add() {
c = a + b;
System.out.println("Addition = " + c);
}
}
public static void main(String[] args) {//Running the main for P8 class
test obj = new test();
test.getdata(200, 100);
test.add();
}
}
One of the reasons nesting classes is a bad idea is it strips the class of its privacy. The 'private' tag in java take whatever variable is tagged with it, and will only let that class access it, but if the class is inside another, both classes can freely access those private variables.
For two utility classes with the same names, which contain only static methods, I proceeded as follows:
Simply imported the first
Created an instance of the second class.
Example:
package util1;
public class Utility {
public static void method() {
System.out.println("First Utility. static method");
}
}
package util2;
public class Utility {
public static void method() {
System.out.println("Second Utility. static method");
}
}
import util1.Utility;
public class Component {
private static final util2.Utility anotherUtility = new util2.Utility();
public static void usedByReflection() {
Utility.method();
anotherUtility.method();
}
}
Now I don't need to write a full second util-class name for invoke its methods, but maybe I did not foresee something...?
P.S:
The methods of the class Component are called through a reflection by a certain BlackBox. All the multithread-safe features are in BlackBox.
UPD: I have found better trick:
import util1.Utility;
public class Component {
private static final util2.Utility anotherUtility = null; // There are some changes
public static void usedByReflection() {
Utility.method();
anotherUtility.method();
}
}
Now I dont create new object, but is it possible to use it without any bugs?
IMO, this is confusing and could much more clearly be handled by something like:
public class CombinedUtilityComponent {
public static void usedByReflection() {
util1.Utility.method();
util2.Utility.method();
}
}
Or, better yet, in your code you can just fully qualify the class names and they become unique names without any confusing tricks.
Yes, this works. I wouldn't do it, though.
You're calling a static method as if it were an instance method. anotherUtility.method() has a useless reference to anotherUtility.
You also have an unnecessary instantiation of util2.Utility. This technique wouldn't work if the default constructor were disabled.
I want to create a wrapper class that calls static methods and member fields from a class that is provided by a library I am unable to view the code.
This is to avoid boilerplate setting code of the global member fields when I need to use a static method in a specific context.
I want to try to avoid creating wrapper methods for each static method.
My question:
Is it possible to return a class with static methods from a method to access just the static methods without instantiating it?
Code is below with comments in-line.
The code is used to demonstrate a change in a static value when the method getMath() is invoked.
I want to avoid the setting of the value before calling the static method.
StaticMath.setFirstNumber(1);
StaticMath.calc(1);
StaticMath.setFirstNumber(2);
StaticMath.calc(1);
I am using the Eclipse IDE and it comes up with Warnings, which I understand, but want to avoid.
I tried searching for something on this subject, so if anyone can provide a link I can close this.
public class Demo {
// Static Methods in a class library I don't have access to.
static class StaticMath {
private static int firstNum;
private StaticMath() {
}
public static int calc(int secondNum) {
return firstNum + secondNum;
}
public static void setFirstNumber(int firstNum) {
StaticMath.firstNum = firstNum;
}
}
// Concrete Class
static class MathBook {
private int firstNum;
public MathBook(int firstNum) {
this.firstNum = firstNum;
}
// Non-static method that gets the class with the static methods.
public StaticMath getMath() {
StaticMath.setFirstNumber(firstNum);
// I don't want to instantiate the class.
return new StaticMath();
}
}
public static void main(String... args) {
MathBook m1 = new MathBook(1);
MathBook m2 = new MathBook(2);
// I want to avoid the "static-access" warning.
// Answer is 2
System.out.println(String.valueOf(m1.getMath().calc(1)));
// Answer is 3
System.out.println(String.valueOf(m2.getMath().calc(1)));
}
}
I'd just wrap it to make for an atomic operation:
public static class MyMath{
public static synchronized int myCalc( int num1 , int num2 ){
StaticMath.setFirstNum(num1);
return StaticMath.calc(num2);
}
}
Drawback: You'll have to make sure, StaticMath is not used avoiding this "bridging" class.
Usage:
int result1 = MyMath.myCalc( 1, 1 );
int result1 = MyMath.myCalc( 2, 1 );
You shouldnt call a static method through an object reference. You should directly use class reference to call a static method like this:
StaticMath.calc(1)
But if you still need it for some reason, you can return null in getMath method, but you will still get warning in Eclipse:
public StaticMath getMath() {
StaticMath.setFirstNumber(firstNum);
return null;
}
I infer that question is not properly asked if the answer is not
StaticMath.calc(1)
Other issue you may be facing due to package visibility to static inner classes. Which is a design choice by the writer of Demo class. If you can mark your classes MathBook and StaticMath public then you can access them like below:
Demo.StaticMath.calc(1);
I'm trying to initialize a static class, with an argument, and then run some more static code in that class.
I'm aware of the static block, but it seems it can't take any arguments.
Is there a way to pass arguments to a static constructor?
If not, what is the recommended technique to initialize a Static class using an argument?
Edit:
A static class to my understanding is a class which cannot be instantiated (in c# they're called static classes, if Java has a different term for them, sorry for not being aware of it) - it's accessed through it's class name rather than an object name.
What I'm trying to achieve (very simplified) is a class which receives a dictionary as String, parses it, and has methods manipulate it like GetRandomEntry.
Here's an elaborated snippet of my code:
public class QuestionsRepository {
private static Map<String,String[]> easyDefinitions = new HashMap<String,String[]>();
//...
staticĀ
{
// need to receive and parse dictionary here
}
//...
Taking the relevant parts of a code snippet is never easy, hope i have chosen wisely (:
Another detail that may be relevant - I'm a c# programmer, usually. Just Started learning Java lately.
Thanks.
I think you would need to initialize the static fields of the class according to some input. You can do it in the following way by calling the static method of another class:
class ClassToInitialize {
static {
staticField = ParamPassClass.getParameter();
}
private static String staticField;
ClassToInitialize() {
System.out.println("This is the parameter: " + staticField);
}
}
class ParamPassClass {
private static String parameter;
static String getParameter() {
return parameter;
}
static void setParameter(String parameter) {
ParamPassClass.parameter = parameter;
}
}
class Main {
public static void main(String args[]) {
ParamPassClass.setParameter("Test param");
new ClassToInitialize();
}
}
Java doesn't have static constructors. It only has static initializers and static initializers do not take any arguments. It is executed when the class is first loaded, and there is no way to call it yourself.
You either need to use actual objects, or add some way of configuring the class (eg through a static method).
you should mention the member class with a static qualifier, otherwise there is no such a thing as a static class
Here you can find the explanation of using the word 'static' in this context.
Now you should just call its constructor and pass all the arguments you want,
the only restriction that you have on a static member class is that it can't refer the non-static fields of its outer class, it resembles a static methods on class that can't refer the non-static fields of class.
I didn't understand why do you mention a static initialization block here, could you please clarify a little?
Be aware also that in java there is no such a thing as static constructor....
Hope this helps
You can have a static method public static void setUp(Arg1 arg1, Arg2 arg2...) which sets up all your static fields and invoke it when your program starts.
You have to make sure this method will be called only once [or only when you want to reset these fields]
It is not possible to pass arguments directly to the static initializes (JLS:static initializers).
It would be nice if you could share more information about your goals.
You could use an enum to initialize a singleton with a string parameter like this
import java.util.*;
class Data {
static Map<String,String[]> easyDefinitions = new HashMap<String,String[]>();
}
public enum QuestionsRepository
{
repository("primary=red,green,blue;secondary=cyan,yellow,magenta");
QuestionsRepository(String dictionary) {
String[] rules = dictionary.split(";");
for (String rule:rules) {
String[] keyValuePair = rule.split("=",2);
Data.easyDefinitions.put(keyValuePair[0],keyValuePair[1].split(","));
}
}
}
I understand that in this code:
class Foo {
public static void method() {
System.out.println("in Foo");
}
}
class Bar extends Foo {
public static void method() {
System.out.println("in Bar");
}
}
.. the static method in Bar 'hides' the static method declared in Foo, as opposed to overriding it in the polymorphism sense.
class Test {
public static void main(String[] args) {
Foo.method();
Bar.method();
}
}
...will output:
in Foo
in Bar
Re-defining method() as final in Foo will disable the ability for Bar to hide it, and re-running main() will output:
in Foo
in Foo
(Edit: Compilation fails when you mark the method as final, and only runs again when I remove Bar.method())
Is it considered bad practice to declare static methods as final, if it stops subclasses from intentionally or inadvertantly re-defining the method?
(this is a good explanation of what the behaviour of using final is..)
I don't consider it's bad practice to mark a static method as final.
As you found out, final will prevent the method from being hidden by subclasses which is very good news imho.
I'm quite surprised by your statement:
Re-defining method() as final in Foo will disable the ability for Bar to hide it, and re-running main() will output:
in Foo
in Foo
No, marking the method as final in Foo will prevent Bar from compiling. At least in Eclipse I'm getting:
Exception in thread "main" java.lang.Error: Unresolved compilation problem: Cannot override the final method from Foo
Also, I think people should always invoke static method qualifying them with the class name even within the class itself:
class Foo
{
private static final void foo()
{
System.out.println("hollywood!");
}
public Foo()
{
foo(); // both compile
Foo.foo(); // but I prefer this one
}
}
Static methods are one of Java's most confusing features. Best practices are there to fix this, and making all static methods final is one of these best practices!
The problem with static methods is that
they are not class methods, but global functions prefixed with a classname
it is strange that they are "inherited" to subclasses
it is surprising that they cannot be overridden but hidden
it is totally broken that they can be called with an instance as receiver
therefore you should
always call them with their class as receiver
always call them with the declaring class only as receiver
always make them (or the declaring class) final
and you should
never call them with an instance as receiver
never call them with a subclass of their declaring class as receiver
never redefine them in subclasses
NB: the second version of you program should fails a compilation error. I presume your IDE is hiding this fact from you!
If I have a public static method, then it's often already located in a so-called utility class with only static methods. Self-explaining examples are StringUtil, SqlUtil, IOUtil, etcetera. Those utility classes are by itselves already declared final and supplied with a private constructor. E.g.
public final class SomeUtil {
private SomeUtil() {
// Hide c'tor.
}
public static SomeObject doSomething(SomeObject argument1) {
// ...
}
public static SomeObject doSomethingElse(SomeObject argument1) {
// ...
}
}
This way you cannot override them.
If yours is not located in kind of an utility class, then I'd question the value of the public modifier. Shouldn't it be private? Else just move it out to some utility class. Do not clutter "normal" classes with public static methods. This way you also don't need to mark them final.
Another case is a kind of abstract factory class, which returns concrete implementations of self through a public static method. In such case it would perfectly make sense to mark the method final, you don't want the concrete implementations be able to override the method.
Usually with utility classes - classes with only static methods - it is undesirable to use inheritence. for this reason you may want to define the class as final to prevent other classes extending it. This would negate putting final modifiers on your utility class methods.
The code does not compile:
Test.java:8: method() in Bar cannot
override method() in Foo; overridden
method is static final
public static void method() {
The message is misleading since a static method can, by definition, never be overridden.
I do the following when coding (not 100% all the time, but nothing here is "wrong":
(The first set of "rules" are done for most things - some special cases are covered after)
create an interface
create an abstract class that implements the interface
create concrete classes that extend the abstract class
create concrete classes that implements the interface but do not extend the abstract class
always, if possible, make all variables/constants/parameters of the interface
Since an interface cannot have static methods you don't wind up with the issue. If you are going to make static methods in the abstract class or concrete classes they must be private, then there is no way to try to override them.
Special cases:
Utility classes (classes with all static methods):
declare the class as final
give it a private constructor to prevent accidental creation
If you want to have a static method in a concrete or abstract class that is not private you probably want to instead create a utility class instead.
Value classes (a class that is very specialized to essentially hold data, like java.awt.Point where it is pretty much holding x and y values):
no need to create an interface
no need to create an abstract class
class should be final
non-private static methods are OK, especially for construction as you may want to perform caching.
If you follow the above advice you will wind up with pretty flexible code that also has fairly clean separation of responsibilities.
An example value class is this Location class:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class Location
implements Comparable<Location>
{
// should really use weak references here to help out with garbage collection
private static final Map<Integer, Map<Integer, Location>> locations;
private final int row;
private final int col;
static
{
locations = new HashMap<Integer, Map<Integer, Location>>();
}
private Location(final int r,
final int c)
{
if(r < 0)
{
throw new IllegalArgumentException("r must be >= 0, was: " + r);
}
if(c < 0)
{
throw new IllegalArgumentException("c must be >= 0, was: " + c);
}
row = r;
col = c;
}
public int getRow()
{
return (row);
}
public int getCol()
{
return (col);
}
// this ensures that only one location is created for each row/col pair... could not
// do that if the constructor was not private.
public static Location fromRowCol(final int row,
final int col)
{
Location location;
Map<Integer, Location> forRow;
if(row < 0)
{
throw new IllegalArgumentException("row must be >= 0, was: " + row);
}
if(col < 0)
{
throw new IllegalArgumentException("col must be >= 0, was: " + col);
}
forRow = locations.get(row);
if(forRow == null)
{
forRow = new HashMap<Integer, Location>(col);
locations.put(row, forRow);
}
location = forRow.get(col);
if(location == null)
{
location = new Location(row, col);
forRow.put(col, location);
}
return (location);
}
private static void ensureCapacity(final List<?> list,
final int size)
{
while(list.size() <= size)
{
list.add(null);
}
}
#Override
public int hashCode()
{
// should think up a better way to do this...
return (row * col);
}
#Override
public boolean equals(final Object obj)
{
final Location other;
if(obj == null)
{
return false;
}
if(getClass() != obj.getClass())
{
return false;
}
other = (Location)obj;
if(row != other.row)
{
return false;
}
if(col != other.col)
{
return false;
}
return true;
}
#Override
public String toString()
{
return ("[" + row + ", " + col + "]");
}
public int compareTo(final Location other)
{
final int val;
if(row == other.row)
{
val = col - other.col;
}
else
{
val = row - other.row;
}
return (val);
}
}
It might be a good thing to mark static methods as final, particularly if you are developing a framework that you expect others to extend. That way your users won't inadvertently end up hiding your static methods in their classes. But if you are developing a framework you might want to avoid using static methods to begin with.
Most of this final issue dates back to the time when VM-s were quite dumb/conservative. Back then if you marked a method final it meant (among other things), that the VM can inline it, avoiding method calls. That is not case since a long-long (or long double :P ) time: http://java.sun.com/developer/technicalArticles/Networking/HotSpot/inlining.html .
I guess that Idea/Netbeans inspection warns you, because it thinks that you want to use the final keyword for optimization and they think that you are unaware of the fact that it is unneeded with modern VMs.
Just my two cents...
I encountered one detriment to using final methods using Spring's AOP and MVC. I was trying to use spring's AOP put in security hooks around one of the methods in the AbstractFormController which was declared final. I think spring was using the bcel library for injection in classes and there was some limitation there.
When I create pure utility classes, I declare then with a private constructor so they cannot be extended. When creating normal classes, I declare my methods static if they are not using any of the class instance variables (or, in some cases, even if they were, I would pass the arguments in the method and make it static, it's easier to see what the method is doing). These methods are declared static but are also private - they are there just to avoid code duplication or to make the code easier to understand.
That being said, I don't remember running into the case where you have a class that has public static methods and that can/ should be extended. But, based on what was reported here, I would declare its static methods final.
Because static methods are the properties of the class and they are called with the name of the class rather than of object. If we make the parent class method final as well it will not be overloaded as final methods does not allow to change its memory location but we can update the final data member at the same memory location...