Java: static field in abstract class - java

I just start out with an example, that explains it best:
public abstract class A{
static String str;
}
public class B extends A{
public B(){
str = "123";
}
}
public class C extends A{
public C(){
str = "abc";
}
}
public class Main{
public static void main(String[] args){
A b = new B();
A c = new C();
System.out.println("b.str = " + b.str);
System.out.println("c.str = " + c.str);
}
}
This will print out:
b.str = abc
c.str = abc
But I would like a solution where each subclass that instantiate the super class, has their own class variable, at the same time I want to be able to reference that class variable through the identifier, or a method call, defined in the abstract super class.
So I would like the output to be:
b.str = 123
c.str = abc
Is that doable?

If you want classes B and C to have separate static variables, you'll need to declare the variables in those classes. Basically, static members and polymorphism don't go together.
Note that accessing static members through references is a really bad idea in terms of readability - it makes it look like it depends on the value of the reference, when it doesn't really. So your current code won't even compile when you've moved str down to B and C. Instead, you'll need
System.out.println("b.str = " + B.str);
System.out.println("c.str = " + C.str);
If you really need to access the value polymorphically (i.e. through an instance of A) then one option is to make a polymorphic getter:
public class A {
public abstract String getStr();
}
public class B extends A {
private static String str = "b";
#Override public String getStr() {
return str;
}
}
(and the same for C).
That way you get the behaviour you want in terms of not having a separate variable per instance, but you can still use it polymorphically. It's a little odd for an instance member to return a static value like this, but you're using the value for polymorphism of type, basically...

public abstract class A {
private String str;
public String getStr() { return str;}
protected void setStr(String str) { this.str = str; }
}
Then you'll be able to have
B b = new B();
b.getStr();
The setter and getter are my addition, you can go by simply making the variable non-static.
Update If you want to have the static-per-subclass, then you can have:
protected static Map<Class, String> values;
public abstract String getValue();
and then:
public String getValue() {
values.get(getClass());
}
public void setValue(String value) {
values.set(getClass(), value);
}
But this is generally a bad idea.

Put the static varibale in each subclass and add a (not static) abstract method to the abstract superclass:
abstract String getStr();
Then implement the getStr() method in each subclass by returning the static field of this special subclass.
public class B extends A {
private static String str;
#Override
public String getStr() {
return B.str;
}
}

only one instance of static variable is present in the system.
static variable will load into the system in the start before class is loaded.
reason both time abc is printed is because you set the value of str as abc in the last.

This will print the output you want:
public abstract class A{
}
public class B extends A{
static String str;
public B(){
str = "123";
}
}
public class C extends A{
static String str;
public C(){
str = "abc";
}
}
public class Main{
public static void main(String[] args){
A a = new B();
A c = new C();
System.out.println("B.str = " + B.str);
System.out.println("C.str = " + C.str);
}
}

Since you hardcode the value or str in subclasses anyway, you can do something like this:
public abstract class A{
public abstract String getStr();
}
public class B extends A{
public String getStr(){
return "123";
}
}
public class C extends A{
public String getStr(){
return "abc";
}
}
This would do the trick in your case.
Of course, then you should call it by method, like this:
public class Main{
public static void main(String[] args){
A b = new B();
A c = new C();
System.out.println("b.str = " + b.getStr());
System.out.println("c.str = " + c.getStr());
}
}

It is what I did to avoid to have to implement the same method in every subclass. It is based on the answer of Bozho. Maybe it may help someone.
import java.util.HashMap;
import java.util.Map;
/**
*
* #author Uglylab
*/
public class SandBox {
public static void main(String[] args) {
A b = new B();
A c = new C();
System.out.println("b.str = " + B.getStr(b.getClass()));
System.out.println("c.str = " + C.getStr(c.getClass()));
}
}
abstract class A{
protected static Map<Class, String> values = new HashMap<>();
public static String getStr(Class<? extends A> aClass) {
return values.get(aClass);
}
public static void setStr(Class<? extends A> aClass, String s) {
values.put(aClass, s);
}
}
class B extends A{
public B(){
setStr(this.getClass(),"123");
}
}
class C extends A{
public C(){
setStr(this.getClass(),"abc");
}
}

I think one way to approach this is to use a singleton for class B and C to mimic static methods and fields. The can both extend abstract class A, but will have their own values of str..

Related

Modifiy method called from extended class

I have three classes, and I need to modify first class through the second that is extended :
my first class A :
public class A{
private String name;
public void setName(String name) {
this.name= name;
}
my second class B
public abstract class B {
public void init() {
A a = new A();
a.setHost("foo");
}
}
my third class C
public class C extends B {
// I want to use the method setName() of the a declared in class B
b.init.a.setName("bar");//compile error, I tried several syntax I don't know how to do it
}
expected output, in my third class :
a.Getname = "bar"
Your code has multiple issues:
1) Variable b is never declared.
2) Variable a is private to method init, so you can't access it outside the init method.
So the solution should be like:
Class B:
public abstract class B {
protected static A a = new A(); // Protected to make it visible to child class
public void init() {
a.setHost("foo");
}
}
Class C:
public class C extends B {
public static void main(String[] args) {
a.setName("bar");
System.out.println(a.getName()); //Output = bar
}
}
you can return a in the init method of B like below.
public A init() {
A a = new A();
a.setHost("foo");
return a;
}
Then you can set the value in C like below
public class C extends B {
public setNameinA() {
B b = new B();
b.init().setName("bar");
}
}

Cannot get value of property from extending class

I have two Java classes, one of which inherits from other. They are somewhat like the following:
A.java:
public class A {
public String invocations[] = {"foo"};
public A() {
// do stuff
}
}
B.java:
public class B extends A {
public String invocations = {"bar", "baz"};
public B() {
super();
}
}
In this example, assuming I create an instance of B and get its invocations property, it returns {"foo"} instead of the expected {"bar", "baz"}. Why is this, and how can I get the {"bar", "baz"}?
You have one variable hiding another one. You can refer to a variable in a super class by using a cast to the type explicitly. (I am assuming you fix the syntax errors)
public class Main {
static class A {
public String[] invocations = {"foo"};
}
static class B extends A {
public String[] invocations = {"bar", "baz"};
}
public static void main(String... args) {
B b = new B();
System.out.println("((A)b).invocations=" + Arrays.toString(((A) b).invocations));
System.out.println("b.invocations=" + Arrays.toString(b.invocations));
}
}
prints
((A)b).invocations=[foo]
b.invocations=[bar, baz]

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
}
}

String concatenation in inherited class

I have a class called A and there's a String declared in it. And i have 2 other classes B and C which is inherited from A
public abstract class A {
protected String ss="";
public abstract String someMethod();
}
public class B extends A{
public String someMethod(){
int i=8;
return ss+="$"+i;
}
}
public class C extends A {
public String someMethod() {
int i=9;
return ss+="$"+i;
}
}
Test Code:
A aa = new B();
aa.someMethod();
A aaa = new C();
aaa.someMethod();
When I print aaa.someMethod(); - why haven't the strings from class B and C been appended? I want them to be appended. How can I do this ?
/usr/lib/jvm/java-1.7.0-openjdk-amd64/bin/javac A.java B.java C.java Test.java
/usr/lib/jvm/java-1.7.0-openjdk-amd64/bin/java Test
$8
$9
nothing surprising here, B method someMethod() calls B method, C method someMethod() calls C method...
file A.java:
public abstract class A
{
protected String ss="";
public abstract String someMethod();
}
file B.java
public class B extends A
{
public String someMethod()
{
int i=8;
return ss+="$"+i;
}
}
file C.java
public class C extends A
{
public String someMethod()
{
int i=9;
return ss+="$"+i;
}
}
file Test.java
public class Test
{
public static void main(String pArgs[])
{
A aa = new B();
System.out.println(aa.someMethod());
A aaa = new C();
System.out.println(aaa.someMethod());
}
}
Overridden methods in Java do not automatically invoke their superclass parents. So, in your C subclass, calling someMethod does not invoke the method from its parent A, unless you explicitly call super.
public class C extends A
public String someMethod(){
int i=9;
return ss+= super.someMethod()+"$"+i;
}
}
I assume you are doing this to learn, because otherwise this is a pretty terrible way to manage your inherited classes and their properties.

How to call a super method (ie: toString()) from outside a derived class

existantial question
if i have a class hierarchy like:
public class TestSuper {
public static class A {
#Override
public String toString() { return "I am A"; }
}
public static class B extends A {
#Override
public String toString() { return "I am B"; }
}
public static void main(String[] args) {
Object o = new B();
System.out.println( o ); // --> I am B
// ?????? // --> I am A
}
}
From the main method, is it possible to call the toString of A when the instance is of type B ???
of course, something like o.super.toString() doesn't compile ...
You can't, and very deliberately so: it would break encapsulation.
Suppose you had a class which used a method to validate input by some business rules, and then call the superclass method. If the caller could just ignore the override, it would make the class pretty much pointless.
If you find yourself needing to do this, revisit your design.
You can just add another method to call the super string. Something like:
public string getSuperString(){
return super.toString();
}
You can either
Add a method to A or B which you call instead.
// to A
public String AtoString() {
return toString();
}
// OR to B
public String AtoString() {
return super.toString();
}
Inline the code of A.toString() to where it is "called"
// inlined A.toString()
String ret = "I am A";
System.out.println( ret );
Both these options suggest a poor design in your classes, however sometimes you have existing classes you can only change in limited ways.
It's not possible, because toString() of A is overriden by B (I guess, you meant "class B extends A").
In your code it is not possible, in case B extends A
public class TestSuper {
public static class A {
#Override
public String toString() { return "I am A"; }
}
public static class B {
#Override
public String toString() { return "I am B"; }
}
public static void main(String[] args) {
B b = new B();
System.out.println( b ); // --> I am B
A a = (A)b;
System.out.println( a );
}
}

Categories