I have 3 classes:
public class Alpha {
public Number number;
}
public class Beta extends Alpha {
public String number;
}
public class Gama extends Beta {
public int number;
}
Why does the following code compile? And, why does the test pass without any runtime errors?
#Test
public void test() {
final Beta a = new Gama();
a.number = "its a string";
((Alpha) a).number = 13;
((Gama) a).number = 42;
assertEquals("its a string", a.number);
assertEquals(13, ((Alpha) a).number);
assertEquals(42, ((Gama) a).number);
}
Member variables cannot be overridden like methods. The number variables in your classes Beta and Gama are hiding (not overriding) the member variable number of the superclass.
By casting you can access the hidden member in the superclass.
Fields can't be overridden; they're not accessed polymorphically in the first place - you're just declaring a new field in each case.
It compiles because in each case the compile-time type of the expression is enough to determine which field called number you mean.
In real-world programming, you would avoid this by two means:
Common-sense: shadowing fields makes your code harder to read, so just don't do it
Visibility: if you make all your fields private, subclasses won't know about them anyway
As a workaround, you can use getter methods:
class A {
private String field = "A: field";
String getField() {
return field;
}
}
class B extends A {
private String field = "B: field";
#Override
String getField() {
return field;
}
}
Java Hiding a field
When successor has a field with the same name as a superclass's field it is called - Hiding a field
Java's field does not support polymorphism and does not take a field's type into account
class A {
String field = "A: field";
String foo() {
return "A: foo()";
}
}
class B extends A {
//B's field hides A's field
String field = "B: field";
String foo() {
return "B: foo()";
}
}
#Test
public void testPoly() {
A a = new A();
assertEquals("A: field", a.field);
assertEquals("A: foo()", a.foo());
B b = new B();
assertEquals("B: field", b.field);
assertEquals("B: foo()", b.foo());
//B cast to A
assertEquals("A: field", ((A)b).field); //<--
assertEquals("B: foo()", ((A)b).foo());
}
[Swift override property]
Related
In general - equivalent of final field in Java is the readonly field in C#. But the more I read about C# the more I see that there are some differences in details.
I've found myself two differences:
Fields marked as readonly assigned as part of definition can be reasigned in constructor
In Java it is not possible to do that with final fields. Examples:
Example - C Sharp
public class Foo
{
public readonly int a = 1;
public Foo()
{
a = 2;
}
}
and now
Foo f = new Foo();
Console.WriteLine(f.a);
will give us 2 as an output
(side question - is this behavior can be actualy used for something useful? As far as I know I cannot assign value to base class' readonly field in dervied class)
Example - Java
class Foo {
private final int i = 3;
public Foo() {
// compilation error
// i = 2;
}
}
Orders of initalization of readonly and final fields in class hierarchy are different in both languages
In Java it will go from base class to dervied.
In C# it will go from derived class to base.
Example - C Sharp
Based on article Eric Lippert: Why Do Initializers Run In The Opposite Order As Constructors? Part One:
public class Print
{
public Print(string text)
{
Console.WriteLine(text);
}
}
public class Base
{
private readonly Print #base = new Print("Base class");
}
public class Derived : Base
{
private readonly Print derived = new Print("Derived class");
}
In case of calling new Derived() we will see:
Derived class
Base class
As far as I understood - this order of initalization guarantees that readonly fields are always initalized before usage. In case of following code (based on second part of Eric's article - Why Do Initializers Run In The Opposite Order As Constructors? Part Two):
public class Foo
{
}
public class Base
{
public Base()
{
if (this is Derived)
{
((Derived)this).danger();
}
}
}
public class Derived : Base
{
private readonly Foo derived = new Foo();
public void danger()
{
Console.WriteLine("access: {0}", derived.GetHashCode());
}
}
Calling new Derived() is safe.
Example - Java
Similar code in Java:
class Print {
public Print(String text) {
System.out.println(text);
}
}
class Base {
private final Print base = new Print("Base class");
}
class Derived extends Base {
private final Print derived = new Print("Derived class");
}
Call new Derived() will result with:
Base class
Derived class
So in case of following code:
class Base {
public Base() {
if (this instanceof Derived) {
((Derived)this).danger();
}
}
}
class Derived extends Base {
private final Foo field = new Foo();
public void danger()
{
System.out.println("access: " + field.hashCode());
}
}
The call new Derived() will result with NullPointerException
Question
My question is: Are there other differences (even small ones) between Java's final fields and readonly fields in C# ? To make question more clear - I have in mind only final instance fields in Java (so no static finals, no final variables, no other final "thigs")
It's been a rather long time since I've messed around with Java Abstraction and/or Interfaces, but I'm coming back to it now for a project and something is getting on my nerves. Below is a snippet of my code.
public class A {
private static String name = "None";
private static String description = "No description";
public A() {}
public A(User user) {
user.setData(this);
}
public static String getName() {
return name;
}
public static String getDescription() {
return description;
}
}
public class B extends A {
private static String name = "B";
private static String description = "This is B";
public B() {}
public B(User user) {
super(user);
}
}
public class User {
private A a;
public void setData(A a) {
this.a = a;
}
public A getData() {
return a;
}
}
When I use B.getName() I expect it to return "B" but it's instead returning "None".
Now I'm obviously doing something wrong, and searching around didn't help a bit. I'm fairly positive that this is possible someway, unless I'm getting confused with another language.
Could someone please point me in the right direction? Thanks.
You called the getName method on the class B. B doesn't have a static method called getName, so it looks for it in the superclass, A, which does.
Maybe you expect B's version of name to override A's? Variables don't get overridden. A is accessing the static variable name defined on A, that the method was originally called on B doesn't affect that.
Inheritance and static methods don't work well together. OO concepts like polymorphism rely on runtime dispatching, the word static should imply the opposite of that. With polymorphism the program works at a high level of abstraction, referring to the objects by a super type and letting the subclasses work out the details. With static methods you have to refer to the specific subclass you want the method called on, so you don't have that level of abstraction.
Welcome back to Java again.
You are using static variable in class A and B. These variables are associated with class instead of the objects.
If you change your method to get name from the User, it will work as you are expecting.
You need to override the method getName():
public class B extends A {
private static String name = "B";
private static String description = "This is B";
public B() {}
#Override
public static String getName() {
return name;
}
public B(User user) {
super(user);
}
}
The problem you are facing lies in the definition of the methods getName and getDescription: They are defined in class A as static members. This means that even when calling B.getName() the actual call is A.getName() and there the static member variable value of name is set to None.
When thinking about inheritance you have be careful what you declare as static. This has nothing to do with Interfaces or abstract classes.
public class A {
protected String name = "None";
protected String description = "No description";
public A() {}
public A(User user) {
user.setData(this);
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
}
public class B extends A {
public B() {
name = "B";
description = "This is B"
}
public B(User user) {
super(user);
}
}
public class User {
private A a;
public void setData(A a) {
this.a = a;
}
public A getData() {
return a;
}
}
With the protected keyword you can access the fields from the extending class.
See also:
http://www.javatpoint.com/static-keyword-in-java
https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html
A couple of things to note in your class :
name and description are static variables in both A and B
getName is a static method in A
static variables are bound to the class and static methods can't be overridden
This is the expected behavior since getName() method of class A has access to member variable of its own class that is "name" of class A. It is NOT because of name is static even if you make it non-static and you access it as shown in below code snippet it would return "None". Remember that only methods get overridden not member variables. So "name" of class B is not overriding "name" of class "A".
B b = new B();
System.out.println(b.getName()); --> "None" ("name" is non-static)
----------------------------------------------
System.out.println(B.getName()); --> "None" ("name" is static)
Also, if you want to get "B" as output , override getName() method of class A in class B and make method and variable non-static.
In the below code, why is the super still referring to the subclass variable, and not the super class variable?
class Feline {
public String type = "f ";
public Feline() {
System.out.print("feline ");
}
}
public class Cougar extends Feline {
public Cougar() {
System.out.print("cougar ");
}
public static void main(String[] args) {
new Cougar().go();
}
void go() {
type = "c ";
System.out.print(this.type + super.type);
}
}
What subclass variable? You haven't declared one, so this.type refers to the superclass's variable.
If you declared public String type; in both the superclass and the subclass, it will work the way you are expecting. But right now, the only type variable you've declared is the one on the superclass.
Also, shadowing variables like this is bad practice, as it easily gets confusing as to what type you mean.
Firstly, you don't have subclass variable "type". Hence you are using super(parent) class variable(which is public available for both super and subclass) in the subclass. Hence when you change
type="c"
Super class variable is changed and hence this.type and super.type prints c
Hence in order to get your output, declare "type" in subclass.
public class Cougar extends Feline {
private String type = "f"; //or something else and see the output.
}
When the object of child class is created, the memory is allocated to instance member of the classes in the hierarchies.
There is only one copy in the memory for instance member type that is assigned for super-class but the visibility of that instance variable is public that why you can access it in child class as well using this.type but internally it's same location in the heap that is allocated for that object.
so this.type will change the value of instance member type defined in super class.
Summary: Child class is not defining a new instance member type instead it's inherited from super class.
Read What is purpose of using inheritance?
When type='c' is done in the subclass, it makes the super-class variable hidden, so that the super class variable is no longer available. Hence both this.type and super.type returns the value available ie, 'c', as type='f' is not visible to the code.
At the same time, if we change type='c' to String type='c' here we are creating a local variable, and not overriding the super-class variables. Hence the solution for
public class Feline {
public String type = "f ";
public Feline() {
System.out.println("In 1....feline ");
}
}
public class Cougar extends Feline
{
public Cougar() {
System.out.println("2.....cougar ");
}
public static void main(String[] args) {
new Cougar().go();
}
void go() {
String type = "c ";
System.out.println(this.type + super.type);
System.out.println("Subclass type::"+type);
System.out.println("this.type::"+this.type);
System.out.println("super.type::"+super.type);
}
}
The output is::::::: In 1....feline
2.....cougar
f f
Subclass type::c
this.type::f
super.type::f
In this case a new local variable is created, therefore the super-class variable is not hidden
Please have a look at this code :
class Foo {
public int a;
public Foo() {
a = 3;
}
public void addFive() {
a += 5;
}
public int getA() {
System.out.println("we are here in base class!");
return a;
}
}
public class Polymorphism extends Foo{
public int a;
public Poylmorphism() {
a = 5;
}
public void addFive() {
System.out.println("we are here !" + a);
a += 5;
}
public int getA() {
System.out.println("we are here in sub class!");
return a;
}
public static void main(String [] main) {
Foo f = new Polymorphism();
f.addFive();
System.out.println(f.getA());
System.out.println(f.a);
}
}
Here we assign reference of object of class Polymorphism to variable of type Foo, classic polmorphism. Now we call method addFive which has been overridden in class Polymorphism. Then we print the variable value from a getter method which also has been overridden in class Polymorphism. So we get answer as 10. But when public variable a is SOP'ed we get answer 3!!
How did this happen? Even though reference variable type was Foo but it was referring to object of Polymorphism class. So why did accessing f.a not result into value of a in the class Polymorphism getting printed? Please help
You're hiding the a of Polymorphism - you should actually get a compiler warning for that. Therefore those are two distinct a fields. In contrast to methods fields cannot be virtual. Good practice is not to have public fields at all, but only methods for mutating private state (encapsulation).
If you want to make it virtual, you need to make it as a property with accessor methods (e.g. what you have: getA).
This is due to the fact that you can't override class varibles. When accessing a class variable, type of the reference, rather than the type of the object, is what decides what you will get.
If you remove the redeclaration of a in the subclass, then I assume that behaviour will be more as expected.
I'm trying to create an object using a constructor from a subclass but I can't assign values to that object in the subclass Constructor.
Here is the superclass.
public class Bike
{
String color = "";
String type = "";
int age = 0;
public static void main (String [] args)
{
}
public Bike (String s, int i) // Constructor
{
color = s;
age = i;
}
public void PrintBike ()
{
if (type == "")
{
System.out.print(" You didn't give the proper kind of bike.");
}
else
{
System.out.print(" Your bike is a " + type + " bike. \n");
}
}
}
This is the subclass.
public class BikeAdv extends Bike
{
private String type;
public BikeAdv (String color, int age, String BikeType)
{
super (color, age);
type = BikeType;
}
}
Here is the class that calls the constructor.
public class Green
{
public static void main (String [] args)
{
Bike greenBike = new BikeAdv ("Green", 20, "Mountain");
greenBike.PrintBike();
}
}
When I run the class "Green", the output is " You didn't give the proper kind of bike." whereas I would expect to see "Your bike is a Mountain Bike".
Thanks!
The type field in the subclass shadows the type field in the superclass. The field in the superclass is never populated, and that's the one being checked.
If you simply remove the field in the subclass, the assignment there will populate the superclass field, and your code will likely work as you expect.
As noted in other answers though, it would be better to have the fields private or protected according to your need rather than default visibility.
You have declared these attributes without explicit visibility:
String color = "";
String type = "";
int age = 0;
Also, you have type redeclared in BikeAdv, that is probably an error (you don't need to).
If you want to have these attribute only accessible from its class, then you should declared them private. But, in that case, you have to parametrize the constructor to be able to modify all of them. Or maybe create setters for them (be aware that this way you will grant accessibility from outside the class).
private String color = "";
private String type = "";
private int age = 0;
If you want them to be unmodifiable from outside its class, but accessible from its subclasses, then declare them as protected:
protected String color = "";
protected String type = "";
protected int age = 0;
As you can see, there are a lot of possibilities. Check them out here:
http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
The class Bike is not abstract or an interface, that means that all of it's methods are as they said in the Bike class. When you assign greenBike to be a Bike, not a BikeAdv you tell it to use the methods in the Bike class, instead of the BikeAdv class. Your best bet would be to make Bike abstract and leave the PrintBike void without a body.
Also: you never pass the BikeType String to the super class so there is no way it can receive it.