zoukankan      html  css  js  c++  java
  • java笔记3(动手动脑)

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

    原因:已有的Foo()是带一个int型参数的构造方法,不存在无参的构造方法Foo()

    "构造方法"

    当创建一个对象时,它的构造方法会被自动调用。构造方法与类名相同,没有返回值

    ,它的作用是对类进行初始化,

    如果类没有定义构造函数,Java编译器在编译时会自动给它提供一个没有参数的“默认构造方法”

    但是如果已经有了一个有参数的构造方法,,即重写了构造方法,那么原来的默认的无参构造方法会被重写的构造方法所覆盖
     
    2.根据下列代码的输出结果,总结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就对了

  • 相关阅读:
    第一次作业
    第07组 Alpha事后诸葛亮
    2019SDN第4次作业
    第07组 Alpha冲刺(4/4)
    第07组 Alpha冲刺(3/4)
    第07组 Alpha冲刺(2/4)
    2019 SDN上机第3次作业
    2019 SDN阅读作业
    第07组 Alpha冲刺(1/4)
    2019 SDN上机第2次作业
  • 原文地址:https://www.cnblogs.com/sdysyhj/p/7699874.html
Copyright © 2011-2022 走看看