Monday, August 27, 2012

Differences between equals() and hashCode() methods for String and Object reference

Before moving to the explanation we will check the contract, copied from the Object specification [JavaSE6]:

  • Whenever it is invoked on the same object more than once during an execution
    of an application, the hashCode method must consistently return the
    same integer, provided no information used in equals comparisons on the
    object is modified. This integer need not remain consistent from one execution
    of an application to another execution of the same application. 

  • If two objects are equal according to the equals(Object) method, then calling
    the hashCode method on each of the two objects must produce the same
    integer result.

  • It is not required that if two objects are unequal according to the equals(Object)
    method, then calling the hashCode method on each of the two objects
    must produce distinct integer results. However, the programmer should be
    aware that producing distinct integer results for unequal objects may improve
    the performance of hash tables.

First we consider the String object. 

Assume I create two String instances (without using new keyword) like as bellow,

String s1 = "Hello World";
String s2 = "Hello World";


When we print s1 == s2 it should print true. Because these two String references refer the same location.
Likewise s1.equals(s2) is also returns true.

Note:  When we create the two different String instance(without new keyword) with the same value, both references refer the same location in memory.

Now we create two different String objects(with new keyword) but the contents are same.

String s1 = new String("Hello World");
Strung s2 = new String("Hello World");

When we print s1.equals(s2) it should print true because the the String equals methods checks the content of the String instance. If the content is true then the equals methods returns true.

According to the java contract if equals objects returns true the the hashCode also should returns true(this is not applicable for all scenarios). So s1.equals(s2) returns true.

s1 == s2 print false as these are two different objects.

Now we move to the real word objects

Assume we already have the Student class with two properties studentId, name, and age.

public class Student {

    private int studentId;
    private String name;
    private int age;

    public int getStudentId() {
        return studentId;
    }

    public void setStudentId(int studentId) {
        this.studentId = studentId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}


Now I am creating two instances for student class.

Student student1 = new Student();
student1.setStudentId(11111);
student1.setName("K.Senthuran");
student1.setAge(29);

Student student2 = new Student();
student2.setStudentId(11111);
student2.setName("K.Senthuran");
student2.setAge(29);


We will discuss what is the output for following print statements.

1. student1 == student2
With out any confusion we can tell the output should be false as these student1 and student2 are two different objects.

2. student1.equals(student2)
This prints false because when this statement executes, it calls the Object equals() method. The current implementation for the object equals() method is as following,

public boolean equals(Object obj) {
   return (this == obj)
}

So this should print false.

3. student1.hashCode() == student2.hashCode()
This returns false because the two different objects have different hashcodes.

Now we override the equals method to return true for the objects which has same contents.

@Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (studentId != other.studentId)
            return false;
        return true;
    }


Now if we print student1.equals(student2) it should print true (According to the above equals() method implementation).


According to the contract if two objects are equal according to the equals(Object) method, then calling
the hashCode method on each of the two objects must produce the same integer result. But when we print the hash code for these two objects those return different value.

So we break the contract by overriding the equals() method. Check the bellow example.

For example, consider the following simplistic PhoneNumber class, whose equals method is constructed:

public final class PhoneNumber {
   private final short areaCode;
   private final short prefix;
   private final short lineNumber;
   public PhoneNumber(int areaCode, int prefix, int lineNumber) {
   rangeCheck(areaCode, 999, "area code");
   rangeCheck(prefix, 999, "prefix");
   rangeCheck(lineNumber, 9999, "line numberthis.areaCode = (short) areaCode;
   this.prefix = (short) prefix;
   this.lineNumber = (short) lineNumber;
}


private static void rangeCheck(int arg, int max, String name) {


   if (arg < 0 || arg > max)
      throw new IllegalArgumentException(name +": " + arg);
}


@Override public boolean equals(Object o) {
   if (o == this)
      return true;
   if (!(o instanceof PhoneNumber))
      return false;
   PhoneNumber pn = (PhoneNumber)o;
   return pn.lineNumber == lineNumber && pn.prefix == prefix && pn.areaCode == areaCode;
}
// Broken - no hashCode method!
... // Remainder omitted
}

Suppose you attempt to use this class with a HashMap:
Map<PhoneNumber, String> m = new HashMap<PhoneNumber, String>();
m.put(new PhoneNumber(707, 867, 5309), "Jenny");


At this point, you might expect m.get(new PhoneNumber(707, 867, 5309)) to return "Jenny", but it returns null. Notice that two PhoneNumber instances are involved: one is used for insertion into the HashMap, and a second, equal, instance is used for (attempted) retrieval. The PhoneNumber class’s failure to override
hashCode causes the two equal instances to have unequal hash codes, in violation of the hashCode contract. Therefore the get method is likely to look for the phone number in a different hash bucket from the one in which it was stored by the put method. Even if the two instances happen to hash to the same bucket, the get
method will almost certainly return null, as HashMap has an optimization that caches the hash code associated with each entry and doesn’t bother checking for object equality if the hash codes don’t match. Fixing this problem is as simple as providing a proper hashCode method for the PhoneNumber class as bellow.

@Override
    public int hashCode() {
        int result = hashCode;
        if (result == 0) {
            result = 17;
            result = 31 * result + areaCode;
            result = 31 * result + prefix;
            result = 31 * result + lineNumber;
            hashCode = result;
        }
        return result;
    }

Now we can access the value "Jenny" by using the key new PhoneNumber(707, 867, 5309).


Likewise if we want to avoid the contract problem mentioned in Student class we need to override the hashcode() method properly as bellow,

@Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + studentId;
        return result;
    }


Conclusion: If we override the equals() method we should override the hashCode() method also.





Saturday, March 10, 2012

Difference between Absolute and Relative Paths

Absolute Path

Absolute paths are called that because they refer to the very specific location, including the domain name. The absolute path to a Web element is also often referred to as the URL. For example, the absolute path to this Web page is:
http://webdesign.about.com/library/weekly/aa040502a.htm

You typically use the absolute path with the domain to point to Web elements that are on another domain than your own. For example, if I want to link to the Graphic Design Guide's site - I need to include the domain in the URL: http://graphicdesign.about.com/. So a link to her glossary entry would look like this:
<a href="http://graphicdesign.about.com/library/glossaries/web/blabsoluteurl.htm"> ...</a>

If you're referring to a Web element that is on the same domain that you're on, you don't need to use the domain name in the path of your link. Simply leave off the domain, but be sure to include the first slash (/) after the domain name.

For example, the Beginner's Resource Center has the URL: http://webdesign.about.com/library/beginning/bl_begin.htm If I were to link to this URL from another page on my site, I could link to it in this way:
<a href="/library/beginning/bl_begin.htm">...</a>

It is a good idea to use absolute paths, without the domain name, on most Web sites. This format insures that the link or image will be usable no matter where you place the page. This may seem like a silly reason to use longer links, but if you share code across multiple pages and directories on your site, using absolute paths will speed up your maintenance.


Relative Path

Relative paths change depending upon what page the links are located on. There are several rules to creating a link using the relative path:

  • links in the same directory as the page have no path information listed
    filename
  • sub-directories are listed without any preceding slashes
    weekly/filename
  • links up one directory are listed as
    ../filename

How to determine the relative path:

  1. Determine the location of the page you are editing.
    This article is located in the/library/weekly folder on my site.
  2. Determine the location of the page or image you want to link to.
    The Beginner's Resource Center is located here: /library/beginning/
  3. Compare the locations and to decide how to point to it
    From this article, I would need to step up one directory (to/library) and then go back down to the beginning directory
  4. Write the link using the rules listed above:
    &lt;a href="../beginning/bl_begin.htm"> ... </a>

Thursday, May 26, 2011

Becoming a Better Programmer: A Conversation With Java Champion Heinz Kabutz

In the early days of Java programming, I sometimes resorted to "clever" coding. For example, when I was optimizing a system written by a company in Germany, I changed the String addition to use StringBuffer after we had optimized the architecture and design of the system and wanted to improve things a bit. Don't read too much into microbenchmarks. Performance advantages come from good design and an appropriate architecture.

We start with a basic concatenation based on +=:

  public static String concat1(String s1, String s2, String s3,
String s4, String s5, String s6) {
String result = "";
result += s1;
result += s2;
result += s3;
result += s4;
result += s5;
result += s6;
return result;
}

String is immutable, so the compiled code will create many intermediate String objects, which can strain the garbage collector. A common remedy is to introduce StringBuffer, causing it to look like this:

public static String concat2(String s1, String s2, String s3,
String s4, String s5, String s6) {
StringBuffer result = new StringBuffer();
result.append(s1);
result.append(s2);
result.append(s3);
result.append(s4);
result.append(s5);
result.append(s6);
return result.toString();
}

But the code is becoming less legible, which is undesirable.

Using JDK 6.0_02 and the server HotSpot compiler, I can execute concat1() a million times in 2013 milliseconds, but concat2() in 734 milliseconds. At this point, I might congratulate myself for making the code three times faster. However, the user won't notice it if 0.1 percent of the program becomes three times faster.

Here's a third approach that I used to make my code run faster, back in the days of JDK 1.3. Instead of creating an empty StringBuffer, I sized it to the number of required characters, like so:

  public static String concat3(String s1, String s2, String s3,
String s4, String s5, String s6) {
return new StringBuffer(
s1.length() + s2.length() + s3.length() + s4.length() +
s5.length() + s6.length()).append(s1).append(s2).
append(s3).append(s4).append(s5).append(s6).toString();
}

I managed to call that a million times in 604 milliseconds. Even faster than concat2(). But is this the best way to add the strings? And what is the simplest way?

The approach in concat4() illustrates another way:

  public static String concat4(String s1, String s2, String s3,
String s4, String s5, String s6) {
return s1 + s2 + s3 + s4 + s5 + s6;
}

You can hardly make it simpler than that. Interestingly, in Java SE 6, I can call the code a million times in 578 milliseconds, which is even better than the far more complicated concat3(). The method is cleaner, easier to understand, and quicker than our previous best effort.

Sun introduced the StringBuilder class in J2SE 5.0, which is almost the same as StringBuffer, except it's not thread-safe. Thread safety is usually not necessary with StringBuffer, since it is seldom shared between threads. When Strings are added using the + operator, the compiler in J2SE 5.0 and Java SE 6 will automatically use StringBuilder. If StringBuffer is hard-coded, this optimization will not occur.

When a time-critical method causes a significant bottleneck in your application, it's possible to speed up string concatenation by doing this:

  public static String concat5(String s1, String s2, String s3,
String s4, String s5, String s6) {
return new StringBuilder(
s1.length() + s2.length() + s3.length() + s4.length() +
s5.length() + s6.length()).append(s1).append(s2).
append(s3).append(s4).append(s5).append(s6).toString();
}
However, doing this prevents future versions of the Java platform from automatically speeding up the system, and again, it makes the code more difficult to read.

Source: http://java.sun.com/developer/technicalArticles/Interviews/community/kabutz_qa.html

Sunday, May 22, 2011

யூடியூப் காணொளிகளை தரவிறக்கம் செய்ய இலகுவான வழி

கூகுளின் யூடியூப் என்பது மிகப்பிரபலம் பெற்ற இணையத்தளமாகும். இதில் பல இலட்சக்கணக்கான காணொளிகள் தரவேற்றப்பட்டுள்ளன. இவற்றை நாம் இலவசமாக கண்டுகளிக்கமுடியும்.

இதில் இல்லாத காணொளிகள் இல்லை என்று சொல்லுமளவிற்கு பழையவை முதல் புதியவை வரை அனைத்தும் உள்ளன. இவற்றில் சிலவற்றை எமக்கு தரவிறக்கம் செய்து கொள்ள ஆர்வமிருக்கும். இவற்றிற்காக நாம் சில மென்பொருட்களை உபயோகப்படுத்துவது வழக்கம்.

அவ்வாறு நாம் தரவிறக்கும் காணொளிகள் FLV என்ற வடிவத்திலேயே கிடைக்கும். இவற்றை பின்னர் நாம் நமக்கு தேவையான வடிவத்திற்கு மாற்றிக் கொள்வது வழக்கம்.

ஆனால் வேறு எந்த மென்பொருட்களின் துணையுமின்றி மிக இலகுவாக Mp3, Mp4, FLV வடிவத்தில் யூடியுப் வீடியோவின் கீழ் தோன்றும் பட்டனின் உதவியுடனேயே தரவிறக்கம் செய்யமுடியும்.



கீழுள்ள இணைப்புகளின் ஊடாக அதனை தரவிறக்கம் செய்துகொள்ள முடியும்.

பயர்பொக்ஸ் பாவனையாளர்கள்

https://addons.mozilla.org/en-us/firefox/addon/easy-youtube-video-downl-10137/

குரோம் பாவனையாளர்கள்

http://www.chromeextensions.org/other/easy-youtube-video-downloader/

Source: www.virakesari.lk