类的加载顺序,父类和子类初始化的顺序和重写所遇到的上塑造型
来源:互联网 发布:证券从业资格证软件 编辑:程序博客网 时间:2024/06/12 18:55
类的加载顺序 什么时候类加载 第一次需要使用类信息时加载。 类加载的原则:延迟加载,能不加载就不加载。 触发类加载的几种情况: (1)、调用静态成员时,会加载静态成员真正所在的类及其父类。 通过子类调用父类的静态成员时,只会加载父类而不会加载子类。 (2)、第一次 new 对象的时候 加载(第二次再 new 同一个类时,不需再加载)。 (3)、加载子类会先加载父类。(覆盖父类方法时所抛出的异常不能超过父类定义的范围) 注:如果静态属性有 final 修饰时,则不会加载,当成常量使用。 例:public static final int a =123; 但是如果上面的等式右值改成表达式(且该表达式在编译时不能确定其值)时则会加载类。 例:public static final int a = math.PI 如果访问的是类的公开静态常量,那么如果编译器在编译的时候能确定这个常量的值,就不会被加载; 如果编译时不能确定其值的话,则运行时加载 .类加载的顺序: 1.加载静态成员/代码块: 先递归地加载父类的静态成员/代码块(Object的最先);再依次加载到本类的静态成员。 同一个类里的静态成员/代码块,按写代码的顺序加载。 如果其间调用静态方法,则调用时会先运行静态方法,再继续加载。同一个类里调用静态方法时,可以不理会写代码的顺序。 调用父类的静态成员,可以像调用自己的一样;但调用其子类的静态成员,必须使用“子类名.成员名”来调用。 2.加载非静态成员/代码块:(实例块在创建对象时才会被加载。而静态成员在不创建对象时可以加载) 先递归地加载父类的非静态成员/代码块(Object的最先);再依次加载到本类的非静态成员。 同一个类里的非静态成员/代码块,按写代码的顺序加载。同一个类里调用方法时,可以不理会写代码的顺序。 但调用属性时,必须注意加载顺序。一般编译不通过,如果能在加载前调用,值为默认初始值(如:null 或者 0)。 调用父类的非静态成员(private 除外),也可以像调用自己的一样。 3.调用构造方法: 先递归地调用父类的构造方法(Object的最先)也就是上溯下行;默认调用父类空参的,也可在第一行写明调用父类某个带参的。 再依次到本类的构造方法;构造方法内,也可在第一行写明调用某个本类其它的构造方法。 注意:如果加载时遇到 override 的成员,可看作是所需创建的类型赋值给当前类型。 其调用按多态用法:只有非静态方法有多态;而静态方法、静态属性、非静态属性都没有多态。 假设子类override父类的所有成员,包括静态成员、非静态属性和非静态方法。 由于构造子类时会先构造父类;而构造父类时,其所用的静态成员和非静态属性是父类的,但非静态方法却是子类的; 由于构造父类时,子类并未加载;如果此时所调用的非静态方法里有成员,则这个成员是子类的,且非静态属性是默认初始值的。
一例子:package com.base.chapter4;class Base{ public static int a = 10; public int b = 20; static { System.out.println("Static Init Base " + a); //System.out.println("Null Init " + b); } public Base() { System.out.println("Init Base " + this.b); }}/** *一级子类和基类包含的内容一样 **/class SuperClass extends Base{ //静态变量、静态块执行顺序,按书写先后顺序 public static int a1 = getSuperStaticNumber(); public int b1 = getSuperInstanceNumber(); public SuperClass() { System.out.println("Init SuperClass" + this.b1); } static { System.out.println("Static Init SuperClass" + a1); } public static int getSuperStaticNumber() { System.out.println("Static member init"); return 100; } public int getSuperInstanceNumber() { System.out.println("Instance member init"); return 200; }}/** *二级子类为测试该代码的驱动类 */public class Sub extends SuperClass{ public static int a2 = getStaticNumber(); public int b2 = getInstanceNumber(); public Sub() { System.out.println("Init SubClass " + this.b2); } public static int getStaticNumber() { System.out.println("Static member init Sub"); return 1000; } public int getInstanceNumber() { System.out.println("Instance member init Sub"); return 2000; } static { System.out.println("Static Init " + a2); } /** * 程序入口,main * * */ public static void main(String args[]) { new Sub(); }}结果:Static Init Base 10Static member initStatic Init SuperClass100Static member init SubStatic Init 1000Init Base 20Instance member initInit SuperClass200Instance member init SubInit SubClass 2000
继承中注意的问题:
1 重写(也叫覆盖,也叫重构):重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值类型;
重写方法不能使用比被重写方法更严格的访问权限。
重写是类与类之间的关系,两者必须是继承关系。重载是方法与方法之间的关系。
2 关键字super:
在Java类中使用super来引用父类的成分
super可用于访问父类中定义的属性
super可用于调用父类中定义的成员方法
super可用于在子类构造方法中调用父类的构造方法
super的追溯不仅于直接父类,就是father的father。。。。。。
Supper关键字有两个特殊的用途:
在子类构造函数中调用父类的构造函数
在子类中调用父类的方法。
3 多态:多态就是重写和重载!而上塑造型或虚方法的调用更好的体现了多态。
上溯造型(也叫虚方法,将子类转换成父类)中,方法是调用子类自己的,属性是调用父类的,其他就不变。(一个引用类型变量如果声明为父类的类型,
但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法)
package cn.test;public class Father { public String name = "Father"; public void bidBoy(){ System.out.println(" 父类的 bidBoy被调用 "); } public void say(Father father){ System.out.println("调用父类的方法,该对象的类型为:"+father.getClass()); father.bidBoy(); } public void say(Son son){ System.out.println("*******************调用父类的方法,该对象的类型为:"+son.getClass()); son.bidBoy(); }}
package cn.test;public class Son extends Father{ public String name = "Son"; public void bidBoy(){ //重写 System.out.println(" 子类的 bidBoy被调用 "); System.out.println(name);//如果子类没有name,那么这个name就输出父类的。 } public void say(Father father){ System.out.println("调用子类的方法,该对象的类型为:"+father.getClass()); father.bidBoy(); } public void say(Son son){ System.out.println("*******************调用子类的方法,该对象的类型为:"+son.getClass()); son.bidBoy(); }}
package cn.test;public class Test{public static void main(String args[]){/* * 总结:* 1、 从父类(真实类型)不能转换称子类,编译没有错,运行就会报错。例如:Father f = new Father(); Son son1 = (Son) f;* 2、 上溯造型中Father f1 = new Son(),方法是调用子类自己的,属性是调用父类的,如测试1。* 3、 对于类中的重载方法调用,如果对象是上溯造型,则会调用参数为父类的方法。如果直接创建子类对象,则调用参数为子类类型的方法。* 4、 对于类中的重载方法调用,当前参数是什么类型(包括强制转换),就进入那个重载方法。* 5、 上溯造型调用子类的方法,父类的属性;对子类和父类做为函数的重载类型时,当前对象是谁就进入那个重载方法。如测试7。*///下面对象中f1,f2是上溯造型,他们调用bidBoy方法时,调用的都是子类中的方法 System.out.println("-----------------测试1---------------------"); Father f1 = new Son(); //上溯造型,虚方法调用 f1.bidBoy(); //调用子类方法 System.out.println(f1.name); //调用父类的属性名称 System.out.println("-----------------测试2---------------------"); Father f2 = new Son(); Son son = (Son) f2; son.say(f2); //子类say方法被调用,这个方法需要一个Father对象,然后子类调用bidBoy方法。 System.out.println("-----------------测试3---------------------"); Father father = new Father(); son.say(father); //子类say方法被调用,传入的父类对象,调用父类的bidBoy方法。 System.out.println("-----------------测试4---------------------"); f2.say(f1); //子类say方法被调用,传入的是上溯造型,然后子类调用bidBoy方法。 System.out.println("-----------------测试5---------------------"); father.say(f2); //父类say方法被调用,传入的是上溯造型,然后子类调用bidBoy方法。 System.out.println("-----------------测试6---------------------"); father.say(father); //父类say方法被调用,传入的父类对象,调用父类的bidBoy方法。 System.out.println("-----------------测试7---------------------"); Son son2 = new Son(); f2.say(son2); //son2当前是Son,那么进入是say(Son son)方法。 f2.say(f1); //f1上溯造型,但是当前被转换成Father对象,那么进入的是say(Father father)方法。 f2.say(father);/*-----------------测试1---------------------子类的 bidBoy被调用 SonFather-----------------测试2---------------------调用子类的方法,该对象的类型为:class cn.test.Son子类的 bidBoy被调用 Son-----------------测试3---------------------调用子类的方法,该对象的类型为:class cn.test.Father父类的 bidBoy被调用 -----------------测试4---------------------调用子类的方法,该对象的类型为:class cn.test.Son子类的 bidBoy被调用 Son-----------------测试5---------------------调用父类的方法,该对象的类型为:class cn.test.Son子类的 bidBoy被调用 Son-----------------测试6---------------------调用父类的方法,该对象的类型为:class cn.test.Father父类的 bidBoy被调用 -----------------测试7---------------------*******************调用子类的方法,该对象的类型为:class cn.test.Son子类的 bidBoy被调用 Son调用子类的方法,该对象的类型为:class cn.test.Son子类的 bidBoy被调用 Son调用子类的方法,该对象的类型为:class cn.test.Father父类的 bidBoy被调用*/}}
同类收集( homogenous collections)
MyDate[] m = new MyDate[2];
m[0] = new MyDate(22, 12, 1964);
m[1] = new MyDate(22, 7, 1964);
异类收集(heterogeneous collections)
Person [] p= new Person[3];
p[0] = new Student();//跟person有继承关系
p[1] = new Person();
p[2] = new Graduate();//跟person有继承关系
方法声明的参数类型为父类类型,可以使用子类的对象作为实参调用该方法
public class Test{
public void method(Person e) {
//……
e.getInfo();
}
public static void main(String args[]){
Test t = new Test();
Student m = new Student();
t.method(m);
}
}
4 instanceof 操作符:instanceof操作符的作用是判断一个变量是否是右操作数指出的类的一个对象,
由于java语言的多态性使得可以用一个子类的实例赋值给一个父类的变量,而在一些情况
下需要判断变量到底是一个什么类型的对象,这时就可以使用instanceof了。当左操作数是
右操作数指出的类的实例或者是子类的实例时都返回真,如果是将一个子类的实例赋值给
一个父类的变量,用instanceof判断该变量是否是子类的一个实例时也将返回真。
5 对象造型 :
对Java对象的强制类型转换称为造型
在造型前可以使用instanceof操作符测试一个对象的类型
从子类到父类的类型转换可以自动进行
从父类到子类的类型转换必须通过造型(强制类型转换)实现
无继承关系的引用类型间的转换是非法的
public class Test{ public void method(Person e) { System.out.println(e.getschool()); //非法,因为从子类到父类的类型转换可以自动进行,故这里已经是父类了。父类的对象只能调用父类中有的方法。 if(e intstanceof Student){ Student me = (Student)e; System.out.println(me.getschool()); } } public static void main(Stirng args[]){ Test t = new Test(); Student m = new Student(); t.method(m); }}
二、父类和子类初始化的顺序:
package com.cjonline.ship.action;public class Parent { public String a = "test"; public Parent() { super(); System.out.println(1); } public Parent(String a) { super(); System.out.println(2); //System.out.println(pstr); // } { System.out.println(" Parent hello..."); } static { System.out.println(" Parent static 1..."); } static { System.out.println(" Parent static 2..."); } public static String pstr=init(); public static String init(){ System.out.println(" 静态属性和静态代码块之间初始化的顺序与放在类中的位置有关,靠前面的先执行"); return "Parent static properties init"; } public String pstr2=init2(); public String init2(){ System.out.println(" 成员初始化优先于构造函数"); return "Parent static properties init"; } public static void main(String[] args) { Child child = new Child("12"); Parent test = (Parent) child; System.out.println(test.a); System.out.println(child.a); System.out.println(child.a); } static class Child extends Parent { public String a = "child"; public Child() { super(); System.out.println(3); } public Child(String a) {// super(a);//写这行代码调用父类带参数的Parent(String a)构造函数输出2,否则调用父类默认的构造函数Parent()输出1 System.out.println(4); new Parent(""); } { System.out.println(" Child hello..."); } static { System.out.println(" Child static..."); } } }/**执行结果: Parent static 1... Parent static 2... 静态属性和静态代码块之间初始化的顺序与放在类中的位置有关,靠前面的先执行 Child static... Parent hello... 成员初始化优先于构造函数1 Child hello...4 Parent hello... 成员初始化优先于构造函数2testchildchild*/ // 最终结论 // 1.父类静态属性或静态代码块 // 2.子类静态属性或静态代码块 // 3.父类属性初始化 // 4.父类构造函数 // 5.子类属性初始化 // 6.子类类构造函数
静态优先于非静态(属性或方法或构造函数),父类构造函数优先于子类构造函数
- 类的加载顺序,父类和子类初始化的顺序和重写所遇到的上塑造型
- java类的加载顺序,父类和子类初始化的顺序和重写所遇到的上塑造型
- C# 子类和父类的初始化顺序
- 006.子类和父类的加载顺序
- 类的加载和初始化顺序
- java子类父类的加载顺序
- java 类及子类的初始化顺序
- 类的加载,初始化顺序
- Java类的加载和初始化顺序分析
- Java类的加载和初始化顺序分析
- java类的成员初始化顺序和初始化块顺序
- JAVA中子类与父类对象的初始化顺序
- 继承关系中,子类父类的初始化顺序
- java子类和父类的执行顺序
- Java的子类和父类实例化顺序
- Java中子类和父类的实例化顺序
- 项目中遇到的子类父类方法执行顺序
- Java类和对象的初始化顺序
- 正则表达式的与或非
- js 剪切板应用clipboardData
- 生成时间轴:记录你的生活轨迹——facebook工程师讲述时间轴的开发始末
- JS获得月最后一天和js得到一个月最大天数
- gson在java和json串之间的应用
- 类的加载顺序,父类和子类初始化的顺序和重写所遇到的上塑造型
- 获取子窗口中使用jQuery.data()设置的参数
- form的默认提交方式
- WS之cxf简单实现
- Axis,axis2,Xfire以及cxf对比
- WS之cxf处理的复杂类型(Map)
- 利用SVM解决2维空间向量的3级分类问题
- WS之cxf的权限拦截器应用
- java数据类型