课程作业06:验证课件上的代码,并将所有的动手动脑或要求发表博客作业部分整理成一篇博客发表。

1.以下代码为何无法通过编译?哪儿出错了?

 

验证结论:如果类提供了一个自定义的构造方法,将导致系统不再提供默认的构造方法。所以此时需要无参的构造方法时,需要自己写一个空的构造方法,即系统默认的构造方法。

 

2. 如果一个类中既有初始化块,又有构造方法,同时还设定了字段的初始值,谁说了算?

 

 

请依据代码的输出结果,自行总结Java字段初始化的规律。

 

规律一:类字段的初始化顺序

1.执行类成员定义时指定的默认值或类的初始化块,到底执行哪一个要看哪一个“排在前面”,输出结果是排在后边的那个,先执行的被修改为后执行的。

2.执行类的构造函数。

规律二:类初始化块的应用

类的初始化块不接收任何的参数,而且只要一创建类的对象,它们就会被执行。因此,适合于封装那些“对象创建时必须执行的代码”。

 

3.请运行TestStaticInitializeBlock.java示例,观察输出结果,总结出“静态初始化块的执行顺序”。

package give3;

 

public class TestStaticInitializeBlock {

 

    public static void main(String[] args) {

       new Leaf();

       }

}

 

class Root

{

    static{

       System.out.println("Root的静态初始化块");

    }

    {

       System.out.println("Root的普通初始化块");

    }

    public Root()

    {

       System.out.println("Root的无参数的构造器");

    }

}

class Mid extends Root

{

    static{

       System.out.println("Mid的静态初始化块");

    }

    {

       System.out.println("Mid的普通初始化块");

    }

    public Mid()

    {

       System.out.println("Mid的无参数的构造器");

    }

    public Mid(String msg)

    {

       //通过this调用同一类中重载的构造器

       this();

       System.out.println("Mid的带参数构造器,其参数值:" + msg);

    }

}

class Leaf extends Mid

{

    static{

       System.out.println("Leaf的静态初始化块");

    }

    {

       System.out.println("Leaf的普通初始化块");

    }  

    public Leaf()

    {

       //通过super调用父类中有一个字符串参数的构造器

       super("Java初始化顺序演示");

       System.out.println("执行Leaf的构造器");

    }

}

结果截图:

 

静态初始化的执行顺序:

1.静态初始化块只执行一次。

2.创建子类型的对象时,也会导致父类型的静态初始化块的执行。

 

4.静态方法中只允许访问静态数据,那么,如何在静态方法中访问类的实例成员(即没有附加static关键字的字段或方法)?请编写代码验证你的想法。

 

类的静态成员(变量和方法)属于类本身,在类加载的时候就会分配内存,可以通过类名直接去访问;非静态成员(变量和方法)属于类的对象,所以只有在类的对象产生(创建类的实例)时才会分配内存,然后通过类的对象(实例)去访问。

 

5. 两对整数明明完全一样,为何一个输出true,一个输出false?

 

输出结果表明i1和i2指向的是同一个对象,而i3和i4指向的是不同的对象。此时只需一看源码便知究竟,下面这段代码是Integer的valueOf方法的具体实现:

public static Integer valueOf(int i) {

        if(i >= -128 && i <= IntegerCache.high)

            return IntegerCache.cache[i + 128];

        else

            return new Integer(i);

    }

而其中IntegerCache类的实现为:

 private static class IntegerCache {

        static final int high;

        static final Integer cache[];

 

        static {

            final int low = -128;

 

            // high value may be configured by property

            int h = 127;

            if (integerCacheHighPropValue != null) {

                // Use Long.decode here to avoid invoking methods that

                // require Integer's autoboxing cache to be initialized

                int i = Long.decode(integerCacheHighPropValue).intValue();

                i = Math.max(i, 127);

                // Maximum array size is Integer.MAX_VALUE

                h = Math.min(i, Integer.MAX_VALUE - -low);

            }

            high = h;

 

            cache = new Integer[(high - low) + 1];

            int j = low;

            for(int k = 0; k < cache.length; k++)

                cache[k] = new Integer(j++);

        }

 

        private IntegerCache() {}

    }

 

从这2段代码可以看出,在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。上面的代码中i1和i2的数值为100,因此会直接从cache中取已经存在的对象,所以i1和i2指向的是同一个对象,而i3和i4则是分别指向不同的对象。

 

posted @ 2017-10-20 17:30  Felix_9190  阅读(185)  评论(0编辑  收藏  举报