Wanted to share few key points i learned from this chapter.
a) In section 8.1.1.1 abstract Classes it states
Enum types (§8.9) must not be declared abstract; doing so will result in a compile-time error. It is a compile-time error for an enum type E to have an abstract method m as a member unless E has one or more enum constants, and all of E's enum constants have class bodies that provide concrete implementations of m. It is a compile-time error for the class body of an enum constant to declare an abstract method.
For example below program will give an compilation problem if any of the enum constants donot implement the abstract method.
enum enumFirst {
ONE {
public int eval() {
return 1;
}
}
,
TWO {
public int eval() {
return 2;
}
}
,
THREE {
public int eval() {
return 3;
}
};
public abstract int eval();
}
public class EnumDemo {
enumFirst demo=enumFirst.ONE;
public static void main(String[] args) {
EnumDemo demo=new EnumDemo();
System.out.println(demo.demo.equals(enumFirst.ONE));
}
}
b) In Section 8.1.1.3 it states
The effect of the strictfp modifier is to make all float or double expressions within the class declaration be explicitly FP-strict (§15.4). This implies that all methods declared in the class, and all nested types declared in the class, are implicitly strictfp.
Hence below program compiles fine as expected but can you predict the program output?
strictfp class OuterClass {
static float f=1.0f;
OuterClass() {
m1();
}
void m1() {
System.out.println(f);
}
static strictfp class InnerClass {
float f=OuterClass.f;
void m1() {
System.out.println(f);
}
}
}
public class StrictFPExample {
public static void main(String[] args) {
OuterClass.InnerClass inner=new OuterClass.InnerClass();
}
}
c) In section 8.1.2 it states that
It is a compile-time error if a generic class is a direct or indirect subclass of Throwable.
Reason:
This restriction is needed since the catch mechanism of the Java virtual machine works only with non-generic classes.
class SomeException extends Throwable {
public String getMessage() {
return "subclass method";
}
}
Below line gives compile time exception
class Generic<T extends SomeException> extends Throwable {
d) In the same section it also states that
It is a compile-time error to refer to a type parameter of a class C anywhere in the declaration of a static member of C or the declaration of a static member of any type declaration nested within C. It is a compile-time error to refer to a type parameter of a class C within a static initializer of C or any class nested within C.
For example below code generate compile time error.
class Generic<T> {
static T t;
Generic(T t) {
this.t=t;
}
}
e) I found a tricky program under the section Parameterized class declarations can be nested inside other declarations.
Below program gives an example for the implementation.
Man it took me 20 min to understand the program itself.
class Seq<T> {
T head;
Seq<T> tail;
Seq() { this(null, null); }
boolean isEmpty() { return tail == null; }
Seq(T head, Seq<T> tail) { this.head = head; this.tail = tail; }
class Zipper<S> {
Seq<Pair<T,S>> zip(Seq<S> that) {
if (isEmpty() || that.isEmpty()) {
System.out.println("Entered into this block");
return new Seq<Pair<T,S>>();
}
else {
System.out.println("Entered into this 2nd block");
return new Seq<Pair<T,S>>(
new Pair<T,S>(head, that.head),
this.zip(that.tail));
}
}
}
}
class Pair<T, S> {
T fst; S snd;
Pair(T f, S s) {fst = f; snd = s;}
}
class Client {
public static void main(String[] args) {
Seq<String> strs =
new Seq<String>("a", new Seq<String>("b",
new Seq<String>()));
Seq<Number> nums =
new Seq<Number>(new Integer(1),
new Seq<Number>(new Double(1.5),
new Seq<Number>()));
Seq<String>.Zipper<Number> zipper =
strs.new Zipper<Number>();
Seq<Pair<String,Number>> combined = zipper.zip(nums);
System.out.println(combined.head.fst);
System.out.println(combined.head.snd);
System.out.println(combined.tail.head.fst);
System.out.println(combined.tail.head.snd);
System.out.println(combined.tail.tail.head.fst);
System.out.println(combined.tail.tail.head.snd);
}
}
f) In 8.1.3 section Inner Classes and Enclosing Instances
Inner classes may not declare static members, unless they are compile-time constant fields (§15.28).
class HasStatic{
static int j = 100;
}
class Outer{
class Inner extends HasStatic{
static final int x = 3; // ok - compile-time constant
static int y = 4; // compile-time error, an inner class
}
static class NestedButNotInner{
static int z = 5; // ok, not an inner class
}
interface NeverInner{} // interfaces are never inner
}
Member interfaces (§8.5) are always implicitly static so they are never considered to be inner classes.
g) In 8.1.5 Superinterfaces Below code will not compile.
class B implements I<Integer>
class C extends B implements I<String>
This requirement was introduced in order to support translation by type erasure (§4.6).
h) In section 8.3.1.4 volatile Fields it states that
A compile-time error occurs if a final variable is also declared volatile.
i) In section 8.3.2.3 Restrictions on the use of Fields during Initialization
Rules for declaration of a member are as follows
he declaration of a member needs to appear textually before it is used only if the member is an instance (respectively static) field of a class or interface C and all of the following conditions hold:
1)The usage occurs in an instance (respectively static) variable initializer of C or in an instance (respectively static) initializer of C.
2) The usage is not on the left hand side of an assignment.
3) The usage is via a simple name.
4) C is the innermost class or interface enclosing the usage.
5) A compile-time error occurs if any of the four requirements above are not met.
This means that a compile-time error results from the test program:
class Test {
int i = j; // compile-time error: incorrect forward reference
int j = 1;
}
whereas the following example compiles without error:
class Test {
Test() { k = 2; }
int j = 1;
int i = j;
int k;
}
even though the constructor (§8.8) for Test refers to the field k that is declared three lines later.
Accesses by methods are not checked in this way, so:
class Z {
static int peek() { return j; }
static int i = peek();
static int j = 1;
}
class Test {
public static void main(String[] args) {
System.out.println(Z.i);
}
}
produces the output:
0
A more elaborate example is:
class UseBeforeDeclaration {
static {
x = 100; // ok - assignment
int y = x + 1; // error - read before declaration
int v = x = 3; // ok - x at left hand side of assignment
int z = UseBeforeDeclaration.x * 2;
// ok - not accessed via simple name
Object o = new Object(){
void foo(){x++;} // ok - occurs in a different class
{x++;} // ok - occurs in a different class
};
}
{
j = 200; // ok - assignment
j = j + 1; // error - right hand side reads before declaration
int k = j = j + 1;
int n = j = 300; // ok - j at left hand side of assignment
int h = j++; // error - read before declaration
int l = this.j * 3; // ok - not accessed via simple name
Object o = new Object(){
void foo(){j++;} // ok - occurs in a different class
{ j = j + 1;} // ok - occurs in a different class
};
}
int w = x = 3; // ok - x at left hand side of assignment
int p = x; // ok - instance initializers may access static fields
static int u = (new Object(){int bar(){return x;}}).bar();
// ok - occurs in a different class
static int x;
int m = j = 4; // ok - j at left hand side of assignment
int o = (new Object(){int bar(){return j;}}).bar();
// ok - occurs in a different class
int j;
}
j) In section 8.4.3 "Method Modifiers" it states
A compile-time error occurs if a method declaration that contains the keyword abstract also contains any one of the keywords private, static, final, native, strictfp, or synchronized. A compile-time error occurs if a method declaration that contains the keyword native also contains strictfp.
An instance method that is not abstract can be overridden by an abstract method.
k) In section 8.4.3.3 final Methods it states
At run time, a machine-code generator or optimizer can "inline" the body of a final method, replacing an invocation of the method with the code in its body. The inlining process must preserve the semantics of the method invocation. In particular, if the target of an instance method invocation is null, then a NullPointerException must be thrown even if the method is inlined. The compiler must ensure that the exception will be thrown at the correct point, so that the actual arguments to the method will be seen to have been evaluated in the correct order prior to the method invocation.
Consider the example:
final class Point {
int x, y;
void move(int dx, int dy) { x += dx; y += dy; }
}
class Test {
public static void main(String[] args) {
Point[] p = new Point[100];
for (int i = 0; i < p.length; i++) {
p[i] = new Point();
p[i].move(i, p.length-1-i);
}
}
}
Here, inlining the method move of class Point in method main would transform the for loop to the form:
for (int i = 0; i < p.length; i++) {
p[i] = new Point();
Point pi = p[i];
int j = p.length-1-i;
pi.x += i;
pi.y += j;
}
The loop might then be subject to further optimizations.
Such inlining cannot be done at compile time unless it can be guaranteed that Test and Point will always be recompiled together, so that whenever Point-and specifically its move method-changes, the code for Test.main will also be updated.
l) Section 8.4.6 Method Throws states
Type variables are allowed in throws lists even though they are not allowed in catch clauses.
interface PrivilegedExceptionAction<E extends Exception> {
void run() throws E;
}
class AccessController {
public static <E extends Exception>
Object doPrivileged(PrivilegedExceptionAction<E> action) throws E
{ ... }
}
class Test {
public static void main(String[] args) {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction<FileNotFoundException>() {
public void run() throws FileNotFoundException
{... delete a file ...}
});
} catch (FileNotFoundException f) {...} // do something
}
}
m) In section 8.4.7 Method Body it states
Note that it is possible for a method to have a declared return type and yet contain no return statements. Here is one example:
class DizzyDean {
int pitch() { throw new RuntimeException("90 mph?!"); }
}
The presence or absence of the strictfp modifier has absolutely no effect on the rules for overriding methods and implementing abstract methods. For example, it is permitted for a method that is not FP-strict to override an FP-strict method and it is permitted for an FP-strict method to override a method that is not FP-strict.
n) In section 8.4.8.2 Hiding (by Class Methods) it states
Two different methods of a class may not override methods with the same erasure.
class C<T> { T id (T x) {...} }
interface I<T> { Tid(T x); }
class D extends C<String> implements I<Integer> {
String id(String x) {...}
Integer id(Integer x) {...}
}
This is also illegal, since D.id(String) is a member of D, D.id(Integer) is declared in D and:
the two methods have the same name, id
the two methods have different signatures.
D.id(Integer) is accessible to D
D.id(String) overrides C
o) In section 8.8.7.1 Explicit Constructor Invocations
If an anonymous class instance creation expression appears within an explicit constructor invocation statement, then the anonymous class may not refer to any of the enclosing instances of the class whose constructor is being invoked.
class Top {
int x;
class Dummy {
Dummy(Object o) {}
}
class Inside extends Dummy {
Inside() {
super(new Object() { int r = x; }); // error
}
Inside(final int y) {
super(new Object() { int r = y; }); // correct
}
}
}
Solutions for various questions.
In point (b) program does not print anything because InnerClass is not a subclass of OuterClass but rather a innerclass. hence the constructor of OuterClass will not be called.
In point (e) it prints
Entered into this 2nd block
Entered into this 2nd block
Entered into this block
a
1
a
1.5
Exception in thread "Main Thread" java.lang.NullPointerException
at Client.main(Client.java:49)
Hope this explanation helps if any.
2 comments:
I have seen some cases where it would be really useful to have abstract enums that didn't define any constants - just code that knew how to act on a set of enums to be determined later.
Fortunately, Fred Simon has been on the case for a while and has a working prototype to allow abstract enums.
Alex,
Thanks a lot.Sorry for late reply.
I will go through your blog regarding this today.
Thanks
Prashant
Post a Comment