Inheritence - Mock Exam - java

I have this code:
class A {
protected int x;
public int getX() {
return x;
}
}
class B extends A {
private int answer;
public void someMethod() {
answer = x;
answer = this.x;
answer = this.getX();
answer = super.x;
answer = super.getX();
}
}
Which of the assignment statements in someMethod are valid?
I'm thinking that the two 'super' lines are correct?

Which of the assignment statements in someMethod are valid?
All of them.
x, this.x and super.x all point to protected int x in class A which is visible to the subclass B. this.getX() and super.getX() both call public int getX() in class A which is visible to the subclass B.
answer, x and the return value of getX() are all of type int, so the assignment is valid.

Related

Java - Setting Class Properties Before Super [duplicate]

This question already has answers here:
What's wrong with overridable method calls in constructors?
(8 answers)
Closed 2 years ago.
I have the follow classes:
public abstract class MyAbstractClass {
protected int x;
protected int number;
public MyAbstractClass(int x) {
this.x = x;
this.number = this.generateNumber();
}
public abstract int generateNumber(); // This class is called in the super constructor and elsewhere
}
public class MySubClass extends MyAbstractClass {
private int y;
public MySubClass(int x, int y) {
super(x);
this.y = y;
}
#Override
public int generateNumber() {
return this.x + this.y; // this.y has not been initialized!
}
}
My issue is that MySubClass's y property has to be initialized before the super constructor is run, because a method using y is run in the super constructor.
I am aware that this may not be possible even with some sneaky workaround, but I am yet to find an alternative solution.
Also please keep in mind that I will have many more derived classes, with different values being passed into their constructors.
You can defer the number calculation until it is needed.
public abstract class MyAbstractClass {
protected int x;
protected Integer number;
public MyAbstractClass(int x) {
this.x = x;
}
public int getNumber() {
if (number == null) {
number = generateNumber();
}
return number.intValue();
}
protected abstract int generateNumber();
}

final variable initialization in subClass

public class A {
final int x;
public A(int x) {
if ( this instanceof B ) {
if(x > 5)
this.x = x;
else
this.x = 0;
} else {
this.x = 0;
}
}
}
public class B extends A {
public B(int x) {
super(x);
}
}
I want to put the if in the class B to avoid instanceof ( because i have more sub classes and the x value depends on the subClass ), but when i do that i get compiler error: Constructor call must be the first statement in a constructor!
Can you help me avoid instanceof?
There are two ways we can initialize constants, first one is to initialize them in place on the same line as in the answer by Adam, second is to use constructors, which you're trying to implement.
Using inline initialization is generally more flexible because we are not bound to the rules of the constructor, like this(...) or super(...) call should be the first in the constructor. However if you do want to use constructor for the purpose you can use method containing logic as inline call as argument to the this(...) or super(...). This method should be static as the instance of the class doesn't exist yet as we're in constructor. Following is a simple solution for the same.
class A {
final int x;
public A(int x) {
this.x = 0;
}
}
class B extends A {
public B(int x) {
super(getValueForX(x));
}
private static int getValueForX(int x) {
return x > 5 ? x : 0;
}
}
Just create an abstract method in A and implement it in your derived classes like this:
public abstract class A {
final int x;
abstract int calculateX(int x);
public A(int x) {
this.x = calculateX(x);
}
}
public class B extends A {
#Override
int calculateX(int x) {
return x + 1;
}
public B(int x) {
super(x);
}
}

Java Spark Dataset autogen compile exception

I'm running into issues with Java Spark Dataset's groupByKey method. The following code, when run locally in a test environment (Spark 2.1.0, spark-core_2.11, spark-sql_2.11), throws the following exception:
java.lang.Exception: failed to compile: org.codehaus.commons.compiler.CompileException: File 'generated.java', Line 43, Column 21: No applicable constructor/method found for zero actual parameters; candidates are: "public int org.package.example.ExampleTest$1ExampleClass.getX()
Code is:
class ExampleClass implements Serializable {
private int x;
private int y;
public ExampleClass() {}
public ExampleClass(int x, int y) {this.x = x; this.y = y;}
public int getX() {return x;}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ExampleClass that = (ExampleClass) o;
if (x != that.x) return false;
return y == that.y;
}
#Override
public int hashCode() {
int result = x;
result = 31 * result + y;
return result;
}
}
ExampleClass exampleClass1 = new ExampleClass(1, 1);
ExampleClass exampleClass2 = new ExampleClass(1, 2);
ExampleClass exampleClass3 = new ExampleClass(1, 3);
List<ExampleClass> exampleClasses = Lists.newArrayList(
exampleClass1,
exampleClass2,
exampleClass3
);
Dataset<ExampleClass> dataset = spark.createDataset(exampleClasses, Encoders.bean(ExampleClass.class));
KeyValueGroupedDataset<Integer, ExampleClass> grouped = dataset.groupByKey(
(MapFunction<ExampleClass, Integer>) ExampleClass::getX,
Encoders.INT()
);
}
It looks like it can't find the default parameter-less constructor, or I'm leaving something out. Also interesting, if I change the ints to boxed Integers, it says the candidate is getY() not getX().
Any help is much appreciated!
EDIT: After messing around with it some more, moving ExampleClass out of a nested class in my test and into its own file fixes the problem. I still don't know why though so any answers are still appreciated.
I had the same issue. The problem in my case and I suspect in yours, is that your class isn't declared with the public modifier.
public class ExampleClass implements Serializable
Kudos to Andy Grove: https://www.mail-archive.com/user#spark.apache.org/msg55084.html

Objects override each other

I have the class GameObject:
public class GameObject{
private Coordinate coordinates;
public GameObject(){
coordinates = new Coordinate();
}
public void setCoordinates(int x, int y){
coordinates.x = x;
coordinates.y = y;
}
//More methods here
}
public class Coordinate{
public int x, y;
public Coordinate(){
}
public Coordinate(int x, int y){
this.x = x;
this.y = y;
}
public void setCoordinate(int x, int y){
this.x = x;
this.y = y;
}
And two classes Champion and Spell:
public class Spell extends GameObject{
//Some methods
}
public class Champion extends GameObject{
//Some methods
public Spell fireBall = new Spell();
}
And in my main class:
Champion character = new Champion();
If I call character.setCoordinates(200, 300); (just random numbers), the character goes to these exact coordinates. But the Spell fireBall also goes to (200, 300). So the coordinates in Spell are overriden by the setCoordinates(int x, int y) call to character. How is this possible?
TL;DR - Two classes from GameObject, Spell extends GameObject and Champion extends GameObject, override eachother coordinates. Why?
For full source code:
GameObject.java
Spell.java
Champion.java
Coordinate.java
Looking at your code in gitHub you have 2 methods:
//Set the coordinates for this GameObject
public void setCoordinates(int x, int y){
this.coordinates.x = x;
this.coordinates.y = y;
}
public void setCoordinates(Coordinate coordinates){
this.coordinates = coordinates;
}
If you ever use the 2nd one, then you are sharing the same instance of Coordinates so changing one will change the other
The solution is to copy the values instead
public void setCoordinates(Coordinate coordinates){
this.coordinates.x = coordinates.x;
this.coordinates.y = coordinates.y;
}
In the class Spell you set the coordinates:
this.startCoordinates = startCoordinates;
setCoordinates(this.startCoordinates);
Subsequently this code
if (getCoordinates().x - startCoordinates.x < range) {
is equivalent to
if (getCoordinates().x - getCoordinates().x < range) {
because getCoordinates() references the same object as startCoordinates does.
Your setter method just sets the reference, but it does not copy the object.

error: constructor Miclass in class Miclass cannot be applied to given types;

I'm trying to compile this in java and get this error: error: constructor Miclass in class Miclass cannot be applied to given types.
what's happening?
class Miclass {
public int x;
private int y;
protected int z;
public Miclass(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
}
public class A extends Miclass {
public static void main(String [] args) {
Miclass m_class = new Miclass(2, 4, 8);
System.out.println("m_class.x = " + m_class.x);
System.out.println("m_class.y = " + m_class.y);
System.out.println("m_class.z = " + m_class.z);
}
}
As there is already a constructor defined in Miclass you need to add a constructor in A that invokes this constructor in the super-class:
public class A extends Miclass {
public A(int x, int y, int z) {
super(x, y, z);
}
// methods/fields specific to `A`
...
}
The code will not compile after this change as the variable y is not visible to A. To allow the code to compile you can add a getter method to access the variable.
I have correct your code, try this, and read my explanation after..
class Miclass {
public int x;
private int y;
protected int z;
public Miclass(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public int getY()
{
return y;
}
}
public class A {
public static void main(String [] args) {
Miclass m_class = new Miclass(2, 4, 8);
System.out.println("m_class.x = " + m_class.x);
System.out.println("m_class.y = " + m_class.getY());
System.out.println("m_class.z = " + m_class.z);
}
}
Java provides default no-arg constructor only when there is no other constructor defined
In this case you have defined a constructor with 3 int arguments for class Miclass and you have not called it from class A which extends Miclass
due to this, when a default no-argument constructor will be provided to A class, a call to super no-argument will be done which is not possible because you do not have a no-argument constructor in Miclass
to solve these issues you will either have to create a no-arg constructor in superclass or create a constructor with 3 int arguments.
also your variable is not visible in class A because private variables are visible only in the same class

Categories

Resources