How does java support instance variables of java enum constants? - java

I know that in Java an enum constant is implicitly static final variable. But the enum class can have an instance variable say size. So each enum constant will have a copy of 'size'.
What is the equivalent Java code for this? I mean it "seems" the static enum constant is using a non-static instance variable which is not possible normally?
enum Members{
A(1),B(2),C(3); // I have 3 enum constants here
private int size;
Members (int size) {
//System.out.println("Initializing var with size = "+size);
}
}
Equivalent code I know so far:
public final class Member extends Enums<Members> {
public static final Members A;
// ...
// What happened to size? How do A,B,C get a copy of size?
}
Edit : To restate my question-
I am interested in behind the scene implementation by compiler. I already know how to use enums. I am looking for what the compiler does? (so for example, if I simply write A, the compiler translates it to "public static final Member A". I want to know how compiler gives a copy of size to each A,B,C.

I mean it "seems" the static enum constant is using a non-static instance variable which is not possible normally?
It is absolutely possible: each static variable in the enum is an object in its own right, complete with its instance variables. The instance is static in the enum, but it does not make the context of the instance itself a static context.
public final class Member extends java.lang.Enums<Members> {
public static final Members A = new Member(1) {
public String toString() { return "A:"+size; }
};
public static final Members B = new Member(2) {
public String toString() { return "B:"+size; }
};
public static final Members C = new Member(3) {
public String toString() { return "C:"+size; }
};
private final int size;
protected Member(int size) { this.size = size; }
}

I mean it "seems" the static enum constant is using a non-static instance variable which is not possible normally?
What I meant by "normally" was that in non-enum classes a static variable can't access non static variables
It's still true: a static variable can't access non-static variables.
In your example code, you don't do this:
there is no static variable accessing non-static variables.
The constructor Members(int size) is not in a static context (a constructor never is).
A, B and C are all instances of the enum type Members,
and when these instances are created,
the constructor is called with the size parameter.
Once constructed, these objects will be treated as static constant values.
Perhaps another example can help:
class Person {
private final String name;
Person(String name) {
this.name = name;
}
}
class EmployeeDatabase {
private static final Person CEO = new Person("Jack");
}
Here EmployeeDatabase.CEO is a static constant object with a non-static field name.
This is just like Members.A, a static constant object with a non-static field size.
I want to know how compiler gives a copy of size to each A,B,C.
Exactly the same way as it passes constructor parameters to any object.
You can read all about enums in the docs.

Related

If enums are implicitly static, why are they able to make use of the "this" keyword internally?

Please forgive the beginner-level question, but I'm confused by the implicit static status of enums.
On one hand, you can't declare them within methods because they are implicitly static, and you can reference them from a static context like any other static class.. but on the other, internally, they refer to themselves as "this" as though they were an instance.
Code sample:
public class EnumTest {
enum Seasons{
SUMMER,
FALL,
WINTER,
SPRING;
public String toString()
{
switch(this)
{
case SUMMER:
return "Hot Summer";
case FALL:
return "Colorful Fall";
case WINTER:
return "Crisp Winter";
case SPRING:
return "Allergy Season";
default
return "wth?";
}
}
}
public static void main(String[] args)
{
System.out.println(EnumTest.Seasons.SUMMER.toString());
}
}
Note how within toString() in the enum definition, there is a switch on "this".
Within the static method main, the Enum is accessed in typical static class manner.
I know that enums are a special type of class, but I'm still trying to understand the reasons for some of their unconventional quirks.
Is there some sort of Factory-pattern type of auto-construction going on when an enum constant is referenced? At exactly what point does it transition from being a static class to an instance?
Thanks!
The constants defined in the enum class are the only things that are implicitly static. It's close to (but not quite equivalent to):
public static final Seasons SUMMER = new Seasons();
public static final Seasons FALL = new Seasons();
public static final Seasons WINTER = new Seasons();
public static final Seasons SPRING = new Seasons();
This allows you to write code such as Seasons.SUMMER.
The rest of the class body is like a normal class body - public String toString() is not implicitly static, therefore it has access to this.
Think of the enum constants as statically declared objects like here:
class A {
public final static A FOO = new A ("FOO");
public final static A BAR = new A ("BAR");
private final String text;
private A(String text) {
this.text = text;
}
public String toString() {
return this.text;
}
}
Although statically declared, the objects for each of the constants can provide non-static methods you can call.

why compiler says a public static field in interface is "final" although it is not

Please see the below code --
public interface TestInterface {
public static String NON_CONST_B = "" ;
}
public class Implemented implements TestInterface {
public static String NON_CONST_C = "" ;
}
public class AutoFinal {
public static String NON_CONST_A = "" ;
public static void main(String args[]) {
TestInterface.NON_CONST_B = "hello-b" ;
Implemented.NON_CONST_C = "hello-c";
AutoFinal.NON_CONST_A = "hello-a" ;
Implemented obj = new Implemented();
}
}
However, the compiler complains that TestInterface.NON_CONST_B is final --
AutoFinal.java:6: error: cannot assign a value to final variable NON_CONST_B
TestInterface.NON_CONST_B = "hello-b" ;
^
1 error
why ?
Regarding:
public interface TestInterface {
public static String NON_CONST_B = "" ;
}
public class AutoFinal {
public static void main(String args[]) {
TestInterface.NON_CONST_B = "hello-b" ;
// ....
}
}
However, the compiler complains that TestInterface.NON_CONST_B is final --
But it in fact is final whether you explicitly declare it to be or not since it is declared in an interface. You can't have non-final variables (non-constants) in an interface. It's also public and static whether or not it has been explicitly declared as such.
Per the JLS 9.3 Interface Field (Constant) Declarations:
Every field declaration in the body of an interface is implicitly public, static, and final. It is permitted to redundantly specify any or all of these modifiers for such fields.
In java, all variables was declared in Interfacel are public static final default
Variables declared in interface are always public static final by default in java. Interface variables are static because Java interfaces cannot be instantiated in their own right; the value of the variable must be assigned in a static context in which no instance exists. The final modifier ensures the value assigned to the interface variable is a true constant that cannot be re-assigned by program code.
As all answers saying that by default all the variables declared in Interface are static final variables.
FYI, you can not declare a static method in interface. You can find the reason in this SO question.
however, you can declare Inner Class in an interface that can contain static methods and non static and non final variables.

Private members in Enum Java [duplicate]

This question already has answers here:
Why can outer Java classes access inner class private members?
(10 answers)
Closed 9 years ago.
public class Test {
public static enum MyEnum {
valueA(1),valueb(2),valuec(3),valued(4);
private int i;
private Object o;
private MyEnum(int number) {
i = number;
}
public void set(Object o) {
this.o = o;
}
public Object get() {
return o;
}
}
public static void main(String[] args) {
System.out.println(MyEnum.valueA.i); // private
}
}
output: 1
Why 1 is shown if it a private member in enum?
Outer classes have full access to the member variables of their inner classes, therefore
i is visible in the Test class.
In contrast, if MyEnum was external to the Test class, the compiler would complain about the visibility of i,
It's (i) a member field being referenced within the same class (MyEnum); no access modifier prevents that - the private access modifier defined on i will prevent it's visibility outside this class.
Suggested Reading
private access from a containing type to a nested type is permitted, see Why are private fields on an enum type visible to the containing class?
vlaueA is considered a static variable so you can call it within MyEnum since i in the
same enum whice play the same as a class so MyEnum can access valueA which can access i
Outer class will have the access to inner class member even if it is private because you have defined main method inside the outer class.

Static variables in an Abstract Class java

If I have an abstract class that has variables of the form
protected static final int blah;
protected static final int blah2;
And i have two classes that extend this abstract class, and set these variables to "static final int" values from a constants file in their constructors, will they clobber eachother's values? If I want to do such a thing, what would you recommend I do?
So, for example, if i have
impl1 class:
public impl1 extends absClass{
public impl1(){
this.blah = CONSTANTS.impl1_blah;
this.blah2 = CONSTANTS.impl1_blah2;
}
}
impl2 class:
public impl2 extends absClass{
public impl2(){
this.blah = CONSTANTS.impl2_blah;
this.blah2 = CONSTANTS.impl2_blah2;
}
}
Is this allowed? If not, what should I do?
this.blah = CONSTANTS.impl2_blah;
this.blah2 = CONSTANTS.impl2_blah;
this allowed?
This isn't allowed, since your blah variables are declared as final. You must initialize them during class initialization, either in their declaration or in a static initializer block.
Furthermore, these variables are static, and so accessing them using this won't work: the variables belong to the class and not an instance.
If not, what should I do?
Use non-final variables in the superclass, or use specific constants in the subclasses.
if classes extending that abstract class are supposed to give their own values for those variables then you should consider a couple of protected abstract methods instead.
static variables can't be overridden. Those will be associated with the classes where you have defined them.
static final variables must be initialized when the class that declares them is initialized. This is before any instances of the class (or any subclass) are created. Your code won't compile without some sort of initialization for blah and blah2—either an initialization expression:
protected static final int blah = 42;
protected static final int blah2 = 1;
or in a static initializer block:
protected static final int blah;
protected static final int blah2;
static {
blah = 42;
blah2 = 1;
}
In either case, subclasses have no say in what blah and blah2 get assigned.
It seems from your example code that you want constants that can vary on a per-instance basis. It doesn't make sense for them to be static. You can do something like this:
public AbsClass {
protected final int blah;
protected final int blah2;
protected AbsClass(int blah, int blah2) {
this.blah = blah;
this.blah2 = blah2;
}
. . .
}
public class Impl1 extends AbsClass {
public Impl1() {
super(CONSTANTS.impl1_blah, CONSTANTS.impl1_blah2);
}
}
public class Impl2 extends AbsClass {
public Impl1() {
super(CONSTANTS.impl2_blah, CONSTANTS.impl2_blah2);
}
}
Polymorphism in Java don't work with attributes. Use some protected abstract getMethods() instead.
First of all this is final+static which means nothing to do with OOP, If you make them not static then It makes sense to talk about OOP on it. If you do not do them as private and access them using getters/setters then you are breaking encapsulation.
And you are making it final, means it can be initialized only once. You will get exception when you try to change the value of final attr.

Let a constructor access a static variable

Right now I have two .java files.
The Main.java:
public class Main {
static int integer = 15;
NeedInteger need = new NeedInteger();
}
and the NeedInteger.java
public class NeedInteger {
System.out.println(integer);
}
This is of course very simplified, but is there any way I can accomplish this?
As many have answered, the correct method is to pass the value in to the constructor of the new class.
If for some reason you cannot do that, then you can use a public static accessor method in Main to access the value (this would be slightly better than just making the field public).
E.g.
public class Main
{
private static int integer = 15;
public static int getInteger()
{
return integer;
}
}
public class NeedInteger
{
public NeedInteger()
{
int integer = Main.getInteger();
}
}
Add a constructor to NeedInteger (and optionally a member if you need to also store it):
public class NeedInteger {
private int integer;
public NeedInteger(int integer) {
this.integer = integer;
System.out.println(integer);
}
}
Then pass your value when you create the instance:
public class Main {
static int integer = 15;
NeedInteger need = new NeedInteger(integer);
}
You would have to do some bad juju moves (like using a global variable) or pass it to the constructor.
NOTE: your
public class NeedInteger {
System.out.println(integer);
}
has no method in it. I would recommend all this to be rewritten as such:
public Class NeedInteger {
NeedInteger(int integer) {
System.out.println(integer);
}
}
If you really want the work to be done on construction.
EDIT: From your comment above.
Instead, have the class structured so:
public Class NeedStringArray {
NeedStringArray(String[][][] stringArr) {
//work with String array here
}
}
That has no real additional overhead, since the actual array will not be passed, but only a reference to it. You WILL likely want to set the array to be final or something, to avoid it being edited in the NeedStringArray constructors.
integer is private, so it cannot be accessed by NeedInteger. you'll have to make it public or use a setter or getter and you'll need to use Main.integer since it's static.
Generally, you set in the Constructor.
Pass in the variable to the class constructor.
An array reference would be just that--a reference.
Or you could pass in the class itself, or use a static (meh).
Per your comment I'd say you can either host your array in a singleton
or as others suggested have the second class accept the reference to the array in the constructor. You can then use Dependency Injection framework (e.g. Guice) to get wire them up

Categories