I want to know how many instances of a static member class can be created by the enclosing class. I assume one only, but then the following extract from Bloch doesn't make sense to me.
Quoting Joshua Bloch's Effective Java - Item 22*: Favor static member classes over nonstatic.
A common use of private static member classes is to represent components of the object represented by their enclosing class. For example, consider a Map instance, which associates keys with values. Many Map implementations have an internal Entry object for each key-value pair in the map. While each entry is associated with a map, the methods on an entry (getKey, getValue and setValue) do not need access to the map. Therefore, it would be wasteful to use a nonstatic member class to represent entries: a private static member class is best. If you accidentally omit the static modifier in the entry declaration, the map will still work, but each entry will contain a superfluous reference to the map, which wastes space and time.
He states that the map creates an Entry object for each key-value pair in the map, i.e. multiple instances of the static member class.
So my assumption is wrong! That means my understanding of static member classes is wrong. Everyone knows how a static member variable behaves, the classic static final string for instance - there is only one instance of the object.
Does this mean then that a static member class is not actually instantiated when the enclosing object is instantiated?
Well in that case, what's the point of Map using a static member class for Entry? Why not just use an interface on the API? Every other Collections class could then just provide it's own implementation.
[*] Just realised that it's item 18 in the PDF version of the book I have
This is a common misinterpretation of the static keyword.
When you use static with a variable it means there will be only one of these for all objects of this class or something like that.
static Object thereWillBeOnlyOne = new Object();
However, in the context of inner classes it means something completely different. A static inner class has no connection with an object of the enclosing class while a non-static inner class does.
A static inner class:
public class TrieMap<K extends CharSequence, V> extends AbstractMap<K, V> implements Map<K, V> {
private static class Entry<K extends CharSequence, V> implements Map.Entry<K, V> {
The Map.Entry class used by my TrieMap class does not need to refer to the object that created it so it can be made static to save the unnecessary reference.
A non-static inner class:
public final class StringWalker implements Iterable<Character> {
// The iteree
private final String s;
// Where to get the first character from.
private final int start;
// What to add to i (usually +/- 1).
private final int step;
// What should i be when we stop.
private final int stop;
// The Character iterator.
private final class CharacterIterator implements Iterator<Character> {
// Where I am.
private int i;
// The next character.
private Character next = null;
CharacterIterator() {
// Start at the start.
i = start;
}
public boolean hasNext() {
if (next == null) {
if (step > 0 ? i < stop : i > stop) {
next = s.charAt(i);
i += step;
}
}
return next != null;
}
The CharacterIterator inside a StringWalker object refers to the string to be iterated as s which only exists once in the StringWalker object. I can therefore create many iterators of a StringWalker and they all walk the same string.
Why this weirdness?
This seemingly illogical duality derives from the use of the static keyword in C.
In C you can (or at least used to be able to) do:
void doSomething () {
static int x = 1;
if ( x < 3 ) {
} else {
}
x += 1;
}
and each time you called the function, x would be as you left it last time around - incremented in this case.
The concept was that the static keyword indicated that the variable was scopefully enclosed by its enclosing block but semantically enclosed by its parent block. I.e. the above code was roughly equivalent to:
int x = 1;
void doSomething () {
if ( x < 3 ) {
} else {
}
x += 1;
}
but x was only allowed to be referenced inside the function.
Take that concept forward into Java and things now make a little more sense. A static inner class behaves exactly like it was declared outside the class while a non-static inner bonds much more tightly to its enclosing instance - in fact it can refer to the instance directly.
Also:
class Thing {
static Object thereWillBeOnlyOne = new Object();
behaves much like
Object thereWillBeOnlyOne = new Object();
class Thing {
if it were legal.
Here endeth the lesson.
I think the Java team messed up the naming on this one. A static inner class (strictly speaking their correct name is "static nested class") is in no way different from an ordinary class except it has a fancy name (Something.MyClass instead of MyClass) and can be made private (i.e. not instantiable from other classes).
In case of Map, it was solely chosen because the name Map.Entry makes it clear that Entry relates to Map. As you suggest, it would have been perfectly reasonable to just use an ordinary class for this. The only difference is you don't get to write Map.Entry.
I think what they should have done is to use the syntax for "non-static" inner classes (i.e. just class in an enclosing class) for static nested classes, and instead invent a new keyword to create "non-static" inner classes, because it's these that behave different from normal classes. Maybe something like attached class. AFAIK the keyword static was chosen in order to avoid having too many reserved keywords, but I think it just encouraged confusion.
Yes, you can have many instances of the nested class, no matter that the nested class is static.
When the nested class is static you can create instances of it without having an instance of the enclosing class, this is one of the benefits, and basically the main difference between static and non-static nested classes.
Does this mean then that a static member class is not actually instantiated when the enclosing object is instantiated?
It's instantiated when it's constructor is called. Not any different from non-static classes. The nested class itself is loaded by the JVM, when the code first accesses it. Again this is not any different when compared to other classes, I think (not 100% sure of this though, but you can test it yourself). So I think you're kind of mixing the terms "loading the class by the JVM" and "instantiating the class".
Well in that case, what's the point of Map using a static member class for Entry? Why not just use an interface on the API?
As said, it's easier to create instances of static nested classes. You don't need an enclosing instance which is sometimes (maybe most of the times) exactly what you want.
See also:
(1) Nested Classes
(2) How can the JVM decide if a class is nested into another class?
(3) Loading of a nested class by the JVM
You can search for other references along these lines.
The reference (2) seems advanced and kind of peripheral to your question.
what's the point of Map using a static member class for Entry?
That's because, it makes the package structure logically correct.
Why not just use an interface on the API?
Now, this is a design discussion nobody would like to be dragged into.
Related
I have several Java Objects using the following classes (all part of the same super class).
Object Class one:
Class one extends Superobject {
int no;
int i;
String s;
}
Object Class two:
Class two extends Superobject {
int no;
int i;
String s;
}
I want to create many of these Objects by reading a text file and calling the constructor for Object one and Object two after every word.
I have tried storing all the Objects in a list in the super class, but somehow, I can't get the list to be non-static.
Class Superobject {
int no;
int i;
String s;
List<Superobject> li; // of course, when called with the
//method below: static List<Superobject> li
}
When I try to add Objects to the list, eclipse yells that li has to be made static.
public static void somemethod(Object one[] ones) {
for (one o : ones) {
li.add(o);
}
}
Is there a way to make it non-static or is there a better way to store the Objects?
It seems you're trying to access your non-static member l from the static method somemethod. You need to either change somemethod to be non-static as well or make l static.
Non static methods are associated with instances of the class, while static methods are associated with class itself. You are trying to access a non static member from static method.
So, the compiler cannot associate the non-static member with any object.
What you can do is either make both of them static, which you should as you trying to save several instances of Superobject in the list. If you dont make it static, every instance of Superobject will have its own list.
OR you can create a separate class and call it SuperobjectCollection and provide methods such as Add, Remove, Get etc to access the underlying List.
Consider the following pseudocode
class SuperobjectCollection {
private List<Superobject> list;
public AddObj(Superobject obj) {
list.add(obj);
}
}
You can add any logic as you see during adding, retrieving, or removing objects.
If you want to keep the list in Superobject class, you have to make it static and access it using static method. If you don't do that (like the code that you have presented), you would have following situation:
Class Superobject {
int no;
int i;
String s;
List<Superobject> li;
}
If you create two instances like:
Superobject a = new one();
Superobject b = new two();
Both a and b would contain separate li. If your somemethod is non-static you can then access this list in that method like
li.add();
or like
this.li.add();
Here this is either object a if you called the method like a.somemethod() or b if you called it like b.somemethod()
Static methods are associate with class not instance, and as such you access it like so:
Superobject.someobject();
not like
a.someobject();
It would be a terrible design decision, but assuming you can change the signature of the static method, this would help.
public static void somemethod(Object one[] ones, List<Superobject> li) {
for (one o : ones) {
li.add(o);
}
}
However, if you could change the signature of this method, you'd probably want to make it non-static anyway.
On the other hand, if all you want to achieve is to add the elements to the list. Why doesn't the following work for you?
li.addAll(Arrays.asList(ones));
From the question What's the meaning of System.out.println in Java? I found that out in System.out.println is a static field.
From C/C++ background, it's easy to understand static method, as it's the same as function in C. However, I'm not sure the use case of static field.
Is it just a way to use multiple methods without instantiating an object just as we use System.out.println without instantiating anything? Or is there any use cases for static field?
static variables/methods not only have the property of being used without instantiation, but they are also consistent across multiple instances.
For example,
public class A {
public int a = 1;
public static int b = 2;
}
Now, when I do A a1 = new A() and A a2 = new A(), A.a gets 2x the memory and is stored in the object instance, while A.b gets the memory only once and is stored outside the instance.
A prime example of this would be
a1.b = 3;
System.out.println(a2.b);
This will print 3, instead of 2, because a1 changed the value of b for the whole class, and therefore, all the instances.
A static field is a property of the class, which gets allocated on the heap and is independent of a particular object instance.
You could use a static variable to count the number of instances of a class for example.
out is an object of PrintStream.
System is a class in java.lang package
println is an instance method(not a static method) of PrintStream class
To access the field out in System without instantiating System, the field is declared static.
The System class has only one instance of the OutputStream that writes to standard output (called out) so it's a static variable. We don't need more than one instance because there's only one standard output.
A static field, is a field that is set-up and can be get without instantiating a class (using new ClassName()).
For example:
public class MyClass {
public static int number = 1;
}
With the code above, you can get the "number" field using MyClass.number.
public class MyClass {
public int number = 1;
}
Now, you need to instantiate MyClass via constructor. Since there is no constructor declared, you just use new MyClass():
MyClass cl = new MyClass();
cl.number; // <-- The number
Static fields are also known as 'class' fields (as opposed to 'instance' fields).
That means that they are accessible without you needing to instantiate the class first.
So, you can call class methods (like Math.abs() on the Math class) without having to instantiate a Math class. You can also access properties like Math.PI.
Also, changing a class property means that it affects all instances of that class, meaning that every object that was instantiated will see this value change, allowing you to affect them with a single property change.
In addition to the .out var in System, it can either be used as a shared variable that all instances of a class can update
private static int meatballsConsumed;
Or as a general-purpose shared variable
public static String thisSeemsDangerous;
Or as a constant
public static final String FLD_OF_DREAMS = "COSTNER,KEVIN";
The following code works & runs perfectly.
public class Complex {
private int real, imag;
Complex(int r, int i) {
real = r;
imag = i;
}
public static Complex add(Complex c1, Complex c2) {
return new Complex(c1.real + c2.real, c1.imag + c2.imag);
}
public String toString() {
return real + "+i" + imag;
}
public static void main(String[] args) {
Integer.parseInt("5");
System.out.println(Complex.add(new Complex(2, 3), new Complex(3, 4)));
}
}
Now according to Object oriented design model, private instance members shouldn't be accessed through a object reference (which has been done here by c1.real ).
So, in that sense,there should be compiler error. But it doesn't object.
Now according to my understanding it's allowed because
c1.real code is written in the body of the private class Complex class itself.
Developer of Complex class should have access to all instance members [be it private,protected whatever] when accessing through an object reference, since Developer knows very well what he's doing unlike any third party. That's why object oriented model model isn't followed here.
Can anyone suggest a better explanation about why c1.real code is allowed here?
private means it cannot be access from another outer class. It is class based, not object based security. Note: classes in the same outer class can access private member of any other class in that file.
http://vanillajava.blogspot.co.uk/2012/02/outer-class-local-access.html
The short answer is that because that's the way Java defined the private access modifier.
The longer answer is that they probably assumed that strict encapsulation only makes sense above source file level, so even an inner class can access private members of its outer class (and vice versa): it simply makes no sense to hide members within the same source file. If you've got access to the source file of a class, you can easily modify any access modifiers anyway.
(Although the inner-outer class thing is achieved via synthetic accessors, but they're almost completely transparent.)
Recently, I've noticed, it is possible to have:
class Test {
public enum Season { WINTER, SPRING, SUMMER, FALL }
Season field = Season.WINTER.SPRING; // why is WINTER.SPRING possible?
}
Is there a reason for this?
When you access a static member of an object (including enums) in Java, the compiler effectively replaces the object with its static type. More concretely,
class ExampleClass {
static int staticField;
static void staticMethod() {
ExampleClass example = new ExampleClass();
example.staticField; // Equivalent to ExampleClass.staticField;
example.staticMethod(); // Equivalent to ExampleClass.staticMethod();
}
}
Similarly, since enums are effectively "static", Season.WINTER.SPRING is equivalent to Season.SPRING; Season.WINTER is replaced with its enum type Season.
As a side note, accessing static members from instances is discouraged because it can be quite confusing. For example, if you saw a piece of code that contained someThread.sleep(), you might be tricked into believing that someThread is put to sleep. However, since sleep() is static, that code is actually invoking Thread.sleep() which sleeps the current thread.
It's because enums are kind of special classes. If we take a look at the fields inside of Season.WINTER, for example:
for (Field field : Test.Season.WINTER.getClass().getFields())
System.out.println(field);
We'll see as output:
public static final TestEnum$Test$Season TestEnum$Test$Season.WINTER
public static final TestEnum$Test$Season TestEnum$Test$Season.SPRING
public static final TestEnum$Test$Season TestEnum$Test$Season.SUMMER
public static final TestEnum$Test$Season TestEnum$Test$Season.FALL
So each enum value is actually also a static constant of the enum class, Season, and so have access to Season's static fields, or the other enum values (including itself).
However, it's probably better to just access the enum values directly from the enum, like Season.SPRING, since it's simpler and less likely to confuse someone reading your code.
This question already has answers here:
Are static methods inherited in Java?
(15 answers)
Closed 4 years ago.
I've read Statics in Java are not inherited. I've a small program below which compiles and produces 2 2 as output when run. From the program it looks like k (a static variable) is being inherited !! What am I doing wrong?
class Super
{
int i =1;
static int k = 2;
public static void print()
{
System.out.println(k);
}
}
class Sub extends Super
{
public void show()
{
// I was expecting compile error here. But it works !!
System.out.println(" k : " + k);
}
public static void main(String []args)
{
Sub m =new Sub();
m.show();
print();
}
}
The scope in which names are looked up in includes the super class.
The name print is not found in Sub so is resolved in the Super.
When the compiler generates bytecode, the call will be made to Super.print, rather than a call on a method in Sub.
Similarly the k is visible in the sub-class without qualifying it.
There is no polymorphism here, only inheritance of the contents of a name space. Static methods and all fields do not have polymorphic dispatch in Java, so can only be hidden by sub-classes, not overridden. The post you link to in your comments is using 'inheritance' in a somewhat unconventional way, mixing it up with polymorphism. You can have polymorphism without inheritance and inheritance without polymorphism.
Sub extends Super so it can see all the public/protected/package (static) members of Super.
I guess this is what you described as "Statics in Java are not inherited"
change
static int k = 2;
to
private static int k = 2;
and your Sub program won't see 'k' anymore and won't compile;
also try to create a new 'static int k=3;' in Sub, and see what happens.
It's pretty much the same as accessing Math.PI or any other global constant (which also have public and final modifiers).
In your case you have default (package) scope.
It's independed of inheritance only the scope restricts whether it is visible.
I think you might be wrong about static variables not being inherited. I suppose some properties of it are not inherited. For instance a static var normally means that all instances of the class have access to the same place in memory.
When you inherit, the derived class does not refer to the same memory as the base class.
Static member can be static data member and static method which can be accessed without using the object. It is used by nested class