I know and fully agree that sharing constants through interfaces is considered as a bad practice, but I didn't choose this implementation. Whatever:
interface SuperClassConstants {
public static final String CONSTANT = "super";
}
interface SubClassConstants extends SuperClassConstants {
public static final String CONSTANT = "sub";
}
class SuperClass implements SuperClassConstants {
}
class SubClass extends SuperClass implements SubClassConstants {
public SubClass() {
System.out.println(CONSTANT);
// The field CONSTANT is ambiguous
}
}
Why ambiguous? Isn't the constant hidden? I thought Java would have understood I was expecting "sub"...
As per the JLS 9.3:
If two fields with the same name are inherited by an interface because, for example, two of its direct superinterfaces declare fields with that name, then a single ambiguous member results. Any use of this ambiguous member will result in a compile-time error.
The field CONSTANT in SubClassConstants has hidden the CONSTANT of SuperClassConstants. But the class SubClass has access to both the CONSTANT as it virtually implements both the interfaces.
You can remove the ambiguity by specifying the Interface name :
System.out.println(SubClassConstants.CONSTANT);
Also read JLS 6.5.6.1:
If an expression name consists of a single Identifier, then there must be exactly one declaration denoting either a local variable, parameter, or field visible (§6.4.1) at the point at which the Identifier occurs. Otherwise, a compile-time error occurs.
Related
I was reading about Interfaces in a Book and I came upon this Line that confused me.
Interfaces are syntactically similar to classes, but they lack instance variables.
As far as I know about Interfaces, we can define variables inside an Interface which are by default final.
My question is, What does that Line mean? and What is the Difference between an Instance Variable and the Variable defined in the Interface??
My question is, What does that Line mean?
Amongst other things, it means the book's terminology is off. By "instance variable," they mean "instance field."
An instance field is a field that is specific to an individual instance of a class. For example:
class Foo {
// Instance field:
private int bar;
// Static field:
public static final int staticBar;
}
The field bar is per-instance, not class-wide. The field staticBar is class-wide (a static field, sometimes called a "class field").
Interfaces don't have instance fields. They do have static fields. When you do this:
interface FooInterface {
int staticBar;
}
staticBar is automatically declared public, static, and final (per JLS §9.3). So that staticBar is roughly equivalent to the one on our Foo class before.
This means you cant have instance variable but a constant static final variable within an interface as per JLS. For e.g.
interface MyIface {
public static final int MY_CONSTANT = 1;
}
And access it using interface name like:
int variable = MyIface.MY_CONSTANT;
When I attempt to compile the following the code, I get the compilation error:
unexpected type System.out.println( new Test().C.i );
^
required: class,package
found: value
class Test {
class C {
static final int i = 0;
}
public static void main(String... z) {
System.out.println( new Test().C.i );
}
}
But, if I change new Test().C.i to new Test().new C().i it compiles just fine.
Why? If i is static in C, then I shouldn't have to instantiate C. I should just be able to call it through the class C, not a C object.
What am I missing?
The problem is that "." Identifier in the Java syntax expects the identifier to refer to a variable and not a type.
This is specified in 6.5.6.2. Qualified Expression Names of the JLS (among other places):
If Q is a type name that names a class type (§8 (Classes)), then:
If there is not exactly one accessible (§6.6) member of the class
type that is a field named Id, then a compile-time error occurs.
Otherwise, if the single accessible member field is not a class
variable (that is, it is not declared static), then a compile-time
error occurs.
Otherwise, if the class variable is declared final, then Q.Id denotes
the value of the class variable.
The type of the expression Q.Id is the declared type of the class
variable after capture conversion (§5.1.10).
If Q.Id appears in a context that requires a variable and not a value,
then a compile-time error occurs.
Otherwise, Q.Id denotes the class variable.
The type of the expression Q.Id is the declared type of the class
variable after capture conversion (§5.1.10).
Note that this clause covers the use of enum constants (§8.9), since
these always have a corresponding final class variable.
While I can definitely appreciate the logic of why you'd think that it'd work like that - I actually expected it to work as well - it's not a big deal: Since there is always exactly only one i you can refer to it by Test.C.i. If i is non-static new Test().new C().i would be the correct way to access it.
Another way to look at it is to read 15.8. Primary Expressions which has the actual syntax for primary expressions (which is what we deal with here): It allows ClassInstanceCreationExpression (which is why new Test().new C().i works) as well as FieldAccess (which works for Test.C.i because the "class" is resolved recursively - only the last identifier has to refer to a field then).
I think the reason why new Test().new C().i works is because class Test is a top-level class and is treated as static. If you were to change your inner class C to be static then new C().i would work.
However, you should NOT access static members in a non-static way.
To access your static field do:
System.out.println(C.i);
Edit:
For those saying that class Test is not static please refer to this stackoverflow answer.
All top-level classes are, by definition, static.
What the static boils down to is that an instance of the class can
stand on its own. Or, the other way around: a non-static inner class
(= instance inner class) cannot exist without an instance of the outer
class. Since a top-level class does not have an outer class, it can't
be anything but static.
Because all top-level classes are static, having the static keyword in
a top-level class definition is pointless.
Just to show you how dumb of an idea it is to access a static field this way I created the following project:
class Test {
class C {
static final int i = 0;
}
public static void main(String[] args) {
// BAD:
System.out.println(new Test().new C().i);
// Correct:
System.out.println(C.i);
}
}
If you compile the class and view it in jd-gui you can see how it was compiled:
class Test {
public static void main(String[] args) {
void tmp13_10 = new Test(); tmp13_10.getClass(); new C(); System.out.println(0);
System.out.println(0);
}
class C {
static final int i = 0;
C() {
}
}
}
In Java, if I have a class such as this
abstract class TestClass
{
int mMember = 0;
int getMember()
{
return mMember;
}
}
and a class that extends this class:
class TestExtended extends TestClass
{
int mMember = 1;
}
If I create an instance of TestExtended, and call testExtended.getMember(); would it return 0, or 1?
In other words, when I extend a class, and don't override a method from said class, does it call the method and act on the members in said class, or in the extended class?
Would I need to re-implement (copy-paste) the function in the extended class to get the function to return 1?
It will return 0, not 1.
This is because you cannot "override" fields from a superclass. You can set them, so long as they are not private, but if you declare a new variable with the same name, it will simply shadow the superclass variable.
On the other hand, you can override methods.
Now, shadowing member variables in this way is usually a Very Bad Idea™, and is another reason to avoid public fields. This is why:
TestExtended sub = new TestExtended();
sub.mMember = 5;
System.out.println(sub.mMember); // prints '5', as expected
TestClass sup = sub; // this is fine, TestExtended extends TestClass
System.out.println(sup.mMember); // prints '0'!
The compiler will choose which version of the variable to use based on the compile-time type, breaking polymorphism. Don't shadow member variables, and avoid public fields, and this will never matter. Use getters and setters instead.
It can be confirmed by running. It will return 0. This is because the fields cannot be overridden. What you are actually doing is hiding the instance variable as per jls.
overriding of methods differs from hiding of fields (§8.3), for it is
permissible for a field to hide a field of another type.
Check Example 8.4.8.3-4. in language specification for more info
To get the subclass version, you would have to:
class TestExtended extends TestClass
{
int mMember = 1;
#Override
int getMember(){
return mMember;
}
}
Base class methods cannot access subclass fields (at least, without using reflection). Full stop.
Also, fields do not participate in overriding, unlike methods.
Using testExtended.getMember(); obviously means you are calling the abstract class method because you dont override the method in your sub-class. if you would have overridden it then the preference would have been given to subclass method first if your object is of type subclass. so in this case it will give you 0 unless you override the method.
I found interesting thing while working with reflection. I tried to retrieve constructors of simple class and their modifiers.
public class Test {
public Test(Object... args) {}
}
Here is the code to retrieve constructor modifiers:
Class<?> clazz = Test.class;
Constructor<?>[] ctors = clazz.getDeclaredConstructors();
for (Constructor<?> ctor : ctors) {
int mod = ctor.getModifiers();
/*if not package-private modifier*/
if(mod!=0) {
System.out.println( Modifier.toString(mod)));
}
}
The result is:
public transient
If I pass to constructor not variable parameters, but just array, it's ok.
public class Test {
public Test(Object[] args) {}
}
The result is:
public
The same happens regardless of constructor modifier (public, protected, private) or parameters type (primitive or reference). How could it be, whereas "transient" is not valid modifier for constructor?
Access modifiers are encoded as bit masks inside the class file. The JVM spec assigns different meaning to some of the bits depending on whether they appear in a method modifier or a field modifier. Bit 7 (0x0080) is one such bit.
For methods:
ACC_VARARGS 0x0080 Declared with variable number of arguments.
For fields:
ACC_TRANSIENT 0x0080 Declared transient; not written or read by a persistent
object manager.
Since you're looking at a method, the correct interpretation of this modifier is ACC_VARARGS and not ACC_TRANSIENT.
However, the Modifier class only appears capable of dealing with a subset of modifiers defined in the JVM spec. Because all it takes is an int, it's unable to tell ACC_VARARGS and ACC_TRANSIENT apart.
Consider the following superclass and subclass pair, how do you access the superclass member?
class Super {
Number aNumber;
}
class Subbie extends Super {
Float aNumber;
}
You can access the super Member by super.aNumber provided it is an instance of the Subclass.
Given that the attribute does not have a visiblity modifier, it is assumed to be package private. Subbie will only be able to access Super's aNumber if they're in the same package.
If it was, you could access it like this: super.aNumber. Notice super here is a keyword that implicitly refers to the superclass, and doesn't have anything to do with the superclass being named Super.
class Super {
Number aNumber;
}
class Subbie extends Super {
Float aNumber;
public Number getNumberFromSuper() {
return super.aNumber;
}
}
I'd suggest to take a read on the excellent Java tutorials online, for instance:
Inheritance
Controlling Access to Members of a Class
You can define a field with different keywords known as Access Modifiers (check the links at the end for a detailed explanation on this topic), each one defining a scope for access/use. I'll focus this explanation on fields.
Public: Accessible by everyone. This Access Modifier is regulary used with methods and not with fields. In Java, it is encouraged the use of get and set methods to access the value of a field and change it (respectively). You can access a field this way:
AClass c = new AClass();
c.publicField = 3; //Setting a value in a field, int in this case
int sum = c.publicField + 4; //Obtaining the value of publicField to use it
Private: Definining a field as private makes it visible only to the class itself, meaning no one outside the boundaries of a class will be able to see that field. A common class in Java usually has private fields and accessors (get & set methods).
public class AClass {
public int publicField;
private String privateField = "Can't see me!";
public String getPrivateField() {
return privateField;
}
public void setPrivateField(String newValue) {
privateField = newVaule;
}
}
Getters and Setters let you control the access to your private fields, allowing you to perform any logic you desire before updating the value of that field or preparing a field in a particular before returning its value if you need it.
Protected: Only subclasses of a class and classes in the same package can access a field defined with this keyword. In your case Subbie has access to the protected fields of Super and any other class in the same package as Super has access to those fields as well.
No Access Modifier: This is your current case and the answer to your question relies strongly on the structure of your classes. If they are in the same package, then you can access Super's field from Subbie. Otherwise, if Subbie is in another package, you won't be able to access that field. This field is referenced as Package-Private.
Some related articles you might want to check:
Inheritance in Java
Controlling the Access to Members of a Class