This question already has answers here:
Is "new String()" immutable as well?
(15 answers)
Closed 7 years ago.
I know Strings are immutable in nature. But I have a question.
String a = new String("abc");
If we create a string like above instead of a literal, then isn't it not immutable any more since it is created as a new object? Please clarify. Thanks.
No. It doesn't. A java String is always immutable irrespective of how it is created.
Actually using new to create Strings is redundant and should be avoided in 99 percent of the cases (unless you are doing some micro-bench marking)
Immutable means an instance cannot be modified once it is created. When you look at all the methods of String, none of them actually modifies the original String passed to it. They either return the same String or create a new one.
This is a mutable object:
class Person {
private name;
Person(String name) { this.name = name; }
void setName(String name) { this.name = name; }
}
Because you can change its state after it has been created:
Person john = new Person("John");
john.setName("Fred"); //oops, John's name is not John any more...
On the other hand, once you have created a String there is no method that allows you to change the value of that string.
String john = "John";
john.setValue("Fred"); //No, that's not possible...
That does not prevent you from creating new Strings with similar or different values of course.
Your String is immutable as String is always immutable (view The Java Language Specification)
The difference between String a = "abc"; and String a = new String("abc"); is not the mutability, is the use of the String pool. When you do
String a = "abc";
you are using the Java String pool (See String intern)
And when you do
String a = new String("abc");
you are not using the String pool.
The String pool stores different String instances, that's why when you create two different objects using the pool, the references are the same.
In both cases anyways, you cannot change the state of your String instance (String is immutable).
Creating Strings using new can be avoided almost always.
Related
This question already has answers here:
How do I print my Java object without getting "SomeType#2f92e0f4"?
(13 answers)
Closed 2 years ago.
This might be an easy answer but I'm new and my professor hasn't been much help, also feel free to correct my terminology. Essentially I have a class "Employee" and I'm trying to add several instances of it to an ArrayList to be printed later in Main. It looks kind of like this:
public Employee(int id, String name, String bday, String gender, String job, int org)
{
this.id = id;
this.name = name;
this.bday = bday;
this.gender = gender;
this.job = job;
this.org = org;
}
All I really need to know how to do is print the values I've managed to assign to the constructor i.e. when I call a specific object from the ArrayList I'll be able to print the object's specific id, name, etc. I figured out that I can do it by creating a method for each individual variable but that would be really messy and inefficient, I'm looking for one method to call that would be able to do this.
Override Object.toString() in Employee. Something like,
#Override
public String toString() {
return String.format("Employee id=%d, name=%s, bday=%s, gender=%s, job=%s, org=%s",
id, name, bday, gender, job, org);
}
Then whenever you try and print it, the toString of Employee will be invoked.
System.out.println(new Employee(1, "Test", "A Birthday",
"Yes", "Something", "Somewhere"));
Q.1. How many Objectes are created in the below example?
ex.
String s1="isaq";
String s2="isaq";
String s3="isaq";
if answer is 1 or 3 ,explain me why?
When we try to create a String Object JVM first checks the String constant pool,if string doesn't exist in the pool then it will creates a new String Object isaq and reference maintained in the pool.The Variable S1 also refer the same String Object.
String s1="isaq";
Above statement create one String Object in String pool.
Now you are doing the
String s2="isaq";
Above statement won't create any String Object in String pool and S2 refers the same object as S1.Because JVM will check the Pool and it found String object is already present.
To Validate it you can compare String reference using equality operator(==). to check whether they are referring the same String Object or not.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How many java objects generated by this code? and why?
I am very confused in the following
String s1 = new String("Java");
String s2 = new String("Java");
How many objects are created here?
String s1 = new String("Java");
String s2 = new String("Ruby");
How many objects are created here?
String s1 = new String("Java");
String s2 = "Java";
How many objects are created here?
String s1 = "Java";
String s2 = "Java";
How many objects are created here?
Your first part of code:
2 objects are created.
If "Java" is not present in String Pool, a string is created and added there.
Your 2nd part of code:
2 objects are created and if neither "Java" nor "Ruby" are present in String Pool, both strings are created and added to it.
Your 3rd part of code:
one object created. and same condition is executed to add to String Pool.
Your 4th part of code:
Only one object created, if "Java" not present in String Pool. else no new object created.
String s1 = new String("Java");
String s2 = new String("Java");
It will create 2 objects in heap.
String s1 = new String("Java");
String s2 = new String("Ruby");
This will create 2 objects in heap.
String s1 = new String("Java");
String s2 = "Java";
This will create one object in heap for first line.
For second line, it will check whether "Java" exists in string pool or not.If exists, it wont create a new string.It will return the reference to already existing string in pool
String s1 = "Java";
String s2 = "Java";
First line will check whether "Java" exists in string pool or not.If exists, it wont create a new string.It will return the reference to already existing string in pool.
Second line will get the reference to already created string.So no new objects if "Java" exists or maximum one object
This question already has answers here:
Create new object using reflection?
(2 answers)
What is reflection and why is it useful?
(23 answers)
Closed 7 years ago.
Suppose I have this class:
public class Person {
private String name;
private int age;
//setters and getters
...
}
The following code is not correct, but I want something similar.
String className="Person";
String att1 = "name";
String att2 = "age;
object o = createClassByName(className);
setValueForAttribute(o,att1,"jack");
setValueForAttribute(o,att2,21);"
Are you familiar with hashes?
I think you could use a HashMap, which is a common Hash implementation built into the Java library:
HashMap<String,Object> person1 = new HashMap<String,Object>();
person1.put("className", "Person");
person1.put("name", "Jack");
person1.put("age", 21);
Everytime you want to change the values, do: person1.put("name", "Jill")
And to get the values, it's person1.get("name")
If you want to take the class into account, you'll have to get the className and manually compare it in your code, to do different things according to the "class" of the object (which in reality is a HashMap, but nevermind).
Small reminder: doing things this way is considered very messy ;)
This is more of a design question with implications for code simplicity vs. performance.
Lets say you want to make sure a set of values for a given user id are the same between two systems. The example here is to check that a student id has the same number of course enrollments in System A and System B.
For this we create:
List<String> studentList = new ArrayList<String>();
Set<String> sysAEnrollments = new HashSet<String>();
Set<String> sysBEnrollments = new HashSet<String>();
private Map<String, String> badEnrollList = new HashMap<String, String>();
And fill them appropriately, given a list of student ids(studentList):
studentList = getCurrentStudentList();
for (String id : studentList){
sysAEnrollments = getSysAEnrollments(id);
sysBEnrollments = getSysBEnrollments(id);
if (!sysAEnrollments.containsAll(sysBEnrollments)){
badEnrollList.put(id, getBadEnrollmentsById(id, sysAEnrollments, sysBEnrollments));
}
}
Question: What should the method 'getBadEnrollmentsById' return?
Either a concatenated string with enough meaning so it can just be printed out.
Or have a new object, for example another collection with the list of course ids that could be used for further processing but harder to use for printed output.
Is it worth designing thoroughly all expected objects or replace some of them with concatenated strings for clarity and performance?
NOTES:
System A is preferred as the authoritative source
Output from getBadEnrollmentsById should have all courses and flag those missing in system B.
PROPOSED SOLUTION: (2012-SEP-14)
EDIT (2012-SEP-17): Updated the Course class to include hashCode and equals
As suggested by user351721 I continued modelling the remaining objects that match the expected results/requirements.
Slight changes made a big difference and allowed me to go over this design flaw and finish with the implementation.
The revised collections are:
List<String> studentList = new ArrayList<String>();
Enrollment sysAEnrollments;
Enrollment sysBEnrollments;
Map<String, List<String>> badEnrollList = new HashMap<String, List<String>>();
And we populate the Enrollments:
for (String id : studentList){
sysAEnrollments = getSysAEnrollments(id);
sysBEnrollments = getSysBEnrollments(id);
if (!sysAEnrollments.getCourses().containsAll(sysBEnrollments.getCourses())){
List<String> missingCourses = getProblemEnrollmentListById(id, sysAEnrollments, sysBEnrollments);
badEnrollList.put(id, missingCourses);
}
}
So for now the output can be printed from badEnrollList by getting at each ArrayList and printing the course names. A course name with a * will mean that it's missing in sysB.
The Enrollment class looks like this:
public class Enrollment {
private Set<Course> courses = new HashSet<Course>();
public void setCourses(Set<Course> courses){
this.courses = courses;
}
public Set<Course> getCourses(){
return this.courses;
}
}
And the Course class ended up like this:
public class Course {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
// Must override hashCode() and equals()
#Override
public boolean equals(Object o){
if (o == this)
return true;
if (!(o instanceof Course))
return false;
Course c = (Course) o;
return c.id.equals(this.id) && c.name.equals(this.name);
}
#Override
public int hashCode(){
// Magic numbers as shown on Joshua Bloch's book "Effective Java" 2nd Edition, p.48
int result = 17;
result = 31 * this.id.hashCode();
result = 31 * this.name.hashCode();
return result;
}
}
The changes might look subtle but the important clue is that Enrollments are not a collection of strings, Enrollments are a collection of Courses AND each Course has a name and a availability property. They don't seem to do much but by using them I am defining the objects that I'm working with and documenting how these classes can be reused in the future.
"Growing Object-Oriented Software, Guided by Tests" addresses this question: chapter 7, "Value Types". Worth reading. An excerpt:
The more code we write, the more we’re convinced that we should define types to represent value concepts in the domain, even if they don’t do much. It helps to create a consistent domain model that is more self-explanatory. If we create, for example, an Item type in a system, instead of just using String, we can f ind all the code that’s relevant for a change without having to chase through the method calls
concatenated strings
would mean you have to define a pattern and corresponding set of valid strings and implement validation and translation to entity classes. Providing an interface or class would make it easier to update your code in a year or so, not to mention other programmers that might work with your application. Why not store student, enrollment or course objects in badEnrollList? How do these objects look like and what do you want to do with them?
In general: Yes, designing thoroughly all expected objects is worth it.
I feel that a collection, such as List<String> would be a desirable return value. This allows you to more efficiently capture multiple discrepancies between the two sets, and process the missing courses in your second object more intuitively. Printing the list wouldn't be that hard, either - depending on how you wished to convey the information.
It's also worth mentioning that the .equals() method for Set is a cleaner and more intuitive way to ensure equivalence between two sets.
Instead of using all these sets and maps, I'd use Plain Old Java Objects (POJOs) that reflect the actual business objects in question. From what you've indicated, you have Students who have an id of some sort, and who are enrolled in classes on System A and on System B. I would build up a set of Student objects defined like so:
public class Student {
private String id;
private List<String> enrollmentsA;
private List<String> enrollmentsB;
// appropriate getters and setters
}
Depending on if you want to do anything else with Classes, it may even be preferable to create some form of EnrolledClass object to represent that too.
Within the students class, I'd then have a method that would determine the "bad" enrollments. If all that you want to do with this data is generate an email message, it may even be as simple as a String:
public String getBadEnrollmentsMessage() {
List<String> enrolledBoth = getCommonEnrollments();
List<String> enrolledOnlyA = getAOnlyEnrollments();
List<String> enrolledOnlyB = getBOnlyEnrollments();
StringBuilder output;
// format the contents of the above lists into output
// format should be however you want it in the email.
return output.toString();
}
Then you could have a map of Students to email enrollments messages:
HashMap<Student, String> studentEmails;
for (Student s : allStudents) {
studentEmails.put(s, s.getBadEnrollmentsMessage());
}
Of course, if you have a method like getBadEnrollmentsMessage(), I'm not even sure you need the Map of students and strings in the first place. Frankly you could just create a sendEnrollmentEmail method, pass in a Student, and extract the message via getBadEnrollmentsMessage() right there.