1.以下代码为何无法通过编译?哪儿出错了?
原因:已有的Foo()是带一个int型参数的构造方法,不存在无参的构造方法Foo()
"构造方法"
当创建一个对象时,它的构造方法会被自动调用。构造方法与类名相同,没有返回值
,它的作用是对类进行初始化,如果类没有定义构造函数,Java编译器在编译时会自动给它提供一个没有参数的“默认构造方法”
但是如果已经有了一个有参数的构造方法,,即重写了构造方法,那么原来的默认的无参构造方法会被重写的构造方法所覆盖1 /** 2 * 3 */ 4 5 /** 6 * @author 信1605-3 20163471 吴鑫 7 * 8 */ 9 class InitializeBlockClass { 10 { 11 field=200; 12 } 13 public int field=100; 14 public InitializeBlockClass(int value) { 15 // TODO 自动生成的构造函数存根 16 this.field=value; 17 } 18 public InitializeBlockClass(){ 19 } 20 /** 21 * @param args 22 */ 23 public static void main(String[] args) { 24 // TODO 自动生成的方法存根 25 InitializeBlockClass obj=new InitializeBlockClass(); 26 System.out.println(obj.field); 27 28 obj=new InitializeBlockClass(300); 29 System.out.println(obj.field); 30 } 31 }
对此结果的分析:
1. 类开始的 { field=200;}是类的初始化块,用大括号"{","}"直接包裹的,是做为类的成员,这种“没有名字”的成员大多是初始化的字段。
2. 后面的 public int field=100;是类在定义的时候进行的初始化,函数到这里的field=100.
3.所以在主函数中的System.out.println(obj.field);输出的filed=100.
4.obj=new InitializeBlockClass(300); System.out.println(obj.field);是调用了构造函数,使用构造函数进行了初始化,赋值300,故输出的filed=300.
对规律进行的总结:
1. 执行类成员定义时指定的默认值或类的初始化块,到底执行哪一个要看哪一个“排在前面”。
2. 执行类的构造函数。
3. 类的初始化块不接受任何的参数,而且只要一创建类的对象,他们就会被执行。因此,适合于封装那些“对象创建时必须执行的代码”。
3.请运行以下程序,观察输出结果,总结出“静态初始化块的执行顺序”。
1 package 课堂3; 2 class Root 3 { 4 static{ 5 System.out.println("Root的静态初始化块"); 6 } 7 { 8 System.out.println("Root的普通初始化块"); 9 } 10 public Root() 11 { 12 System.out.println("Root的无参数的构造器"); 13 } 14 } 15 class Mid extends Root 16 { 17 static{ 18 System.out.println("Mid的静态初始化块"); 19 } 20 { 21 System.out.println("Mid的普通初始化块"); 22 } 23 public Mid() 24 { 25 System.out.println("Mid的无参数的构造器"); 26 } 27 public Mid(String msg) 28 { 29 //通过this调用同一类中重载的构造器 30 this(); 31 System.out.println("Mid的带参数构造器,其参数值:" + msg); 32 } 33 } 34 class Leaf extends Mid 35 { 36 static{ 37 System.out.println("Leaf的静态初始化块"); 38 } 39 { 40 System.out.println("Leaf的普通初始化块"); 41 } 42 public Leaf() 43 { 44 //通过super调用父类中有一个字符串参数的构造器 45 super("Java初始化顺序演示"); 46 System.out.println("执行Leaf的构造器"); 47 } 48 49 } 50 51 public class TestStaticInitializeBlock 52 { 53 public static void main(String[] args) 54 { 55 new Leaf(); 56 57 58 } 59 }
結果:
静态初始化块的执行顺序:
1.静态初始化块只执行一次。
2.创建子类型的对象时,也会导致父类型的静态初始化块的执行。
父类的静态初始化块
子类的静态初始化块
父类的初始化块
父类的构造函数
子类的初始化块
子类的构造函数
4.一个有趣的问题
静态方法中只允许访问静态数据,那么,如何在静态方法中访问类的是实例成员(即没有附加static关键字的字段方法)?
1 /** 2 * 3 */ 4 5 /** 6 * @author 信1605-3 20163471 吴鑫 7 * 8 */ 9 public class Test { 10 11 /** 12 * @param args 13 */ 14 int value1=1;//实例变量 15 static int value2=2;//类的静态变量 16 public static void print()//静态方法 17 { 18 System.out.println("实例变量value1="+new Test().value1); 19 //在静态方法中访问类的实例变量需进行类的实例化 20 System.out.println("静态变量value2="+value2); 21 //在静态方法中课直接访问类的静态变量 22 } 23 public static void main(String[] args) { 24 // TODO 自动生成的方法存根 25 Test test=new Test(); 26 Test.print(); 27 System.out.println("结果是:实例变量="+test.value1); 28 //访问实例成员 29 } 30 31 }
运行结果:
Integer类的装箱和拆箱到底是怎样实现的?
让我们先来了解一下装箱和拆箱
装箱就是 自动将基本数据类型转换为包装器类型;拆箱就是 自动将包装器类型转换为基本数据类型。
下表是基本数据类型对应的包装器类型:
1 public class BoxAndUnbox { 2 3 /** 4 * @param args 5 */ 6 public static void main(String[] args) 7 8 { 9 int value=100; 10 11 Integer obj=value; //装箱 12 13 int result=obj*2; //拆箱 14 System.out.println(result); 15 16 System.out.println(obj); 17 18 } 19 20 }
反编译class文件之后得到如下内容
由此可见 在装箱的时候自动调用的是Integer的valueOf(int)方法。而在拆箱的时候自动调用的是Integer的intValue方法。
因此可以用一句话总结装箱和拆箱的实现过程:
装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的 intValue方法实现的.
5.一段神奇的代码
1 public class MagicCode { 2 3 /** 4 * @param args 5 */ 6 public static void main(String[] args) { 7 // TODO 自动生成的方法存根 8 Integer i1=100; 9 Integer j1=100; 10 System.out.println(i1=j1);//ture 11 12 Integer i2=129; 13 Integer j2=129; 14 System.out.println(i2=j2);//false 15 } 16 17 }
以上是一段神奇的代码,乍一看,是两个true,然而一运行却是一个true一个false,这是为什么?
我们首先来编译一下
没毛病啊,再来反编译一下
我们可以看到使用的Integer方法的路径,打开JDK,找到它
打开它,用eclipse整理一下,然后其中有一段如下所示
1 /** 2 * Cache to support the object identity semantics of autoboxing for values between 3 * -128 and 127 (inclusive) as required by JLS. 4 * 5 * The cache is initialized on first usage. The size of the cache 6 * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. 7 * During VM initialization, java.lang.Integer.IntegerCache.high property 8 * may be set and saved in the private system properties in the 9 * sun.misc.VM class. 10 */ 11 12 private static class IntegerCache { 13 static final int low = -128; 14 static final int high; 15 static final Integer cache[]; 16 17 static { 18 // high value may be configured by property 19 int h = 127; 20 String integerCacheHighPropValue = 21 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); 22 if (integerCacheHighPropValue != null) { 23 try { 24 int i = parseInt(integerCacheHighPropValue); 25 i = Math.max(i, 127); 26 // Maximum array size is Integer.MAX_VALUE 27 h = Math.min(i, Integer.MAX_VALUE - (-low) -1); 28 } catch( NumberFormatException nfe) { 29 // If the property cannot be parsed into an int, ignore it. 30 } 31 } 32 high = h; 33 34 cache = new Integer[(high - low) + 1]; 35 int j = low; 36 for(int k = 0; k < cache.length; k++) 37 cache[k] = new Integer(j++); 38 39 // range [-128, 127] must be interned (JLS7 5.1.7) 40 assert IntegerCache.high >= 127; 41 } 42 43 private IntegerCache() {} 44 } 45 46 /** 47 * Returns an {@code Integer} instance representing the specified 48 * {@code int} value. If a new {@code Integer} instance is not 49 * required, this method should generally be used in preference to 50 * the constructor {@link #Integer(int)}, as this method is likely 51 * to yield significantly better space and time performance by 52 * caching frequently requested values. 53 * 54 * This method will always cache values in the range -128 to 127, 55 * inclusive, and may cache other values outside of this range. 56 * 57 * @param i an {@code int} value. 58 * @return an {@code Integer} instance representing {@code i}. 59 * @since 1.5 60 */ 61 public static Integer valueOf(int i) { 62 if (i >= IntegerCache.low && i <= IntegerCache.high) 63 return IntegerCache.cache[i + (-IntegerCache.low)]; 64 return new Integer(i); 65 } 66 67 /** 68 * The value of the {@code Integer}. 69 * 70 * @serial 71 */
在以上代码的12行我们可以看到IntegerCache类,它定义了一个[-128,127]的数组
在类加载时就将-128 到 127 的Integer对象创建了,并保存在cache数组中
然后我们再来看看61行的ValueOf方法,有段很明显的
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
也就是说,如果取的值是在-128 到 127 之间,
就直接在cache缓存数组中去取Integer对象,
然而超出范围,就得return new Integer(i);
也就是说随机的一个数,
这个值反正是[-128,127]之间,肯定不会是129就对了
来源:https://www.cnblogs.com/sdysyhj/p/7699874.html