课后作业
1、使用类的静态字段和构造函数,我们可以跟踪某个类所创建对象的个数。请写一个类,在任何时候都可以向它查询“你已经创建了多少个对象?”。
设计思路:定义类的构造函数时使静态变量i进行i++,即每构造一次就叠加一个构造的对象数。
程序流程图:
源程序代码:
1 package tiaoshi; 2 import java.util.Scanner; 3 public class Tiaoshi 4 { 5 static int i=0; 6 public Tiaoshi() 7 { 8 i++; 9 } 10 public static int getTimes() 11 { 12 return i; 13 } 14 public static void main(String[] args) 15 { 16 int x=1; 17 Scanner con=new Scanner(System.in); 18 for(;x!=0;) 19 { 20 System.out.print("构建个数(0退出):"); 21 x=con.nextInt(); 22 for(int t=0;t<x;t++) 23 { 24 Tiaoshi g=new Tiaoshi(); 25 } 26 System.out.println("程序已经创建对象的个数为:"+getTimes()); 27 } 28 } 29 }
结果截图:
2、验证ClassAndObjectTest.java(使用自定义类)
1 public class ClassAndObjectTest 2 { 3 public static void main(String[] args) 4 { 5 //创建类的实例,定义一个对象变量引用这一实例 6 MyClass obj = new MyClass(); 7 //通过对象变量调用类的公有方法 8 obj.myMethod("Hello"); 9 //给属性赋值 10 obj.setValue(100); 11 //输出属性的当前值 12 System.out.println(obj.getValue()); 13 //直接访问对象公有字段 14 obj.Information = "Information"; 15 //输出对象公有字段的当前值 16 System.out.println(obj.Information); 17 } 18 } 19 class MyClass 20 { 21 public String Information = ""; 22 public void myMethod(String argu) 23 { 24 System.out.println(argu); 25 } 26 private int value; 27 public int getValue() 28 { 29 return value; 30 } 31 public void setValue(int value) 32 { 33 this.value = value; 34 } 35 }
验证结果:
3、早期我们经常这样定义变量“int value=100;”,而前面的示例中这样定义变量“MyClass obj=new MyClass();”,这两种方式定义的变量是一样的吗?
这两种变量是不一样的。
前者是原始数据类型,例如int,float之类的变量,当声明一个原始数据类型的变量时,实际上并没有创建一个对象,此变量=null。
后者是引用类型变量,“引用”一个对象的变量称为“引用类型”的变量,定义一个原始类型的变量时,会马上给其分配内存,而对象变量的初始化中,该变量若不引用一个真实的对象,则必须声明为null。而且引用对象后的对象变量,且如果不再使用此变量,将会回收类定义的对象所占用的内存。
4、对于原始数据类型的变量(比如int),可以直接使用“==”判断两变量值是否相等,那么对象变量也可以使用“==”判断两变量值是否相等吗?
不可以,类似于字符串的比较大小,使用equals()进行比较,用法与其相同。当“==”施加于“原始数据类型”变量时,是比较变量所保存的数据是否相等,当“==”施加于“引用类型”变量时,是比较这两个变量是否引用同一对象。引用代表地址,所以“==”实际上相当于比较两个引用类型变量中保存的对象地址是否相同。
5、请输入并运行以下代码,得到什么结果?
1 public class Test 2 { 3 public static void main(String[] args) 4 { 5 Foo obj1 = new Foo(); 6 Foo obj2 = new Foo(); 7 System.out.println(obj1==obj2); 8 } 9 } 10 class Foo 11 { 12 int value=100; 13 }
结果截图:
6、如何比较两个对象的“内容”是否一样?
“内容相等”,其实是就“对应字段值”一致。
在JAVA中要比对两个对象的字段值,可以 重写基类的equals()方法;Object是Java的最顶层基类,其中定义了equals( )方法。
重写基类的equals()方法:
1 public class ObjectEquals 2 { 3 public static void main(String[] args) 4 { 5 MyTestClass obj1=new MyTestClass(100); 6 MyTestClass obj2=new MyTestClass(100); 7 System.out.println(obj1==obj2); 8 System.out.println(obj1.equals(obj2)); 9 } 10 } 11 class MyTestClass 12 { 13 public int Value; 14 public boolean equals(Object obj) 15 { 16 return ((MyTestClass)obj).Value==this.Value; 17 } 18 public MyTestClass(int initValue) 19 { 20 Value=initValue; 21 } 22 }
结果截图:
7、以下代码为何无法通过编译?哪儿出错了?
1 public class Test 2 { 3 public static void main(String[] args) 4 { 5 Foo obj1 = new Foo(); 6 } 7 } 8 class Foo 9 { 10 int value; 11 public Foo(int initValue) 12 { 13 value=initValue; 14 } 15 }
结论:如果类提供了一个自定义的构造方法,就将导致系统不再提供默认构造方法。所以,“Foo obj1 = new Foo();”中需要添加默认的参数。
8、如果一个类中既有初始化块,又有构造方法,同时还设定了字段的初始值,谁说了算?
1 package tiaoshi; 2 public class Tiaoshi 3 { 4 public static void main(String[] args) 5 { 6 tiao obj=new tiao(); 7 System.out.println(obj.field); 8 obj=new tiao(300); 9 System.out.println(obj.field); 10 } 11 } 12 class tiao 13 { 14 { 15 field=200; 16 } 17 public int field=100; 18 public tiao(int value) 19 { 20 this.field=value; 21 } 22 public tiao() 23 { 24 25 } 26 }
在“public int field = 100;”在“{field=200;}”之前时,是“{field=200;}”说了算;在之后时,是“public int field = 100;”说了算。也就是谁比较靠后就是谁初始化起作用。执行类成员定义时指定的默认值或类的初始化块,到底执行哪一个要看哪一个“排在前面”。
构造函数,类的初始化块不接收任何的参数,只要一创建类的对象,它们就会被执行。因此,适合于封装那些“对象创建时必须执行的代码”。
运行结果:
①“public int field = 100;”在“{field=200;}”之前:
②“public int field = 100;”在“{field=200;}”之后:
9、请运行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 System.out.println("Mid的带参数构造器,其参数值:" + msg); 32 } 33 } 34 class Leaf extends Mid 35 { 36 static 37 { 38 System.out.println("Leaf的静态初始化块"); 39 } 40 { 41 System.out.println("Leaf的普通初始化块"); 42 } 43 public Leaf() 44 { 45 super("Java初始化顺序演示"); 46 System.out.println("执行Leaf的构造器"); 47 } 48 } 49 public class TestStaticInitializeBlock 50 { 51 public static void main(String[] args) 52 { 53 new Leaf(); 54 } 55 }
结果截图:
10、静态方法中只允许访问静态数据,那么,如何在静态方法中访问类的实例成员(即没有附加static关键字的字段或方法)?
1 public class text4 2 { 3 public static void main(String[] args) 4 { 5 System.out.println("(静态变量)total_employees = "+Employee.clear()); 6 Employee e = new Employee(); 7 System.out.print("(实例变量)name = "+e.name); 8 } 9 } 10 class Employee 11 { 12 String name = "2"; 13 static int total_employees = 0; 14 static int clear() 15 { 16 return total_employees; 17 } 18 static void clear2() 19 { 20 21 } 22 }
结果截图:
11、 两对整数明明完全一样,为何一个输出true,一个输出false?
1 public static voidmain(String[] args) 2 { 3 Integer i1=100; 4 Integer j1=100; 5 System.out.println(i1=j1); 6 Integer i2=129; 7 Integer j2=129; 8 System.out.println(i2=j2); 9 }
通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,将返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。i1和i2的数值为100,所以会直接从cache中取已经存在的对象,所以i1和j1指向的是同一个对象,而i2和j2则是分别指向不同的对象。