03-类与对象——课后动手动脑
1.早期我们经常这样定义变量
int value=100;
前面的示例中这样定义变量
MyClass obj = new MyClass();
这两种方式定义的变量是一样的吗?
这两种方式定义的变量是一样的,因为它们都是类的实例化,只是第一种是一个简便的写法,第二种是正常的对类进行实例化。
2.对象变量也可以使用“==”判断两变量值是否相等吗?
当“==”施加于引用类型变量时,是比较这两个变量是否引用同一对象,换句话说,“==”实际上相当于比较两个引用类型变量中保存的对象地址是否相同。
在Java中要比对两个对象的字段值,可以重写基类的equals()方法。将其改成自己类的一个方法用来调用。
3.请输入并运行以下代码,得到什么结果?
public class Test { public static void main(String[] args) { Foo obj1=new Foo(); Foo obj2=new Foo(); System.out.println(obj1==obj2); } } class Foo{ int value=100; }
运行结果:
原因:按照第2条,我们可知,“==”实际上相当于比较两个引用类型变量中保存的对象地址是否相同。obj1和obj2虽然都是Foo类型的变量,但其指向的空间或者地址不同,所以输出的是false。
4.
请总结一下,这个方法有哪些“与众不同之处”,你能列出几条?
1.方法名与类名完全相同。
2.无返回值,也没有void关键字。
5.以下代码为何无法通过编译?哪儿出错了?
原因:在类中如果提供了一个构造函数,那么在进行类的实例化时,调用的就是这个构造函数。此例中,Foo类本身提供了一个有参构造函数,这就导致系统不会提供默认的构造函数,那么定义obj1时就无法调用无参构造函数,所以整个程序当中会出现错误。
6.如果一个类中既有初始化块,又有构造方法,同时还设定了字段的初始值,谁说了算?
例:
1 public class InitializeBlockClass { 2 3 { 4 5 field = 200; 6 7 } 8 9 public int field = 100; 10 11 public InitializeBlockClass(int value){ 12 13 this.field = value; 14 15 } 16 17 public InitializeBlockClass(){ 18 19 } 20 21 public static void main(String[] args) { 22 // TODO Auto-generated method stub 23 InitializeBlockClass obj = new InitializeBlockClass(); 24 25 System.out.println(obj.field); 26 27 28 obj = new InitializeBlockClass(300); 29 30 System.out.println(obj.field); 31 32 } 33 34 }
运行结果:
Java字段初始化的规律:
如果有多个不同地方对字段进行初始化,那么该字段的最终取值取决于最后一次初始化。
7.请运行TestStaticInitializeBlock.java示例,观察输出结果,总结出“静态初始化块的执行顺序”。
TestStaticInitializeBlock.java
1 class Root 2 { 3 static{ 4 System.out.println("Root的静态初始化块"); 5 } 6 { 7 System.out.println("Root的普通初始化块"); 8 } 9 public Root() 10 { 11 System.out.println("Root的无参数的构造器"); 12 } 13 } 14 class Mid extends Root 15 { 16 static{ 17 System.out.println("Mid的静态初始化块"); 18 } 19 { 20 System.out.println("Mid的普通初始化块"); 21 } 22 public Mid() 23 { 24 System.out.println("Mid的无参数的构造器"); 25 } 26 public Mid(String msg) 27 { 28 //通过this调用同一类中重载的构造器 29 this(); 30 System.out.println("Mid的带参数构造器,其参数值:" + msg); 31 } 32 } 33 class Leaf extends Mid 34 { 35 static{ 36 System.out.println("Leaf的静态初始化块"); 37 } 38 { 39 System.out.println("Leaf的普通初始化块"); 40 } 41 public Leaf() 42 { 43 //通过super调用父类中有一个字符串参数的构造器 44 super("Java初始化顺序演示"); 45 System.out.println("执行Leaf的构造器"); 46 } 47 48 } 49 50 public class TestStaticInitializeBlock 51 { 52 public static void main(String[] args) 53 { 54 new Leaf(); 55 56 57 } 58 }
执行结果:
“静态初始化块的执行顺序”:
1.静态初始化块只执行一次。
2.创建子类型的对象时,也会导致父类型的静态初始化块的执行。
8.静态方法中只允许访问静态数据,那么,如何在静态方法中访问类的实例成员(即没有附加static关键字的字段或方法)?
在静态方法中使用new进行实例化,然后再调用非静态成员。
例:
1 public class Task { 2 3 public int a = 2; 4 5 static int b = 3; 6 7 static void display() 8 9 { 10 11 Task t1 = new Task(); 12 13 System.out.println("a="+t1.a); 14 15 } 16 public static void main(String[] args) { 17 // TODO Auto-generated method stub 18 Task t2 = new Task(); 19 20 t2.display(); 21 22 } 23 24 }
执行结果:
9.请看以下的神奇代码:
public class StrangeIntegerBehavior {
public static void main(String[] args){ Integer i1=100; Integer j1=100; System.out.println(i1==j1); Integer i2=129; Integer j2=129; System.out.println(i2==j2); } }
执行结果:
两对整数明明完全一样,为何一个输出true,一个输出false?
首先,利用javap对该程序进行反汇编。结果如图:
可以看到其调用了Integer中的valueOf方法,valueOf方法的源代码为:
可以看到,valueOf(int i)调用了IntegerCache.cache,通过网上查找,我得到了它的源代码如下:
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 8 int h = 127; 9 String integerCacheHighPropValue = 10 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); 11 if (integerCacheHighPropValue != null) { 12 try { 13 int i = parseInt(integerCacheHighPropValue); 14 i = Math.max(i, 127); 15 // Maximum array size is Integer.MAX_VALUE 16 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 }
通过这两段代码,我们可知,在[-128,127]这个区间中“”==”比较的是这两个数的数值,但当超出这个范围时,其就会创建一个新的对象,对于对象来说,我们是无法通过“==”进行比较的,因为“==”比较的是这两个对象所指向的空间是否相同,所以第二个会输出false。