0

The program's purpose was to teach me how to create a character list, and practice using toString and booleanequals(object other).

public class CharList {

    private char[] Array =  new char[100];
    private int numElements = 0;
    public CharList() {
    
    }
    public CharList(String startStr){
        Array=startStr.toCharArray();
    }
 
    public CharList(CharList other){
        other.Array=new char[100];
    }
    public void add(char next) {
        Array[numElements++] = next;
    }
    public char get(int index) {
        return Array[index];
    }
    private int size() {
        return numElements; 
    }
    @Override
    public String toString() {
        String str = new String(Array); 
        return str;
    }

    public boolean equals(Object other) {

        if(other == null) {
            return false;
        }
        if(other instanceof CharList == false) {
            return false;
        }
        else {
            CharList that = (CharList) other;
            return this.Array == that.Array ; 
        }
    
    }

    public static void main(String[] args) {
        System.out.println("uncomment the code to use the charListDriver");
        CharList a = new CharList();
        CharList b = new CharList("Batman");
        CharList c = new CharList(b);
    
        a.add('k');
        a.add('a');
        a.add('t');
        a.add('n');
        a.add('i');
        a.add('s');
    
        System.out.println("a is :"+a.toString() +" and has " + a.size() + " chars");
        System.out.println("b is :"+b.toString() +" and has " + b.size() + " chars");
        System.out.println("c is :"+c.toString() +" and has " + c.size() + " chars")         
        System.out.println("B and A are equal : " + b.equals(a));
        System.out.println("B and C are equal : " + b.equals(c));       
    }
}
my output is: 
a is: katnis and has 6 chars
b is:     and has 0 chars
c is:     and has 0 chars

The main function was provided for me by my instructor. I don't understand why it is not printing out "batman".

BSMP
  • 4,596
  • 8
  • 33
  • 44

2 Answers2

0

2 Things to go over (plus a 0th thing):

0)

You need to have a getArray() function. Because Array is marked private, there is no way to access it from the outside. You can write other.Array, but because Array is private, it is better practice to use a getArray function. Adding a getArray() is the way to go. (it would be simple, and look like: getArray() {return this.Array;})

1)

Your constructors that you wrote that looks like:

public CharList() {
    
}
public CharList(CharList other){
    other.Array=new char[100];
}

is wrong. You should change these like so:

public CharList() {
    this.Array=new char[100];
}
public CharList(CharList other){
    this.Array=other.Array;
}

Here, we made the empty constructor initialize to a set char length of 100. For the other, we made it so that this.Array = other.Array by using other.getArray(). Now, if you try this, it should work.

2) Lets say you had this:

CharList batman1 = new CharList("batman");
CharList batman2 = new CharList("batman");

Then, java batman1.equals(batman2) would return false. This is because of pointers in java, and the way variable assignment works. for batman1.Array to equal batman2.array, it is not enough for their values to be equal. They also have to have to be pointing to the same thing. See Shallow copy for arrays, why can't simply do newArr = oldArr? for more info.

To fix this, we need a getArray(). Assuming we have it:

public boolean equals(Object other) {
    if(other == null) {
        return false;
    }
    if(!(other instanceof CharList)) {
        return false;
    }
    if(other.size()!=this.size()) {
        return false;
    }
    CharList that = (CharList) other;
    for (int i=0; i<other.size(); i++) {
        if (that.get(i)!=other.get(i)) return false;
    }
    return true; 

}

I did a lot of things here. First, we cleaned up the if statements. You don't need that else at the end. Then, I implemented what is known as a shallow check. It checks if the two Arrays have the same values. If everything is the same, then return true.

If you have followed all of these steps, then it should work.

Dharman
  • 30,962
  • 25
  • 85
  • 135
KarmaPenny
  • 164
  • 1
  • 13
  • A class is allowed to access its own private members. So other.Array is accessible. – Michael Welch Oct 17 '20 at 01:08
  • Okay, thanks for letting me know. I guess it makes sense, I've done it before, but it still is good practice to use a getArray function otherwise (outside of the equals checker). – KarmaPenny Oct 17 '20 at 01:10
  • adding `getArray` will completely break encapsulation. Don't expose your private implementation details without very good reason. Since Arrays are mutable if you add `getArray` any one can modify an instance of CharList by modifying the array returned. Hence why in my answer I'm cloning other.Array – Michael Welch Oct 17 '20 at 01:17
0

The issue is with your constructor that takes a CharList

public CharList(CharList other){
    other.Array=new char[100];
}

You see that it is setting other.Array equal to a new array of size 100.

So when you do this

CharList c = new CharList(b);

You are setting the Array of b to be a new array wiping out the array that contained the characters from "Batman".

If you fix the constructor in question to be

Array = other.Array.clone()

it'll fix the problem. I cloned the other array so that b and c aren't pointing to the exact same array. If they were then when you added chars to one, it would add chars to the other as well.

Next you'll see an issue with your size() method. It returns numElements but numElements isn't set in your constructors that take a String or a CharList so it's always 0. So be sure to set numElements in those constructors. You'll see that because of this error that when you call add on a CharList that was initialized form a String it changes the first char instead of adding it to the end.

I've only really answered the question about Batman and then size. But there are several other issues with this code as well.

  1. What happens if someone calls add more than 100 times on a CharList initialized with default constructor
  2. equals method is doing a reference equality check rather than making sure the chars in the arrays are identical
  3. What happens when you call add to a CharList instantiated with String or CharList? As I noted it currently changes the char at index 0. But even if you fix that and set numElements correctly what will happen? It'll try to write past the end of the Array.
Michael Welch
  • 1,754
  • 2
  • 19
  • 32
  • the instructor just want me to have 100 arrays, I added this.numElements = Array.length; to my constructor, but I still have issues with size() because it still print out 0 for the C is batman. – Tony Tong Oct 17 '20 at 01:48