Java superclass variable and subclass copy constructor issue - java

I know that in Java due to inheritance, a superclass type variable can hold a reference to a subclass object. Example, say ClassA is the superclass to ClassB. You could set an element of a ClassA[] to reference a ClassB object. I'm running into a problem doing this while using a copy constructor of the subclass.
public Items copyFromMasterInventory(String str){
Items itemToReturn = null;
int length = masterInventory.length;
int iterator = 0;
while (iterator < length){
String name = masterInventory[iterator].getName();
if (name.equals(str)){
if (name.getClass().equals(Collectible.class)){
itemToReturn = new Collectible(masterInventory[iterator]);
}
if (name.getClass().equals(Props.class)){
itemToReturn = new Props(masterInventory[iterator]);
}
}
}
return itemToReturn;
}
In this case, there are three class. Items, Props, and Collectible. Props and Collectible are subclasses of Items. masterInventory is an array of Items storing both Collectible and Props objects. The purpose of this method is to create and return a copy of an item in the masterInventory array. To avoid .clone(), I've created copy constructors for Collectible and Props. But the way I have it now shows an incompatible types error, that Items cannot be converted to Collectible or Props, even though the object stored in that element is a Collectible or Props object. If been reading and searching for hours but can't seem to come up with a solution. Does anyone know a way around this issue? All help is appreciated.

You could add an abstract method Item getCopy() to the Item class, implement it in both Props and Collectible, and call it in de while loop:
itemToReturn = masterInventory[iterator].getCopy();
the benefit here is that you do not need the condition on class.

The solution is simple - casting :
if (masterInventory[iterator] instanceof Collectible) {
itemToReturn = new Collectible((Collectible) masterInventory[iterator]);
}
if (masterInventory[iterator] instanceof Props) {
itemToReturn = new Props((Props) masterInventory[iterator]);
}

Related

Java return datatype when class is stored in an array

This is my sample class
public class Value<E> {
public final E value;
public Value(E value) {
this.value = value;
}
}
And this returns a String and no Object, so I don't need to cast it.
String a = new Value<String>("test").value;
However, if I want to do this, then I need to cast it.
ArrayList<Value<?>> a = new ArrayList<>();
a.add(new Value<String>("test"));
String b = a.get(0).value; // Runtime error
If I add the value to the ArrayList it returns an Object, but I want it to return what I defined the Element to be.
How can I solve this?
Replace
ArrayList<Value<?>> a = new ArrayList<>();
with
ArrayList<Value<String>> a = new ArrayList<>();
You can't. You defined that you don't know (or care) what types are contained inside with Value<?>, so you can only treat them as Object as that's the one thing they're guaranteed to be (they can also be subclasses, but they'll still always be Objects too).
If you think and hope you can store Strings and Integers in the same List, that's not possible except by treating them as Objects. Besides, you shouldn't be storing different types (except through inheritance hierarchy) in the same collection anyway.

Transformation of an object into a subclass object without loosing the references to the object

This is my first problem I can't solve by searching. It's a general OOP problem, but the code is in java. Perhaps I miss an essential point?
Assume there is a baseclass and a subclass. An object of the baseclass is in many lists. There is a transformer class with one duty to transform the object into a subclass object. The transformer should not know anything about the lists. But as a result of the transformation the new subclass object should be in all the lists. (replace the former base class object)
Can this be done somehow?
class BaseClass {
//
}
class SubClass extends BaseClass{
//
}
class Transformer{
BaseClass base;
public Transformer(BaseClass base){
this.base = base;
}
public void transform(){
//transforms the Object to a subtype-object
// ???
// (move the references of the old object to the new one)
this.base = new SubClass(); //something like this (but not so!!!)
}
}
class Programm{
private List<BaseClass> list1 = new ArrayList<>();
private List<BaseClass> list2 = new ArrayList<>();
private List<BaseClass> list3 = new ArrayList<>();
//many more Lists
private List<BaseClass> listn = new ArrayList<>();
public void main() {
BaseClass myObject = new BaseClass();
list1.add(myObject);
list2.add(myObject);
list3.add(myObject);
listn.add(myObject);
Transformer transformer = new Transformer(myObject);
transformer.transform();
//required result
// All Lists contain the transformed Object (from Type SubClass)
}
}
What you're trying to do is luckily impossible (imagine if your objects started changing classes in the middle of your code). You can create a subclass object based on a superclass object (if you can sensibly fill in any missing properties), but you can't turn an existing object into its subclass (such that the reference equality would work as you're hoping in your example code, i.e. converting myObject would affect all the lists).
I don't know how you came up with this idea, but somewhere along the way you've gone down the wrong path. If you tell us what you're trying to achieve, we can provide you with a better solution.
Edit:
Since you're doing checkers and you need to crown a piece, you have the simple choice of adding a boolean crowned property to pieces, and writing logic based on that.
In a more complex situation you could for example use the strategy pattern, where you would have a Piece class, and they would have a Type property that specifies the actual type of the piece. This way the object you put in lists (Piece) always stays the same, but if you replace its Type property, it would seem as if the piece magically changes it's type!

Is it possible to iterate through an array list with elements of different data types and put them out?

Without generics it is possible to create an ArrayList with elements of different types. I want to iterate through it and put out the elements. I can not use a for-each-loop, because it wants a specific type. I tried Iterator but wasn't successful.
So I have two questions:
Is it possible to iterate through an array list and put out (e. g. with System.out.println) all elements no matter of which type they are?
Is it possible to iterate through an array list and put out only the elements which are of a specific type (e. g. only the Strings)?
Sure!
The toString method is defined on the Object class. The Object class is the base class of every user-defined class. You could easily write:
for (Object item: itemList) {
// prints all items
System.out.println(item);
if (item instanceof YourDesiredClass) {
YourDesiredClass specificItem = (YourDesiredClass) item;
//doSomethingElse(specificItem)
}
}
Is it possible to iterate through an array list and put out (e. g.
with System.out.println) all elements no matter of which file type
they are?
Yes, You can use the Object class
List<Object> myList = new ArrayList<>();
myList.add("Hello World"); // string
myList.add(Math.PI); // a double
myList.add(188); // an int
myList.add(9099099999999L); // a Long
// for java8
myList.forEach(System.out::println);
//before java8
for (Object object : myList) {
System.out.println(object);
}
Is it possible to iterate through an array list and put out only the
elements which are of a specific file type (e. g. only the strings)?
Yes, you can use the iterator and get the Object checking it against the class you need....
Iterator<Object> it = myList.iterator();
while (it.hasNext()) {
Object x = it.next();
if (x instanceof String) {
System.out.println("this is a String: " + x);
}
}
As far as I know, yes.
You can make ArrayList which contains Objects (see Java class Object), because each class you define in Java at least extends class Object which is a top class.
Now let me answer your questions:
yes, it is. Each object in the list knows which class it is instance of and has method toString(). When you swipe through ArrayList and call toString() for every object, the most specific method toString() will be called. For example, if it's instance of Integer (let's say it's called number) and you casted it to Object, call number.toString();, although compiler now looks at that number as the Object, it will call toString() method from Integer class. That's called dynamic polymorphism
yes, you can check which class is the Object instance of. Each of these objects has that info; casting it to Object class is just like saying to compiler "here is some object, I want you to look at it as an instance of class Object" - just like putting glasses to a compiler.
And object knows which class it is, so you can just ask, for example:
if(myObject instanceof String){
//do something;
}
Hope it helped, I tried to explain it the best way I could so you understand what's going on "under the hood" :)
Just object
new ArrayList<Object>().iterator().forEachRemaining(element -> {
System.out.println(element);
});
A specific type
new ArrayList<Object>().stream().filter(element -> element instanceof String).iterator()
.forEachRemaining(System.out::println);
Edit: this answer requires Java 8
Is it possible to iterate through an array list and put out (e. g. with System.out.println) all elements no matter of which file type they are?
Sure, you can iterate a list (or arraylist) of Objectclass and do what you need.
Is it possible to iterate through an array list and put out only the elements which are of a specific file type (e. g. only the strings)?
Yes, you can use instanceof and do specific actions for specific classes.
Usage example:
List<Object> genericList = new ArrayList<>();
genericList.add("test");
genericList.add(2);
genericList.add('c');
for (Object object: genericList) {
// "Put" out object (question 1)
System.out.println(object);
// Check object type (question 2)
if (object instanceof AnyClass) {
//doSomething()
}else if (object instanceof AnotherClass){
//doSomethingElse()
}
}
You can always use a Type all the Objects have in common. The last one will always be Object, since every Class extends Object.
But since we don't like to cast it's mostly the better approach to build a basic class for that:
public abstract class FileType
{
public abstract String getTypeName();
public abstract String getTypeDescription();
}
public class JSON extends FileType
{
#Override
public String getTypeName()
{
return "JSON";
}
#Override
public String getTypeDescription()
{
return "JavaScript Object Notation";
}
}
public class TXT extends FileType
{
#Override
public String getTypeName()
{
return "TXT";
}
#Override
public String getTypeDescription()
{
return "Textfile";
}
}
Now you can make a List of FileType's and use the Methods of it:
List<FileType> fileTypes = new ArrayList<>();
list.add(new JSON()); // JSON fits good in here
list.add(new TXT()); // TXT also
for (FileType fileType : list)
{
System.out.println(fileType.getTypeName()); // have the FileType-Methods savely available
}

Java Object reference

This is regarding the usage of ArrayList returned by another class instance variable.
Class A {
//assigned list of string to it.
private List < String > newAl;
//returns the list
public List < String > getList() {
return newA1;
}
}
Class Test {
public void go() {
List < String > list = a.getList();
list.add("");
}
}
In the Test class when i retreive list and manipulate the list.Because of the reference ,class A list also got manipulated.If A is part of third party code.How do I correct my code in Test class so that original object wouldnt be affected?
The ArrayList constructor takes a Collection so you can use that:
List<String> list = new ArrayList(a.getList());
I think it's better to do it like this, but depending on what you're doing, you may want to construct the new List in the getter. That also helps type hiding.

In Java, Is it possible to concatenate the value of a variable into a variable name (Sounds messed up, but please read details)

Basically I have a variable, zlort = one;
I want to concatenate the value of zlort into a variable (object reference) name.
Like
BankAccount Accountzlort = new BankAccount;
I want the zlort in Account.zlort to actually be the replaced with value of zlort (one--meaning I want the value to be Accountone), and not zlort itself.
Is it possible to do this?
Thanks!
No you can't, but you might put the instance in a map:
Map<String,BankAccount> map = new HashMap<String,BankAccount>();
map.put("Account" + zlort, new BankAccount());
If you mean dynamically choosing the name to assign a variable to, then no.
You could use a HashMap to achieve the same effect.
It is not possible to change the name of a variable at runtime. That would lead to extreme security and stability problems when dealing with any real-world application.
However, as the two answers here have mentioned, a HashMap might acheive what you are looking for. (See the javadoc!!)
A HashMap (or any other map, for that matter) maps a Key to a Value. The concept is similar to a variable, which is a name -> value mapping. The only difference is that variables are part of the actual program code, which is effectively unmodifiable after compiling. A Map is a data structure that can be modified by the running program. This allows you to freely add key-value pairings to it.
Note that in Java, type-safety is encouraged through the use of Generics. Basically this ensures that the key can only be of one type (e.g. String) and the value can be of only one type (BankAccount). A thorough coverage of Generics can be found here.
You would declare this as follows:
Map<String, BankAccount> accounts = new HashMap<String, BankAccount>();
And then to add a key-value pair to the map, you would use the put() method (which 'puts' a value into the map, associated with a key)
String key = "Key"
BankAccount value = new BankAccount();
accounts.put(key, value);
To retrieve it, you would use the get() method.
BankAccount retrievedValue;
retrievedValue = accounts.get(key);
After reading the explanations in your comments, the fact that you can't use an array but can use an `ArrayList'...
Rather than creating a new variable name (or array element, or map value) for each BankAccount, you can probably use scope to your advantage.
Scope is the concept that a reference to a variable only has meaning within a certain part of code. If you declare a variable inside a method, that variable can only be seen within that method. A variable declared within a block (a loop, if statement, etc ) can only be seen from within that block.
Class fields have a different kind of scoping that can be adjusted with keywords (see here).
For example:
public class ScopeExample
int classInt = 10;
public void method() {
int methodInt = 0; // This integer can only be seen by code in
// this method
}
public void method2() {
//doSomething(methodInt) // This line won't compile because i is
// declared in a different method!
doSomething(classInt); // This line will compile and work
// because x is declared in the class that
// contains this method.
int index = 0;
while (index < 3) {
int whileInt = index; // This integer can only be seen from within
// this while loop! It is created each
// loop iteration.
doSomething(whileInt);
}
doSomething(whileInt); //This line won't work, whileInt is out of scope!
}
public doSomething(int a) {
System.out.println(a);
}
}
SO! If you create a BankAccount object within the loop, you don't have to worry about creating a new name for the next one. Each time the loop iterates it will become a new object (when you create it).
If you have to store it, you definitely will need to use an array or other data structure (ArrayList!).
Building on the idea of scope, you -can- have the same variable name for each new BankAccount. A variable reference name isn't guaranteed to be paired with the object that it refers to. That is a convenience to the programmer, so you don't have to know the exact memory address it is being stored in.
For example:
public static void main(String[] args) {
Object o;
int i = 0;
while (i < 5) {
Object reference = new Object(); // Create a new Object and store
// it in 'reference'
o = obj; // The Object 'o' now refers to the object in 'reference'
i++;
}
System.out.println(o); // This should print information about the
// LAST object created.
}
The new Object created in the loop does not belong to 'obj'. You as a programmer use 'obj' to point to the Object. The program doesn't really know what obj means, other than the fact that it points to the Object you just created.
Finally, you can use this along with an ArrayList to make your life easier.
public static void main(String[] args) {
// Our new ArrayList to hold our objects!
ArrayList<Object> stuff = new ArrayList<Object>();
int i = 0;
while (i < 5) {
Object obj = new Object(); // Create an object and make obj point to it.
stuff.add(obj); // Put "the object that 'obj' points to" in 'stuff'.
i++;
}
// This loop goes through all of the Objects in the ArrayList and prints them
for (int index = 0; index < stuff.size(); index++) {
System.out.println(stuff.get(i)); // This will print a single
// object in the ArrayList each time.
}
}

Categories