Java类的初始化、继承
2015-08-17 08:43
573 查看
y上面的几个关键词都是Java中比较常见也比较混淆的几个。
其次是类中成员变量的初始化。
然后是类中的初始化块(如果有多个则按照顺序执行)。
最后是类的构造方法。
如果类有父类,则先按照上面的顺序初始化父类。
如果运行上面的代码,结果为:
至于为什么是
为什么有两次
然后就是最重要的
所以上面代码的执行顺序为:
引用别人博客的一句话:
其实就是可见性的问题。 父类和子类的变量是同时存在的,即使是同名。 子类中看到的是子类的变量,父类中看到的是父类中的变量。
它们互相隐藏,而同名的方法则是实实在在的覆盖。
如A x = new B(); x是一个B,也是一个A, 那么调用方法时,是根据对象的实际类型调用的,
实际类型是B,所以永远调用子类的方法。
而访问成员变量就不同了,它是B时,访问的是子类的成员变量, 转型为A的话,访问的就是父类的成员变量了。
最后再写一个例子:
运行结果是:
Java类的初始化
首先是Java的cinit方法,这个方法有Java虚拟机加载类时自动执行,这个方法会收集所有的静态变量及静态块执行,并且仅执行一次(按照顺序执行)。
其次是类中成员变量的初始化。
然后是类中的初始化块(如果有多个则按照顺序执行)。
最后是类的构造方法。
如果类有父类,则先按照上面的顺序初始化父类。
Java的继承
这一部分涉及比较多的是多态。而多态又涉及到方法的重写。关于重写的相关内容之前在博客中已经涉及了。这里说说变量的“重写”。之所以在重写上加引号,是因为变量是没有重写的。看下面的代码:[code]public class Test { public static void main(String[] args) { Base b = new Sub(); System.out.println(b.x); } } class Base{ int x = 10; public Base(){ this.printMessage(); //printMessage(); x = 20; } public void printMessage(){ System.out.println("Base.x = " + x); } } class Sub extends Base{ int x = 30; public Sub(){ this.printMessage(); x = 40; } public void printMessage(){ System.out.println("Sub.x = " + x); } }
如果运行上面的代码,结果为:
[code]Sub.x = 0 Sub.x = 30 20
至于为什么是
Sub.x应该比较清楚了,java是动态单分配,方法调用只根据对象的实际类型,即使是调用了父类的方法,如果这个父类方法中有被重写的方法,那还是调用子类的重写方法。
为什么有两次
Sub.x输出呢?因为在初始化子类时,虚拟机会保证先初始化父类。
然后就是最重要的
x的值了。为什么有0,有30,还有20呢?在Java中如果在子类中声明了和父类相同名字的变量,以上面的代码为例,变量
x实际上会有两份值,一个是父类的
x,一个是子类的
x。如果在子类中获取x的值,那就会取子类的
x,除非特除声明用
super.x。
所以上面代码的执行顺序为:
[code]1.调用Sub类的构造方法 2.在执行Sub类初始化前,先初始化Base类 3.在Base类中x为10,调用printMessage()方法,实际调用了子类的printMessage方法。 4.子类的printMessage方法输出子类x的值,由于子类的x还没有初始化,所以输出0. 5.父类的x为20. 6.子类的初始化过程,子类的x为30. 7.子类的构造方法,输出30. 8.Main方法的输出,输出Base的x值。
引用别人博客的一句话:
其实就是可见性的问题。 父类和子类的变量是同时存在的,即使是同名。 子类中看到的是子类的变量,父类中看到的是父类中的变量。
它们互相隐藏,而同名的方法则是实实在在的覆盖。
如A x = new B(); x是一个B,也是一个A, 那么调用方法时,是根据对象的实际类型调用的,
实际类型是B,所以永远调用子类的方法。
而访问成员变量就不同了,它是B时,访问的是子类的成员变量, 转型为A的话,访问的就是父类的成员变量了。
总结
个人认为在出现变量隐藏(类型可以不同,但不可以private的)的情况下,如果是直接调用变量,那么得到的值跟外观类型有关。否则与方法在的类有关。最后再写一个例子:
[code]package test; public class Test3 { public static void main(String[] args) { Base b = new Sub(); System.out.println(b.x); System.out.println(b.get()); } } class Base{ int x = 10; public Base(){ printMessage(); printMessage2(); x = 20; } public int get(){ System.out.println("Base get"); return x; } public void printMessage(){ System.out.println("Base.x = " + x); } public void printMessage2(){ System.out.println("v2---Base.x = " + x); } } class Sub extends Base{ int x = 30; public Sub(){ printMessage(); x = 40; } public int get(){ System.out.println("Sub get"); return super.get(); } public void printMessage(){ System.out.println("Sub.x = " + x); } }
运行结果是:
[code]Sub.x = 0 v2---Base.x = 10 Sub.x = 30 20 Sub get Base get 20
相关文章推荐
- javafx Hanoi
- 使用 Eclipse 的 SVN 主要插件创建项目/支/标签
- spring框架内置笔记本
- 《Java设计模式》之单例模式
- Java用native2ascii命令做unicode编码转换
- java多线程(二)锁对象
- JavaFX它ListView使用
- Java泛型范围缩减(继承实现)
- java finalize方法
- Java IO: ByteArrayInputStream
- web挖掘之Apriori算法 JAVA实现
- Java: arr==null vs arr.length==0
- Java: arr==null vs arr.length==0
- Head First Java 中文高清版
- 模拟实现Spring IoC功能
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之一简介
- 开发java程序的基本步骤:JDK中的其他几个工具
- Java I/O 概述---文件读写总结
- 10种Java开发者编写SQL语句时常见错误
- 因酷Java版开源网校系统,轻松实现线下到线上的转变