1、早期我们经常这样定义变量“int value=100;”,而前面的示例中这样定义变量“MyClass obj=new MyClass();”,这两种方式定义的变量是一样的吗?
不一样,前者为原始数据类型;后者为引用类型的变量,又简称对象变量。当声明一个对象的变量时,实际上并没有创建一个对象,此变量=null,定义一个原始数据类型时的变量时会马上给其分配内存。在定义变量时,java要求显示初始化变量。对象变量如果不引用一个真实的对象,则必须声明为null。当对象不再使用时,JVM会回收MyClass对象所占用的内存,这个过程称为“垃圾回收
2、对于原始数据类型的变量(比如int),可以直接使用“==”判断两变量值是否相等
对象变量也可以使用“==”判断两变量值是否相等吗?
当“==”施加于原始数据类型变量时,是比较变量所保存的数据是否相等
当“==”施加于引用类型变量时,是比较这两个变量是否引用同一对象。
引用代表地址,所以“==”实际上相当于比较两个引用类型变量中保存的对象地址是否相同。
3、如何比较两个对象的“内容”是否一样?
两个对象的“内容”,其实是指它们在某一时刻的所有字段的值,“内容相等”,其实是就“对应字段值”一致。
在Java中要比对两个对象的字段值,可以 “重写(override)”基类的equals()方法
4、 以下代码为何无法通过编译?哪儿出错了?
主类里调用的是默认构造函数,与Foo类里自定义的构造函数参数不同。
如果类提供了一个自定义的构造方法,将导致系统不再提供默认构造方法。
5、如果一个类中既有初始化块,又有构造方法,同时还设定了字段的初始值,谁说了算?
public class InitializeBlockDemo {
public static void main(String[] args) {
InitializeBlockClass obj=new InitializeBlockClass();
System.out.println(obj.field);
obj=new InitializeBlockClass(300);
System.out.println(obj.field);
}
}
class InitializeBlockClass{
//下面这句在初始化块之前与之后,会影响到field字段的初始值
//public int field=100;
{
field=200;
}
public int field=100;
public InitializeBlockClass(int value){
this.field=value;
}
public InitializeBlockClass(){
}
}
执行类成员定义时指定的默认值或类的初始化块,到底执行哪一个要看哪一个“排在前面”,也就是谁比较靠后就是谁初始化起作用。。执行类的构造函数。类的初始化块不接收任何的参数,而且只要一创建类的对象,它们就会被执行。因此,适合于封装那些“对象创建时必须执行的代码”。
“public int field = 100;”在“{field=200;}”之后:
“public int field = 100;”在“{field=200;}”之前:
6、请运行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();
}
}
运行结果:
静态初始化块只执行一次。
创建子类型的对象时,也会导致父类型的静态初始化块的执行。
7、静态方法中只允许访问静态数据,那么,如何在静态方法中访问类的实例成员(即没有附加static关键字的字段或方法)?
请编写代码验证你的想法。
public class Test {
int a=2;
static int b=3;
public static void test()
{
System.out.println("实例变量a="+new Test().a);
System.out.println("静态变量b="+b);
}
public static void main(String[] args) {
Test.test();
Test test1=new Test();
System.out.println("结果是:实例变量="+test1.a);
}
}
8、Integer类的装箱和拆箱到底是怎样实现的?
首先了解:基本数据类型仅仅提供了数据,却缺少一些常用的功能,为此,Java提供了包装类。包装类 = 基本数据类型的数据 + 扩充的一些方法和字段。包装类是引用类型,可以创建相应的对象。
代码:
public class BoxAndUnbox {
/**
* @param args
*/
public static void main(String[] args) {
int value=100;
Integer obj=value; //装箱
int result=obj*2; //拆箱
}
}
在JAVA中,数据类型可分为两大种,基本数据类型(值类型)和类类型(引用数据类型)。基本类型的数据不是对象,所以对于要将基本数据类型当对象使用的情况,JAVA提供的包装类。
所谓装箱,就是把基本类型用他们相对应的引用类型包装起来,使他们可以具有对象的特质,如我们可以把int型包装成Integer类的对象,或者把double包装成Double等等。
所谓拆箱,就是跟装箱的方向相反,将Integer及Double这样的引用类型的对象重新简化为值类型的数据。
J2SE5.0后提供了自动装箱和拆箱的功能,此功能事实上是编译器来帮忙,编译器在编译时依照编写的方法,决定是否进行装箱或拆箱动作。
自动装箱的过程:每当需要一种类型的对象时,这种基本类型就自动的封装到与它相同类型的包装中。
自动拆箱的过程:每当需要一个值时,被装箱对象中的值就被自动的提取出来,没必要再去调用intValue()和doubleValue()方法。
自动装箱只需将该值赋给一个类型包装器引用,java会自动创建一个对象。
9、两对整数明明完全一样,为何一个输出true,一个输出false?
第一次比较的是同一个地址的数字,而第二次比较的数是创建了l两个不同地址的对象。