课后作业3

一:使用自定义类

 1 public class ClassAndObjectTest
 2 {
 3 
 4     public static void main(String[] args)
 5     {
 6         //创建类的实例,定义一个对象变量引用这一实例
 7         MyClass obj = new MyClass();
 8         //通过对象变量调用类的公有方法
 9         obj.myMethod("Hello");
10         //给属性赋值
11         obj.setValue(100);
12         //输出属性的当前值
13         System.out.println(obj.getValue());
14         //直接访问对象公有字段
15         obj.Information = "Information";
16         //输出对象公有字段的当前值
17         System.out.println(obj.Information);
18     }
19 }
20 
21 /**
22  * 自定义Java类的示例
23  */
24 class MyClass
25 {
26     // 公有字段
27     public String Information = "";
28 
29     // 自定义公有Java实例方法
30     public void myMethod(String argu)
31     {
32         System.out.println(argu);
33     }
34 
35     // 定义属性:私有字段+get方法+set方法
36     private int value;
37     public int getValue()
38     {
39         return value;
40     }
41     public void setValue(int value)
42     {
43         this.value = value;
44     }
45 
46 }

运行结果:

 小结:

需要定义一个对象变量 然后“创建(new)”一个对象,赋值给对象变量 现在就可以通过对象变量使用对象,主要方式有: (1)直接调用类的方法; (2)存取类的字段。

二、进行实验:

 1 public class test{
 2 public static void main(String[] args){
 3     Foo obj1=new Foo();
 4     Foo obj2=new Foo();
 5     System.out.println(obj1==obj2);
 6 }
 7 
 8 }
 9 class Foo{
10     int value=100;
11 }

结果为:false

结论:

当“==”施加于原始数据类型变量时,是比较变量所保存的数据是否相等 当“==”施加于引用类型变量时,是比较这两个变量是否引用同一对象。 引用代表地址,所以“==”实际上相当于比较两个引用类型变量中保存的对象地址是否相同。

三、如何比较两个对象的“内容”是否一样?
 1 public class ObjectEquals 
 2 {
 3 
 4     
 5     
 6     public static void main(String[] args) 
 7     {
 8         
 9         MyTestClass obj1=new MyTestClass(100);
10         
11         MyTestClass obj2=new MyTestClass(100);
12                         System.out.println(obj1==obj2);
13         
14         System.out.println(obj1.equals(obj2));
15     
16     }
17 
18 
19 }
20 
21 class MyTestClass
22 
23 {
24     
25     public int Value;
26     
27     //注意:只有参数类型为Object的,才是重写了Object的equals方法
28     
29     //参数类型为MyTestClass的,仅仅是Overload了equals方法。
30  
31     //   @Override
32 
33     //   public boolean equals(Object obj)
34     
35 //    {
36     
37 //        return ((MyTestClass)obj).Value==this.Value;
38     
39 //    }
40     
41    
42         public boolean equals(MyTestClass obj)
43    
44         {
45        
46             return obj.Value==this.Value;
47    
48         }
49     
50         public MyTestClass(int initValue)
51     
52         {
53         
54             Value=initValue;
55     
56         }
57 
58 }

结果:

false

true

结论:两个对象的“内容”,其实是指它们在某一时刻的所有字段的值,“内容相等”,其实是就“对应字段值”一致。 在Java中要比对两个对象的字段值,可以 “重写(override)”基类的equals()方法

当你定义一个类时,如果不显式指明它的“父亲”类是哪个,则默认是Object。 Object是Java的最顶层基类,其中定义了equals( )方法

四、动手动脑:下面代码为何无法通过编译
 1 public class Test{
 2     public static void main(String[] args){
 3         Foo obj1=new Foo();
 4     }
 5 }
 6 class Foo{
 7     int value;
 8     public Foo(int initValue){
 9         value=initValue;
10     }
11 }

结论:如果类提供了一个自定义的构造方法,将导致系统不再提供默认构造方法。

 五、进行实验:如果一个类中既有初始化块,又有构造方法,同时还设定了字段的初始值,谁说了算?以下代码输出结果是什么?

 1 public class Test {
 2     public static void main(String[] args){
 3      InitializeBlockClass obj=new InitializeBlockClass();
 4         System.out.println(obj.field);
 5         obj=new InitializeBlockClass(300);
 6         System.out.println(obj.field);
 7     }
 8 }
 9 class InitializeBlockClass{
10     {
11         field=200;
12     }
13     public int field=100;
14     public InitializeBlockClass(int value){
15         this.field=value;
16     }
17     public InitializeBlockClass(){}
18 }

结果:

100

300

结论:类字段的初始化顺序:1执行类成员定义时指定的默认值或类的初始化块,到底执行哪一个要看哪一个“排在前面”,排到后面的是最终执行的。 2执行类的构造函数

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

六、动手动脑:请运行TestStaticInitializeBlock.java示例,观察输出结果,总结出“静态初始化块的执行顺序”。
 1 class Root
 2 {
 3     static
 4     {
 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     {
19         System.out.println("Mid的静态初始化块");
20     }
21     {
22         System.out.println("Mid的普通初始化块");
23     }
24     public Mid()
25     {
26         System.out.println("Mid的无参数的构造器");
27     }
28     public Mid(String msg)
29     {
30         //通过this调用同一类中重载的构造器
31         this();
32         System.out.println("Mid的带参数构造器,其参数值:" + msg);
33     }
34 }
35 class Leaf extends Mid
36 {
37     static
38     {
39         System.out.println("Leaf的静态初始化块");
40     }
41     {
42         System.out.println("Leaf的普通初始化块");
43     }
44     public Leaf()
45     {
46         //通过super调用父类中有一个字符串参数的构造器
47         super("Java初始化顺序演示");
48         System.out.println("执行Leaf的构造器");
49     }
50 
51 }
52 
53 public class TestStaticInitializeBlock
54 {
55     public static void main(String[] args)
56     {
57         new Leaf();
58 
59 
60     }
61 }

结果:

Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Mid的带参数构造器,其参数值:Java初始化顺序演示
Leaf的普通初始化块
执行Leaf的构造器

结论:静态初始化的执行顺序:静态初始化块只执行一次。 创建子类型的对象时,也会导致父类型的静态初始化块的执行。

七、静态方法中只允许访问静态数据,那么,如何在静态方法中访问类的实例成员(即没有附加static关键字的字段或方法)?

解决方法:把静态方法的参数设置为类的实例,这样通过参数传递的方式就可以访问实例的成员了

 1 public class Test
 2 {
 3     public static void main(String[] args)
 4     {
 5     Testgaga T=new Testgaga();
 6     Testgaga X=new Testgaga();
 7     T.show(X);
 8     }
 9 }
10 class Testgaga{
11     int num=10;
12     static void show(Testgaga T){
13         System.out.println(T.num);
14     }
15 }

结果:10

八、Integer的“诡异”特性”,上述神奇代码(StrangeIntegerBehavior.java)输出诡异的结果,原因何在?

 1 public class StrangeIntegerBehavior
 2 {
 3 
 4 
 5     public static void main(String[] args)
 6     {
 7 
 8 
 9         Integer i1=100;
10 
11         Integer j1=100;
12 
13         System.out.println(i1==j1);
14 
15 
16         Integer i2=129;
17 
18         Integer j2=129;
19 
20         System.out.println(i2==j2);
21 
22     }
23 
24 
25 }

结果:

true 

false

结论:

当我们使用Integer类来包装整型数据时,Java会自动进行装箱操作,将整型数据封装为Integer对象。在这个过程中,对于较小的整数(范围在-128到127之间),Java会将它们缓存起来,以便提高性能和节省内存。

在你的代码中,i1和j1的值都是100,这个值在缓存范围内,因此当装箱操作发生时,Java会从缓存中返回同一个Integer对象。换句话说,i1和j1实际上引用的是同一个对象,因此它们比较相等,输出结果为true。

而对于i2和j2的值都是129,超出了缓存范围。当装箱操作发生时,Java会创建新的Integer对象来表示这个值。所以i2和j2实际上引用的是两个不同的对象,它们比较不相等,输出结果为false。

需要注意的是,这种缓存机制只适用于自动装箱,如果是使用new关键字手动创建Integer对象,不会应用缓存,即使数值相同,比较结果也会是false。

posted @ 2023-09-27 17:25  千恒  阅读(3)  评论(0编辑  收藏  举报