课后作业2
题目要求
验证课件上的代码,并将所有的动手动脑或要求发表博客作业部分整理成一篇博客发表。
具体实现
动手动脑1
A. 问题
以下代码为何无法通过编译?哪儿出错了?
B. 问题解决
1. 程序验证
public class Test {
public static void main(String [] args)
{
foo obj=new foo();
}
}
class foo{
int value;
public foo(int initvalue)
{
value=initvalue;
}
}
2. 报错反馈信息
Unresolved compilation problem: The constructor foo() is undefined
3. 结论
Java程序会自动添加默认构造函数当且仅当用户没有定义任何构造函数的情况下。
动手动脑2
A. 问题:
如果一个类中既有初始化块,又有构造方法,同时还设定了字段的初始值,谁说了算?
B. 问题解决:
1. 编写程序
程序1
public class Test {
public static void main(String [] args)
{
foo obj=new foo();
System.out.println(obj.value);
obj=new foo(300);
System.out.println(obj.value);
}
}
class foo{
{
value=100;
}
public int value=200;
public foo(int initvalue)
{
value=initvalue;
}
public foo()
{
}
}
程序2
public class Test {
public static void main(String [] args)
{
foo obj=new foo();
System.out.println(obj.value);
}
}
class foo{
{
value=100;
}
public int value=200;
public foo(int initvalue)
{
value=300;
}
public foo()
{
}
}
2. 程序分析
程序1运行结果是输出200,300。也就是按照先初始化块,再设定字段的初始值,最后是构造方法的情况下如果不调用构造函数,块初始化的值会丢失,但是把快初始化放在设定字段的初始值之后,结果输出100,300。说明这个与代码执行的先后顺序有关。
程序2运行结果输出200,但是如果把块初始化放在字段初始值和构造函数之后,结果都是100。
3. 结论
类的变量以字符初始值和块方式初始化等级相同,出现在后面的赋值方式会覆盖掉前面的方式。但是他们的等级同时高于无参的构造函数。
动手动脑3
A. 问题
请运行TestStaticInitializeBlock.java示例,观察输出结果,总结出“静态初始化块的执行顺序”。
TestStaticInitializeBlock.java程序:
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的构造器");
}
}
public class TestStaticInitializeBlock
{
public static void main(String[] args)
{
new Leaf();
}
}
B. 问题解决
1. 程序分析
程序执行结果为:
Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Mid的带参数构造器,其参数值:Java初始化顺序演示
Leaf的普通初始化块
执行Leaf的构造器
2. 结论
静态初始化块会在其他所有代码执行之前执行,且只执行一次。
动手动脑4
A. 问题:
静态方法中只允许访问静态数据,那么,如何在静态方法中访问类的实例成员(即没有附加static关键字的字段或方法)?
请编写代码验证你的想法。(发表到博客)
B. 问题解决:
1. 程序设计
public class Test {
String name="The name";
long salary=3;
short employee_id=4;
static int total_employees;
static void clear(){
total_employees=10;
System.out.println(total_employees);
System.out.println(new Test().salary);
}
public static void main(String [] args)
{
Test.clear();
}
}
2. 程序分析
运行结果输出10,3。静态方法如果直接调用非静态的变量会报错,但是如果在静态方法中声明一个对象,用这个对象去访问非静态变量就好了。
3. 结论
我的理解
类中静态的方法或属性,会在类被初始化之前就执行,但是在类被执行前并没有初始化这个类对象的其他属性,自然就没有值了,也就是为什么在静态方法中不能访问非静态的方法。
要想在静态方法中访问非静态的变量,可以声明一个该类的对象,然后调用这个对象的方法。
别人的答案:
类中静态的方法或属性,本质上来讲并不是该类的成员,在Java虚拟机装载该类的时候,这些静态的东西已经有了对象,它只是在这个类中“寄居”不需要通过类的构造器(构造函数)实现实例化;
而非静态的属性或者方法,在类装载时并没有存在,需在执行了该构造函数之后才可依赖类的实例对象存在。
动手动脑5
A. 问题
上述神奇代码(StrangeIntegerBehavior.java)输出诡异的结果,原因何在?
StrangeIntegerBehavior.java程序:
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);
}
}
程序运行结果:
提示:
使用javap来分析生成class文件,看它调用了Interger类的哪个方法,然后打开JDK源文件查看源码,就可以找到答案。
B. 问题解决
使用javap分析生成class文件,显示的是:
声明i1、j1等的时候调用的是Integer.valueOf:(I)这个方法。
查询该API显示:
This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
结果显示这个方法只能接受-128到127之内的数。