How do I get object and not address without using String/ toString? - java

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());
}
}

Related

Java's toString() static or non-static (based on my example)

I am new to the concepts of oop and therefore what I write have may have bad assumptions. Please correct me where appropriate.
In some code I saw a function takes in an argument in the form of int number. Then, in the function the following line is written outputString = Integer.toString( number );
I interpreted this as go the the class Integer, find a method called toString() and feed this the int called number and set the output of that to outputString. Since the syntax is class.method(arg) I assumed that toString() is a static function.
I wanted to test if it was static. I rewrote the code with the argument as Integer number and then did outputString = number.toString(); and it worked. This has the form obj.method(arg) which I had assumed would only work for non static methods.
I am unsure what conclusion to draw from this or if I have made a wrong assumption. Thanks.
If you're talking about the class Integer, it has two methods toString, one static and the other one is not static.
Integer a = 5;
a.toString() // Is valid
Integer.toString(5); // Also is valid
There are 3 methods in java.lang.Integer class.
public static String toString(int i);
public static String toString(int i, int radix);
public String toString();
In your first case, you have used the 1st one ( a static method).
In your second case, you have used the 3rd one ( a non-static method).
I think you should know more information about inheritance in java. All classes extend Object class, that is why all classes have non-static toString() method and can override it. Class Integer have also static toString(int number) that returns String representation of int.
The Integer class has 2 methods as below;
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
char[] buf = new char[size];
getChars(i, size, buf);
return new String(buf, true);
}
AND
public String toString() {
return toString(value);
}
Both the methods are self explanatory. To Note second method calls the first one.
Integer.toString(1); // Calls method 1
Integer one = 1;
one.toString(); // Calls method 2
You may also want to lookup the Object's toString() method, which by the way gets inherited in every objects in java. This method is not static. The Integer's toString(int) method is only specific to the Integer class. This method is static (does not work on objects, but only on the Integer class). You will also want to check out the concepts of "method overriding", "method overloading" and "polymorphism". Here's a page containing almost exactly your question: https://www.geeksforgeeks.org/can-we-overload-or-override-static-methods-in-java/

Anybody can tell me why this sentence works fine: System.out.println(p[i]);

Reading about cryptography, can not understand why the indicated line of code print data:
Provider p[] = Security.getProviders()
for (int i = 0; i < p.length; i++) {
System.out.println(p[i]); // <<<--- THIS LINE
why this print out data if it's not a string, it's a provider object
Thanks.
because println() accept many types, there are many signature of this method for example :
println(int i){...} //when you set int you call this
println(String i){...} //when you set String you call this
println(boolean i){...} //when you set boolean you call this
println(char i){...} //when you set char you call this
println(java.lang.Object i){...} //when you set Object you call this
... and so on
Take a look here java.lang.System
Basically, println() calls the Object's toString() method (i.e. Provider's toString()) to print the string representation of the object. (If Provider class has implemented toString() else the default toString() which is inherited from Object class)
Javadoc link : https://docs.oracle.com/javase/7/docs/api/java/io/PrintStream.html#println(java.lang.Object)
public void println(Object x)
Prints an Object and then terminate the line. This method calls at first String.valueOf(x) to get the printed object's string value, then behaves as though it invokes print(String) and then println().
Parameters:
x - The Object to be printed.
If Object (i.e.Provider in your case) class hasn't overridden default java.lang.Object's class toString() then what would it display?
It actually prints the class name + "#" symbol + the hex value of Object's hashcode method. (hashcode is also inherited from Object class)
public class Solution {
private int i;
public Solution() {
this.i = 10;
}
public static void main(String... args) {
Solution solution = new Solution();
System.out.println(solution);
// what is default toString prints?
System.out.println(Integer.toHexString(solution.hashCode()));
}
}
Sample Run
Solution#5eba06ff
5eba06ff
If Object (i.e.Provider in your case) has overridden default java.lang.Object's class toString() then what would it display?
It actually prints what you intent to print in toString().
public class Solution {
private int i;
public Solution() {
this.i = 10;
}
#Override
public String toString() {
return "Solution [i=" + i + "]";
}
public static void main(String... args) {
Solution solution = new Solution();
System.out.println(solution);
}
}
Sample Run
Solution [i=10]
Edit: All the classes in Java (not most of them as stated below, thanks for that) have toString() method which returns String representation of an object, the same applies for Provider class. When writing your own class you can override toString() method, meaning that you can write the method called toString() which will then be called whenever you try to access that object as a String (for example in System.out.println()).
Hope this helps, if not, just google toString().
In java, whenever we try to 1. print an object directly 2. or concat an object with string directly, the toString method is automatically called. By default, to string prints class name # hashcode
Like in your example, p[i].toString() is happening.
Since, object class is parent of every class directly or indirectly, all of its 11 functions (including toString() ) are inherited in the child class.
Provider class overrides the function toString() from the Hashtable<Object,Object> class. This overridden toString() returns a string with the name and the version number of this provider.
public class ExamineSecurity {
public static void main(String args[]) {
try {
Provider p[] = Security.getProviders();
for (int i = 0; i < p.length; i++) {
System.out.println(p[i]);
for (Enumeration e = p[i].keys(); e.hasMoreElements();)
System.out.println("\t" + e.nextElement());
}
}
catch (Exception e) {
System.out.println(e);
}
}
}
If we run this program with the 1.2 Sun security provider, we get this output:
Class Definition
SUN version 1.2
Alg.Alias.MessageDigest.SHA
Alg.Alias.Signature.SHAwithDSA
Alg.Alias.Signature.1.3.14.3.2.13
Alg.Alias.Signature.OID.1.2.840.10040.4.3
Alg.Alias.Signature.SHA-1/DSA
Alg.Alias.Signature.DSS
Alg.Alias.Signature.SHA1withDSA
Alg.Alias.Signature.OID.1.3.14.3.2.13
AlgorithmParameters.DSA
KeyFactory.DSA
Alg.Alias.Signature.1.2.840.10040.4.3
Alg.Alias.MessageDigest.SHA1
AlgorithmParameterGenerator.DSA
Alg.Alias.AlgorithmParameters.1.2.840.10040.4.1
MessageDigest.MD5
Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1
MessageDigest.SHA-1
Alg.Alias.KeyPairGenerator.OID.1.3.14.3.2.12
Signature.DSA
Alg.Alias.KeyPairGenerator.1.3.14.3.2.12
Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1
Alg.Alias.Signature.1.3.14.3.2.27
Alg.Alias.Signature.SHA/DSA
Two things are readily apparent from this example. First, the strings that contain only an engine name and an algorithm implement the expected operations that we listed in Table 8-1. Second, as we mentioned in the section on the Provider class, security providers often leverage the fact that the Provider class is a subclass of the Properties class to provide properties that may make sense only to other classes that are part of the provider package. Hence, the signature algorithm 1.3.14.3.2.13 may make sense to one of the classes in the Sun security provider,but it is not a string that will necessarily not make sense to other developers. In fact, those aliases--including the ones that are prefaced by OID--do have meanings within the cryptography standards world, but for our purposes we'll stick with the standard algorithm names that we listed earlier.
The toString() method of the class Provider seems to be implemented.

How does System.out.print() work?

I have worked with Java for a quite a long time, and I was wondering how the function System.out.print() works.
Here is my doubt:
Being a function, it has a declaration somewhere in the io package. But how did Java developers do that, since this function can take in any number of arguments and any argument types no matter how they are arranged? e.g:
System.out.print("Hello World");
System.out.print("My name is" + foo);
System.out.print("Sum of " + a + "and " + b + "is " + c);
System.out.print("Total USD is " + usd);
No matter what is the datatype of variables a, b, c, usd, foo or how they are passed, System.out.print() never throws an error.
For me, I have never worked on any project where the requirement was like this. Provided, if I get a requirement like this, I really don't know how to solve it.
Can anyone explain to me how it's done?
System.out is just an instance of PrintStream. You can check its JavaDoc. Its variability is based on method overloading (multiple methods with the same name, but with different parameters).
This print stream is sending its output to so called standard output.
In your question you mention a technique called variadic functions (or varargs). Unfortunately that is not supported by PrintStream#print, so you must be mistaking this with something else. However it is very easy to implement these in Java. Just check the documentation.
And if you are curious how Java knows how to concatenate non-string variables "foo" + 1 + true + myObj, it is mainly responsibility of a Java compiler.
When there is no variable involved in the concatenation, the compiler simply concatenates the string. When there is a variable involved, the concatenation is translated into StringBuilder#append chain. There is no concatenation instruction in the resulting byte code; i.e. the + operator (when talking about string concatenation) is resolved during the compilation.
All types in Java can be converted to string (int via methods in Integer class, boolean via methods in Boolean class, objects via their own #toString, ...). You can check StringBuilder's source code if you are interested.
UPDATE: I was curious myself and checked (using javap) what my example System.out.println("foo" + 1 + true + myObj) compiles into. The result:
System.out.println(new StringBuilder("foo1true").append(myObj).toString());
Even though it look as if System.put.print...() take a variable number of arguments it doesn't. If you look closely, the string is simply concatenated and you can do the same with any string. The only thing that happens is, that the objects you are passing in, are implicitily converted to a string by java calling the toString() method.
If you try to do this it will fail:
int i = 0;
String s = i;
System.out.println(s);
Reason is, because here the implicit conversion is not done.
However if you change it to
int i = 0;
String s = "" + i;
System.out.println(s);
It works and this is what happens when using System.put.print...() as well.
If you want to implement a variable number of arguments in java to mimimc something like C printf you can declare it like this:
public void t(String s, String ... args)
{
String val = args[1];
}
What happens here is that an array of Strings is passed in, with the length of the provided arguments. Here Java can do the type checking for you.
If you want truly a printf then you have to do it like this:
public void t(String s, Object ... args)
{
String val = args[1].toString();
}
Then would you have to cast or interpret the arguments accordingly.
It is a very sensitive point to understand how System.out.print works.
If the first element is String then plus(+) operator works as String concate operator. If the first element is integer plus(+) operator works as mathematical operator.
public static void main(String args[]) {
System.out.println("String" + 8 + 8); //String88
System.out.println(8 + 8+ "String"); //16String
}
Evidently, the compiler was made in a confusing way although the compiler developers thought they added some smartness. The true smartness they should really add is to look entire argument and interpret + operator consistently. For example, System.out.println(1+2+"hello"+3+4); should output 3hello7 instead of 3hello34
I think you are confused with the printf(String format, Object... args) method. The first argument is the format string, which is mandatory, rest you can pass an arbitrary number of Objects.
There is no such overload for both the print() and println() methods.
Its all about Method Overloading.
There are individual methods for each data type in println() method
If you pass object :
Prints an Object and then terminate the line. This method calls at first String.valueOf(x) to get the printed object's string value, then behaves as though it invokes print(String) and then println().
If you pass Primitive type:
corresponding primitive type method calls
if you pass String :
corresponding println(String x) method calls
You can convert anything to a String as long as you choose what to print. The requirement was quite simple since Objet.toString() can return a default dumb string: package.classname + # + object number.
If your print method should return an XML or JSON serialization, the basic result of toString() wouldn't be acceptable. Even though the method succeed.
Here is a simple example to show that Java can be dumb
public class MockTest{
String field1;
String field2;
public MockTest(String field1,String field2){
this.field1=field1;
this.field2=field2;
}
}
System.out.println(new MockTest("a","b");
will print something package.Mocktest#3254487 ! Even though you only have two String members and this could be implemented to print
Mocktest#3254487{"field1":"a","field2":"b"}
(or pretty much how it appears in the debbuger)
#ikis, firstly as #Devolus said these are not multiple aruements passed to print(). Indeed all these arguments passed get
concatenated to form a single String. So print() does not teakes multiple arguements (a. k. a. var-args). Now the concept that remains to discuss is how print() prints any type of the arguement passed
to it.
To explain this - toString() is the secret:
System is a class, with a static field out, of type PrintStream. So you're calling the println(Object x) method of a
PrintStream.
It is implemented like this:
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
As wee see, it's calling the String.valueOf(Object) method. This is implemented as follows:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
And here you see, that toString() is called.
So whatever is returned from the toString() method of that class, same gets printed.
And as we know the toString() is in Object class and thus inherits a default iplementation from Object.
ex: Remember when we have a class whose toString() we override and then we pass that ref variable to print, what do you see printed? - It's what we return from the toString().
The scenarios that you have mentioned are not of overloading, you are just concatenating different variables with a String.
System.out.print("Hello World");
System.out.print("My name is" + foo);
System.out.print("Sum of " + a + "and " + b + "is " + c);
System.out.print("Total USD is " + usd);
in all of these cases, you are only calling print(String s) because when something is concatenated with a string it gets converted to a String by calling the toString() of that object, and primitives are directly concatenated.
However if you want to know of different signatures then yes print() is overloaded for various arguments.

Java array, prints something else

I'm trying to print the items from my array, but when I run the program, it prints out Orders:testorder#4, testorder#5 and so on. Any tips on how I can fix it so it writes 123 Buy?
package hej;
public class TestOrder {
public static void main(String[] args) {
Order order1 = new Order("123", "Buy");
Order order2 = new Order("456", "Sell");
Order order3= new Order("231", "Buy");
Order order4= new Order("987", "Buy");
OrderRegister orderregister = new OrderRegister();
orderregister.addOrder(order1);
orderregister.addOrder(order2);
orderregister.addOrder(order3);
orderregister.addOrder(order4);
System.out.println("Orders: ");
for (int i = 0; i < orderregister.getArrayList().size(); i++){
System.out.println(orderregister.getArrayList().get(i) + "-");
}
}
}
Because you don't have a toString() method defined for your Order class.
When Java tries to print an Object, it attempts to call the toString() method for that Object, if it can't find one it uses the toString() from the Object superclass.
And the Object toString() by default does this:
getClass().getName() + '#' + Integer.toHexString(hashCode())
which is exactly what you are seeing as output.
Have TestOrder override the toString() method.
When you concatenate an object with a String (like in your System.out.println(...) statements), the toString() method is called on the object to convert it to a String first.
You need to override the toString() method on your Order class and have it generate the string form of the order.
This is exactly what you should expect, given that you haven't told Java any other way to convert an Order to a String. Override Order.toString() if you want Java to use some particular way of converting an Order to a String.
You could/should try overriding the toString() method(which is called implicitly in your example) as others have suggested.
For example:
#Override public String toString()
{
return String.format("%s , %s", this.getID(), this.getAction());
}

Custom 'String' Class

I'm trying to figure out how java classes work.
When I create a StringBuilder:
StringBuilder testString = new StringBuilder("Hello World!);
If I want to, say, get the value that testSting holds a reference to, I can simply call it like: System.out.println(testString);
This is cool behavior, but I'm unsure how to replicate it in classes that I make.
For instance, if I were to try and re-implement my own version of StringBuilder, the approach I would take (as a beginner), would be this:
class MyBuilder {
char[] string;
public MyBuilder(String s) {
string = new char[s.length()];
string = s.toCharArray();
}
So, to make the string an array I had to store it in a data field of the class. But then, to access this in my code, I can't print it by simply calling the variable name. I would have to use .property syntax. Thus, to duplicate the above example, I would have to type System.out.println(testString.value); Which isn't nearly as pretty.
How do you make a class such that it behaves like String or StringBuilder and returns its value without manually accessing the data fields?
Implement a toString method.
toString is a method on Object, so every java object inherits one. The default implementation that you inherit is only useful for getting the class type, and for distinguishing one object from another; the format is: ClassName#HashCode. There are no details unique to your implementation.
In your own classes, to get the description that you want you'll need to override the toString method, so that in contexts where a String is expected, e.g. when you call System.out.println(myObject.toString());, your own format is used.
It's often a good idea to do this, for a more readable description of your object. You can always call super.toString to include the output from the default - ClassName#HashCode - in your own output.
You can override Object.toString() in your object MyBuilder. System.out.println calls on this method for every object used. For example here, you could use:
#Override
public String toString() {
return Arrays.toString(string);
}
Overwrite the toString-Method
private String value;
public MyClass(String value) {
this.value = value;
}
public String toString() {
return value;
}

Categories