“==”符的注意事项、类的构造与使用、静态初始块的执行顺序
一、==符的使用
问题:
观察以下代码,两对整数明明完全一样,为何一个输出true,一个输出false?
原因分析:
(1)知识点:
当“==”施加于原始数据类型变量时,是比较变量所保存的数据是否相等。
当“==”施加于引用类型变量时,是比较这两个变量是否引用同一对象。
(2)通过查看Integer.java这个类就清楚了。当声明一个Integer j1 = 100;的时候。此时会进行自动装箱操作,也就是把基本数据类型转换成Integer对象,Integer中把-128~127 缓存了下来。官方解释是小的数字使用的频率比较高,所以为了优化性能,把这之间的数缓存了下来。这就是为什么这道题的答案回事false和ture了。当声明的Integer对象的值在-128~127之间的时候,引用的是同一个对象,所以结果是true。
二、关于类的构造和引用:
问题:
以下代码为何无法通过编译?哪儿出错了?
原因分析:
如果类提供了一个自定义的构造方法,将导致系统不再提供默认构造方法。因此必须使用自定义的构造方法中的参数类型。
修改方法:
如下图被荧光笔标注的部分,括号里的参数应该存放int类型的参数。
三、构造函数
问题1:
如果一个类中既有初始化块,又有构造方法,同时还设定了字段的初始值,谁说了算?
问题2:
使用问题1中的幻灯片中定义的类,以下代码输出结果是什么?
提示:
这是一个生造出来展示Java语法特性的示例类,在实际开发中不要这样写代码,应该尽量保证一个字段只初始化一次!
(1)运行结果与分析:
第一次创建nitializeBlockClass()类时,括号里面没有参数,因此输出中的obj.field等于nitializeBlockClass类中自定义的数据:100.
第二次创建nitializeBlockClass(300)时,括号里面有和自定义的public InitializeBlockClass(int value)的构造函数,且函数中做了this.field=value;的操作,因此结果为300。
从以上可以看出Java字段初始化规律:
Java进行初始化的地方有两个:初始化块和构造函数,其中初始化块又分为静态初始化块和实例初始化块。静态初始化块是类中由static修饰的初始化块,实例初始化块为类中没有任何关键字修饰的初始化语句。
当定义类时,先找寻是否有自定义构造函数,若有则引用,没有则使用默认构造函数。
(2)类的总的加载及初始化顺序为:
静态变量--静态初始化块--静态方法--非静态变量--非静态初始化块--非静态方法--构造器。
四、静态初始化块的执行顺序:
问题:
请运行TestStaticInitializeBlock.java示例,观察输出结果,总结出“静态初始化块的执行顺序”。
TestStaticInitializeBlock.java源代码如下:
class Root
{
static{
System.out.println("Root的静态初始化块");//【1】
}
{
System.out.println("Root的普通初始化块");//【4】
}
public Root()
{
System.out.println("Root的无参数的构造器");//【5】
}
}
class Mid extends Root
{
static{
System.out.println("Mid的静态初始化块");//【2】
}
{
System.out.println("Mid的普通初始化块");//【6】
}
public Mid()
{
System.out.println("Mid的无参数的构造器");//【7】
}
public Mid(String msg)
{
//通过this调用同一类中重载的构造器
this();
System.out.println("Mid的带参数构造器,其参数值:" + msg); //【8】
}
}
class Leaf extends Mid
{
static{
System.out.println("Leaf的静态初始化块");//【3】
}
{
System.out.println("Leaf的普通初始化块");//【10】
}
public Leaf()
{
//通过super调用父类中有一个字符串参数的构造器
super("Java初始化顺序演示");//【9】
System.out.println("执行Leaf的构造器");//【11】
}
}
public class TestStaticInitializeBlock
{
public static void main(String[] args)
{
new Leaf();
}
}
输出结果顺序在源代码后用“//【顺序号】”标注。
运行结果:
原因分析:
①其中使用了super 和extends方法,具体使用方法如下。
②类的总的加载及初始化顺序为:静态变量--静态初始化块--静态方法--非静态变量--非静态初始化块--非静态方法--构造器。
(一)、super的用法:
super指父类,子类自动继承父类的属性和方法(除private修饰),一般情况下,直接使用父类的属性和方法,也可使用 this来指明本对象,但有时为了明确指明父类的属性和方法,使用关键字super。但使用super不能访问子类自己定义的属性和方法。
super出现在继承了父类的子类中,有三种存在方式如下:
①super.xxx;(xxx为变量名或对象名)
这种方法意义为:获取父类中的名字为xxx的变量或方法引用。
使用这种方法可以直接访问父类中的变量或对象,进行修改赋值等操作
②super.xxx();(xxx为方法名)
这种方法意义为:直接访问并调用父类中的方法。
③super();
这种方法意义为:调用父类的初始化方法,其实就是调用父类中的public xxx()方法
原文链接 :http://blog.csdn.net/crazy_kid_hnf/article/details/53188677##1
(二)super使用注意事项:
在使用super时,super指的是调用“对象”本身,而不是父类中看见的属性和方法。由于他指的是对象,所以不能在static的环境中使用,包括类变量(static field)、类方法(static method)和static语句块。
(三)Java中“extends”与 “implements”的区别:
1.在类的声明中,通过关键字extends来创建一个类的子类。一个类通过关键字implements声明自己使用一个或者多个接口。
extends是继承某个类,继承之后可以使用父类的方法,也可以重写父类的方法;implements 是实现多个接口,接口的方法一般为空的,必须重写才能使用。
2.extends是继承父类,只要那个类不是声明为final或者那个类定义为abstract的就能继承,JAVA中不支持多重继承,但是可以用接口来实现,这样就要用到implements,继承只能继承一个类,但implements可以实现多个接口,用逗号分开就行了
比如
Class A extends B mplements C,D,E
extends是继承父类,只要那个类不是声明为final或者那个类定义为abstract的就能继承,JAVA中不支持多重 继承,但是可以用接口来实现,这样就要用到implements,继承只能继承一个类,但implements可以实现多个接口,用逗号分开就行了
比如
Class A extends B implements C,D,E
参考文献:https://wenku.baidu.com/view/70c59d155f0e7cd1842536d2.html
五、静态方法中只允许访问静态数据,那么,如何在静态方法中访问类的实例成员(即没有附加static关键字的字段或方法)?
解决方法:
在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。比如以下: