That's because "user.dir" indicates the current user directory in effect when the JVM is run; in Windows, this is often the location of the JAR unless you specify otherwise. In OSX there may well be no concept of a current dir, but more likely it just has a different default.
Though I have never specifically tested this code under OSX, you can try this to locate the directory from which any class was loaded:
static public File getClassLocation(Class cls, boolean trmjar) {
ClassLoader cl; // class loader
URL uo; // url object
String ef; // external form of URL
String lc; // lowercase external form of URL
File rf; // return file
if((cl=cls.getClassLoader())==null) { cl=ClassLoader.getSystemClassLoader(); }
if((uo=cl.getResource(cls.getName().replace('.','/')+".class"))==null) {
return null;
}
ef=uo.toExternalForm();
lc=ef.toLowerCase();
while(lc.startsWith("jar:") || lc.startsWith("file:/")) {
if(lc.startsWith("jar:")) {
if(lc.indexOf("!/")!=-1) { ef=ef.substring("jar:".length(),(ef.indexOf("!/"))); } // strip encapsulating "jar:" and "!/..." from JAR url
else { ef=ef.substring("jar:".length() ); } // strip encapsulating "jar:"
}
if(lc.startsWith("file:/")) {
ef=ef.substring("file:/".length()); // strip encapsulating "file:/"
if(!ef.startsWith("/")) { ef=("/"+ef); }
while(ef.length()>1 && ef.charAt(1)=='/') { ef=ef.substring(1); }
}
lc=ef.toLowerCase();
}
ef=TextDecode.urlString(ef);
rf=new File(ef);
if(lc.endsWith(".class") || (trmjar && lc.endsWith(".jar"))) { rf=rf.getParentFile(); }
if(rf.exists()) { rf=rf.getAbsoluteFile(); }
return rf;
}
it's worked reliably for me for years under Windows for all versions of Java since Java 1.