Access a private variable of the super() class in Java - JChart2D - java

I have extended a class in Java that has a private variable that I want to get the value of before it is changed. There are no methods to access this variable in the super class. I have tried super().m_zoomArea (the variable is in the ZoomableChart class of jChart2D). The variable is updated when the mouseDragged method is called. I have overridden this method and would like to get the value of the variable before it is updated.

You can access private variable of any class, but it's a bad idea, because you're breaking one of the basic principles of OOP - encapsulation.
But sometimes programmer are forced to break it. Here is the code, which solves your problem:
Extended class
public class ExtZoomableChart
extends ZoomableChart {
public Rectangle2D getZoomArea() {
try {
Field field = ZoomableChart.class.getDeclaredField("m_zoomArea");
field.setAccessible(true);
Object value = field.get(this);
field.setAccessible(false);
if (value == null) {
return null;
} else if (Rectangle2D.class.isAssignableFrom(value.getClass())) {
return (Rectangle2D) value;
}
throw new RuntimeException("Wrong value");
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
and call example:
public class Main {
public static void main(String[] args) {
ExtZoomableChart extZoomableChart = new ExtZoomableChart();
Rectangle2D d = extZoomableChart.getZoomArea();
System.out.println(d);
}
}
You don't need to extend ZoomableChart to get private variable. You can get it value almost from everywhere. But remember - usually it's a bad practice.

You can't. The whole point of it being private is that you can't get at the variable. If the class hasn't given any way of finding it out, you can't get it. That may or may not be a design flaw in the class, but unless you use reflection with suitable privileges (which I don't recommend - you're basically relying on private implementation details) you're going to have to think of an alternative approach.

You could use reflection but it's a bad idea. A private field is private because the developer doesn't want you to mess with it.
I won't give you the way to do it here, but if you really know what you do, follow the links below at your own risks. Again, you shouldn't even think about doing this.
On the same topic :
Does reflection breaks the idea of private methods, because private methods can be access outside of the class?
Accessing private variables in Java via reflection
Is it possible in Java to access private fields via reflection

You can't access private variables from outside of the class. In order to access it you would have to have it be protected.

You can do this with the Reflection API (Specifically, see the setAccessible() method). Anyway, this is a hack and may not work if there is a SecurityManager installed in the VM.

Related

Should I initialize my JComponents when declared or initialize them inside the constructor? [duplicate]

Is there any advantage for either approach?
Example 1:
class A {
B b = new B();
}
Example 2:
class A {
B b;
A() {
b = new B();
}
}
There is no difference - the instance variable initialization is actually put in the constructor(s) by the compiler.
The first variant is more readable.
You can't have exception handling with the first variant.
There is additionally the initialization block, which is as well put in the constructor(s) by the compiler:
{
a = new A();
}
Check Sun's explanation and advice
From this tutorial:
Field declarations, however, are not part of any method, so they cannot be executed as statements are. Instead, the Java compiler generates instance-field initialization code automatically and puts it in the constructor or constructors for the class. The initialization code is inserted into a constructor in the order it appears in the source code, which means that a field initializer can use the initial values of fields declared before it.
Additionally, you might want to lazily initialize your field. In cases when initializing a field is an expensive operation, you may initialize it as soon as it is needed:
ExpensiveObject o;
public ExpensiveObject getExpensiveObject() {
if (o == null) {
o = new ExpensiveObject();
}
return o;
}
And ultimately (as pointed out by Bill), for the sake of dependency management, it is better to avoid using the new operator anywhere within your class. Instead, using Dependency Injection is preferable - i.e. letting someone else (another class/framework) instantiate and inject the dependencies in your class.
Another option would be to use Dependency Injection.
class A{
B b;
A(B b) {
this.b = b;
}
}
This removes the responsibility of creating the B object from the constructor of A. This will make your code more testable and easier to maintain in the long run. The idea is to reduce the coupling between the two classes A and B. A benefit that this gives you is that you can now pass any object that extends B (or implements B if it is an interface) to A's constructor and it will work. One disadvantage is that you give up encapsulation of the B object, so it is exposed to the caller of the A constructor. You'll have to consider if the benefits are worth this trade-off, but in many cases they are.
I got burned in an interesting way today:
class MyClass extends FooClass {
String a = null;
public MyClass() {
super(); // Superclass calls init();
}
#Override
protected void init() {
super.init();
if (something)
a = getStringYadaYada();
}
}
See the mistake? It turns out that the a = null initializer gets called after the superclass constructor is called. Since the superclass constructor calls init(), the initialization of a is followed by the a = null initialization.
my personal "rule" (hardly ever broken) is to:
declare all variables at the start of
a block
make all variables final unless they
cannot be
declare one variable per line
never initialize a variable where
declared
only initialize something in a
constructor when it needs data from
the constructor to do the
initialization
So I would have code like:
public class X
{
public static final int USED_AS_A_CASE_LABEL = 1; // only exception - the compiler makes me
private static final int A;
private final int b;
private int c;
static
{
A = 42;
}
{
b = 7;
}
public X(final int val)
{
c = val;
}
public void foo(final boolean f)
{
final int d;
final int e;
d = 7;
// I will eat my own eyes before using ?: - personal taste.
if(f)
{
e = 1;
}
else
{
e = 2;
}
}
}
This way I am always 100% certain where to look for variables declarations (at the start of a block), and their assignments (as soon as it makes sense after the declaration). This winds up potentially being more efficient as well since you never initialize a variable with a value that is not used (for example declare and init vars and then throw an exception before half of those vars needed to have a value). You also do not wind up doing pointless initialization (like int i = 0; and then later on, before "i" is used, do i = 5;.
I value consistency very much, so following this "rule" is something I do all the time, and it makes it much easier to work with the code since you don't have to hunt around to find things.
Your mileage may vary.
Example 2 is less flexible. If you add another constructor, you need to remember to instantiate the field in that constructor as well. Just instantiate the field directly, or introduce lazy loading somewhere in a getter.
If instantiation requires more than just a simple new, use an initializer block. This will be run regardless of the constructor used. E.g.
public class A {
private Properties properties;
{
try {
properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("file.properties"));
} catch (IOException e) {
throw new ConfigurationException("Failed to load properties file.", e); // It's a subclass of RuntimeException.
}
}
// ...
}
Using either dependency injection or lazy initialization is always preferable, as already explained thoroughly in other answers.
When you don't want or can't use those patterns, and for primitive data types, there are three compelling reasons that I can think of why it's preferable to initialize the class attributes outside the constructor:
avoided repetition = if you have more than one constructor, or when you will need to add more, you won't have to repeat the initialization over and over in all the constructors bodies;
improved readability = you can easily tell with a glance which variables will have to be initialized from outside the class;
reduced lines of code = for every initialization done at the declaration there will be a line less in the constructor.
I take it is almost just a matter of taste, as long as initialization is simple and doesn't need any logic.
The constructor approach is a bit more fragile if you don't use an initializer block, because if you later on add a second constructor and forget to initialize b there, you'll get a null b only when using that last constructor.
See http://java.sun.com/docs/books/tutorial/java/javaOO/initial.html for more details about initialization in Java (and for explanations on initalizer blocks and other not well known initialization features).
I've not seen the following in the replies:
A possible advantage of having the initialisation at the time of declaration might be with nowadays IDE's where you can very easily jump to the declaration of a variable (mostly
Ctrl-<hover_over_the_variable>-<left_mouse_click>) from anywhere in your code. You then immediately see the value of that variable. Otherwise, you have to "search" for the place where the initialisation is done (mostly: constructor).
This advantage is of course secondary to all other logical reasonings, but for some people that "feature" might be more important.
Both of the methods are acceptable. Note that in the latter case b=new B() may not get initialized if there is another constructor present. Think of initializer code outside constructor as a common constructor and the code is executed.
I think Example 2 is preferable. I think the best practice is to declare outside the constructor and initialize in the constructor.
The second is an example of lazy initialization. First one is more simple initialization, they are essentially same.
There is one more subtle reason to initialize outside the constructor that no one has mentioned before (very specific I must say). If you are using UML tools to generate class diagrams from the code (reverse engineering), most of the tools I believe will note the initialization of Example 1 and will transfer it to a diagram (if you prefer it to show the initial values, like I do). They will not take these initial values from Example 2. Again, this is a very specific reason - if you are working with UML tools, but once I learned that, I am trying to take all my default values outside of constructor unless, as was mentioned before, there is an issue of possible exception throwing or complicated logic.
The second option is preferable as allows to use different logic in ctors for class instantiation and use ctors chaining. E.g.
class A {
int b;
// secondary ctor
A(String b) {
this(Integer.valueOf(b));
}
// primary ctor
A(int b) {
this.b = b;
}
}
So the second options is more flexible.
It's quite different actually:
The declaration happens before construction. So say if one has initialized the variable (b in this case) at both the places, the constructor's initialization will replace the one done at the class level.
So declare variables at the class level, initialize them in the constructor.
class MyClass extends FooClass {
String a = null;
public MyClass() {
super(); // Superclass calls init();
}
#Override
protected void init() {
super.init();
if (something)
a = getStringYadaYada();
}
}
Regarding the above,
String a = null;
null init could be avoided since anyway it's the default.
However, if you were to need another default value,
then, because of the uncontrolled initialization order,
I would fix as follow:
class MyClass extends FooClass
{
String a;
{
if( a==null ) a="my custom default value";
}
...

How to allow variables being set only once in java

I need to implement a class in java where its field needs to be set only once, but it's value is not known at field declaration. To do so I have:
public class MyClass {
private String field1 = null;
public void setField1(String value) {
if (field1 == null) {
field1 = value;
}
}
}
However what I have do not prevent users to call setField1 more than once. That may lead to confusion where a user is trying to set it (without knowing it has been set somewhere else) and then the user will get confused by the field1 is not giving the value they set - until they go into the setField1 method to see what happened.
The other solution that I don't like is make a constructor to take into the value of field1, and then provide no setter. Because it makes the class a lot harder to be extended, when multiple String fields are needed - in this approach, the constructor will need to take in a couple String as parameters, and then the user can be so easily confused by/missing the parameters.
And apparently setting field1 as final won't work either.
What should I do to prevent the issue I mentioned above?
The common practice in such case is to throw a RuntimeException. In your case IllegalStateException suits best:
public void setField1(String value) {
if (field1 != null) {
throw new IllegalStateException("setField1 was already called");
}
field1 = Objects.requireNonNull(value);
}
Also note that it's better to check the passed string for null (I added Objects.requireNonNull for this).
You cannot control this at compile time, because it's impossible to analyze program to say exactly whether the method called once or more without actually running the program.
You should generally use the builder pattern for cases like this: https://en.wikipedia.org/wiki/Builder_pattern
MyClass instance = (new MyClassBuilder())
.setField1(...)
.setField2(...)
.build();
Your builder object lets you set all the fields and options you like, but the MyClass instance that it builds does not.

Is there any way to use a non-static method in a static class?

I'm trying to implement a simple spreadsheet using Java. It interacts with the user through some menus on the console, and a user can import a given file with some pre-made info about the spreadsheet to be created (lines, columns, and content of cells).
I am trying to make a static class which I called Parser, and the goal of this class is to break down each line of the import into little pieces so I can then apply the correct methods to them (read the cell to which content is being added, and what type of content am I trying to add).
I made my Parser static, because I want to use it without the need of instantiating a new object every time I need it (is this correct?). I have a specific method that is giving me trouble though. Whenever I receive input like this: 1;1|=2;3it means that my cell 1;1 references the cell 2;3. I am telling the parser to return a new Reference(getCell(i,j)). This is because my Reference class constructor receives a Cell, but of course the java compiler tells me I cannot use a non-static method, which is the case of the getCell, inside that static class.
So my question is: is there any way to overcome this problem? Any way to use a non-static method in a static class or should I instantiate a new Parser object when I try to read an import file?
It might be helpful to see some of your code to determine which method is more appropriate, but as this is a common pitfall in object oriented design, I'll try to answer the question generically.
If you define something as static, that means it has no association with any instances, even though it shares the class name. For instance,
public class Table {
List<Cell> cells;
public Table() {
while (someCondition)
parseInput(nextInput);
}
public Cell getCell(int i, int j) {
...
}
public static Cell parseInput(String input) {
Cell cellToReturn = new Cell();
...
if (input.references(cell)) cell = getCell(i,j); //Error here!
...
return cellToReturn;
}
}
The problem arises because the parseInput method is static, and yet it is referencing a specific instance's list of cells! Which one is it referencing? Who knows!
You can solve the issue two ways:
1: Make the parser non-static: public Cell parseInput(String input) {
2: Pass the table to the parser, so it knows what to reference:
public static Cell parseInput(String input, Table target) {
Cell cellToReturn = new Cell();
...
if (input.references(cell)) cell = target.getCell(i,j); //No more error!
...
return cellToReturn;
}
Now, as you stated, the parser is a class, not just a method. But the general rule still applies. You cannot reference an instance field from a static method, because that static method is not associated with any instance!
I made my Parser static, because I want to use it without the need of instantiating a new object every time I need it (is this correct?).
Maybe, but not for the reason you state. Why don't you want to create an instance of your class? If that's your only reason for making it static, then it's not a very relevant one. Indeed, something like the Singleton Pattern essentially achieves the same thing, ensuring that you don't have to keep creating an instance, because there's always exactly one instance to use.
If your object is exactly that... an object, then it should probably be modeled as an instance. I generally tend to think of things which are objects as non-static by nature and things which are concepts about an object are more static by nature.
Let's use the belabored OO example of cars for a moment. If I want to know the price of a car, that's a property of a particular car. I'd have to specify an instance of an Accord for example in order to query it for that property. If, on the other hand, I want to know the average price for a particular model, that's more of a static concept. I'm not talking about any particular instance of Accord, just Accords in general. So where something like getPrice() would be an instance method on Car, something like getAveragePrice() might not.
should I instantiate a new Parser object when I try to read an import file?
Is that such a bad thing?
Now, for the problem at hand, which reference specifically is the compiler complaining about? I guess I'm having trouble picturing it, can you provide a simplified code example so I can see how these static and non-static classes/members relate? Essentially you can reference instance members from a static location, you just need to reference an instance in order to do it. Taking my belabored example above, I can't do this:
class Car {
int getPrice() {
return 20000;
}
static int getAveragePrice() {
return Car.getPrice();
}
}
But I can do this (albeit probably ill-advised in this overly-contrived example):
class Car {
int getPrice() {
return 20000;
}
static int getAveragePrice() {
var someRandomCar = new Car();
return someRandomCar.getPrice();
}
}
If your static method need access to non-static methods (without instantiating anything or accessing instance directly), then MUST be defined as non-static.
private static Parser INSTANCE = new Parser();
public static Parser getInstance() {
return INSTANCE;
}
...
public void nonStaticMethod() {
Parser parser = Parser.getInstance();
parser.whateverParserMethodYouWant();
}
Editing to make this more clear:
class Parser {
private Parser() {}
private static Parser INSTANCE = new Parser();
public static Parser getInstance() {
return INSTANCE;
}
}
...
class ParserClient {
...
public void nonStaticMethod() {
Parser parser = Parser.getInstance();
parser.whateverParserMethodYouWant();
}
}

Should I instantiate instance variables on declaration or in the constructor?

Is there any advantage for either approach?
Example 1:
class A {
B b = new B();
}
Example 2:
class A {
B b;
A() {
b = new B();
}
}
There is no difference - the instance variable initialization is actually put in the constructor(s) by the compiler.
The first variant is more readable.
You can't have exception handling with the first variant.
There is additionally the initialization block, which is as well put in the constructor(s) by the compiler:
{
a = new A();
}
Check Sun's explanation and advice
From this tutorial:
Field declarations, however, are not part of any method, so they cannot be executed as statements are. Instead, the Java compiler generates instance-field initialization code automatically and puts it in the constructor or constructors for the class. The initialization code is inserted into a constructor in the order it appears in the source code, which means that a field initializer can use the initial values of fields declared before it.
Additionally, you might want to lazily initialize your field. In cases when initializing a field is an expensive operation, you may initialize it as soon as it is needed:
ExpensiveObject o;
public ExpensiveObject getExpensiveObject() {
if (o == null) {
o = new ExpensiveObject();
}
return o;
}
And ultimately (as pointed out by Bill), for the sake of dependency management, it is better to avoid using the new operator anywhere within your class. Instead, using Dependency Injection is preferable - i.e. letting someone else (another class/framework) instantiate and inject the dependencies in your class.
Another option would be to use Dependency Injection.
class A{
B b;
A(B b) {
this.b = b;
}
}
This removes the responsibility of creating the B object from the constructor of A. This will make your code more testable and easier to maintain in the long run. The idea is to reduce the coupling between the two classes A and B. A benefit that this gives you is that you can now pass any object that extends B (or implements B if it is an interface) to A's constructor and it will work. One disadvantage is that you give up encapsulation of the B object, so it is exposed to the caller of the A constructor. You'll have to consider if the benefits are worth this trade-off, but in many cases they are.
I got burned in an interesting way today:
class MyClass extends FooClass {
String a = null;
public MyClass() {
super(); // Superclass calls init();
}
#Override
protected void init() {
super.init();
if (something)
a = getStringYadaYada();
}
}
See the mistake? It turns out that the a = null initializer gets called after the superclass constructor is called. Since the superclass constructor calls init(), the initialization of a is followed by the a = null initialization.
my personal "rule" (hardly ever broken) is to:
declare all variables at the start of
a block
make all variables final unless they
cannot be
declare one variable per line
never initialize a variable where
declared
only initialize something in a
constructor when it needs data from
the constructor to do the
initialization
So I would have code like:
public class X
{
public static final int USED_AS_A_CASE_LABEL = 1; // only exception - the compiler makes me
private static final int A;
private final int b;
private int c;
static
{
A = 42;
}
{
b = 7;
}
public X(final int val)
{
c = val;
}
public void foo(final boolean f)
{
final int d;
final int e;
d = 7;
// I will eat my own eyes before using ?: - personal taste.
if(f)
{
e = 1;
}
else
{
e = 2;
}
}
}
This way I am always 100% certain where to look for variables declarations (at the start of a block), and their assignments (as soon as it makes sense after the declaration). This winds up potentially being more efficient as well since you never initialize a variable with a value that is not used (for example declare and init vars and then throw an exception before half of those vars needed to have a value). You also do not wind up doing pointless initialization (like int i = 0; and then later on, before "i" is used, do i = 5;.
I value consistency very much, so following this "rule" is something I do all the time, and it makes it much easier to work with the code since you don't have to hunt around to find things.
Your mileage may vary.
Example 2 is less flexible. If you add another constructor, you need to remember to instantiate the field in that constructor as well. Just instantiate the field directly, or introduce lazy loading somewhere in a getter.
If instantiation requires more than just a simple new, use an initializer block. This will be run regardless of the constructor used. E.g.
public class A {
private Properties properties;
{
try {
properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("file.properties"));
} catch (IOException e) {
throw new ConfigurationException("Failed to load properties file.", e); // It's a subclass of RuntimeException.
}
}
// ...
}
Using either dependency injection or lazy initialization is always preferable, as already explained thoroughly in other answers.
When you don't want or can't use those patterns, and for primitive data types, there are three compelling reasons that I can think of why it's preferable to initialize the class attributes outside the constructor:
avoided repetition = if you have more than one constructor, or when you will need to add more, you won't have to repeat the initialization over and over in all the constructors bodies;
improved readability = you can easily tell with a glance which variables will have to be initialized from outside the class;
reduced lines of code = for every initialization done at the declaration there will be a line less in the constructor.
I take it is almost just a matter of taste, as long as initialization is simple and doesn't need any logic.
The constructor approach is a bit more fragile if you don't use an initializer block, because if you later on add a second constructor and forget to initialize b there, you'll get a null b only when using that last constructor.
See http://java.sun.com/docs/books/tutorial/java/javaOO/initial.html for more details about initialization in Java (and for explanations on initalizer blocks and other not well known initialization features).
I've not seen the following in the replies:
A possible advantage of having the initialisation at the time of declaration might be with nowadays IDE's where you can very easily jump to the declaration of a variable (mostly
Ctrl-<hover_over_the_variable>-<left_mouse_click>) from anywhere in your code. You then immediately see the value of that variable. Otherwise, you have to "search" for the place where the initialisation is done (mostly: constructor).
This advantage is of course secondary to all other logical reasonings, but for some people that "feature" might be more important.
Both of the methods are acceptable. Note that in the latter case b=new B() may not get initialized if there is another constructor present. Think of initializer code outside constructor as a common constructor and the code is executed.
I think Example 2 is preferable. I think the best practice is to declare outside the constructor and initialize in the constructor.
The second is an example of lazy initialization. First one is more simple initialization, they are essentially same.
There is one more subtle reason to initialize outside the constructor that no one has mentioned before (very specific I must say). If you are using UML tools to generate class diagrams from the code (reverse engineering), most of the tools I believe will note the initialization of Example 1 and will transfer it to a diagram (if you prefer it to show the initial values, like I do). They will not take these initial values from Example 2. Again, this is a very specific reason - if you are working with UML tools, but once I learned that, I am trying to take all my default values outside of constructor unless, as was mentioned before, there is an issue of possible exception throwing or complicated logic.
The second option is preferable as allows to use different logic in ctors for class instantiation and use ctors chaining. E.g.
class A {
int b;
// secondary ctor
A(String b) {
this(Integer.valueOf(b));
}
// primary ctor
A(int b) {
this.b = b;
}
}
So the second options is more flexible.
It's quite different actually:
The declaration happens before construction. So say if one has initialized the variable (b in this case) at both the places, the constructor's initialization will replace the one done at the class level.
So declare variables at the class level, initialize them in the constructor.
class MyClass extends FooClass {
String a = null;
public MyClass() {
super(); // Superclass calls init();
}
#Override
protected void init() {
super.init();
if (something)
a = getStringYadaYada();
}
}
Regarding the above,
String a = null;
null init could be avoided since anyway it's the default.
However, if you were to need another default value,
then, because of the uncontrolled initialization order,
I would fix as follow:
class MyClass extends FooClass
{
String a;
{
if( a==null ) a="my custom default value";
}
...

Use of Initializers vs Constructors in Java

So I've been brushing up on my Java skills as of late and have found a few bits of functionality that I didn't know about previously. Static and Instance Initializers are two such techniques.
My question is when would one use an initializer instead of including the code in a constructor? I've thought of a couple obvious possibilities:
static/instance initializers can be used to set the value of "final" static/instance variables whereas a constructor cannot
static initializers can be used to set the value of any static variables in a class, which should be more efficient than having an "if (someStaticVar == null) // do stuff" block of code at the start of each constructor
Both of these cases assume that the code required to set these variables is more complex than simply "var = value", as otherwise there wouldn't seem to be any reason to use an initializer instead of simply setting the value when declaring the variable.
However, while these aren't trivial gains (especially the ability to set a final variable), it does seem that there are a rather limited number of situations in which an initializer should be used.
One can certainly use an initializer for a lot of what is done in a constructor, but I don't really see the reason to do so. Even if all constructors for a class share a large amount of code, the use of a private initialize() function seems to make more sense to me than using an initializer because it doesn't lock you into having that code run when writing a new constructor.
Am I missing something? Are there a number of other situations in which an initializer should be used? Or is it really just a rather limited tool to be used in very specific situations?
Static initializers are useful as cletus mentioned and I use them in the same manner. If you have a static variable that is to be initialized when the class is loaded, then a static initializer is the way to go, especially as it allows you to do a complex initialization and still have the static variable be final. This is a big win.
I find "if (someStaticVar == null) // do stuff" to be messy and error prone. If it is initialized statically and declared final, then you avoid the possibility of it being null.
However, I'm confused when you say:
static/instance initializers can be used to set the value of "final"
static/instance variables whereas a constructor cannot
I assume you are saying both:
static initializers can be used to set the value of "final" static variables whereas a constructor cannot
instance initializers can be used to set the value of "final" instance variables whereas a constructor cannot
and you are correct on the first point, wrong on the second. You can, for example, do this:
class MyClass {
private final int counter;
public MyClass(final int counter) {
this.counter = counter;
}
}
Also, when a lot of code is shared between constructors, one of the best ways to handle this is to chain constructors, providing the default values. This makes is pretty clear what is being done:
class MyClass {
private final int counter;
public MyClass() {
this(0);
}
public MyClass(final int counter) {
this.counter = counter;
}
}
Anonymous inner classes can't have a constructor (as they're anonymous), so they're a pretty natural fit for instance initializers.
I most often use static initializer blocks for setting up final static data, especially collections. For example:
public class Deck {
private final static List<String> SUITS;
static {
List<String> list = new ArrayList<String>();
list.add("Clubs");
list.add("Spades");
list.add("Hearts");
list.add("Diamonds");
SUITS = Collections.unmodifiableList(list);
}
...
}
Now this example can be done with a single line of code:
private final static List<String> SUITS =
Collections.unmodifiableList(
Arrays.asList("Clubs", "Spades", "Hearts", "Diamonds")
);
but the static version can be far neater, particularly when the items are non-trivial to initialize.
A naive implementation may also not create an unmodifiable list, which is a potential mistake. The above creates an immutable data structure that you can happily return from public methods and so on.
Just to add to some already excellent points here. The static initializer is thread safe. It is executed when the class is loaded, and thus makes for simpler static data initialization than using a constructor, in which you would need a synchronized block to check if the static data is initialized and then actually initialize it.
public class MyClass {
static private Properties propTable;
static
{
try
{
propTable.load(new FileInputStream("/data/user.prop"));
}
catch (Exception e)
{
propTable.put("user", System.getProperty("user"));
propTable.put("password", System.getProperty("password"));
}
}
versus
public class MyClass
{
public MyClass()
{
synchronized (MyClass.class)
{
if (propTable == null)
{
try
{
propTable.load(new FileInputStream("/data/user.prop"));
}
catch (Exception e)
{
propTable.put("user", System.getProperty("user"));
propTable.put("password", System.getProperty("password"));
}
}
}
}
Don't forget, you now have to synchronize at the class, not instance level. This incurs a cost for every instance constructed instead of a one time cost when the class is loaded. Plus, it's ugly ;-)
I read a whole article looking for an answer to the init order of initializers vs. their constructors. I didn't find it, so I wrote some code to check my understanding. I thought I would add this little demonstration as a comment. To test your understanding, see if you can predict the answer before reading it at the bottom.
/**
* Demonstrate order of initialization in Java.
* #author Daniel S. Wilkerson
*/
public class CtorOrder {
public static void main(String[] args) {
B a = new B();
}
}
class A {
A() {
System.out.println("A ctor");
}
}
class B extends A {
int x = initX();
int initX() {
System.out.println("B initX");
return 1;
}
B() {
super();
System.out.println("B ctor");
}
}
Output:
java CtorOrder
A ctor
B initX
B ctor
A static initializer is the equivalent of a constructor in the static context. You will certainly see that more often than an instance initializer. Sometimes you need to run code to set up the static environment.
In general, an instance initalizer is best for anonymous inner classes. Take a look at JMock's cookbook to see an innovative way to use it to make code more readable.
Sometimes, if you have some logic which is complicated to chain across constructors (say you are subclassing and you can't call this() because you need to call super()), you could avoid duplication by doing the common stuff in the instance initalizer. Instance initalizers are so rare, though, that they are a surprising syntax to many, so I avoid them and would rather make my class concrete and not anonymous if I need the constructor behavior.
JMock is an exception, because that is how the framework is intended to be used.
There is one important aspect that you have to consider in your choice:
Initializer blocks are members of the class/object, while constructors are not.
This is important when considering extension/subclassing:
Initializers are inherited by subclasses. (Though, can be shadowed)
This means it is basically guaranteed that subclasses are initialized as intended by the parent class.
Constructors are not inherited, though. (They only call super() [i.e. no parameters] implicitly or you have to make a specific super(...) call manually.)
This means it is possible that a implicit or exclicit super(...) call might not initialize the subclass as intended by the parent class.
Consider this example of an initializer block:
class ParentWithInitializer {
protected String aFieldToInitialize;
{
aFieldToInitialize = "init";
System.out.println("initializing in initializer block of: "
+ this.getClass().getSimpleName());
}
}
class ChildOfParentWithInitializer extends ParentWithInitializer{
public static void main(String... args){
System.out.println(new ChildOfParentWithInitializer().aFieldToInitialize);
}
}
output:
initializing in initializer block of: ChildOfParentWithInitializer
init
-> No matter what constructors the subclass implements, the field will be initialized.
Now consider this example with constructors:
class ParentWithConstructor {
protected String aFieldToInitialize;
// different constructors initialize the value differently:
ParentWithConstructor(){
//init a null object
aFieldToInitialize = null;
System.out.println("Constructor of "
+ this.getClass().getSimpleName() + " inits to null");
}
ParentWithConstructor(String... params) {
//init all fields to intended values
aFieldToInitialize = "intended init Value";
System.out.println("initializing in parameterized constructor of:"
+ this.getClass().getSimpleName());
}
}
class ChildOfParentWithConstructor extends ParentWithConstructor{
public static void main (String... args){
System.out.println(new ChildOfParentWithConstructor().aFieldToInitialize);
}
}
output:
Constructor of ChildOfParentWithConstructor inits to null
null
-> This will initialize the field to null by default, even though it might not be the result you wanted.
I would also like to add one point along with all the above fabulous answers . When we load a driver in JDBC using Class.forName("") the the Class loading happens and the static initializer of the Driver class gets fired and the code inside it registers Driver to Driver Manager. This is one of the significant use of static code block.
As you mentioned, it's not useful in a lot of cases and as with any less-used syntax, you probably want to avoid it just to stop the next person looking at your code from spending the 30 seconds to pull it out of the vaults.
On the other hand, it is the only way to do a few things (I think you pretty much covered those).
Static variables themselves should be somewhat avoided anyway--not always, but if you use a lot of them, or you use a lot in one class, you might find different approaches, your future self will thank you.
Note that one big issue with static initializers that perform some side effects, is that they cannot be mocked in unit tests.
I've seen libraries do that, and it's a big pain.
So it's best to keep those static initializers pure only.

Categories

Resources