I am trying to have a string use a method from another class to change a certain character to a different character. However when I run my program nothing happens.
In my main class I have:
String example = "example";
Pears.mToX(example);
System.out.println(example);
and in my second class called "Pears.java" I have:
public static void mToX(String word){
word.replace("m", "x");
}
Strings are immutable, meaning they can't be changed, so when you use replace it returns the result as a new String, which you're doing nothing with. You'll need to restructure your code like so:
String example = "example";
example = Pears.mToX(example);
System.out.println(example);
And the method:
public static String mToX(String word){
return word.replace("m", "x");
}
Related
I need to create my own String class called MyString without using default String class/vector API. I have to work on some required methods, and their return types are predetermined. I can add other methods as long as String is not used.
Expected use would be:
(at main) System.out.println(str.toLowerCase()) - returns lower case of str
When I want to work with toLowerCase() method with return type MyString, I can't return the object content but only return the address.
Normally, this problem would require modification of toString(), but since this method requires return type of String by default, I can't use modification of toString() for the assignment.
The assignment is supposed to be not so hard and should not require complex extensions. My constructor may be the problem, but I can't specify which part is.
Code
public class MyString {
private char value[];
MyString(char[] arr){
this.value = Arrays.copyOf(arr, arr.length);
}
...
MyString toLowerCase() { // can't change return type
for (int i =0; i<value.length; i++) {
if ((int)value[i] > 64 && (int)value[i] < 91) {
value[i] = (char) (value[i]+32);
}
}
return this; // this returns address, and I can't override toString
}
Problem with System.out.println(str.toLowerCase()) is it ends up calling PrintStream.println(Object o), but that method internally at some point calls o.toString() which uses code inherited from Object#toString() (since you couldn't override toString as it expect as result String which is forbidden in your project) which result in form TypeInfo#hexHashCode.
This means you can't use System.out.println(MyString).
BUT PrintStream (which instance is held by System.out) allows us to provide data to print in different forms. In this case you can use println(char[]). All you need to do is adding to MyString method like toCharArray() which would return (preferably a copy of) array of characters held by MyString class.
This way you can use it like System.out.println(myStringInstance.toCharArray()) so code from your main method would need to look like
System.out.println(str.toLowerCase().toCharArray());
// ^^^^^^^^^^^--this should return char[]
Firstly, the String class is an immutable type, i.e. the methods of String do not change the internal state (i.e. the char array), instead they return a new instance of type String.
To mirror that behavior you could implement something like this:
public MyString toLowerCase() {
char temp = new char[value.length];
// [...] Your code performing the actual logic on temp
return new MyString(temp);
}
The immutability (and its implications) of the String class is very important to understand in practice. For example, the following code procudes the intended result:
String word = "Word";
System.out.println("I can produce upper case (" + word.toUpperCase() + ") " +
"and lower case (" + word.toLowerCase() + ") " +
"without any side-effects on the original (" + word + ").");
However, it's not possible (without "hacky" solutions) to implement a method like this:
void shortenString(String inputAndOutput);
Second, the assignment expects that the class/method must be used as follows:
System.out.println(str.toLowerCase());
The attribute out is effectively a PrintStream, which offers (besides other methods) the following two:
println(Object x) - Prints an Object and then terminate the line.
println(String x) - Prints a String and then terminate the line.
If the method is called with an Object parameter, the internal implementation calls toString() on the given object, thus the only way to satisfy the requirement is to override this method. Unfortunately, this is not allowed by the assignment.
However, if it is not explicitly stated that the solution has to use java.lang.System, you could simply implement your own System class which accepts MyString, e.g.:
public class System {
public static class MyPrintStream /* optional: extends PrintStream */ {
public void println(MyString x) {
java.lang.System.out.println(x.getCharArray());
}
}
public static final out = new MyPrintStream();
}
This would allow you to use it exactly as described in the assignment:
import my.package.System;
public class Main {
public static void main(String[] args) {
// [...] Instantiate str
System.out.println(str.toLowerCase());
}
}
I understand that on passing an array asn argument to a function, and making some change to the elements of the array inside the function, the changes will be reflected in the calling function as well, since arrays operates directly on memory (call by reference)
However, why is it that the same behavior does not apply to Strings? I was expecting Strings as well to work in the same way since a String is basically an array of characters.
Please see my code below.
I pass in a String (character array) as well as an int array in to a function and make some changes in it. On printing these in main, I see that the String remains unaffected whereas the changes to the array are reflected.
import java.util.Arrays;
public class TestString
{
public static void main(String[] args)
{
String s = "hello";
int[] a = new int[5];
Arrays.fill(a, -1);
fun(s,a);
System.out.println(s);
System.out.println(a[0]);
}
static void fun(String s, int[] a)
{
s = "world";
a[0] = 99;
}
}
Output
hello
99
First, the claim that a String is an array of characters is wrong. A String is an object, that has methods and is designed specifically not to allow any changes to be made in it.
Second, what you are doing is not changing some element of the parameter. You are changing the parameter variable. The parameter variable is basically a local variable, which receives a reference to the string that was passed as argument. Doing this:
s = "world";
Is not changing the string that was passed. It replaces contents of the local variable s with a new string. Since Java is always pass by value, this is not reflected outside of the method. It would be the same if you had:
a = new int[30];
inside the method. Outside of it you would still see the 5-element int[] that you passed inside.
a[0] = 99;
Is changing an element inside the array. So it looks at a, checks what it refers to, goes to that referred array, and changes its 0th element.
Since String is designed to be immutable, there is no way to do something similar in it. You can't do something like:
s.setCharacter(0,'a'); // This doesn't exist in Java
But you can do this with mutable objects. For example, if you had:
public static void manipulateStringBuilder( StringBuilder sb ) {
sb.append(": manipulated");
sb = new StringBuilder("New value assigned");
}
Then you could write something like:
StringBuilder sb = new StringBuilder("My string");
System.out.println(sb);
manipulateStringBuilder( sb );
System.out.println(sb);
And the output would be:
My string
My string: manipulated
This is because StringBuilder is a mutable object, combined with the fact that the value that you assigned to sb inside your method is never seen outside of it.
Because Strings in java are immutable. Every "change" done to a string does not changes the original string but creates a new String object.
It is because Strings are immutable. If you want to change the value of the String you should return it from the method and store it in the variable s again.
import java.util.Arrays;
public class TestString
{
public static void main(String[] args)
{
String s = "hello";
int[] a = new int[5];
Arrays.fill(a, -1);
s = fun(s,a);
System.out.println(s);
System.out.println(a[0]);
}
static String fun(String s, int[] a)
{
s = "world";
a[0] = 99;
return s;
}
}
I expect it will be helpful for you!
Java is not call by reference, but call by value, it is just that it passes references as values. More details here.
Strings are immutable, so you can't change the content (the char array) of a String, you can just replace it with a different one, i.e. you are changing the reference. But since the reference is passed by value, the change is not visible outside a method.
Actually you can change the content of String using reflection, which results in very interesting behavior. You use this only when you want to play a prank on a coworker.
I've got a method that creates a String and another method that changes Strings
void create(){
String s;
edit(s);
System.out.println(s);
}
void edit(String str){
str = "hallo";
}
My compiler says that it "may not have been initialized".
Can someone explain this?
Variable may not have been initialized
As you define the s inside a method you have to init s in it somewhere every variable in a program must have a value before its value is used.
Another thing not less important, your code won't never work as you expected cause
Strings in java are inmutable then you cannot edit your String, so you should change your method edit(Str s).
I Change your code to something like this but i think your edit method should do another thing rather than return "hallo".
void create(){
String s=null;
s =edit(); // passing a string to edit now have no sense
System.out.println(s);
}
// calling edit to this method have no sense anymore
String edit(){
return "hallo";
}
Read more about that java is passed by value in this famous question : Is Java "pass-by-reference"?
See this simple Example showing that java is passed by value. I cannot make an example with only Strings cause Strings are inmutable. So i create a wrapper class containing a String that is mutable to see differences.
public class Test{
static class A{
String s = "hello";
#Override
public String toString(){
return s;
}
}
public static void referenceChange(A a){
a = new A(); // here a is pointing to a new object just like your example
a.s = "bye-bye";
}
public static void modifyValue(A a){
a.s ="bye-bye";// here you are modifying your object cuase this object is modificable not like Strings that you can't modify any property
}
public static void main(String args[]){
A a = new A();
referenceChange(a);
System.out.println(a);//prints hello, so here you realize that a doesn't change cause pass by value!!
modifyValue(a);
System.out.println(a); // prints bye-bye
}
}
You declare local variable s in method create, so that you need to initialized it before you use it. Remember that java does not have default value for local variable.
Init String s = "" or whatever value than your code will run normally.
try to initialize the string "s" to a null value, since you have declared a variable "s" but it has not been initialized. Hence it can't pass the reference of that variable while used as parameter.
String s = null;
Hope this helps
Give your variable S a value or as Jeroen Vanneve said "Change it to String s = null;"
Here's a question that goes right back to basics (I think) although had me stumped in a recent coding project I undertook with a few friends.
Here's code variation one:
public class Test {
private String test;
public Test(){
test = "tester";
changeString(test);
}
public void changeString(String t){
t = "blue apples";
}
public String getTest(){
return test;
}
public static void main(String[] args){
Test t = new Test();
System.out.println(t.getTest());
}
}
Why does the program print out "tester" instead of "blue apples"? Shouldn't the method changeString(String) turn the field 'test' into "blue apples"?
Thanks for your responses in advance!
Java is pass by value and not pass by reference. Therefore, the changes made to the passed t String, won't be reflected in your test String.
public void changeString(String t){
t = "blue apples";
test = t; // Include this line to assign the value of `t` to `test`.
}
First you assign "Tester" to test. Next you call changeString passing it a reference of test.
This method simply assigns "blue apples" to t. In doing so, it creates a new String before making the assignment. Because t is passed by value, the change is not reflected when the method returns
Instead, you would need to do something more like...
public void changeString(String t){
text = t;
}
And use changeString("blue apples");
or
public String changeString(){
return "blue apples";
}
And use test = changeString();
You are doing,
test = "tester";
changeString(test);
String is immutable in java.
public void changeString(String t){
t = "blue apples";
}
In the above lines you are changing the value of the parameter passed to that method, Not the test.
To see change try
public void changeString(String t){
t= "blue apples";
test=t; // now assigned the value
}
String is immutable in JAVA. Immutablity means once an instance is created it remains the same. In your case
In your case you created a tester reference to point to a new String "Tester"
Since string is immutable when you passed the object to the method and tried to reassign the reference to a new String "Blue Apples" what you did was created a reference t in the scope of method which pointed to blue apples. If you would had had printed t you would have got "Blue Apples" since the scope of t is till the method.
After returning the tester reference still points to the same old string "tester" and hence it gets printed.
As with String all other wrapper classes are also immutable. You would observe same behavior with Integer, Boolean objects
This happens because String object is immutable, hence cannot change its value post assignment. You can use StringBuffer or StringBuilder isntead
I am developing a small application in Java. The following if condition never becomes true, does any body be knows the actual reason?
public int foo()
{
String sTitle = "title";
if (sTitle.equalsIgnoreCase(MyCustomObject.sTitle))
return 5;
else
return 6;
}
It always returns 6. I ran it in debug mode and saw that both strings contains same value.
I also tried swapping the positions of both strings like:
MyCustomObject.sTitle.equalsIgnoreCase(sTitle)
but that didn't work either.
The actual reason is that MyCustomObject.sTitle does not have the value "title" or any case variants.
Check where and when that variable is assigned.
I'm assuming that MyCustomObject.sTitle is a string as well.
My first attempt at debugging would be to add the following line before you test the equality:
System.out.println("*"+MyCustomObject.sTitle+"*");
and check for whitespace.
Try adding this code to the foo method:
if (sTitle.length() != MyCustomObject.sTitle.length())
{
System.out.println("I hate the truth");
}
else
{
System.out.println("The mystery remains!");
}
EqualsIgnoreCase method
Compares this String to another String, ignoring case considerations. Two strings are considered equal ignoring case if they are of the same length, and corresponding characters in the two strings are equal ignoring case.
Two characters c1 and c2 are considered the same, ignoring case if at least one of the following is true:
The two characters are the same (as compared by the == operator).
Applying the method Character.toUpperCase(char) to each character produces the same result.
Applying the method Character.toLowerCase(char) to each character produces the same result.
Based on the above the value of MyCustomObject.sTitle is not matching any of the above criteria.
as previous authors have written MyCustomObject.sTitle does not return any variant of "title". You could try running this piece of code and you can prove for yourself that it's not the equalsIgnoreCase method that doesn't work.
public static void main(String[] args) {
System.out.println(foo());
}
public static int foo()
{
String sTitle = "title";
if (sTitle.equalsIgnoreCase(MyCustomObject.sTitle))
return 5;
else
return 6;
}
public static class MyCustomObject {
public static String sTitle = "TITLE";
}