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.
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;
This question already has answers here:
Java Field Hiding
(3 answers)
Closed 7 years ago.
How to access an interface's field (which is by default public, static and final) using the implementing class's instance (this or super or instanceName if possible) if the field is hidden?
package mypack;
public interface MyInterface {
String str = "MyInterface.str";
String inheritanceTest = "inherited";
}
The field that i want to access is str
The other field inheritanceTest is to prove that interface fields are in fact inherited (unlike interface static methods)
package mypack;
public class Child implements MyInterface {
// Hiding the field
String str = "Child.str";
// Access test.
public String getParentStr() {
String result = "";
// result = MyInterface.super.str; // No enclosing instance of the type MyInterface is accessible in scope
// result = super.str; //str cannot be resolved or is not a field
return result;
}
// A method to check if the field is inherited or not.
public String getInheritedString() {
return this.inheritanceTest;
}
}
Notes
I know that it is discouraged to access static members using an instance instead of accessing it statically (Type.staticMemberNameOrSignature).
As shown, static interface methods are not inherited while static interface fields are inherited.
Non commented lines do not generate any compile-time errors.
Commented lines which are trying to assign a value to the variable result are the ones generating compile-time errors (Added to the line)
I am not asking about how to access the interface field statically.
Clarifying The Question
Is it possible to access an interfaces field that have been hidden by the implementing class using an instance (instance keywords like this or super) of the class?
Is it possible to access an interfaces field that have been hidden by the implementing class using an instance (instance keywords like this or super) of the class?
Yes. Instead of using this or super, just use interface name to access it.
MyInterface.str
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 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.
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