The practice of deep clone failed - java

I tried to make a deep clone via overridong the clone method, but the result is not how a deep clone behaves(blanks and oldBlanks should print differently).
It is supposed to print:
192, []
1_2, [1]
It actually prints:
192, []
192, []
An MCVE is presented.
import java.util.ArrayList;
public class Program {
static class Blank implements Cloneable {
#Override
protected Blank clone() {
Blank b = new Blank(this);
return b;
}
public Blank(String str) {
origin = str;
uradix = str.length();
String strn = str.replaceAll("_","0");
existed = Integer.parseInt(strn);
for (int i = 0; i < uradix; i++) {
int radix = uradix - i;
if (str.charAt(i) == '_'){
not_existed.add(radix-1);
}
}
}
public Blank(Blank b){
this.origin = b.origin;
this.uradix = b.uradix;
this.existed = b.existed;
for (Integer i :
b.not_existed) {
int k = i;
this.not_existed.add(k);
}
}
String origin;
int uradix;
int existed;
ArrayList<Integer> not_existed = new ArrayList<>();//remain sequence: ->, i.e. left to right
}
static Blank[] copy(Blank[] ts){
for (Blank t :
ts) {
t = t.clone();
}
return ts;
}
public static void main(String[] args) {
Blank[] blanks = {new Blank("1_2"),new Blank("_2"),new Blank("_2_")};
Blank[] oldBlanks = copy(blanks);
StringBuilder sb = new StringBuilder(blanks[0].origin);
System.out.println("before the change");
System.out.println(blanks[0].origin+", "+blanks[0].not_existed);
System.out.println(oldBlanks[0].origin+", "+oldBlanks[0].not_existed);
int index = 1;
sb.replace(index,index+1,"9");
blanks[0] = new Blank(sb.toString());
System.out.println("after the change");
System.out.println(blanks[0].origin+", "+blanks[0].not_existed);
System.out.println(oldBlanks[0].origin+", "+oldBlanks[0].not_existed);
}
}
p.s. My tutor said that a static class used in such a pattern is weird, but that should not be the problem because the problem reproduces even if I modify the class Blank outside non-static.

It's not your clone method that causes the problem, bBut rather the way you implemented your copy.
You return the original Blank[] reference and then adapt it.
If you do this:
static Blank[] copy(Blank[] ts){
Blank[] ts_copy = new Blank[ts.length];
for (int i=0; i<ts.length; i++) {
ts_copy[i] = ts[i].clone();
}
return ts_copy;
}
Then I get an output like this:
before the change
1_2, [1]
1_2, [1]
after the change
192, []
1_2, [1]

Related

Printing on same line

I am new to Java and I am trying to print the student numbers and numbers (cijfer in this case) on 1 line. But for some reason I get weird signs etc. Also when I'm trying something else I get a non-static context error. What does this mean and how does this exactly work?
Down here is my code:
import java.text.DecimalFormat;
import java.util.Arrays;
public class Student {
public static final int AANTAL_STUDENTEN = 50;
public int[] studentNummer = new int[AANTAL_STUDENTEN];
public String[] cijfer;
public int[] StudentNummers() {
for (int i = 0; i < AANTAL_STUDENTEN; i++) {
studentNummer[i] = (50060001 + i);
}
return studentNummer;
}
public String[] cijfers(){
for (int i = 0; i < AANTAL_STUDENTEN; i++) {
DecimalFormat df = new DecimalFormat("#.#");
String cijferformat = df.format(Math.random() * ( 10 - 1 ) + 1);
cijfer[i++] = cijferformat;
}
return cijfer;
}
public static void main(String[] Args) {
System.out.println("I cant call the cijfer and studentnummer.");
}
}
Also I'm aware my cijfer array is giving a nullpointer exception. I still have to fix this.
I am not java developer but try
System.out.print
You could loop around System.out.print. Otherwise make your functions static to access them from main. Also initialize your cijfer array.
Besides the things I noted in the comments, your design needs work. You have a class Student which contains 50 studentNummer and cijfer members. Presumably, a Student would only have one studentNummer and and one cijfer. You need 2 classes: 1 for a single Student and one to hold all the Student objects (StudentBody for example).
public class StudentBody {
// An inner class (doesn't have to be)
public class Student {
// Just one of these
public int studentNummer;
public String cijfer;
// A constructor. Pass the student #
public Student(int id) {
studentNummer = id;
DecimalFormat df = new DecimalFormat("#.#");
cijfer = df.format(Math.random() * ( 10 - 1 ) + 1);
}
// Override toString
#Override
public String toString() {
return studentNummer + " " + cijfer;
}
}
public static final int AANTAL_STUDENTEN = 50;
public Student students[] = new Student[AANTAL_STUDENTEN];
// StudentBody constructor
public StudentBody() {
// Create all Students
for (int i = 0; i < AANTAL_STUDENTEN; i++) {
students[i] = new Student(50060001 + i);
}
}
// Function to print all Students
public void printStudents(){
for (int i = 0; i < AANTAL_STUDENTEN; i++) {
System.out.println(students[i]);
}
}
public static void main(String[] Args) {
// Create a StudentBody object
StudentBody allStudents = new StudentBody();
// Print
allStudents.printStudents();
}
}
Just make all your methods and class variables as static. And then you have access to them from main method. Moreover you have got some errors in code:
public class Student {
public static final int AANTAL_STUDENTEN = 50;
// NOTE: static variables can be moved to local ones
// NOTE: only static method are available from static context
public static int[] StudentNummers() {
int[] studentNummer = new int[AANTAL_STUDENTEN];
for (int i = 0; i < AANTAL_STUDENTEN; i++)
studentNummer[i] = 50060001 + i;
return studentNummer;
}
// NOTE: only static method are available from static context
public static String[] cijfers() {
// NOTE: it is better to use same `df` instance
DecimalFormat df = new DecimalFormat("#.#");
String[] cijfer = new String[AANTAL_STUDENTEN];
for (int i = 0; i < AANTAL_STUDENTEN; i++)
// NOTE: remove `i++`, because we have it in the loop
cijfer[i] = df.format(Math.random() * (10 - 1) + 1);
return cijfer;
}
// NOTE: this is `static` method, therefore it has access only to static methods and variables
public static void main(String[] Args) {
String[] cijfer = cijfers();
int[] studentNummer = StudentNummers();
// TODO you can pring two arrays one element per line
for(int i = 0; i < AANTAL_STUDENTEN; i++)
Sytem.out.println(cijfer[i] + '-' + studentNummer[i]);
// TODO as alternative, you can print whole array
System.out.println(Arrays.toString(cijfer));
System.out.println(Arrays.toString(studentNummer));
}
}

All combination of string char

I have string and i need to print all the combination of the string Char's
Example
For the string "123" the output is:
1,2,3,12,13,21,23,31,32,123,132,213,231,312,321
It must be without loops, only with recursion.
Thanks!
public class CharacterRecursion
{
private String str;
private int counter;
public CharacterRecursion()
{
str = "";
counter = 0;
}
public CharacterRecursion(String str1)
{
str = str1;
counter = 0;
}
public String recurse(String str)
{
if (counter == 15)
{
return ;
}
counter++;
// return (recurse(String str _________) _________) _________;
}
public String [] toString()
{
String [] arr = new String[14];
for (int i = 0; i < 14; i++)
{
arr[i] = this.recurse();
}
return arr;
}
public static void main(String [] args)
{
CharacterRecursion recurse = new CharacterRecursion("123")
System.out.println(recurse.toString);
}
}
I think just giving you the full code would be a little to easy for you. This is the simple set up for the code that you would want. The recurse method is not completely finished, the return statement being one of the things that you will need to fix first. By answer the question, this way, I hope that I am still answering the question, but also still allowing you to fully learn and understand recursion on your one. By the way,
for the public static void main(String [] args) part
You would also put that in a separate class like so:
public class CharacterRecursion
{
private String str;
private int counter;
public CharacterRecursion()
{
str = "";
counter = 0;
}
public CharacterRecursion(String str1)
{
str = str1;
counter = 0;
}
public String recurse(String str)
{
if (counter == 15)
{
return ;
}
counter++;
// return (recurse(String str _________) _________) _________;
}
public String [] toString()
{
String [] arr = new String[14];
for (int i = 0; i < 14; i++)
{
arr[i] = this.recurse();
}
return arr;
}
public class CharacterRecursionClient
{
public static void main(String [] args)
{
CharacterRecursion recurse = new CharacterRecursion("123")
System.out.println(recurse.toString);
}
}
That would work just as well if you are required to have a client class. I hope that this help and cleared up at least a couple of things.

How to increase size of array [a][b] every time I call a method?

public static int arraysize=1;
public String namabuku;
public String penulis;
public String Kategori;
public String buku[][]=new String[arraysize][3];
public static int a=0;
public void isiData(String kategori, String buku, String penulis){
this.buku[a][0]=kategori;
this.buku[a][1]=buku;
this.buku[a][2]=penulis;
arraysize++;
a++;
}
Hi guys I tried to increase my array length every time I call a method named "isiData", but it didn't work. I already checked the increment, but nothing wrong with it. Is there any way to increase its length every time I use the method? I want to make a simple way to input book, category, and its author using array.
You cannot increase the size of array.
There are 3 approaches to solve this problem:
Use ArrayList as suggested by others.
You can create another temp array of size one greater than the previous array and then copy the temp array to already created array.
You can use the copyOf(array, size) function of Arrays in Java
For example:
previousArray = Arrays.copyOf(previousArray , arraysize + 1);
arraysize += 1
Just try this Approach:
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
/**
*
* #author Maverick
*/
public class Buku {
public static int arraysize;
public String namabuku;
public String penulis;
public String Kategori;
public List<List<String>> bukuList = new ArrayList<List<String>>();
public static void main(String[] args) {
Buku n = new Buku();
for (int i = 0; i < 5; i++) {
n.isiData("ab" + i, "cd" + i, "ef" + i);
}
n.arraysize = n.bukuList.size();
for (int i = 0; i < n.bukuList.size(); i++) {
System.out.println(n.bukuList.get(i).toString());
}
}
public void isiData(String kategori, String buku, String penulis) {
bukuList.add(Arrays.asList(kategori, buku, penulis));
}
}
Output:
[ab0, cd0, ef0]
[ab1, cd1, ef1]
[ab2, cd2, ef2]
[ab3, cd3, ef3]
[ab4, cd4, ef4]
You have to call new array to change the size of an array. I assume this is an exercise to practice using an array, so I'm going to avoid the classes like Arrays and System in the isiData method. You should look at those classes though.
So something like this:
public class BukuTest
{
public String namabuku;
public String penulis;
public String Kategori;
public String buku[][] = new String[ 0 ][ 3 ];
public void isiData( String kategori, String buku, String penulis )
{
String[][] temp = this.buku;
final int len = temp.length;
this.buku = new String[ len + 1 ][];
for( int i = 0; i < len; i++ )
this.buku[i] = temp[i];
this.buku[len] = new String[ 3 ];
this.buku[len][0] = kategori;
this.buku[len][1] = buku;
this.buku[len][2] = penulis;
// not needed
// arraysize++;
// a++;
}
public static void main(String[] args) {
BukuTest b = new BukuTest();
b.isiData( "test1", "test2", "test3" );
b.isiData( "test4", "test5", "test6" );
b.isiData( "test7", "test8", "test9" );
System.out.println(b);
}
#Override
public String toString()
{
return "BukuTest{" + "namabuku=" + namabuku + ", penulis=" + penulis +
", Kategori=" + Kategori + ", buku=" +
Arrays.deepToString(buku) + '}';
}
}
Using an ArrayList is definitely the way to go here as others have commented and displayed but, if you are absolutely bent on using a Two Dimensional String Array then this can be done with a custom method conveniently named redimPreserve() as I have shown below.
As #Jdman1699 had mentioned in his comment under your post, this is a very inefficient way of doing this sort of thing especially for larger arrays but since you asked, here is how it can be done:
// YOUR METHOD:
public int arraysize = 1;
public String[][] buku = new String[arraysize][3];
public void isiData(String kategori, String buka, String penulis){
// I have renamed the buku argument for this method to buka
// since you can not have a parameter variable named the
// same as a Class Global variable.
buku = redimPreserve(buku, arraysize, 3);
buku[arraysize-1][0] = kategori;
buku[arraysize-1][1] = buka;
buku[arraysize-1][2] = penulis;
arraysize++;
}
// THE redimPreserve() METHOD:
public static String[][] redimPreserve(String[][] yourArray, int newRowSize, int... newColSize) {
int newCol = 0;
if (newColSize.length != 0) { newCol = newColSize[0]; }
// The first row of your supplied 2D array will always establish
// the number of columns that will be contained within the entire
// scope of the array. Any column value passed to this method
// after the first row has been established is simply ignored.
if (newRowSize > 1 && yourArray.length != 0) { newCol = yourArray[0].length; }
if (newCol == 0 && newRowSize <= 1) {
throw new IllegalArgumentException("\nredimPreserve() Method Error!\n"
+ "No Column dimension provided for 2D Array!\n");
}
if (newCol > 0 && newRowSize < 1 && yourArray.length != 0) {
throw new IllegalArgumentException("\nredimPreserve() Method Error!\n"
+ "No Row dimension provided for 2D Array!\n");
}
String[][] tmp = new String[newRowSize][newCol];
if (yourArray.length != 0) {
for(int i = 0; i < yourArray.length; i++) {
System.arraycopy(yourArray[i], 0, tmp[i], 0, yourArray[i].length);
}
}
return tmp;
}

Why is my class variable rewriting itself after an unrelated method runs?

So I'm writing a basic MasterMind game that is... mostly functional. However, its exhibiting odd behavior and I'm unsure why.
The idea is that what defines a Code and its behavior is one file, the gameplay is another, and the Main just creates a new game and starts playing. When I initialize the game, the computer creates a new random string of 4 (the "secret code"), as expected; but then once I get input for the User guess, it seems to rewrite the secret code into whatever I've input. Further, my methods for evaluating matches don't work at all, but considering that the secret code keeps changing means that it's not being set to begin with, and I'm unsure why.
All three classes below. Why is my class variable in Game not setting properly and accessible to the other methods?
Main.java
class Main {
public static void main(String[] args) {
Game newGame = new Game();
newGame.play();
}
}
Code.java
import java.util.Random;
import java.util.HashMap;
import java.util.Collection;
import java.util.ArrayList;
import java.util.Set;
import java.lang.Math;
import java.lang.StringBuilder;
class Code {
private static HashMap<String,String> PEGS;
private static ArrayList<String> pegStrings;
protected static String secretCodeString;
public static void main(String[] args) {
}
public Code(String input){
this.secretCodeString = input;
}
public Code(){
randomize();
}
//literally just creates the peghash
public static void setPegs(){
PEGS = new HashMap<String,String>();
PEGS.put("C","c");
PEGS.put("Y","y");
PEGS.put("R","r");
PEGS.put("P","p");
PEGS.put("O","o");
PEGS.put("G","g");
}
//turns the pegs ito something randomize can use
public static ArrayList<String> makePegArray(){
setPegs();
pegStrings = new ArrayList<String>();
Collection<String> pegValues = PEGS.values();
Object[] pegObjects = pegValues.toArray();
for (int i = 0; i < pegObjects.length; i++){
pegStrings.add(pegObjects[i].toString());
}
return pegStrings;
}
// sets Class Variable secretCode to a four letter combination
public static Code randomize(){
secretCodeString = new String();
Random rand = new Random();
int randIndex = rand.nextInt(makePegArray().size());
for (int i = 0; i < 4; i++){
randIndex = rand.nextInt(makePegArray().size());
secretCodeString = secretCodeString.concat(makePegArray().get(randIndex));
}
Code secretCode = parse(secretCodeString);
return secretCode;
}
public static Code parse(String input) {
setPegs();
makePegArray();
String[] letters = input.split("");
StringBuilder sb = new StringBuilder();
for (String letter : letters) {
if (pegStrings.contains(letter)) {
sb.append(letter);
} else {
System.out.println(letter);
throw new RuntimeException();
}
}
String pegListString = sb.toString();
Code parsedCode = new Code(pegListString);
//System.out.println(parsedCode);
return parsedCode;
}
public int countExactMatches(Code guess){
String guessString = guess.secretCodeString;
int exactMatches = 0;
String[] guessArray = guessString.split("");
String[] winningCodeArray = (this.secretCodeString).split("");
for(int i = 0; i < 4; i++){
if(guessArray[i] == winningCodeArray[i]){
exactMatches++;
}
}
return exactMatches;
}
public int countNearMatches(Code guess) {
String guessString= guess.secretCodeString;
HashMap<String,Integer> guessCount = new HashMap<String,Integer>();
HashMap<String,Integer> secretCodeCount = new HashMap<String,Integer>();
Set<String> codeKeys = guessCount.keySet();
int matches = 0;
int keys = guessCount.keySet().size();
String[] keyArray = new String[keys];
for(int i = 0; i < guessString.length(); i++) {
//removes character from string
String codeCharacter = String.valueOf(guessString.charAt(i));
String guessShort = guessString.replace(codeCharacter,"");
//counts instances of said character
int count = guessString.length() - guessShort.length();
guessCount.put(codeCharacter, count);
}
for(int i = 0; i < secretCodeString.length(); i++) {
//removes character from string
String winningString = this.secretCodeString;
String winningCodeCharacter = String.valueOf(winningString.charAt(i));
String winningCodeShort = guessString.replace(winningCodeCharacter,"");
//counts instances of said character
int count = winningString.length() - winningCodeShort.length();
secretCodeCount.put(winningCodeCharacter, count);
}
for (int i = 0; i < keys; i++) {
codeKeys.toArray(keyArray);
String keyString = keyArray[i];
if (secretCodeCount.containsKey(keyString)) {
matches += Math.min(secretCodeCount.get(keyString), guessCount.get(keyString));
}
}
int nearMatches = matches - countExactMatches(guess);
return nearMatches;
}
}
Game.java
import java.util.Scanner;
class Game {
protected static Code winningCode;
public static void main(String[] args){
}
public Game(){
winningCode = new Code();
}
protected static Code getGuess() {
Scanner userInput = new Scanner(System.in);
int count = 0;
int maxTries = 5;
while(true){
try {
String codeToParse = userInput.next();
Code guess = Code.parse(codeToParse);
return guess;
} catch(RuntimeException notACode) {
System.out.println("That's not a valid peg. You have " + (maxTries - count) + " tries left.");
if (++count == maxTries) throw notACode;
}
}
}
protected static void displayMatches(Code guess){
int nearMatches = winningCode.countNearMatches(guess);
int exactMatches = winningCode.countExactMatches(guess);
System.out.println("You have " + exactMatches + " exact matches and " + nearMatches + " near matches.");
}
protected static void play(){
int turnCount = 0;
int maxTurns = 10;
System.out.println("Greetings. Pick your code of four from Y,O,G,P,C,R.");
while(true){
Code guess = getGuess();
displayMatches(guess);
if (guess == winningCode) {
System.out.print("You win!!");
break;
} else if (++turnCount == maxTurns) {
System.out.print("You lose!!");
break;
}
}
}
}
On every guess, you call Code.parse, Code.parse creates a new Code (new Code(pegListString);) and that constructor sets the secretCodeString and because that's static, all instances of Code share the same variable. You need to avoid mutable static members.
Another tip is to either have a method return a value, or mutate state (of either its input, or its own instance, this), but avoid doing both.
"Why is my class variable rewriting itself after an unrelated method runs?"
Because, actually, it is not unrelated. The "mess" that you have created by declaring variables and methods as static has lead to unwanted coupling between different parts of your code.
It is difficult to say what the correct solution is here because your code has gotten so confused by the rewrites that it is hard to discern the original "design intent".
My advice would be to start again. You now should have a clearer idea of what functionality is required. What you need to do is to redo the object design so that each class has a clear purpose. (The Main and Game classes make sense, but Code seems to be a mashup of functionality and state that has no coherent purpose.)

Clear multi dimensional Object in Java

I want to pass 4 arrays from a method which is in A class, to a method in B class.
I create an instance of class A in the method which is in class B to get the arrays.
The method in A class is defined as Object[] and I use:
return new Object[]{Array1,Array2,Array3,Array4};
to return the arrays.
In method of B class I get the arrays with an object defined as:
private Object outGeoObj[] = new Object[4];
I am retrieving successfully the arrays, but I want to clear the object before I use it again. I tried:
public void ClearValues(){
if (outGeoObj != null){
outGeoObj = null;
}
else{
System.out.println("Object is null");
}
}
but it doesn't work. Any suggestions?
Minimal Working Example:
Class B:
public class MainFem {
private OutGeoMesh outmesh;
private Object outGeoObj[] = new Object[4]; // [0: Xmpoint, 1: Ympoint, 2: Vec, 3: numpoints]
public MainFem() {
outmesh = new OutGeoMesh();
}
public void ClearValues(){
if (outGeoObj != null){
for(int i = 0; i < outGeoObj.length; i++) {
outGeoObj[i] = null;
}
}
else{
System.out.println("Object is null");
}
} // END Method ClearValues
public void MainStart(int Xpoint[][], int Ypoint[][], int nump[], int c2, int Line[][][], DrawPanel drawPanel){
outGeoObj = outmesh.createOutGeomesh(Xpoint, Ypoint, nump, c2, Line, drawPanel);
int temp = (int[][]) outGeoObj[3];
System.out.println(temp[0][0]);
}// End Method MainStart
} // END CLASS MainFem
Class A:
public class OutGeoMesh {
private double Xmpoint[][][] = new double[500][200][20];
private double Ympoint[][][] = new double[500][200][20];
private double Vec[][][] = new double[500][2][20];
private int numpoints[][] = new int[500][20];
public OutGeoMesh() {
// TODO Auto-generated constructor stub
}
public Object[] createOutGeomesh(int Xpoint[][], int Ypoint[][], int nump[], int c2, int Line[][][], DrawPanel drawPanel) {
for (int j = 0; j <= c2; j++) {
for (int i = 0; i < nump[j]; i++) {
Vec[i][0][j] = i;
Vec[i][1][j] = i+1;
Xmpoint[i][0][j] = Xpoint[i][j];
Ympoint[i][1][j] = Ypoint[i][j];
numpoints[i][j] = numpoints[i][j] + 1;
} // END FOR i
} // END FOR j
return new Object[]{Xmpoint,Ympoint,Vec,numpoints};
} // END METHOD createOutGeomesh
// ---------------------------------
} // END CLASS OutGeoMesh
You need to do something like this:
Arrays.fill(outGeoObj, null);
The reason that your code doesn't work is because you are only erasing your reference to the array, but other parts of your code are still using that same array. By using Arrays.fill you can erase the contents of the array.

Categories

Resources