My question is quite simple.
When is the hashcode for a String calculated?
When the String is created, the hashcode is also computed, and always ready in O(1) after construction
The hashcode is computed only the first time the hashCode method is called and is ready in O(1) time for all subsequent calls
The hashcode is computed each time the hashCode method is called
Option 1 seems reasonable because Strings are immutable. The hashcode for a given string will never change. But, this slows down the creation of strings, so it also seems reasonable that option 2 would be used. Option 3 seems silly and a waste of time, but saves on space because the hashcode isn't being stored. There may also be some logical reason that Option 3 is the best approach that I'm not thinking about.
Thanks so much in advance
Option 2. It's calculated the first time hashCode is called and stored in a private field.
In OpenJDK 8 it looks like this:
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/lang/String.java#l1452
In fact, if you take a look at what fields String has, you can see it has a private int called hash.
System.out.println(String.class.getDeclaredFields());
output includes
{ ... private int java.lang.String.hash ... }
From the source code JDK 14
/** Cache the hash code for the string */
private int hash; // Default to 0
#HotSpotIntrinsicCandidate
public String(String original) {
this.value = original.value;
this.coder = original.coder;
this.hash = original.hash;
}
And then
public int hashCode() {
// The hash or hashIsZero fields are subject to a benign data race,
// making it crucial to ensure that any observable result of the
// calculation in this method stays correct under any possible read of
// these fields. Necessary restrictions to allow this to be correct
// without explicit memory fences or similar concurrency primitives is
// that we can ever only write to one of these two fields for a given
// String instance, and that the computation is idempotent and derived
// from immutable state
int h = hash;
if (h == 0 && !hashIsZero) {
h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
if (h == 0) {
hashIsZero = true;
} else {
hash = h;
}
}
return h;
}
I am trying to solve an algorithms problem using java tree set.
The problem as follows:
Find top k frequent words in realtime data stream.
Implement three methods for Topk Class:
TopK(k). The constructor.
add(word). Add a new word.
topk(). Get the current top k frequent words.
And my thought was to use a hashmap to remember frequencies and a treeset as a buffer.
My implementation passed most of the case, except one:
TopK(10)
add("aw")
add("fb")
add("fb")
topk()
The answer supposed to be [fb,aw] but now it's [fb,aw, fb]
However, my code passed test case like:
TopK(10)
add("iiiiii")
add("fb")
add("fb")
topk()
and
TopK(10)
add("fb")
add("fb")
topk()
I have no idea what's wrong, so I printed some value when the comparator is called. It gave me this:
aw aw
11111111
fb aw
33333333
fb aw
33333333
fb aw
222222222
fb aw
222222222
Which means, the second "fb" was compared to "aw" twice and the comparator is done. I spent hours to debug and I have found nothing so far.
Here is my implementation:
public class TopK {
int size;
HashMap<String, Integer> map;
TreeSet<String> seen;
public TopK(int k) {
// do intialization if necessary
size = k;
seen = new TreeSet<String>(new Comparator<String>(){
#Override
public int compare(String str1, String str2){
System.out.println(str1 + " "+ str2);
if (str1.equals(str2)){
System.out.println("11111111");
return 0;
}
// important !https://www.jiuzhang.com/qa/7646/
// 128 δ»₯εintegerε°±δΈεδΊ
int number1 = map.get(str1);
int number2 = map.get(str2);
if (number1 != number2){
System.out.println("222222222");
return map.get(str1) - map.get(str2);
} else {
System.out.println("33333333");
return str2.compareTo(str1);
}
}
});
map = new HashMap<String, Integer>();
}
/*
* #param word: A string
* #return: nothing
*/
public void add(String word) {
// write your code here
if (!map.containsKey(word)){
map.put(word, 0);
}
map.put(word, map.get(word) + 1);
if (seen.contains(word)){
seen.remove(word);
seen.add(word);
} else {
seen.add(word);
if (seen.size() > size){
seen.pollFirst();
}
}
}
/*
* #return: the current top k frequent words.
*/
public List<String> topk() {
// Write your code here
List<String> results = new ArrayList<String>();
Iterator it = seen.iterator();
while(it.hasNext()) {
String str = (String)it.next();
results.add(0, str);
}
return results;
}
}
Our first clue is that case:
aw
fb
fb
Fails but:
iiiii
fb
fb
Succeed.
This can happen only because of the line: return str2.compareTo(str1); - if the number of appearances are different order by string compare (this could be check easily - please do that).
The only explanation I can think of is the contains function of java TreeSet has "optimization" of searching only until where the element should be - if you have order and the element is not where it should be then consider it as none exist in the TreeSet (think about array that should be sort for checking for number you run in log(n) but no on all array - so if he exist in wrong position you will miss him).
Notice that you change the place where the element should be before checking the contains function. So let look at the 2th iteration - we have fb and aw both with value of 1 in the map. On the TreeSet the are as [fb,aw] (because string compare as explain before). Now you change the map and fb have value of 2 -> it should be in the last place but the contains function compare to aw and think it should be after it - but he is the last element so it assume fb does not exist and just add him -> That why you see 2 compares between fb and aw - one for the contain and one for the add.
Hope that was understandable....
I had asked the same question in another forum, but dint get any suitable answers...so Im posting it here. I have the following program:
public void execute(){
public static ArrayList<Long> time = new ArrayList<Long>();
public static ArrayList<Integer> state = new ArrayList<Integer>();
public static ArrayList<Integer> cpu = new ArrayList<Integer>();
for(int i=0; i<time.size(); i++){
if(cpu.get(i).equals(get)){
Long next_time = time.get(i);
Integer next_func = state.get(i);
Integer next_proc = cpu.get(i);
if(next_time.equals(g) && (next_func.equals(test1.func_num))){
Integer func_next = stt.get(i+1);
if(func_next.equals(0)||(func_next.equals(next_func))) {
System.out.println("here");
}
else
System.out.println("here");
if(cpu.get(i+2).equals(get))
if(stt.get(i+2).equals(func_next) || (stt.get(i+2).equals(0)))
System.out.println(stt.get(i+2));
}
}
}
What I want to do is this: I get the value of time, cpu and state from the user. find the match in the arraylist for the corresponding values, then I want to loop through the arraylists for only those values which match the 'cpu'. All the ArrayLists are of same size and contain values corresponding to each other at any given index. How can I do this?
Example:
The ArrayLists contain various values as follows:
time = 1 cpu = 12 state = 24
time = 2 cpu = 12 state = 4
time = 5 cpu = 13 state = 23
time = 6 cpu = 13 state = 26
time = 8 cpu = 11 state = 34
time = 11 cpu = 12 state = 54
time = 13 cpu = 12 state = 56
time = 14 cpu = 11 state = 58
time = 15 cpu = 15 state = 46
This is the situation. And I get value from the user as time=2 cpu=12 state =4....I find the match and after that I want to look for all values corresponding to cpu=12 only..
Base more on the description then code example
You get a input in form of time, cpu and state form user.
You want to find match for those input criteria.
To be able to do that easily, You should create a type for that.
public class Data {
private final int cpu;
private final long time;
private final int state;
public Data(int cpu, long time, int state) {
this.cpu = cpu;
this.time = time;
this.state = state;
}
//add implementation for equals and hashcode methods.
}
The equals and hash code method are responsible to define unique value for object. So when you create an object with the same input the should generate same hashcode.
The you create your collection with those elements
Set<Data> storage = new HashSet<Data>();
in this storage, you should store all data that you want to execute search on.
The search is simple. You create a search item
Data searchItem = new Data(user.getCpu(), user.getTime(), user.getState());
if(storage.contains(searchItem)) {
// action on true
} else {
// action on false
}
Implementing hash code
EDIT:
Q: How to perform on all items for given CPU ?
To support such operation you must have in your code a structure that can deliver you some sort of data based on decision. Typically for this operation is used type Map. This type allow to gather under a key reference to value. The value can be a collection of objects.
Map> dataMap = new HashMap<>();// Java diamond notation.
or you can use [Multimap] from guava.
When you find the match, you do this:
//once you have the index in a Integer var called myVal
Set<Integer> indexes = new HashSet<Integer>();
for(int i=0; i<time.size(); i++){
if (cpu.get(i) == myVal) {
indexes.add(i);
}
}
Now you can use the set of indexes:
for (Integer index: indexes) {
//do whatever
}
This is O(time.size()). Hope this helps
Java is pure oo language. It means not only you must write in Object Oriented Style, but also think everything as objects like real world. Before finding how to solve this problem, I would like to advise you that you should read carefully OOP and Connections framework in Java.
Something like this should work:
bool matchFound = false;
for (int i = 0; i < time.size(); i++) {
long thisTime = time.get(i);
int thisState = state.get(i);
int thisCpu = cpu.get(i);
if (matchFound) {
if (thisCpu == userCpu) {
System.out.println("Time: " + thisTime + " "
+ "State: " + thisState + " "
+ "Cpu: " + thisCpu);
}
} else {
matchFound = (thisTime == userTime
&& thisState == userState
&& thisCpu == userCpu);
}
}
I've been reading some posts here and articles around the web but I can't picture a serial keys based system for my application.
http://www.brandonstaggs.com/2007/07/26/implementing-a-partial-serial-number-verification-system-in-delphi/
I read this one but I can't turn the code into Java and I'm not very familiar with the terms either.
What possible insight can you give me on this? Ideally my application will be for sale but I don't expect it to be much popular, I don't mind much if it gets cracked if I have users that appreciate the product and buy it, but I want to avoid it to be easily cracked. Please be as specific as you can, I'm somewhat new to Java.
Thanks in advance.
I was quite interested in that article, so I implemented the code in Java. may be of use
import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;
public class KeyValidator {
private static final byte[][] params = new byte[][] { { 24, 4, 127 }, { 10, 0, 56 }, { 1, 2, 91 }, { 7, 1, 100 } };
private static final Set<String> blacklist = new TreeSet<String>();
static {
blacklist.add("11111111");
}
private static byte PKV_GetKeyByte(final int seed, final byte a, final byte b, final byte c) {
final int a1 = a % 25;
final int b1 = b % 3;
if (a1 % 2 == 0) {
return (byte) (((seed >> a1) & 0x000000FF) ^ ((seed >> b1) | c));
} else {
return (byte) (((seed >> a1) & 0x000000FF) ^ ((seed >> b1) & c));
}
}
private static String PKV_GetChecksum(final String s) {
int left = 0x0056;
int right = 0x00AF;
for (byte b : s.getBytes()) {
right += b;
if (right > 0x00FF) {
right -= 0x00FF;
}
left += right;
if (left > 0x00FF) {
left -= 0x00FF;
}
}
int sum = (left << 8) + right;
return intToHex(sum, 4);
}
public static String PKV_MakeKey(final int seed) {
// Fill KeyBytes with values derived from Seed.
// The parameters used here must be exactly the same
// as the ones used in the PKV_CheckKey function.
// A real key system should use more than four bytes.
final byte[] keyBytes = new byte[4];
keyBytes[0] = PKV_GetKeyByte(seed, params[0][0], params[0][1], params[0][2]);
keyBytes[1] = PKV_GetKeyByte(seed, params[1][0], params[1][1], params[1][2]);
keyBytes[2] = PKV_GetKeyByte(seed, params[2][0], params[2][1], params[2][2]);
keyBytes[3] = PKV_GetKeyByte(seed, params[3][0], params[3][1], params[3][2]);
// the key string begins with a hexadecimal string of the seed
final StringBuilder result = new StringBuilder(intToHex(seed, 8));
// then is followed by hexadecimal strings of each byte in the key
for (byte b : keyBytes) {
result.append(intToHex(b, 2));
}
// add checksum to key string
result.append(PKV_GetChecksum(result.toString()));
final String key = result.toString();
return key.substring(0, 4) + "-" + key.substring(4, 8) + "-" + key.substring(8, 12) + "-" + key.substring(12, 16) + "-" + key.substring(16, 20);
}
private static boolean PKV_CheckKeyChecksum(final String key) {
// remove cosmetic hyphens and normalise case
final String comp = key.replaceAll("-", "").toLowerCase(Locale.UK);
if (comp.length() != 20) {
return false; // Our keys are always 20 characters long
}
// last four characters are the checksum
final String checksum = comp.substring(16);
return checksum.equals(PKV_GetChecksum(comp.substring(0, 16)));
}
public static Status PKV_CheckKey(final String key) {
if (!PKV_CheckKeyChecksum(key)) {
return Status.KEY_INVALID; // bad checksum or wrong number of
// characters
}
// remove cosmetic hyphens and normalise case
final String comp = key.replaceAll("-", "").toLowerCase(Locale.UK);
// test against blacklist
for (String bl : blacklist) {
if (comp.startsWith(bl)) {
return Status.KEY_BLACKLISTED;
}
}
// At this point, the key is either valid or forged,
// because a forged key can have a valid checksum.
// We now test the "bytes" of the key to determine if it is
// actually valid.
// When building your release application, use conditional defines
// or comment out most of the byte checks! This is the heart
// of the partial key verification system. By not compiling in
// each check, there is no way for someone to build a keygen that
// will produce valid keys. If an invalid keygen is released, you
// simply change which byte checks are compiled in, and any serial
// number built with the fake keygen no longer works.
// Note that the parameters used for PKV_GetKeyByte calls MUST
// MATCH the values that PKV_MakeKey uses to make the key in the
// first place!
// extract the Seed from the supplied key string
final int seed;
try {
seed = Integer.valueOf(comp.substring(0, 8), 16);
} catch (NumberFormatException e) {
return Status.KEY_PHONY;
}
// test key 0
final String kb0 = comp.substring(8, 10);
final byte b0 = PKV_GetKeyByte(seed, params[0][0], params[0][1], params[0][2]);
if (!kb0.equals(intToHex(b0, 2))) {
return Status.KEY_PHONY;
}
// test key1
final String kb1 = comp.substring(10, 12);
final byte b1 = PKV_GetKeyByte(seed, params[1][0], params[1][1], params[1][2]);
if (!kb1.equals(intToHex(b1, 2))) {
return Status.KEY_PHONY;
}
// test key2
final String kb2 = comp.substring(12, 14);
final byte b2 = PKV_GetKeyByte(seed, params[2][0], params[2][1], params[2][2]);
if (!kb2.equals(intToHex(b2, 2))) {
return Status.KEY_PHONY;
}
// test key3
final String kb3 = comp.substring(14, 16);
final byte b3 = PKV_GetKeyByte(seed, params[3][0], params[3][1], params[3][2]);
if (!kb3.equals(intToHex(b3, 2))) {
return Status.KEY_PHONY;
}
// If we get this far, then it means the key is either good, or was made
// with a keygen derived from "this" release.
return Status.KEY_GOOD;
}
protected static String intToHex(final Number n, final int chars) {
return String.format("%0" + chars + "x", n);
}
public enum Status {
KEY_GOOD, KEY_INVALID, KEY_BLACKLISTED, KEY_PHONY
}
}
It's not that hard, if you're somewhat flexible in your requirements -- perhaps the scheme below would work for you.
You could just produce K = [SN, H([X,SN,Y])] which is the concatenation of an incrementing serial number with a hash, where the hash is a secure hash function of the concatenation of the serial number between unique constants X and Y that are secret "salt" you use to prevent the use of rainbow tables.
Use a well-known secure hash algorithm (e.g. SHA-1 or SHA-2; MD5 is probably also adequate, since the known weaknesses for MD5 are collision attacks, and not preimage attacks) and you should be all set, as least as far as the serial key part goes (you'll probably want to prevent two people from using the same key).
The other thing you can do which is helpful is use K = [SN, T, H([X, SN, T, Y])] -- use both the serial number and a timestamp. This can be used to allow only a narrow use window for the serial key: it's valid within N seconds of the timestamp, so it would prevent reuse of the key outside that window.
Then encode/decode K to a representation that can be used to easily allow users to enter the key (e.g. base64).
It's best to have a simple and transparent overall algorithm -- obfuscation is not going to help you if someone reverse-engineers your scheme.
Securing applications in general isn't a simple task. A lot of companies are investing a lot of money to find new securing algorithms, which get all cracked very fast.
Securing Java applications is a bit more difficult. Any serial verification algorithm embedded within your application can be decompiled, so a serial key generator will be pretty easy to build.
A good starting point is the article you gave. It tells you how to build a key verification system, and how to generate keys for your (legitimate) users.
After implementing such an algorithm, I'd suggest you to secure the source code a little, so decompilation become a little more "tricky". Use code obfuscation techniques to hide your verification algorithm implementation. This will also make the task harder for people trying to crack your application just by modifying byte-code.
A good technique could be to export your key verification algorithm on a remote server. The client send the key to the server, which replies with a 'validation code' to tell your application that your key is valid. But this doesn't prevents users from modifying your application to remove any key verification procedure. And this might be very annoying for legitimate users who don't have a 24-hours Internet connection. I'm thinking about Steam, which verify the key validity at every launch on Internet, and which annoys a lot of users.
To find a good protection technique, look around you and try to determine how others people do, which techniques are working, which aren't. They are a lot of example (Video game industry, in particular). But keep in mind that even the best companies aren't able to secure their applications correctly. No techniques are unbreakable.