Inheritance rules in java - java

I have a question about the basics of java. I have the s attribute in each class. The value of s gotten by the instance of the class is different when I use the accessor (getS()). Is there a rule for this case?
The output of the main is :
x.s = One
x.getS() = Three
The classes definition :
package com;
import com.Test1.A;
import com.Test1.B;
public class Test1
{
public static class A
{
public static String s = "One";
public int x = 10;
public String getS()
{
return this.s;
}
}
public static class B extends A
{
public final String s = "Two";
public String getS()
{
return this.s;
}
}
public static class C extends B
{
public static int x = 1;
public static String s = "Three";
public String getS()
{
return this.s;
}
}
public static void main(String [] args)
{
A x = new C();
System.out.println("x.s = "+x.s);
System.out.println("x.getS() = "+x.getS());
}
}

The access of the field (x.s) is resolved through the compile-time type of x (which is A, so A's x ["One"] is returned).
The access through the getter (x.getS()) is resolved through the runtime type of x (which is C, so C's x ["Three"] is returned).
Some other examples:
((B) x).s will return "Two"
((C) x).s will return "Three"
((A) x).getS() will return "Three"
((B) x).getS() will return "Three"
(I leave the why as an exercise for the reader)
As an aside: the result does not change when
static is removed from String s = "One" in A, or
method public String getS() is removed from classes B and C, or
both of the above
Please read #Mike Nakis' answer as well.
One final remark on the code: the import-statements can be removed.

The static keyword in front of your variables probably isn't what you intended and it pushes you into a weird corner of Java's semantics.
Here's what you probably intended:
public class Test1 {
public static class A {
public String s = "One";
public int x = 10;
public String getS() {
return this.s;
}
}
public static class B extends A {
public B() {
this.s = "Two";
}
public String getS() {
return this.s;
}
}
public static class C extends B {
public C() {
this.s = "Three";
}
public String getS() {
return this.s;
}
}
public static void main(String[] args) {
A x = new C();
System.out.println("x.s = " + x.s);
System.out.println("x.getS() = " + x.getS());
}
}
This prints
x.s = Three
x.getS() = Three
as you'd expect.
The main difference between what you wrote and what I wrote is that without the static, we're declaring that every A has an s field; with static, we're saying that the concept of A-ness has an associated s idea. This is useful in some limited circumstances (for instance, the Java Integer class has a static field called MAX_VALUE because the maximum possible integer is associated with the concept of integers; every integer doesn't have its own individual max value), but it's probably not the first concept you want to learn.

There are, of course, rules for everything.
The expression x.s is problematic, because you are accessing a static field via an instance reference, and the compiler / IDE should have been issuing a warning for it. So, what this is telling me is that you are probably trying to compile java without important warnings enabled. Don't do that, if this way you go, only pain you will find. Read up on how to enable warnings on your compiler / IDE and enable as many of them as you possibly can.
The fix for the warning would be to replace x.s with A.s, and that would make clear exactly what is happening.
The s attribute that you are speaking of (more commonly referred to as 'field' in the java world) has been declared as static in some cases, but non-static in one case, and this does not look intentional. Generally, static is to be used only in very special cases, don't use it if you do not have a very good reason for doing so.
Also, some fields are final, some aren't, and this does not look intentional, either. You need to be very careful with these things.
Other than that, Turing85's answer basically covers it.

Related

Use a class field in a lambda [duplicate]

This question already has answers here:
Java lambdas have different variable requirements than anonymous inner classes
(3 answers)
Unexpected error using lambdas in Java 8
(1 answer)
Closed 5 years ago.
I don't understand this behavior.
This piece of code complies:
public class A {
private String s;
private Function<String, String> f = e -> s;
public A(String s) {
this.s = s;
}
}
But if I make s final, then I get a compiler error:
public class A {
private final String s;
private Function<String, String> f = e -> s; // Variable 's' might not have been initialized
public A(String s) {
this.s = s;
}
}
Why is that? If it were the other way around, I'd understand, but how is that the compiler complains when I declare a field final (which forces me to initialize its value in the constructor), and it's OK for it when it's not final?
It has nothing to do with the lambda, this example has the same error:
public class Test {
private final String a;
private String b = a; // // Variable 'a' might not have been initialized
public Test(String a) {
this.a = a;
}
}
It's because the initialization at the place of declaration is executed before the constructor. Therefore, at the place of the declaration of b, a is still not initialized.
It's clear when you use this example:
public class Test {
private String a = "init";
private String b = a;
public Test(String a) {
this.a = a;
}
public static void main(String[] args) {
System.out.println(new Test("constructor").b);
}
}
When you run it, it prints "init" (the value to which field a was originally assigned) and not "constructor" because the initialization of b took place before running the constructor.
The lambda from your example makes the it a bit more convoluted, because we could expect that since the access to a is deferred, it would be OK with the compiler, but apparently the compiler just follows the general rule of "don't access the variable before it's initialized".
You can bypass it using an accessor method:
public class Test {
private final String a;
private String b = getA(); // allowed now, but not very useful
private Function<String, String> f = e -> getA(); // allowed now and evaluated at the time of execution of the function
public Test(String a) {
this.a = a;
}
public static void main(String[] args) {
System.out.println(new Test("constructor").b); // prints "null"
System.out.println(new Test("constructor").f.apply("")); // prints "constructor"
}
public String getA() {
return a;
}
}
A non final member variable will always be initialized (since it has a default value - null in the case of your String variable), so there's no chance of it being uninitialized.
On the other hand, a final variable may only be initialized once, so I'm assuming it is not initialized to its default value.
The closest related thing I found is in JLS 4.12.4.:
4.12.4. final Variables
A variable can be declared final. A final variable may only be assigned to once. It is a compile-time error if a final variable is assigned to unless it is definitely unassigned immediately prior to the assignment
I assume we can understand this last sentence to mean that a final variable is not assigned a default value, since otherwise you'll get a compile time error at this.s = s;.
A better JLS reference (thanks to Holger) is JLS 16:
Chapter 16. Definite Assignment
For every access of a local variable or blank final field x, x must be definitely assigned before the access, or a compile-time error occurs.
The rational behind this requirement is that (in your example) the lambda expression could be invoked before s is initialized:
public A(String s) {
String v = f.apply("x"); // this.s is not initialized at this point
// so it can't be accessed
this.s = s;
}
Note that you can initialize the lambda expression in the constructor after initializing the final variable (I changed the name of the argument to be different than the member variable, so that the lambda expression won't grab that local variable):
public A(String so) {
// f = e -> s; // Error: The blank final field s may not have been initialized
this.s = so;
f = e -> s; // works fine
}
This also possible way to do
public class A {
private final String s;
private Function<String, String> f;
public A(String s) {
this.s = s;
this.f = e -> s;
}
}

Java Abstraction and Interfaces

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.

Overload Java Data Field Type by Another Field Type

Is it possible to overload a field type to be another field type?
If so, would it be possible to provide some examples?
You can't overload fields (only methods can be overloaded), you might be confused with overriding fields - which anyway is not possible, you end up hiding the fields from superclasses. Take a look at this post.
I believe that java supports interfaces, and interfaces should be able to help you achieve what you're trying to achieve
here's an example i found quick
here's a tutorial
just make sure that you're not overloading public members that way.
look at this code
class A<T> {
protected T field1;
}
class B extends A<String> {
public char field1;
public static void main(String[] args) {
A a = new B();
a.field1 = 12442;
}
}
it runs without any exception,
if field1 overrided, it should raise an exception, but it doesn't
and also this runs without any exception
class A<T> {
protected T field1;
}
class B extends A<Character> {
public char field1;
public static void main(String[] args) {
A a = new B();
a.field1 = 12442;
}
}
It's impossible
The Java language (JLS) does not allow it, but Java bytecode (JVMS) does
Oracle JDK 1.8.0_45 even relies on it to implement assert. For example:
public class Assert {
static final int[] $assertionsDisabled = new int[0];
public static void main(String[] args) {
System.out.println(int.length);
assert System.currentTimeMillis() == 0L;
}
}
generates two Oracle JDK 1.8.0_45, one explicit (int[]) and one synthetic (bool), and is happily able to distinguish between them. But if we had declared:
static final boolean $assertionsDisabled = false;
it would fail to compile with:
the symbol $assertionsDisabled conflicts with a compile synthesized symbo
See https://stackoverflow.com/a/31355548/895245 for more details.
Possible rationale why it's not possible
The problem is that it would not be possible to determine the type of the field. Consider:
void f(int i) { System.out.println("int"); }
void f(float i) { System.out.println("float"); }
int i;
float i;
// Which overridden method is called?
void m() { f(i); }

Java constructor of "immutable class" with many fields with default values?

I have a JAVA class with lots of fields. They should basically be set at the constructor phase and never change. Semantically the class then is an immutable one.
public class A{
final int a;
final short b;
final double e;
final String f;
final String g;
//and more
}
The problem is that normally these fields have default values and therefore I do not want to always burden the user with a constructor with all of them. Most time, they just need to set a couple of them. There are a couple of ways to solve this:
I would need lots of constructor with different signature.
Create a bunch of set method of these field and only set those non-default value. But this somehow indicate a different semantics other than immutable nature.
Create a new parameter class that is mutable and use that class as constructor.
None of that is totally satisfactory. Is there any other approach? Thanks.
One way
I would use a combination of a parameter class and a fluent builder API for creating the parameter:
public class A {
private final int a;
private final short b;
private final double e;
private final String g;
public static class Aparam {
private int a = 1;
private short b = 2;
private double e = 3.141593;
private String g = "NONE";
public Aparam a(int a) {
this.a = a;
return this;
}
public Aparam b(short b) {
this.b = b;
return this;
}
public Aparam e(double e) {
this.e = e;
return this;
}
public Aparam g(String g) {
this.g = g;
return this;
}
public A build() {
return new A(this);
}
}
public static Aparam a(int a) {
return new Aparam().a(a);
}
public static Aparam b(short b) {
return new Aparam().b(b);
}
public static Aparam e(double e) {
return new Aparam().e(e);
}
public static Aparam g(String g) {
return new Aparam().g(g);
}
public static A build() {
return new Aparam().build();
}
private A(Aparam p) {
this.a = p.a;
this.b = p.b;
this.e = p.e;
this.g = p.g;
}
#Override public String toString() {
return "{a=" + a + ",b=" + b + ",e=" + e + ",g=" + g + "}";
}
}
Then create instances of A like this:
A a1 = A.build();
A a2 = A.a(7).e(17.5).build();
A a3 = A.b((short)42).e(2.218282).g("fluent").build();
Class A is immutable, the parameters are optional, and the interface is fluent.
Two things you can do:
Many constructor overloads
Use a builder object
This is only a semi-serious suggestion, but we can modify mikera's answer to be typesafe.
Say we have:
public class A {
private final String foo;
private final int bar;
private final Date baz;
}
Then we write:
public abstract class AProperty<T> {
public static final AProperty<String> FOO = new AProperty<String>(String.class) {};
public static final AProperty<Integer> BAR = new AProperty<Integer>(Integer.class) {};
public static final AProperty<Date> BAZ = new AProperty<Date>(Date.class) {};
public final Class<T> propertyClass;
private AProperty(Class<T> propertyClass) {
this.propertyClass = propertyClass;
}
}
And:
public class APropertyMap {
private final Map<AProperty<?>, Object> properties = new HashMap<AProperty<?>, Object>();
public <T> void put(AProperty<T> property, T value) {
properties.put(property, value);
}
public <T> T get(AProperty<T> property) {
return property.propertyClass.cast(properties.get(property));
}
}
Aficionados of advanced design patterns and/or obscure Java tricks will recognise this as a typesafe heterogeneous container. Just be grateful i didn't use getGenericSuperclass() as well.
Then, back in the target class:
public A(APropertyMap properties) {
foo = properties.get(AProperty.FOO);
bar = properties.get(AProperty.BAR);
baz = properties.get(AProperty.BAZ);
}
This is all used like this:
APropertyMap properties = new APropertyMap();
properties.put(AProperty.FOO, "skidoo");
properties.put(AProperty.BAR, 23);
A a = new A(properties);
Just for the lulz, we can even give the map a fluent interface:
public <T> APropertyMap with(AProperty<T> property, T value) {
put(property, value);
return this;
}
Which lets callers write:
A a = new A(new APropertyMap()
.with(AProperty.FOO, "skidoo")
.with(AProperty.BAR, 23));
There are lots of little improvements you could make to this. The types in AProperty could be handled more elegantly. APropertyMap could have a static factory instead of a constructor, allowing a more fluent style of code, if you're into that sort of thing. APropertyMap could grow a build method which calls A's constructor, essentially turning it into a builder.
You can also make some of these objects rather more generic. AProperty and APropertyMap could have generic base classes which did the functional bits, with very simple A-specific subclasses.
If you're feeling particularly enterprise, and your domain objects were JPA2 entities, then you could use the metamodel attributes as the property objects. This leaves the map/builder doing a bit more work, but it's still pretty simple; i have a generic builder working in 45 lines, with a subclass per entity containing a single one-line method.
One interesting option is to create a constructor that takes a Map<String,Object> as input which contains the values that the user wants to specify.
The constructor can use the value provided in the map if present, or a default value otherwise.
EDIT:
I think the random downvoters have completely missed the point - this isn't always going to be the best choice but it is a useful technique that has several advantages:
It is concise and avoids the need to create separate constructors / builder classes
It allows easy programmatic construction of parameter sets (e.g. if you are constructing objects from a parsed DSL)
This is a technique that is frequently used and proven to work in dynamic languages. You just need to write decent tests (which you should be doing anyway!)
Having many fields could be an indication that one class does too much.
Maybe you can split the class up in several immutable classes and pass instances of these classes to the constructors of the other classes. This would limit the number of constructors.

What's the difference between getA() and this.getA()?

Assume that there is a class like the following.
public Class SomeClass {
private A getA() {
...
}
public void show() {
A a = getA(); // CASE #1
...
}
public void show2() {
A a = this.getA(); // CASE #2
...
}
Their result are same, isn't? My idiot co-worker insisted that's right!!(it means they're different.)
They're the same in this context. I'd advocate not using this since it's implied and it's just cluttering up the code by being there, but it makes no practical difference whether it's there or not.
It's not useless though. The this keyword is required sometimes, for instance:
When a local variable / parameter hides a field it's used to differentiate between them
When referring to the outer instance of a class from the inner instance (use Outer.this)
When using explicit generic types to call a method rather than just infered types (you can't just do <String, String>stringMethod(), it has to be this.<String, String>stringMethod().
That's by no means an exhaustive list, just serves as an example to demonstrate while it doesn't make a difference in this case, it can do in other cases!
Your co-worker isn't that much of an idiot after all, because they are the same. In the first case, Java implicitly implies this.
I will cite the best example of this pointer I came across in my school days.
class ThisChk
{
int param1;
public int check(int param1)
{
this.param1 = param1; //this.param1 is the class variable param1, param1 is the function parameter with a local scope
return 0;
}
}
Here's a case where you may want to use 'this' just to be clear.
class Outer {
A a;
public A getA() {
return a;
}
class InnerSuper {
A a;
public A getA() {
return a;
}
}
class Inner extends InnerSuper {
public void test() {
A a = Outer.this.getA();
A a = this.getA();
}
}
}

Categories