I know that an enum
enum Year
{
First, Second, Third, Fourth;
}
gets converted into
final class Year extends Enum<Year>
{
public static final Year First = new Year();
public static final Year Second = new Year();
public static final Year Third = new Year();
public static final Year Fourth = new Year();
}
When I tried to instantiate enum (not class) I got compile time error as:
error: enum types may not be instantiated
Year y = new Year();
As per my knowledge a private constructor makes a class non instantiable. And I thought that compiler is providing a private constructor. But again I got confused when saw we can define a constructor for enum with default modifier and still cannot create an object of type enum.
enum Year
{
First, Second, Third, Fourth;
Year()
{
}
}
class Example
{
public static void main(String[] args)
{
Year y = new Year();
}
}
My doubt is, if it is not about constructors then what makes enum in Java non instantiable?
It is specified in the Java Language Specification:
8.9. Enum Types
...
An enum type has no instances other than those defined by its enum constants. It is a compile-time error to attempt to explicitly instantiate an enum type (§15.9.1).
Hence the compiler ensures that this requirement is met. Since the compiler "knows" that the type is an enum, it can distinguish between enum Year and final class Year.
Also, no access modifier is allowed for an enum constructor:
8.9.2. Enum Body Declarations
...
It is a compile-time error if a constructor declaration in an enum declaration is public or protected.
...
In an enum declaration, a constructor declaration with no access modifiers is private.
So, in practice, an enum constructor looks like package-scoped (no access modifier), but it really is private.
Finally, the same section also states
In an enum declaration with no constructor declarations, a default constructor is implicitly declared. The default constructor is private, has no formal parameters, and has no throws clause.
This makes the enum non-instantiable even if no constructor is explicitly declared.
An enum in java has a default constructor when it's is not defined and it's private.
Default access modifier has different meanings in different scopes. For example inside a class default access modifier for methods and fields is package private.
Where as in an interface default access modifier means public. In fact there can be no other modifier on an interface field so it's implicitly public.
On a top level class it's package private (where only 2 access modifiers are allowed public and default package private)
So the answer to your question is it is so because compiler decides so. Compiler writer had to uphold the language specification contract.
You're right in thinking that it's a normal class after everything. Every object blueprint type in java is a class which can be represented by java.lang.Class. These restrictions for interfaces, enums, abstract classes, anonymous classes, method local classes are validated by compiler only.
If you can somehow escape the compiler and generate your own byte code for enums or other way around if you can modify the byte code of generated enum class so that it's private constructor becomes public may be you would be able to call it's constructor outside the enum's private scope. You can also try experimenting with reflection to do the same. In fact by generating byte code manually JVM languages like Groovy, Jython, JRuby, Clojure are able to provide functionalities that are not in Java itself. They're bypassing java compiler.
Purpose for having constructor in enums is to be able to set fields of constants in one call. All constants inside an enum are instances of the enum class, so they also consist the fields declared in it.
enum Test
{
T1(1), // equivalent to public static final Test T1 = new Test(1);
T2(2); // equivalent to public static final Test T2 = new Test(2);
int id;
Test(int id)
{
this.id = id;
}
}
And finally bellow is the output of decompiled code for above enum by using java -p Test.class
final class Test extends java.lang.Enum<Test>
{
public static final Test T1;
public static final Test T2;
int id;
private static final Test[] $VALUES;
public static Test[] values();
public static Test valueOf(java.lang.String);
private Test(int);
static {};
}
It should give a better understanding of what happens when the class compiles.
Related
I want to define a time interface like that:
public interface TimeInterface<T>
{
static T ZERO;
static T INFINITY;
// some other methods...
}
Is this possible, or how to do that to avoid errors?
Thanks in advance!
From the javadoc directly:
We cannot declare static fields whose types are type parameters
A class's static field is a class-level variable shared by all non-static objects of the class. Hence, static fields of type parameters are not allowed. Consider the following class:
public class MobileDevice<T> {
private static T os;
// ...
}
If static fields of type parameters were allowed, then the following code would be confused:
MobileDevice<Smartphone> phone = new MobileDevice<>();
MobileDevice<Pager> pager = new MobileDevice<>();
MobileDevice<TabletPC> pc = new MobileDevice<>();
Because the static field os is shared by phone, pager, and pc, what is the actual type of os? It cannot be Smartphone, Pager, and TabletPC at the same time. You cannot, therefore, create static fields of type parameters.
The only static thing that can contain type-parameters is the static method, which must define it's own type-parameters. Something like:
static <T> void staticGenericMethod(T param) { .. }
In your case, the type-parameter has a class scope, it's instance-bound and has nothing to do with the static members of the class.
So, you should either remove the static keywords for ZERO and INFINITY or introduce static methods that return ZERO and INFINITY. For example:
public interface TimeInterface<T> {
static <X> X getZero() {
//implementation
}
static <X> X getInfinity() {
}
}
Note that the X type-parameters are valid for the corresponding static method only and are not shared across the class.
The problem, however, with this approach is that there's no way to ensure that the instance type-parameter (T) is the same as the static method's type-parameter (X), which may cause serious problems when used incorrectly.
Also note that static methods are allowed in interfaces in Java8, so if you're using an order Java version, you should convert the TimeInterface to a class.
I used JD to decompile a .jar executable file. I encountered an abstract enum code which does not compile:
private static abstract enum Type {
ANONYMOUS(4) , STANDARD(0);
private final int start;
private Type(int start) {
this.start = start;
}
public int getStart() {
return this.start;
}
public abstract void insertHeader(Sheet paramSheet,
SummaryCodec.Style paramStyle, float paramFloat1,
float paramFloat2);
public abstract String insertCommentSource(String paramString);
public abstract int insertBreakdown(Sheet paramSheet,
SummaryCodec.Style paramStyle, String paramString,
Entry paramEntry, int paramInt);
public abstract void collateComment(List<String> paramList,
String paramString);
}
Compiler errors:
Illegal modifier for the member enum Type; only public, protected, private & static are permitted
The enum constant ANONYMOUS must implement the abstract method collateComment(List, String)
The enum constant STANDARD must implement the abstract method collateComment(List, String)
Where can I find the code for the implementations of the abstract methods for ANONYMOUS, and STANDARD? I can't find it in the same file. Tried looking for it in other files.
JD apparently has a bug decompiling enums with abstract methods; you shouldn't get that class signature (which does correspond to the bytecode but doesn't take into account the magic the Java compiler does with enum).
Each enum instance that overrides a method declared gets its own .class file, just as anonymous classes do. Look for files named like Type$1.class in the same directory as Type.class.
Making an abstract enum does not make sense as you will definitely have instances.
In fact ANONYMOUS and STANDARD are instances of the enum Type which also why the compiler tells you that you have to implement the abstract method insertCommentSource.
I have no idea why the decompiler produced this code but i am very sure that this does not conform to Java language specifications! Also it does not make sense ;)
So I've run across something interesting which is incredibly useful. In an enum you can define an abstract method which each of the enum values is forced to provide an implementation for. For example, the following:
public enum Test {
RAWR ("Burninating the country side") {
#Override
public int doStuff() {
return 0;
}
};
private final String enumStuff;
private Test(String enumStuff) {
this.enumStuff = enumStuff;
}
public abstract int doStuff();
}
I added the private variable so you could see how it works in relation to the standard private constructor.
So this makes me wonder: what is RAWR actually, in relation to the Test class? Normally, this kind of syntax would make me think that I'm defining an anonymous inner class, but that doesn't seem intuitive here, since RAWR is anything but anonymous.
The closest thing I can think of is that the values of an enum are in fact extensions of the enum itself, e.g.,
public class RAWR extends Test {
#Override
public int doStuff() {
return 0;
}
}
So, does anyone know what's really going on with this?
From the JLS
An enum declaration specifies a new enum type, a special kind of class type.
[...]
The optional class body of an enum constant implicitly defines an
anonymous class declaration (§15.9.5) that extends the immediately
enclosing enum type.
The JLS also states
For each enum constant c declared in the body of the declaration of E,
E has an implicitly declared public static final field of type E that
has the same name as c. The field has a variable initializer
consisting of c, and is annotated by the same annotations as c.
The enum type you declare is Test. Every enum constant you declare is an instance of a subclass of Test, if it has a body.
Note that enum types are also implicitly final (you wouldn't be able to subclass them). The Java Language only allows this subclassing behavior for enum constants.
This is a very powerful feature of enums, in that not only is each enum a fully fledged class that can have constructors, setters, getters etc but each individual member of the enum can have its own anonymous implementation of the main enum class.
You actually are defining anonymous inner classes. Execute javap -c <classFile> on the class file of your enum to see how the enum looks when compiled.
You will see that an enum is nothing more than a normal class with public static final variables of the same type as the enum. You will also see that for each variable an anonymous inner class is assigned.
Example:
$ javap-c StatusCode.class
public final class de.haufe.StatusCode extends java.lang.Enum<de.haufe.StatusC ode> {
public static final de.haufe.StatusCode CREATED;
public static final de.haufe.StatusCode BAD_REQUEST;
public static final de.haufe.StatusCode UNAUTHORIZED;
public static final de.haufe.StatusCode NOT_FOUND;
public static final de.haufe.StatusCode PRECONDITION_FAILED;
public static final de.haufe.StatusCode UNSUPPORTED_MEDIA_TYPE;
public static final de.haufe.StatusCode UNPROCESSABLE_ENTITY;
public static final de.haufe.StatusCode LOCKED;
public static final de.haufe.StatusCode INTERNAL_SERVER_ERROR;
public static de.haufe.StatusCode[] values();
}
// more stuff
So this is not the best example because none of the enum value implements a method but you may get an idea what an enum actually is.
If you've ever used enums in generics you will have come across E extends Enum<E> which is the right way of defining the type of an enum. It's a little weird but once you get your head around it you can see that it is saying that an enum actually extends an Enum (note the different case) of itself. So essentially yes, all enums in the group seem to extend the base declaring class but the base declaring class is actually an Enum - sort of.
BTW - You can also make enums implement an interface:
interface Something {
int getValue();
}
enum It implements Something {
One,
Two,
Three;
#Override
public int getValue() {
return ordinal();
}
}
public class A
{
public static int i;
}
public class B extends A
{
public static void main(String[] args)
{
System.out.println("print i=" + B.i); // referred to A.i
}
}
My question here is how B.i is referred to the A.i?
If the static variable i is inherited why java allows to define another variable i in B class also?
A public or protected member of A is visible in all subclasses of A.
If the static variable i is inherited why java allows to define another variable i in B class also?
It's hard to speculate as to why. One possible reason is that this allows one to add members to a base class without breaking any derived classes that already happen to have a member with the same name.
Note that, if you define another i in B, it will shadow A.i, making it difficult to access the latter. I've seen people expecting this to behave polymorphically, but it doesn't (your case is slightly different anyway, since A.i is static).
i here is a static variable.A static variable,in layman terms,means a single copy being accessed by all classes.So,since your class B extends A,B has an access to the static variable of A.
If you define the variable locally,then the local value of the variable hides the parent class value.
there are 2 different things, scope and visibility. you can not redefine a variable in same scope twice (though you can redefine them in nested scopes).
But in case of inheritance, the subclass is out of scope of superclass, but yet has the visibility to that variable because of inheritance. So sub class allows you to define variable i again, though it will hide super class's variable. you wont be able to see its value. (unless used any getter from superclass)
Java allows you to change the specific variable value for the extended class.
This is because, static variables are shared between all objects of the same class.
It is a variable which belongs to the class and not to object(instance).
So, when extending the static variables of the parent class are not actually part of the extended class BUT are accessible (as long as they were not private).
Additionally, this can be used to do things such as:
using different STATIC CONSTANT for extended classes.
A use for this is to identify classes based on a STATIC integer as apposed to utilizing instanceof. This can be further combined with a switch to change behavior based on an objects type.
So, in the most basic example imagine we want to create a variable represent TYPE.
class A
{
public static final int NODE_TYPE = NODE_PERSON;
public static final int NODE_PERSON = 0;
public static final int NODE_CAR = 1;
}
class B extends Class A
{
public static int NODE_TYPE = NODE_CAR;
}
This has been used in many frameworks including Eclipse Abstract Syntax Trees:
http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fjdt%2Fcore%2Fdom%2FASTNode.html
You will see a list of STATIC INTEGERS which represent different Node Types.
I have an abstract class and 2 subclasses. There are 4 constants that relate to all the classes. I was going to place the finals in the abstract class but I understand a final variable is not inherited?
Would I have to define the constant in every class (seems inefficient)? Or just make the constant an instant variable (doesn't sound like a good idea)?
What are ways I can go about this?
The following would be available to all of your sub-classes if defined in the abstract class.
public static final Integer MYCONSTANT = 42;
or
static final Integer MYCONSTANT = 42;
or
protected static final Integer MYCONSTANT = 42;
The second one (package-private) is only available to classes within the same package. The third (protected) would be available to all sub-classes irrespective of their package.
Constants are inherited by childrens. You just have to make sure to have them protected or public so the children can access them.
abstract class A {
protected final static String FOO = "bar";
}
class B extends A {
somemethod() {
System.out.println("foo: " + FOO);
}
}
can be accessed from the class and all its children.
Yes they are. But as they are constant it should be final and static , static modifier make it there will be only one 'copy' and if this will be used only used in subclass only then u can use protected or if from other Classes too the must make it public.