initialise superclass array in subclass (java) - java

I am new to JAVA / Android programming and have a small problem.
I created in a Superclass a Array and wanted to initialize it in multiple subclasses. But when I try to initialize it, it says it's not possible.
My code:
public abstract class Fragen {
String[] Deutsch;
String[] Slowakisch;
static int Anzahl;
Random random;
int randNumber;
byte Fächer;
public String displayQuestion()
{
//TODO Fach abfragen
randNumber = random.nextInt(Anzahl);
return Slowakisch[randNumber];
}
public boolean correctAnswer(String answer)
{
//TODO Fächer +/-
if(answer.equals(Deutsch[randNumber]))
return true;
else
return false;
}
}
(Superclass)
public class Lektion1 extends Fragen
{
private Lektion1()
{
super();
Anzahl = 60;
//Deutsch = new String[];
Deutsch = {"",""};
Slowakisch = {"",""};
}
}
(Subclass)
Kind regards
Thomas

Try this:
public class Lektion1 extends Fragen
{
private Lektion1()
{
super();
Anzahl = 60;
//Deutsch = new String[];
Deutsch = new String[]{"", ""};
Slowakisch = new String[]{"", ""};
}
}

Just create a constructor in your super class and initialize that array there:
public abstract class Fragen {
...
public Fragen() {
Deutsch = new String[];
}
...
}
alternative
or if your fields have appropriate access modifiers, then you can also access them using super keyword
public abstract class Fragen {
public String[] Deutsch;
...
...
}
and in base class:
public class Lektion1 extends Fragen {
private Lektion1()
{
super();
Anzahl = 60;
super.Deutsch = new String[];
Deutsch = {"",""};
Slowakisch = {"",""};
}
}

Edit: For a conrete answer to your concrete question, #MrQuattro’s answer is of course correct and fulfilling.
That said, if you want to learn more of object-oriented design, I still myself like the ideas from my original answer. You can of course throw away or use as you see fit: I propose that it will be more convenient to keep the German and the Slovakian word together, so I’d make a class Frage to hold one word (or phrase or expression) in both languages.
Next I’d want to make a constructor in Fragen that accepts all the Frage objects, for instance as varargs (you should learn about those). This will allow the Lektion1 constructor to contain just
super(new Frage("", ""), new Frage("", ""), new Frage("", ""));
Fragen can count, so you don’t need to: the superclass constructor will set anzahl (please use lowercase a for a variable) to the number of questions received.
If you want to take it a step further, the Frage class could also be given the responsibility of checking whether an answer is correct.
Link: Anti-pattern: parallel collections

Related

Java - changing a variable through pass-by-value

So I've read about the pass-by-value nature of Java and I've tried to change my variable after passing it to a function by having the function return the variable again. I didn't succeed in that.
My code
public class Logic {
private int position;
public class Logic(){
position = 1;
}
public void appendPosition(){
position = calculatePosition(position);
}
}
This is the barebones code. I call this method from an instance of Logic which is instantiated in another class:
public class MainLogic {
ILogic L;
public MainLogic(ILogic L){
this.L = L;
}
public void start(){
L.appendPosition();
}
}
Through repeated debugging I find to my dismay that the position variable does not change at all. The position variable passed to calculatePosition changes fine, as expected. What am I missing? I've tried making the variable public and static.
calculatePosition
private int calculatePosition(int position){
position += 6;
if(snakeLocations[position]>0) {
position -= 6;
}
else if(ladderLocations[position]>0) {
position += 6;
}
return position;
}
private final int[] snakeLocations = new int[] {0,0,0,0,0,0,0,0,0,9,0,0,0,13,0,0,0,0,0,19,0,0,0,0,0};
private final int[] ladderLocations = new int[] {0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,15,0,0,0,0,20,0,0,0,0};
public class Logic {
private int position;
public Logic(){
position = 1;
}
//to get position.....................
public int getPosition(){
return this.position;
}
public void appendPosition(){
position = calculatePosition(position);
}
private int calculatePosition(int position){
position += 6;
if(snakeLocations[position]>0) {
position -= 6;
}
else if(ladderLocations[position]>0) {
position += 6;
}
return position;
}
private final int[] snakeLocations =
new int[] {0,0,0,0,0,0,0,0,0,9,0,0,0,13,0,0,0,0,0,19,0,0,0,0,0};
private final int[] ladderLocations =
new int[] {0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,15,0,0,0,0,20,0,0,0,0};
}
//next class
public class MainLogic {
Logic L;
public MainLogic(Logic L){
this.L = L;
}
public void start(){
L.appendPosition();
}
public static void main(String[] args) {
Logic L = new Logic();
MainLogic ml = new MainLogic(L);
System.out.println(ml.L.getPosition());
ml.start();
System.out.println(ml.L.getPosition());
}
}
Let's read your code.
// There is a logic class.
public class Logic {
// So Logic has a position. it starts with zero.
private int position;
// Logic also has an inner class, also called Logic.
public class Logic(){
position = 1;
// When a new Logic().Logic() is created, the instance
// variable of the parent instance gets set to one. WHAT?!?
}
// ... lots of code
}
So, It's a bit like that Yo Dawg! meme - I heard you like Logic, so we've put A logic instance into your Logic instance so you can Logic while your Logic.
You probably want a constructor.
// So this is Logic.
public class Logic {
private int position;
// When an Logic instance is created, position starts with 1.
public Logic(){
this.position = 1;
}
Ok. So we're not talking about Yo Dawg Memes.
So Let's talk pass by value.
Pass-by-value means classes are like very egotistic children: You can't play with their toys, unless they tell you so.
This is a good thing® since this means only the owning instance is allowed to change their private state. Trust me, it prevents quite a bit of havoc.
One way to allow the outside world to actually change the state is by using query and mutator methods. Back in the day, we used to call them getter and setter, but that sounds too simple, so software architects will usually use the fancier term.
But... all of this doesn't really apply since calculatePosition() is defined at Logic. Oops.
Let's try this:
Renaming some instance variables
Be a bit verbose to help the debugger. baby steps.
(Also, dropping a few jokes to fish for upvotes).
public class Logic {
private int position = 1;
public void appendPosition(){
// When debugging strange stuff,
// keep each step simple.
// Is calculatePosition working as it should?
int newPosition = calculatePosition(this.position);
this.position = newPosition;
}
// Always use parameters as final. It's good karma.
// You don't NEED to declare them as final,
// but let's try to be EXTRA clear.
private int calculatePosition(final int targetPosition){
// Yes, make as much as you can immutable
// You'll save a ton of mental bandwidth.
final int localCopy = targetPosition +6;
if(snakeLocations[localCopy]>0) {
return (localCopy -6);
// Don't force the maintenance programmer to
// read all your stuff. Return often, return early.
// This isn't Cc++, where you need to
// actually free your reference/pointers,
// so there's no point enforcing a single return.
}
if(ladderLocations[localCopy]>0) {
return (localCopy+6);
}
return localCopy;
}
}
So... Did this worked as it should?
I found the answer. This is often my mistake in posting here. I try to strip down my code as much as possible to ease the work for you guys, but sometimes the problem lies outside of the scope of what I provide due to a lack of understanding, or oversight, on my part.
I was actually calling MainLogic from two levels above:
public mainFrame() {
initComponents();
logic = Factory.getMainLogic();
}
where
public static class Factory {
public MainLogic getMainLogic(){
PlayerLogic pL = new PlayerLogic();
ImageLogic iL = new ImageLogic();
DieLogic dL = new DieLogic();
MainLogic mainLogic = new MainLogic(pL,iL,dL);
return mainLogic;
}
}
I forgot I had accidentally put Factory as static. My sincerest apologies for wasting your time.

Factory pattern use for instantiating a complex object of a single class

I have an object which is created on the basis of few conditions, like this -
if (objType.equals("one-type")) {
targetTableName = "one_type_table";
sourceTableName = "one_type_parent";
unitTime = 1;
delayTime = 10;
} else if (objType.equals("two-type")) {
targetTableName = "two_type_table";
sourceTableName = "two_type_parent";
unitTime = 2;
delayTime = 20;
}
Config databaseConfig = new Config(targetTableName, sourceTableName, unitTime, delayTime);
I have been told that my module has to be saved from this monstrosity and the pattern that can save me is Factory. So I decided to use that and create an interface like this -
public interface ConfigInterface {
public String getSourceTable();
public String getTargetTable();
public int getDelay();
public int getUnitTime();
}
and also created a concrete implementation of this interface called Config.
Then create a factory to build this object -
public class ConfigFactory {
public ConfigInterface getConfig (String objType) {
if (objType.equals("one-type")) {
targetTableName = "one_type_table";
sourceTableName = "one_type_parent";
unitTime = 1;
delayTime = 10;
} else if (objType.equals("two-type")) {
targetTableName = "two_type_table";
sourceTableName = "two_type_parent";
unitTime = 2;
delayTime = 20;
}
Config databaseConfig = new Config(targetTableName, sourceTableName, unitTime, delayTime);
return databaseConfig;
}
}
Now I just shifted my monster code inside another function. Even that is fine but my config interface is not really a superclass for many subclasses which are being generated by factory class. There is only one type of Config object, it has all those 5 fields and thats it.
I am sure I am either using it wrong or its not the right solution for this problem. Can anyone tell me whats wrong or is there another magical pattern to solve my problem and get me those ship its.
Why not encapsulate Config subclasses OneType and TwoType that set these values in their constructor. Then change the factory to the following:
public Config getConfig (String objType) {
if (objType.equals("one-type")) {
return new OneType ();
} else if (objType.equals("two-type")) {
return new TwoType ();
}
Alternatively, I use this pattern with enums for this kind of situation:
enum ConfigType {
one-type ("one_type_table", "one_type_parent", 1, 10),
two-type ("two-type_table", "two_type_parent", 2, 20)
;
ConfigType (String table, String parent, int unit, int delay) {
...
}
String getTable () {
return this.table;
}
....
}
Now you can generalize the factory code and work in terms of static enum types instead of runtime evaluated strings.
public Config getConfig (ConfigType type) {
return new Config (type.getTable (),...
The size of the code in the question is small, so any implementation would be as efficient as the other.
If the objType comes from different class instances, say TypeOne and TypeTwo, then you could overload the getConfig() method, e.g.
public ConfigInterface getConfig(TypeOne type)
{
// Create and return the "one-type" object
}
public ConfigInterface getConfig(TypeTwo type)
{
// Create and return the "one-type" object
}
Otherwise, especially if there are many different types, consider creating an enum with all the possible values to objType, as opposed to using a string. You can then use a switch statement, which is more efficient than the consecutive string equals checks.

Better way to call common method on randomly selected object in java

Nice day to everybody.
I have an abstract class with the method runRandomExercise(), and several classes that extends it to add different kind of exercise.
I now want to chose a random type exercise, so I need to randomly choose one of the classes, and call runRandomExercise() on that.
For now I am manually coding this, which is not the very best solution I think. However, I can’t store just the classes in the array since the class type is different, and if I use object[] I can’t call the runRandomExercise() method. Any smart way to handle this?
Here is my code till now. It works, but it’s gonna be a pain to add other classes...
/*Specific classes that extend abstract class TrainingClass with the runRandomExercise() method*/
private MatheMagic mMathMag;
private Mnemonics mMnemonics;
private String[] mTrainingClasses;
/*Initialize classes*/
mMathMag = new MatheMagic();
mMnemonics = new Mnemonics();
/*Manually store classe names*/
mTrainingClasses = new String[2];
mTrainingClasses[0] = "mMathMag";
mTrainingClasses[1] = "mMnemonics";
/*Return random exercise*/
public String[] RandomExercise() {
Random aGenerator = new Random();
/*Get random class name*/
int rnd = aGenerator.nextInt(mTrainingClasses.length);
String aChosen = mTrainingClasses[rnd];
String[] aRes = new String[2];
if (aChosen == "mMathMag") {
aRes = mMathMag.runRandomExercise();
} else if (aChosen == "mMnemonics") {
aRes = mMnemonics.runRandomExercise();
}
return aRes;
}
EDIT
Here is how TrainingClass is defined:
/** Common interface for all exercises */
public interface Exercise {
public String[] run();
}
/** Common interface for all training classes */
public abstract class TrainingClass {
private Random mRandGen = new Random();
public ArrayList<Exercise> mExerciseTypes = new ArrayList<Exercise>();
/** Run a random exercise */
public String[] runRandomExercise() {
int i = mRandGen.nextInt(mExerciseTypes.size());
return mExerciseTypes.get(i).run();
}
}
/*Specific training class*/
public class MatheMagic extends TrainingClass {
public MatheMagic() {
class SomeExercise implements Exercise {
public String[] run() {
String[] mRes = new String[2];
mRes[0] = "Question type 1";
mRes[1] = "Answer type 1";
return mRes;
}
}
class SomeOtherExercise implements Exercise {
public String[] run() {
String[] mRes = new String[2];
mRes[0] = "Question type 2";
mRes[1] = "Answer type 2";
return mRes;
}
}
SomeExercise mN = new SomeExercise();
SomeOtherExercise mS = new SomeOtherExercise();
mExerciseTypes.add(mN);
mExerciseTypes.add(mS);
}
}
Easy solution is to create an interface with the common method and have all your classes extend it.
Create a collection or array of that type instead of Object; you can simply iterate through or randomly select and call the method you want.
It feels like a Command pattern from GoF to me.
public interface Exercise {
void execute();
}
Now your classes do this:
public class MatheMagic implements Execise {
public void execute() {
// special logic here.
}
}
Then you can do this:
int numExercises = 1;
Exercise [] exercises = new Exercise[numExercises];
exercises[0] = new MatheMagic();
for (Exercise exercise : exercises) {
exercise.execute();
}
Yes, yes you can store all those Classes in an array and then call them at random. How? Create an interface and in all your classes derive from that interface. That way you can invoke based on interface, and not on implementation.

Setting an Enum value based on incoming String

I have a number of setter methods which take an enum. These are based on incoming objects attribute. Rather than write a bunch of these is there a way around having to hard code say 10 different case statements. Would there be a way to create a reusable method?
//Side class declared as
public final enum Side
//How I initialise side
static Side side = Side.SELL;//default
//method to set object
Obj.setSide(sideEnum(zasAlloc.getM_buySellCode()));
//How I am implementing it
public static Side sideEnum(String buysell)
{
if(buysell.equalsIgnoreCase("S"))
{
side = Side.SELL; //default
}
else if(buysell.equalsIgnoreCase("B"))
{
side = Side.BUY;
}
return side;
}
You can implement that functionality in your Enum.
public enum Side {
BUY("B"), SELL("S"), ...
private String letter;
private Side(String letter) {
this.letter = letter;
}
public static Side fromLetter(String letter) {
for (side s : values() ){
if (s.letter.equals(letter)) return s;
}
return null;
}
}
You could also do this as a helper static method if you can't edit Side.
public static Side fromString(String from) {
for (Side s: Side.values()) {
if (s.toString().startsWith(from)) {
return s;
}
}
throw new IllegalArgumentException( from );
}
The above method assumes your strings correspond to the names of you enums.
Enums have valueOf() method that can be used to convert from String. Is it what you are looking for?
I ended up using a simple object map:
private static HashMap<String, Side> sideMap = new HashMap<String, Side>(7);
static{
sideMap.put("B", Side.BUY);
sideMap.put("S", Side.SELL);
}
and simply using
Obj.setSide(sideMap.get(zasAlloc.getM_buySellCode()));
I think you need smth like:
Obj.setSide(Side.valueOf(zasAlloc.getM_buySellCode()));

How to model cycles between immutable class instances?

Immutable classes are great but there is one big problem i cant think of a sensible way to solve - cycles.
class Friend {
Set<Friend> friends();
}
How does one model Me having You as a friend who in turn has me as a Friend back ?
IMMUTABILITY
This class from the outside world should definitely be immutable. The value held internally should be constant for the purposes of equality checks.
[[[ Edit: Added code to demonstrate fully immutable concept ]]]
That's why builders are so nice for immutables - they allow mutability during construction to get everything set before you "freeze" it. In this case, I guess you need a Friend builder that supports creating cycles.
final FriendBuilder john = new FriendBuilder().setName("john");
final FriendBuilder mary = new FriendBuilder().setName("mary");
final FriendBuilder susan = new FriendBuilder().setName("susan");
john
.likes(mary)
.likes(susan);
mary
.likes(susan)
.likes(john);
susan
.likes(john);
// okay lets build the immutable Friends
Map<Friend> friends = FriendsBuilder.createCircleOfFriends(john, mary, susan);
Friend immutableJohn = friends.get("john");
Edit: Added immutable example below to demonstrate approach:
There was some discussion in the comments about whether an immutable version was possible.
Fields are final and immutable. A modifiable set is used in the constructor, but it only the unmodifiable reference is kept after construction.
I have another version that uses Guava ImmutableSet for a truly immutable set rather than JDK's unmodifiable wrapper. It works the same, but uses Guava's nice set builder.
Code:
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
/**
* Note: potentially cycle graph - be careful of deep equals/hashCode/toString/etc.
* Immutable
*/
public class Friend {
public static class Builder {
private final String name;
private final Set<Builder> friends =
new HashSet<Builder>();
Builder(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public Set<Builder> getFriends() {
return friends;
}
void likes(final Builder... newFriends) {
for (final Builder newFriend : newFriends)
friends.add(newFriend);
}
public Map<String, Friend> createCircleOfFriends() {
final IdentityHashMap<Builder, Friend> existing =
new IdentityHashMap<Builder, Friend>();
// Creating one friend creates the graph
new Friend(this, existing);
// after the call existingNodes contains all the nodes in the graph
// Create map of the all nodes
final Map<String, Friend> map =
new HashMap<String, Friend>(existing.size(), 1f);
for (final Friend current : existing.values()) {
map.put(current.getName(), current);
}
return map;
}
}
final String name;
final Set<Friend> friends;
private Friend(
final Builder builder,
final Map<Builder, Friend> existingNodes) {
this.name = builder.getName();
existingNodes.put(builder, this);
final IdentityHashMap<Friend, Friend> friends =
new IdentityHashMap<Friend, Friend>();
for (final Builder current : builder.getFriends()) {
Friend immutableCurrent = existingNodes.get(current);
if (immutableCurrent == null) {
immutableCurrent =
new Friend(current, existingNodes);
}
friends.put(immutableCurrent, immutableCurrent);
}
this.friends = Collections.unmodifiableSet(friends.keySet());
}
public String getName() {
return name;
}
public Set<Friend> getFriends() {
return friends;
}
/** Create string - prints links, but does not traverse them */
#Override
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append("Friend ").append(System.identityHashCode(this)).append(" {\n");
sb.append(" name = ").append(getName()).append("\n");
sb.append(" links = {").append("\n");
for (final Friend friend : getFriends()) {
sb
.append(" ")
.append(friend.getName())
.append(" (")
.append(System.identityHashCode(friend))
.append(")\n");
}
sb.append(" }\n");
sb.append("}");
return sb.toString();
}
public static void main(final String[] args) {
final Friend.Builder john = new Friend.Builder("john");
final Friend.Builder mary = new Friend.Builder("mary");
final Friend.Builder susan = new Friend.Builder("susan");
john
.likes(mary, susan);
mary
.likes(susan, john);
susan
.likes(john);
// okay lets build the immutable Friends
final Map<String, Friend> friends = john.createCircleOfFriends();
for(final Friend friend : friends.values()) {
System.out.println(friend);
}
final Friend immutableJohn = friends.get("john");
}
}
Output:
Node 11423854 {
value = john
links = {
susan (19537476)
mary (2704014)
}
}
Node 2704014 {
value = mary
links = {
susan (19537476)
john (11423854)
}
}
Node 19537476 {
value = susan
links = {
john (11423854)
}
}
The correct way to model a cycle is with a Graph. And a single source code line comment can be enough to enforce inmutability: "can't touch this".
What kind of inmutable enforcement are you looking for? Do you want a a velociraptor to appear whenever you modify the inmutable Set? The difference between mutable and inmutable is just a convention. However, the bits on the RAM can be easily modified and with the Reflection API you can break any encapsulation and data hiding conventions.
Ignoring the velociraptor for a moment, Java does not support an inmutable type. As a workaround, you need to model a datatype that behaves like one.
And for the inmutable property to make sense you need to make Friend an interface, having one implementing class: InmutableFriend, and the construction of the object should fully happen inside the constructor.
Then, since the graph contains cycles, before creating the final inmutable instances you need to store the graph nodes in some mutable temporary structure. You also need to return an unmodifiableSet on the InmutableFriend.friends() method.
Finally, to clone the graph you need to implement a Deep-copy algorithm like Breadth-first search on the Mutable graph. One question though is what happens when the graph is not fully connected.
interface Friend {
public Set<Friend> friends();
}
class MutableFriend {
private Set<MutableFriend> relations = new HashSet<MutableFriend>();
void connect(MutableFriend otherFiend) {
if (!relations.contains(otherFriend)) {
relations.add(otherFiend);
otherFriend.connect(this);
}
}
Friend freeze() {
Map<MutableFriend, InmutableFriend> table = ...;
/*
* FIXME: Implement a Breadth-first search to clone the graph,
* using this node as the starting point.
*
* TODO: If the graph is not connected this won't work.
*
*/
}
}
class InmutableFriend() implements Friend {
private Set<Friend> connections;
public Set<Friend> friends() {
return connections;
}
public InmutableFriend(Set<Friend> connections) {
// Can't touch this.
this.connections = Collections.unmodifiableSet(connections);
}
}
Immutability doesn't need to be compiler-enforced to be valid architecturaly. You can have a legitimate immutable object that takes post-construction initialization parameters. For instance...
private Object something;
public void init( final Object something )
{
if( this.something != null )
{
throw new IllegalStateException();
}
this.something = something
}
The member field "something" isn't final, but it cannot be set more than once either.
A more complex variant based on discussion in comments...
private boolean initialized;
private Object a;
private Object b;
public void init( final Object a, final Object b )
{
if( this.initialized )
{
throw new IllegalStateException();
}
this.initialized = true;
this.a = a;
this.b = b;
}
public Object getA()
{
assertInitialized();
return this.a;
}
public Object getB()
{
assertInitialized();
return this.b;
}
private void assertInitialized()
{
if( this.initialized )
{
throw new IllegalStateException( "not initialized" );
}
}

Categories