How to hide a static variable in Java - java

I have three classes with same methods and only constants are different. So what I wanted is to create one base class, which contains all the methods and to add three child classes which contain only constant variables. It looks like it is not possible to do so because of the dynamic binding. Please look at the example:
public class Parent {
static String MY_CONSTANT = "bla bla";
public void printSomething() {
System.out.println(MY_CONSTANT);
}
}
public class Child extends Parent {
static String MY_CONSTANT = "hello world";
}
public class Greetings {
public static void main(String[] args) {
Child hey = new Child();
hey.printSomething();
}
}
The output is "bla bla", but I want the output to be "hello world".
Is there some solution for this problem?

You'll have to override the printSomething() method:
public class Child extends Parent {
static String MY_CONSTANT = "hello world";
#Override
public void printSomething() {
System.out.println(MY_CONSTANT);
}
}
It might be cleaner, though, to have a method that returns the value of the static variable. Then you can override that method, and call it from the base class:
public class Parent {
static String MY_CONSTANT = "bla bla";
public String getConstant() {
return Parent.MY_CONSTANT;
}
public void printSomething() {
System.out.println(getConstant());
}
}
public class Child extends Parent {
static String MY_CONSTANT = "hello world";
#Override
public String getConstant() {
return Child.MY_CONSTANT;
}
}
public class Greetings {
public static void main(String[] args) {
Child hey = new Child();
hey.printSomething();
}
}

How to hide a static variable in Java?
This is all you can do for variables: hide them. Although variables can be inherited, they cannot be overridden.
As actual values are class-specific and static, the only way to reuse a method in this scenario, is by making it take parameters:
public class Parent {
static String MY_CONSTANT = "bla bla";
public void printSomething(String something) {
System.out.println(something);
}
//Essentially, Parent.MY_CONSTANT becomes just the default
public void printSomething() {
System.out.println(MY_CONSTANT);
}
}
And the child can choose what it sends (overriding is basically to reuse the API):
public class Child extends Parent{
static String MY_CONSTANT = "hello world";
#Override
public void printSomething() {
//MY_CONSTANT is hidden and has "hello world"
super.printSomething(MY_CONSTANT);
}
}
The above design allows calls from the test class to behave predictably (or, rather, intuitively):
Child hey = new Child();
//Behaves as Child.
hey.printSomething();
EDIT: Since the getter is an instance method (understandable as you depend on the instance type to read the correct value), you can expose to children the field, or a setter, and all sorts of hiding would be suppressed completely:
public class Parent {
protected String myConstant = "bla bla";
public void printSomething() {
System.out.println(this.myConstant);
}
}
And children would just have to set the value in an initialization block:
public class Child extends Parent{
public Child() {
myConstant = "hello world";
}
}

public class Parent {
static String MY_CONSTANT = "bla bla";
public void printSomething() {
System.out.println(Child.MY_CONSTANT);
}
}
public class Child extends Parent{
static String MY_CONSTANT = "hello world";
#Override
public void printSomething() {
super.printSomething(); // definition define in parent class
}
}
public class LeapTEST {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Child child = new Child();
child.printSomething();
}
}

If you want to use a constant you should combine the static modifier with the final one. The final modifier indicates that the value of this field cannot change (have a look to this link, in the related section). (A static variable is common for all instances of the class. A final variable can not change after it has been set the first time).
If you have a look the Java Language Specification:
A hidden field can be accessed by using a qualified name if it is
static, or by using a field access expression that contains the
keyword super or a cast to a superclass type.
So you can refer a static variable outside the class using ClassName.myStaticVariable:
And since you should access them in this way, there is also no need to worry about hiding them.

I reached the same problem and my solution instead of extending the parent class was by using an enum like this:
public enum MyEnum {
PARENT("Parent constant"),
CHILD("Child constant");
private String myConstant;
MyEnum(String s) {
myConstant = s;
}
public void printConstant(){
System.out.println(myConstant);
}
}
And then, call the printConstant method of the desired enum like:
MyEnum.CHILD.printConstant();
Of course, this is limited but it suites my case so i hope it will help someone too.

Related

Use a static value in class extends

I would like to use a method using a constant according to class she is called.
Sorry for this bad explanation, here is an example :
public class Mom{
public void execute(parameters){
// Some actions
String nf = String.format(C_CARS)
}
}
public class Son1 extends Mom{
private static final String C_CARS=" myFormat "
}
public class Son2 extends Mom{
private static final String C_CARS=" myFormat2 "
}
public static void main(String[] args){
Son1 son1=new Son1();
Son2 son2=new Son2();
son1().execute(myparameters);
son2().execute(myparameters);
}
I would like to do something like that, is there a way ? The problem here is C_CARS is unknown in Mom Class.
This is just not how inheritance works in Java.
You need a guarantee that all instances of Mom have a value. Do this via an instance method, e.g.
public abstract class Mom{
public void execute(parameters){
String nf = String.format(getCCars());
}
protected abstract String getCCars();
}
And then implement in the child classes:
class Son1 extends Mom {
#Override protected String getCCars() {
return "something";
}
}
There is something up with your object oriented design.
Remember: every instance of a Son1 class is also an instance of Mom. But in the real world, most sons aren't mothers.
extends is not the right thing to use here.
Don't use static, it brings troubles.
public class Mom {
private final String cCars;
protected Mom(String cCars) {
this.cCars = cCars;
}
public void execute(parameters){
// Some actions
String nf = String.format(cCars)
}
}
public class Son1 extends Mom {
public Son1() {
super(" myFormat ");
}
}
public class Son2 extends Mom {
public Son2() {
super(" myFormat2 ");
}
}
This can't work because a superclass cannot access the members of it's subclass. Also, you can't override a variable like you can override methods. Try it with the following code instead:
public static abstract class Mom {
public void execute() {
System.out.println(getCCars());
}
abstract String getCCars();
}
public static class Son1 extends Mom {
#Override
String getCCars() {
return " myFormat ";
}
}
public static class Son2 extends Mom {
#Override
String getCCars() {
return " myFormat2 ";
}
}
public static void main(String[] args) {
Son1 son1 = new Son1();
Son2 son2 = new Son2();
son1.execute();
son2.execute();
}
This is the way you would to it in java.
I've tested the code above. It does compile and it produces the desired result.
You cannot override a variable in this way. Use a method instead:
abstract public class Mom {
abstract protected String cCars();
public void execute(parameters){
// Some actions
String nf = String.format(cCars())
}
}
public class Son1 extends Mom{
private static final String C_CARS=" myFormat ";
#Override
protected String cCars() {
return C_CARS;
}
}
Alternatively, you could provide a default implementation in Mom, then there is no need to make the class and method abstract.
A field marked static belongs to the class rather than an instance. Also, C_CARS in Son1 is not related in any way to C_CARS in Son2.
A way to achieve such thing is this:
class Mom {
public abstract String getCCars();
}
Then each ascendant of Mom must override the getCCars() method.
You could also accept a string cCars in the constructor of Mom. Each ascendant then must call the super constructor defined in Mom:
class Mom {
final String cCars;
Mom(String cCars) {
this.cCars = cCars;
}
void execute(String parameters) {
System.out.println(this.cCars);
}
}
class Son1 {
Son1() {
super("MyFormat"); // We have to call the super constructor
}
}

Abstract Class and toString() method

I am a little confused on how to set up the TestHomework method so that it prints properly when using the toString() method. Right now when I run the main method it prints "null - 0" but what I would like it to say is "Math - 6". This program is supposed to extend an abstract class. It is supposed to say how many pages there are for homework and for what subject.
public abstract class Homework {
private int pagesToRead;
private String typeHomework;
{
// initialise instance variables
pagesToRead = 0;
typeHomework = "none";
}
public Homework(int pages, String hw) {
this.pagesToRead = pages;
this.typeHomework = hw;
}
public abstract void createAssignment(int p);
public int getPages() {
return pagesToRead;
}
public void setPagesToRead(int p) {
pagesToRead = p;
}
public String getTypeHomework() {
return typeHomework;
}
public void setTypeHomework(String hw) {
typeHomework = hw;
}
}
public class MyMath extends Homework {
private int pagesRead;
private String typeHomework;
public MyMath(int pages, String hw) {
super(pages,hw);
}
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
public String toString() {
return typeHomework + " - " + pagesRead;
}
}
public class TestHomework {
public static void main(String[] args) {
MyMath one = new MyMath(6, "Math");
one.createAssignment(6);
System.out.println(one);
}
}
That's because you are defining the 2 properties (that one of them happen to have the same name as one of the abstract class's) but you are not initializing them, you are initializing those of the abstract class. (So their values is always set to their type's default)
You need to drop those from the MyMath class, & define the toString method in your abstract class: it's the one to be used by default by its inheriting classes.
public abstract class Homework {
private int pagesToRead;
private String typeHomework;
// Same code
// Define the toString here
#Override
public String toString() {
return typeHomework + " - " + pagesToRead;
}
}
public class MyMath extends Homework {
// You don't need to define any extra attributes
public MyMath(int pages, String hw) {
super(pages,hw);
}
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
}
public static void main(String[] args) {
// Calls the constructor of the MyMath class, which in turn
// invokes the constructor of its superclass, the 'Homework' class
MyMath one = new MyMath(6, "Math");
one.createAssignment(6);
// Invokes the toString of the MyMath class. Since it does not have one,
// The toString method of its superclass (Homework) is called.
System.out.println(one);
}
Your derived class has its own typeHomework and pagesRead fields, which are never set (even though the base class happens to have fields with the same names). Therefore, they stay null and 0.
You should delete those fields and use the data from the base class, via the public getter methods.
Why it doesn't work:
Be careful you redeclared the attribute typeHomework of you parent class. Attributes are automatically added to your extending class so you don't have to write them again.
By redeclaring it you confused the compiler, viewing your code in debug shows, that your one object contains your typeHomework twice:
typeHomework = null // The one from the super class
typeHomework = "Math" // The one from your child class
Your method now uses the typeHomework from your super-class therefor the output is null!
pagesRead is 0 because you are setting the pagesToRead of your super-class to 6(not pagesRead!) when calling setPagesToRead(p);.
Some style tips
Use the #Override annotation when overriding methods like this:
#Override
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
It's not really needed but it's good practice (readers of your code know that it overrides something).
When referring to attributes of your class it's also good practice to use the this statement so it's clear, that you're referring to an attribute and not a local variable:
#Override
public String toString() {
return this.typeHomework + " - " + this.pagesRead;
}

Calling overloaded functions with "null" reference

Let us say I have following overloaded functions
public class Test {
public static void funOne(String s){
System.out.print("String function");
}
public static void funOne(Object o){
System.out.print("Object function");
}
public static void main(String[] args) {
funOne(null);
}
}
Why would funOne(null) call the method with String argument signature? what is the precedence for overloading here?
The class that is lower in the class hierarchy will have precedence in this case. In other words the more specific class type, which would be String in this case because String extends Object technically.
If you have the following
public class A {
...
}
public class B extends A {
...
}
Then when you define overloading methods like the following:
public void test(A object) {
...
}
public void test(B object) {
...
}
Then calling test(null) will call the second method because B is lower in the class hierarchy.
Your question is more fully answered here with references.
Also, you can force a particular method to be called by doing this:
funOne((Object) null);

How can I access a method of an "unnamed" class?

public class Test {
public static void main(String[] args) {
DemoAbstractClass abstractClass = new DemoAbstractClass() {
private String val;
#Override
public void runner() {
val = "test";
System.out.println(val);
this.run();
}
public String getVal() {
return val;
}
};
abstractClass.runner();
/**
* I want to access getVal method here
*/
}
}
abstract class DemoAbstractClass {
public void run() {
System.out.println("running");
}
public abstract void runner();
}
Here, I'm declaring an abstract class DemoAbstractClass. I can obviously create a new class that extends this class and add this method to it. But, I would prefer not doing that in my scenario.
Is there any other way to access getVal method in above code??
You can't. You need to make a proper (non-anomous) class out of it. Make it an inner private class if you want to limit its scope.
Alternatively, you could use a StringBuffer and share a referense to it between the methods. Not extremely clean however.
Related question:
Accessing inner anonymous class members
Short of using reflection, you cannot as you have no access to the concrete type of the object to be able to bind the methodcall to
If you don want to do something like this in a sane manner, declare a named class and use that as the type of abstractClass
Unfortunately, if you cannot name the type, you cannot access the methods at the language level.
What you can do, though, is use the reflection API to get a Method object and invoke it on this object.
This, however, is pretty slow. A private class or private interface would be much faster.
I can obviously create a new class that extends this class and add this method to it.
You've already done this; the end result was an anonymous inner class: new DemoAbstractClass() { ... }; If you just moved that declaration into its own class -- you can even make it a private class -- you can access getVal.
Per your example above:
public class Test {
public static void main(String[] args) {
DemoClass abstractClass = new DemoClass();
abstractClass.runner();
/**
* I want to access getVal method here
*/
abstractClass.getVal(); // can do this here now
}
private class DemoClass extends DemoAbstractClass {
private String val;
#Override
public void runner() {
val = "test";
System.out.println(val);
this.run();
}
public String getVal() {
return val;
}
}
}
}
Another option is to make a StringBuilder a member of the main method and use the closure nature of anonymous inner methods:
public static void main(String[] args) {
final StringBuilder value = new StringBuilder();
DemoAbstractClass abstractClass = new DemoAbstractClass() {
#Override
public void runner() {
value.append( "test" );
System.out.println(val);
this.run();
}
};
abstractClass.runner();
// use val here...
String val = value.toString();
}

Is there a way to override class variables in Java?

class Dad
{
protected static String me = "dad";
public void printMe()
{
System.out.println(me);
}
}
class Son extends Dad
{
protected static String me = "son";
}
public void doIt()
{
new Son().printMe();
}
The function doIt will print "dad". Is there a way to make it print "son"?
In short, no, there is no way to override a class variable.
You do not override class variables in Java you hide them. Overriding is for instance methods. Hiding is different from overriding.
In the example you've given, by declaring the class variable with the name 'me' in class Son you hide the class variable it would have inherited from its superclass Dad with the same name 'me'. Hiding a variable in this way does not affect the value of the class variable 'me' in the superclass Dad.
For the second part of your question, of how to make it print "son", I'd set the value via the constructor. Although the code below departs from your original question quite a lot, I would write it something like this;
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public void printName() {
System.out.println(name);
}
}
The JLS gives a lot more detail on hiding in section 8.3 - Field Declarations
Yes. But as the variable is concerned it is overwrite (Giving new value to variable. Giving new definition to the function is Override). Just don't declare the variable but initialize (change) in the constructor or static block.
The value will get reflected when using in the blocks of parent class
if the variable is static then change the value during initialization itself with static block,
class Son extends Dad {
static {
me = "son";
}
}
or else change in constructor.
You can also change the value later in any blocks. It will get reflected in super class
Yes, just override the printMe() method:
class Son extends Dad {
public static final String me = "son";
#Override
public void printMe() {
System.out.println(me);
}
}
You can create a getter and then override that getter. It's particularly useful if the variable you are overriding is a sub-class of itself. Imagine your super class has an Object member but in your sub-class this is now more defined to be an Integer.
class Dad
{
private static final String me = "dad";
protected String getMe() {
return me;
}
public void printMe()
{
System.out.println(getMe());
}
}
class Son extends Dad
{
private static final String me = "son";
#Override
protected String getMe() {
return me;
}
}
public void doIt()
{
new Son().printMe(); //Prints "son"
}
If you are going to override it I don't see a valid reason to keep this static. I would suggest the use of abstraction (see example code). :
public interface Person {
public abstract String getName();
//this will be different for each person, so no need to make it concrete
public abstract void setName(String name);
}
Now we can add the Dad:
public class Dad implements Person {
private String name;
public Dad(String name) {
setName(name);
}
#Override
public final String getName() {
return name;
}
#Override
public final void setName(String name) {
this.name = name;
}
}
the son:
public class Son implements Person {
private String name;
public Son(String name) {
setName(name);
}
#Override
public final String getName() {
return name;
}
#Override
public final void setName(String name) {
this.name = name;
}
}
and Dad met a nice lady:
public class StepMom implements Person {
private String name;
public StepMom(String name) {
setName(name);
}
#Override
public final String getName() {
return name;
}
#Override
public final void setName(String name) {
this.name = name;
}
}
Looks like we have a family, lets tell the world their names:
public class ConsoleGUI {
public static void main(String[] args) {
List<Person> family = new ArrayList<Person>();
family.add(new Son("Tommy"));
family.add(new StepMom("Nancy"));
family.add(new Dad("Dad"));
for (Person person : family) {
//using the getName vs printName lets the caller, in this case the
//ConsoleGUI determine versus being forced to output through the console.
System.out.print(person.getName() + " ");
System.err.print(person.getName() + " ");
JOptionPane.showMessageDialog(null, person.getName());
}
}
}
System.out Output : Tommy Nancy Dad
System.err is the same as above(just has red font)
JOption Output: Tommy then Nancy then Dad
This looks like a design flaw.
Remove the static keyword and set the variable for example in the constructor. This way Son just sets the variable to a different value in his constructor.
Though it is true that class variables may only be hidden in subclasses, and not overridden, it is still possible to do what you want without overriding printMe () in subclasses, and reflection is your friend. In the code below I omit exception handling for clarity. Please note that declaring me as protected does not seem to have much sense in this context, as it is going to be hidden in subclasses...
class Dad
{
static String me = "dad";
public void printMe ()
{
java.lang.reflect.Field field = this.getClass ().getDeclaredField ("me");
System.out.println (field.get (null));
}
}
https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html
It's called Hiding Fields
From the link above
Within a class, a field that has the same name as a field in the superclass hides the superclass's field, even if their types are different. Within the subclass, the field in the superclass cannot be referenced by its simple name. Instead, the field must be accessed through super, which is covered in the next section. Generally speaking, we don't recommend hiding fields as it makes code difficult to read.
class Dad
{
protected static String me = "dad";
public void printMe()
{
System.out.println(me);
}
}
class Son extends Dad
{
protected static String _me = me = "son";
}
public void doIt()
{
new Son().printMe();
}
... will print "son".
It indeed prints 'dad', since the field is not overridden but hidden. There are three approaches to make it print 'son':
Approach 1: override printMe
class Dad
{
protected static String me = "dad";
public void printMe()
{
System.out.println(me);
}
}
class Son extends Dad
{
protected static String me = "son";
#override
public void printMe()
{
System.out.println(me);
}
}
public void doIt()
{
new Son().printMe();
}
Approach 2: don't hide the field and initialize it in the constructor
class Dad
{
protected static String me = "dad";
public void printMe()
{
System.out.println(me);
}
}
class Son extends Dad
{
public Son()
{
me = "son";
}
}
public void doIt()
{
new Son().printMe();
}
Approach 3: use the static value to initialize a field in the constructor
class Dad
{
private static String meInit = "Dad";
protected String me;
public Dad()
{
me = meInit;
}
public void printMe()
{
System.out.println(me);
}
}
class Son extends Dad
{
private static String meInit = "son";
public Son()
{
me = meInit;
}
}
public void doIt()
{
new Son().printMe();
}
Variables don't take part in overrinding. Only methods do. A method call is resolved at runtime, that is, the decision to call a method is taken at runtime, but the variables are decided at compile time only. Hence that variable is called whose reference is used for calling and not of the runtime object.
Take a look at following snippet:
package com.demo;
class Bike {
int max_speed = 90;
public void disp_speed() {
System.out.println("Inside bike");
}
}
public class Honda_bikes extends Bike {
int max_speed = 150;
public void disp_speed() {
System.out.println("Inside Honda");
}
public static void main(String[] args) {
Honda_bikes obj1 = new Honda_bikes();
Bike obj2 = new Honda_bikes();
Bike obj3 = new Bike();
obj1.disp_speed();
obj2.disp_speed();
obj3.disp_speed();
System.out.println("Max_Speed = " + obj1.max_speed);
System.out.println("Max_Speed = " + obj2.max_speed);
System.out.println("Max_Speed = " + obj3.max_speed);
}
}
When you run the code, console will show:
Inside Honda
Inside Honda
Inside bike
Max_Speed = 150
Max_Speed = 90
Max_Speed = 90
only by overriding printMe():
class Son extends Dad
{
public void printMe()
{
System.out.println("son");
}
}
the reference to me in the Dad.printMe method implicitly points to the static field Dad.me, so one way or another you're changing what printMe does in Son...
You cannot override variables in a class. You can override only methods. You should keep the variables private otherwise you can get a lot of problems.
No. Class variables(Also applicable to instance variables) don't exhibit overriding feature in Java as class variables are invoked on the basis of the type of calling object. Added one more class(Human) in the hierarchy to make it more clear. So now we have
Son extends Dad extends Human
In the below code, we try to iterate over an array of Human, Dad and Son objects, but it prints Human Class’s values in all cases as the type of calling object was Human.
class Human
{
static String me = "human";
public void printMe()
{
System.out.println(me);
}
}
class Dad extends Human
{
static String me = "dad";
}
class Son extends Dad
{
static String me = "son";
}
public class ClassVariables {
public static void main(String[] abc) {
Human[] humans = new Human[3];
humans[0] = new Human();
humans[1] = new Dad();
humans[2] = new Son();
for(Human human: humans) {
System.out.println(human.me); // prints human for all objects
}
}
}
Will print
human
human
human
So no overriding of Class variables.
If we want to access the class variable of actual object from a reference variable of its parent class, we need to explicitly tell this to compiler by casting parent reference (Human object) to its type.
System.out.println(((Dad)humans[1]).me); // prints dad
System.out.println(((Son)humans[2]).me); // prints son
Will print
dad
son
On how part of this question:- As already suggested override the printMe() method in Son class, then on calling
Son().printMe();
Dad's Class variable "me" will be hidden because the nearest declaration(from Son class printme() method) of the "me"(in Son class) will get the precedence.
Just Call super.variable in sub class constructor
public abstract class Beverage {
int cost;
int getCost() {
return cost;
}
}`
public class Coffee extends Beverage {
int cost = 10;
Coffee(){
super.cost = cost;
}
}`
public class Driver {
public static void main(String[] args) {
Beverage coffee = new Coffee();
System.out.println(coffee.getCost());
}
}
Output is 10.
Of course using private attributes, and getters and setters would be the recommended thing to do, but I tested the following, and it works... See the comment in the code
class Dad
{
protected static String me = "dad";
public void printMe()
{
System.out.println(me);
}
}
class Son extends Dad
{
protected static String me = "son";
/*
Adding Method printMe() to this class, outputs son
even though Attribute me from class Dad can apparently not be overridden
*/
public void printMe()
{
System.out.println(me);
}
}
class Tester
{
public static void main(String[] arg)
{
new Son().printMe();
}
}
Sooo ... did I just redefine the rules of inheritance or did I put Oracle into a tricky situation ?
To me, protected static String me is clearly overridden, as you can see when you execute this program. Also, it does not make any sense to me why attributes should not be overridable.
Why would you want to override variables when you could easily reassign them in the subClasses.
I follow this pattern to work around the language design. Assume a case where you have a weighty service class in your framework which needs be used in different flavours in multiple derived applications.In that case , the best way to configure the super class logic is by reassigning its 'defining' variables.
public interface ExtensibleService{
void init();
}
public class WeightyLogicService implements ExtensibleService{
private String directoryPath="c:\hello";
public void doLogic(){
//never forget to call init() before invocation or build safeguards
init();
//some logic goes here
}
public void init(){}
}
public class WeightyLogicService_myAdaptation extends WeightyLogicService {
#Override
public void init(){
directoryPath="c:\my_hello";
}
}

Categories