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。

posted @ 2017-10-20 09:47  编程小大白  阅读(194)  评论(0编辑  收藏  举报