What is Reference Types?
Any class that you create is called Reference Types, it is the memory locations where objects or arrays are stored. This means they point to where the object is stored in the memory rather than holding the data directly. Primitive data types holds the actual data, reference types hold the memory address of the object.
How memory is allocated in Java?
Generally it is stored in Stack and Heap
Stack Memory :Stores references of the object ,each memory has separate stack.
Heap memory: it is kind of common place shared by entire java program here is were all your objects are stored
Null reference: A reference variable that is not pointing to any object has a value of null .why this is essential to understand because trying to use null reference to access an object will result in Null pointer Exception.
What happen behind the scenes?
lets consider the above example: Students Jack= new Students (5);
Students(5) is stored in the location a1 in the Heap which is globally shared ,hence the reference will be created.
When you create a primitive data type like example int i =5; it will be stored in stack ,each method has separate stack. so local variable whenever created in a method will be stored in Stack and reference variable would be stored in Heap.
Example:
Jack -> is stored in stack -> it is the reference variable -> you get the value of location a1
Students (5) -> is stored in heap
when the Students is declared to be nothing;
output would be nothing
variable name -> nothing
location->null
now the memory location is empty it will not refer to anything .when reference variable nothing will be declared to jack
nothing =Jack
the memory allocation of jack will be stored.
Suppose we create one more instance Students Marie = new Students (5); same value it will be stored in different location of heap . When we try to understand the == operation here in reference variables
Marie == Jack will give false though the values are same the are referring the different object it returns false .
Java has some inbuilt reference types
String,
Wrapper
DateTime
String:
It is an object and an special class in Java represents sequence of characters created within the keyword String
String name = "Numpy"
here Numpy is an instance of class string and it is called String literal.
the index in string would be N-->0,u-->1, m-->2,p-->3,y-->4
We have so many utility methods in String some of the commonly used methods:
length() -Returns the length
indexOf() -Returns the index of the first occurred specified character/substring
charAt() -Returns the character at the specified index.
lastIndexOf() -Returns the index of the Last occurred specified character/substring
contains() -Checks if the string contains the specified substring.
startsWith() -Checks if the string starts with the specified substring.
endsWith() -Checks if the string ends with the specified substring.
isEmpty() -Checks if the string is empty.
toUpperCase() -Converts all characters in the string to uppercase.
toLowerCase() -Converts all characters in the string to lowercase.
trim() -Removes the whitespace front and back from the string.
subString() -Returns a new string that is a substring of the specified string.
it will return the portion of the string between the index asked for starting and end
compareTo() - compares two strings lexicographically.
meaning comparing them based on the unicode values of the characters, just as in dictionary order
if the first string comes before the second string in lexicographical order, comparTo() method returns negative integer. same way if the string is smaller than than the second string which is compared will return negative integer and if same it will give zero .
when comparing the string with more characters , what will happen comparison happens until the characters of both string finds the difference or one string runs out of characters.
replace() -replaces all occurrences of a specified character/substring
concat() -appends one string to the end of another.
join() - method is used to join multiple strings with a specified delimiter
matches() - is used to check if the entire string matches a given regular expression.
syntax: public boolean matches(String regex)
Split() syntax: String[] split(String regex)
spliting the String by single character
text gets split with the comma we can also split the string using regular expression
String
jshell> String text ="hello good morning"
text ==> "hello good morning"
jshell> String[] word = text.split("//s")
word ==> String[1] { "hello good morning" }
here i am spliting by space ''//s" double slash the space as delimiter .
String intern()
When we try to create strings using string literal ( without new keyword)
String str1= "Welcome";
String str2= "Welcome";
when string is created using literals, they are stored in heap memory (string pool).when we created String str1="Welcome" java first checks in the String pool if "Welcome" exists, since it doesn't exist, it creates and put it in pool and then returns reference, again when we create String str2= "Welcome" it checks since it already exists it consider , creating new is not required, hence it returns the reference, So str1 and str2 points same object.
when we create with new objects, it is created in the regular heap and it returns reference, they both points different memory. To avoid creating new memory and to optimize the memory, reusing identical objects for which String intern() method can be used.
String str1= "Welcome";// stored in string pool
String str3 = new String("Welcome")//stored in regular heap memory
String str5 = str3.intern()
This concept of string pool is achievable because string are immutable (Thread-safe) .Use of intern is not common it can be used when needed.
Understanding String Immutable
In java Strings are immutable meaning once a string object is created ,it cannot be changed, any operation that modifies the string will result in the creation of a new string object, leaving the original one unchanged in memory. This helps in making string safe.
Lets consider the Example
String name ="Numpy";
here , whenever i am trying to modify a value of the String name and perform the method concat it will not modify the String name , everytime i try to modify new String is created and that will return back. the original string remains unaffected. This behaviour of a string class is called immutability. Once the instance is created with specific value ,you will never be able change the value, over and over if method are perform new string will be created. Best example for handling test data like username and password, any content that doesn't require any modification after creation.
To over come this drawback we have String alternatives
StringBuffer: is synchronized class in Java which can be used to create String ,they are mutable and threadsafe
StringBuilder: same like Stringbuffer performance is better but not threadsafe.
comparing to String, Stringbuffer has no fixed length it can be modified whereas String has fixed length and cannot be modified.
In String we were not able to modify the string if we do so new object will be created but here we can modify hence its mutable.
we have more utilities in string buffer too
append() Appends the specified string to this character sequence.
insert() Inserts the specified string at the specified position.
delete() Removes the characters in a substring of this sequence.
deleteCharAt() Removes the char at the specified position.
replace() Replaces the characters in a substring of this sequence with characters in the specified String
reverse() Causes this character sequence to be replaced by the reverse of the sequence.
toString() Returns a string representing the data in this sequence.
length() Returns the length (character count).
setCharAt() Sets the character at the specified position
capacity( ) returns the total allocated capacity of the StringBuffer object
substring() Returns a new String that contains a subsequence of characters i.e portion of the object.
Wrapper class
Wrapper class encloses around a data type and gives it and object appearance ,core feature they are predefined reference type in Java and allows to perform various operation that are not possible with primitive data type. Primitive data types are not part of object hierarchy and they do not inherit object class, that is we are not able to use the primitive data types as object ,in that case we can use wrapper class, wrapping the primitive data into object .Just like String all wrapper class are immutable.
Wrapper: Boolean, Long, Float, Short, Double, Character, Byte, Integer
Primitive: boolean, long, float, short, double, char, byte, int
if primitive data types are available why wrapperclass is required? wrapper class provide more additional options, if you want to create a boolean from string or integer value from string, float to integer , wrapper class is possible.
to pass the primitive types as reference i.e object to any method which is not possible my primitive data types by default, we wrap the primitive type in object reference using appropriate Wrapper class, and pass the wrap object to the desired method.
there are 2 ways to create Wrapper class
constructor :Integer num1 = new Integer(7)
valueOf method: Integer num4 = Integer.valueOf(7)
constructor method is deprecate now valueOf is better way.
wrapper class provide lot of additional options creation from other datatypes, i want to create a boolean value from String , integer from String is possible. Converting String which is in binary format.
Autoboxing :
The automatic conversion of primitive data types into its equivalent Wrapper type is known as boxing and opposite operation is known as unboxing. constructing object explicitly is not required . compiler in java does lot of work at the back and coverts into wrapper. Lets try to understand this through example
Integer num4 = Integer.valueOf(4) -----> this is manually boxing: object is explicitly created from the primitive int by calling Integer.valueOf(4) this method will return the Integer with int value 4
Integer num4 = 4 -----> this is autoboxing : Here we have not created any object of Integer Wrapper Class, java compiler automatically converts primitive int value 4 to Integer. At the background java would create an instance of it and put the reference .
LocalDate, LocalTime and LocalDateTime.
In Java these class are an immutable class and threadsafe ,this class doesn't store or represents the date time instead Local Date description of date, Local Time description of the time and Local DateTime description of both date and time .It inherits Object class and implements the ChronoLocalDate interface. Based on Joda framework Date and Time can be implemented.
In Java these are available in packages (import java .time.*)
all modification method calls return new objects. it is hard to remember all methods instead we can just give today.
then all possible methods will be returning
setting the value and get the specific value method also possible like i have hardcode the yestday date and set to yesterday, and i have today as well now i can specifically get the month of the year and date of the year even we can compare using the isBefore() and isAfter() method. Same methods also possible with the Time, Hour and seconds.
conclusion:
Reference variable stores the memory of the object which is in heap memory allocation instead of actual object. When one reference variable is assign to another , the memory location is copied not the object. Understanding these concepts helps in writing efficient code, like avoiding Null pointer exception and optimizing memory management in java.
Happy learning!
Thank you for taking time to read this blog Post.