心得:
一周前和一位刚入职阿里蚂蚁金融的学长进行了一次会谈:总的来说,java学了一个学期,可能是急于求成(我身上最大的缺陷),就直接学JAVA的JDBC编程(MYSQL在大二上学期就开始在用了:2002 1064 HY2000 1042 2053等的错踩到心碎,不过踩坑不怕,重要的是你对MYSQL认识了多少,现在一般也是偷懒,很少写.sql建表啊等等操作,哈哈哈都是视图工具Navcat for mysql:需要的同学可以了解一下)我清晰的记得我在学java第二天学的多线程,做了一个买面包的多线程小demo,说实话,现在已经忘的一干二净,可能唯一记住的就是sleep()函数了...个人心得:不管学什么,都得循序渐进学长在“会谈”一直在强调基础,那么java基础是什么呢?一门语言的基础永远不会是老师讲的那些:类的访问权限、包的访问权限,static是一个类静态变量、怎么使用import啊等等肤浅到学了和没学一样的东西(可能是王某愚见....),学长考了我一道题:Integer a=200; Integer b=200; Integer a1=2; Integer b1=2; System.out.println(a==b); //false 1 System.out.println(a1==b1); //true 2
1 Integer c=new Integer(200);2 Integer d=new Integer(200);3 System.out.println(c==d); //false 3
5.既然知道自动装箱和自动拆箱,那么具体什么时候发生这种隐式转化?
首先是:
public final class Integer extends Number implements Comparable<Integer> {}
//Integer 的类声明,第一句要注意三个点:Number类了解多少?Comparable<T>泛型比较接口了解多少?CompareTo()函数的实现原则? 问题一: Integer 是int的包装类,在Integer对象里边包含了一个int基本类型的私有属性值1 /**2 * The value of the { @code Integer}.3 *4 * @serial5 */6 private final int value;
并且Integer也提供了很多供我们使用的方法:
我们从构造函数说起: 1>.向构造函数传int值public Integer(int value) { this.value = value; //为value赋值 }
2> Integer i=2;
经过断点测试: 这一句代码会调用Integer的一个函数:ValueOf() 涉及到缓存(IntegerCache),在第二个问题里边会详细解释
1 public static Integer valueOf(int i) {2 if (i >= IntegerCache.low && i <= IntegerCache.high)3 return IntegerCache.cache[i + (-IntegerCache.low)];4 return new Integer(i);5 }
还有很多ValueOf()的重载函数:基本上都是parseInt()函数的调用
1 public static Integer valueOf(String s, int radix) throws NumberFormatException {2 return Integer.valueOf(parseInt(s,radix));3 }4 public static Integer valueOf(String s) throws NumberFormatException {5 return Integer.valueOf(parseInt(s, 10));6 }
3> 向构造函数传String字符串
1 public Integer(String s) throws NumberFormatException { 2 this.value = parseInt(s, 10); //10为进制 3 } 4 public static int parseInt(String s, int radix) 5 throws NumberFormatException //数字格式异常 6 { 7 8 if (s == null) { 9 throw new NumberFormatException("null");10 }11 12 if (radix < Character.MIN_RADIX) { //java.lang.Character了解多少13 throw new NumberFormatException("radix " + radix +14 " less than Character.MIN_RADIX");15 }16 17 if (radix > Character.MAX_RADIX) {18 throw new NumberFormatException("radix " + radix +19 " greater than Character.MAX_RADIX");20 }21 22 int result = 0;23 boolean negative = false;24 int i = 0, len = s.length();25 int limit = -Integer.MAX_VALUE; //@Native public static final int MAX_VALUE = 0x7fffffff; @Native 了解多少?26 int multmin;27 int digit;28 29 if (len > 0) { //不为空30 char firstChar = s.charAt(0); //String类的操作方法了解多少31 if (firstChar < '0') { // Possible leading "+" or "-" '-'<'0'&&'+'<'0' true ASCLL码的比较 ‘1’<'0' 数据类型的自动转化 (String)‘1’=》(int)1 32 if (firstChar == '-') {33 negative = true; //是一个负数34 limit = Integer.MIN_VALUE;35 } else if (firstChar != '+')36 throw NumberFormatException.forInputString(s);37 38 if (len == 1) // Cannot have lone "+" or "-"39 throw NumberFormatException.forInputString(s);40 i++; 41 }42 multmin = limit / radix; 43 while (i < len) {44 // Accumulating negatively avoids surprises near MAX_VALUE45 digit = Character.digit(s.charAt(i++),radix); //java.lang.Character.digit()方法用法 : 在指定的基数(radix)返回字符ch的数值 //Character.digit('0',10)=0; Character.digit('a',10);=-146 if (digit < 0) {47 throw NumberFormatException.forInputString(s);48 }49 if (result < multmin) {50 throw NumberFormatException.forInputString(s);51 }52 result *= radix; //数值进位制的变化53 if (result < limit + digit) { //结果如果小于所能表示的最小值54 throw NumberFormatException.forInputString(s);55 }56 result -= digit;57 }58 } else {59 throw NumberFormatException.forInputString(s);60 }61 return negative ? result : -result;62 }
4>Integer的ToString()实现(移位运算没看懂......)
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE }; public static String toString(int i) { if (i == Integer.MIN_VALUE) return "-2147483648"; int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); char[] buf = new char[size]; getChars(i, size, buf); return new String(buf, true); } static int stringSize(int x) { for (int i=0; ; i++) if (x <= sizeTable[i]) //本人觉得这里是一个非常巧妙的设计 return i+1; }static void getChars(int i, int index, char[] buf) { int q, r; int charPos = index; char sign = 0; if (i < 0) { sign = '-'; i = -i; } // Generate two digits per iteration while (i >= 65536) { q = i / 100; // really: r = i - (q * 100); r = i - ((q << 6) + (q << 5) + (q << 2)); i = q; buf [--charPos] = DigitOnes[r]; buf [--charPos] = DigitTens[r]; } // Fall thru to fast mode for smaller numbers // assert(i <= 65536, i); for (;;) { q = (i * 52429) >>> (16+3); //????这个为什么是52429我也不知道......但是如果你打几个断点...看看结果还是能看懂的....hhh r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... buf [--charPos] = digits [r]; i = q; if (i == 0) break; } if (sign != 0) { buf [--charPos] = sign; } }
当然还有很多函数,比如:
public static Integer getInteger(String nm, Integer val):返回具有指定名称的系统属性的整数值:注意是返回一个系统属性的属性值,
问题又来了:System 系统类了解多少???(走到哪里都会引发一堆一堆的问题.....最后一定要总结),我就给大家粘贴一下代码吧:
1 public static Integer getInteger(String nm, int val) { 2 Integer result = getInteger(nm, null); 3 return (result == null) ? Integer.valueOf(val) : result; 4 } 5 6 public static Integer getInteger(String nm, int val) { 7 Integer result = getInteger(nm, null); 8 return (result == null) ? Integer.valueOf(val) : result; 9 }10 11 12 13 public static Integer getInteger(String nm, Integer val) {14 String v = null;15 try {16 v = System.getProperty(nm);17 } catch (IllegalArgumentException | NullPointerException e) {18 }19 if (v != null) {20 try {21 return Integer.decode(v);22 } catch (NumberFormatException e) {23 }24 }25 return val;26 }27 public static Integer decode(String nm) throws NumberFormatException {28 int radix = 10;29 int index = 0;30 boolean negative = false;31 Integer result;32 33 if (nm.length() == 0)34 throw new NumberFormatException("Zero length string");35 char firstChar = nm.charAt(0);36 // Handle sign, if present37 if (firstChar == '-') {38 negative = true;39 index++;40 } else if (firstChar == '+')41 index++;42 43 // Handle radix specifier, if present44 if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {45 index += 2;46 radix = 16;47 }48 else if (nm.startsWith("#", index)) {49 index ++;50 radix = 16;51 }52 else if (nm.startsWith("0", index) && nm.length() > 1 + index) {53 index ++;54 radix = 8;55 }56 57 if (nm.startsWith("-", index) || nm.startsWith("+", index))58 throw new NumberFormatException("Sign character in wrong position");59 60 try {61 result = Integer.valueOf(nm.substring(index), radix);62 result = negative ? Integer.valueOf(-result.intValue()) : result;63 } catch (NumberFormatException e) {64 // If number is Integer.MIN_VALUE, we'll end up here. The next line65 // handles this case, and causes any genuine format error to be66 // rethrown.67 String constant = negative ? ("-" + nm.substring(index))68 : nm.substring(index);69 result = Integer.valueOf(constant, radix);70 }71 return result;72 }
第二个问题:缓存(IntegerCache)先上代码:
1 private static class IntegerCache { 2 static final int low = -128; 3 static final int high; 4 static final Integer cache[]; 5 6 static { 7 // high value may be configured by property high的值可能取决于不同的操作系统, //据查阅:在jav5之前,缓存范围是写死在-128-127之间的,但是在 Java 6 中, //最大值映射到 java.lang.Integer.IntegerCache.high,可以使用 JVM 的启动参数设置最大值。 //这使我们可以根据应用程序的实际情况灵活地调整来提高性能, 8 int h = 127; 9 String integerCacheHighPropValue =10 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); //之前一直认为Integer是缓存在JVM里边的,原来是自己没有充分认识到JVM、JDK、JRE的真正区别。 //查阅资料后,Integer是缓存在JDK里的.....虽然现在也不是很理解 String a = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");//??? 我尝试了一下,疑惑加一 //String b = sun.misc.VM.getSavedProperty("high"); =》null //String c = System.getProperty("java.lang.Integer.IntegerCache.high"); =》null //String d = System.getProperty("high"); =》null?????11 if (integerCacheHighPropValue != null) {12 try {13 int i = parseInt(integerCacheHighPropValue);14 i = Math.max(i, 127);15 // Maximum array size is Integer.MAX_VALUE16 h = Math.min(i, Integer.MAX_VALUE - (-low) -1);17 } catch( NumberFormatException nfe) {18 // If the property cannot be parsed into an int, ignore it.19 }20 }21 high = h;22 23 cache = new Integer[(high - low) + 1];24 int j = low;25 for(int k = 0; k < cache.length; k++)26 cache[k] = new Integer(j++);27 28 // range [-128, 127] must be interned (JLS7 5.1.7)29 assert IntegerCache.high >= 127; //断言了解多少?30 }31 32 private IntegerCache() {}33 }
了解了IntegerCache缓存类:再来看ValueOf函数()
1 public static Integer valueOf(int i) {2 if (i >= IntegerCache.low && i <= IntegerCache.high) 3 return IntegerCache.cache[i + (-IntegerCache.low)]; 4 return new Integer(i); 5 }
1 Integer a=1;2 3 Integer b=1;4 5 Integer c=200;7 Integer d=200;
调用valueOf函数之后,确定i是否在缓存范围内,如果在,返回已经缓存下来的,如果不在,就返回一个新的Integer对象
故:a和b其实指向的是同一个Integer对象,c和d返回两个 堆地址不同的但是value相同的Integer对象。
引用类型存在堆中,基本类型与引用存在栈中,这是再基本不过的操作...
补充:
这种缓存行为不仅适用于Integer对象。我们针对所有整数类型的类都有类似的缓存机制。
有 ByteCache 用于缓存 Byte 对象有 ShortCache 用于缓存 Short 对象有 LongCache 用于缓存 Long 对象有 CharacterCache 用于缓存 Character 对象Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。 第三个问题:equals()函数/** * Returns the value of this { @code Integer} as an * { @code int}. */ public int intValue() { return value; }
1 public boolean equals(Object obj) {2 if (obj instanceof Integer) {3 return value == ((Integer)obj).intValue();4 }5 return false;6 } 7 8 Integer a=200; 9 Integer b=200; 10 a.equals(b) //true 实际比较的是包装类中的value值,(int)200和(int)200必定会相等,这就解决了缓存带来的差异
接下来我将贴几个equals():
String类的
1 public boolean equals(Object anObject) { 2 if (this == anObject) { 3 return true; //栈里指向堆的地址相同==引用指向通过一个对象 4 } 5 if (anObject instanceof String) { 6 String anotherString = (String)anObject; 7 int n = value.length; 8 if (n == anotherString.value.length) { 9 char v1[] = value;10 char v2[] = anotherString.value;11 int i = 0;12 while (n-- != 0) {13 if (v1[i] != v2[i])14 return false; //char数组的依次比较,String中的value又是什么呢?15 i++;16 }17 return true;18 }19 }20 return false;21 }
1 public final class String2 implements java.io.Serializable, Comparable, CharSequence {3 /** The value is used for character storage. */4 private final char value[];5 ......6 }
Object 的equals()
1 public boolean equals(Object obj) {2 return (this == obj);3 }
Object作为所有对象的直接父类...大多数的对象都是要重写equals函数;
第四个问题:Object的函数:
这个我本来就知道toString()、hasCode()、equals()、clone();但是通过看了看源码:发现Thread类继承自Object,所以必然会有有关线程的函数...那么问题来了...run()、sleep()又是哪里来的????
public final native void notify();public final native void notifyAll();public final native void wait(long timeout) throws InterruptedException;
第五个问题:autoboxing、unboxing
有一个前辈的博客写的很灵性:两句总结完毕
Integer a = 99; //自动装箱 相当于调用了Integer的valueOf()函数 int b = a;//自动拆箱 调用了intValue()函数 Integer a1=10; int a2=10; System.out.println(a2==a1) //true 懂了原理,这题也太简单了:原理:包装类和基本类型进行运算时,隐式自动拆箱......
之前写的:java基本数据类型的博客:
遗留的问题:
1.移位运算
2.@Native
3.Character类
4.Number类
5.String 类
6.断言
7.System类