关于转型和静态块简单说明
还是首先放出到我在37互娱笔试做到的一道题
class A {
static {
System.out.print("1");
}
public A() {
System.out.print("2");
}
}
class B extends A{
static {
System.out.print("a");
}
public B() {
System.out.print("b");
}
}
public class Test {
public static void main(String[] args) {
A ab = new B();
ab = new B();
}
}
说实话,刚看到的时候还是感觉稳的,上转型和类加载顺序我都有“学习”到,然而真正下手时却迷惑了,基础不扎实,不出所料最后回过头来验证还是写错了。
正确结果是:1a2b2b
分析:这是一道带有欺骗性的题目,如果对于转型和类加载机制知识不熟悉的话很容易做错,上转型放在这道题其实并没有改变什么结果,跟B b =new B()最后得出来的结果是一样的
上转型和下转型
向上转型:子类对象转为父类,父类可以是接口。公式:Father f = new Son();Father是父类或接口,son是子类。
向下转型:父类对象转为子类。公式:Son s = (Son)f;
上转型(不需强制转型)后父类的引用所指向的属性是父类的属性,如果子类重写(Override)了父类的方法,那么父类引用调用的方法就是子类的方法,这个叫动态绑定。向上转型后父类引用不能调用子类自己的方法。上转型能解决需要将子类对象传递给父类方法的情况,避免代码冗余。(父类为参数,调有时用子类作为参数)
下转型(需要强制转型)后就可以调用子类的属性和子类的方法了,下转型需要考虑安全性,只有先经过向上转型的对象才能继续向下转型,如果父类引用的对象是父类本身即
Father f = new Father();
Son son = (Son)f;
,那么在向下转型的过程中是不安全的,编译不会出错,但是运行时会出现java.lang.ClassCastException错误。它可以使用instanceof来避免出错此类错误即能否向下转型。
即
if (f instanceof Son){ Son son = (Son)f; son.myMethod(); }
类的初始化过程
父类的静态变量->父类的静态代码块->子类的静态变量->子类的静态代码块->父类的非静态变量->父类的非静态代码块->父类的构造函数->
子类的非静态变量->子类的非静态代码块->子类的构造函数
规律:父类优于子类
静态优于非静态
变量优于代码块
然后着重讲一下静态代码块,静态块中的代码只在类加载的过程中执行一次。在虚拟机jvm的生命周期中所有的类只会加载一次,而静态块又是伴随类加载而加载。不管你new出多少新的实例,静态块只会加载一次。
静态块的加载时机:
- 调用
Class.forName
的时候。相当于调用Class.forName(className, true, currentLoader)}
,如果将true改为false,表示类不会进行初始化,那么静态块也就不会执行。 - 当new一个类的新的实例的时候。因为new 一个新实例相当于:
Class.forName("").newInstance()
- 调用类的静态方法
Test.display()
- 调用类的静态变量
Test.x
Class.forName("")返回的是类
Class.forName("").newInstance()返回的是object,且newInstance()的使用有局限,因为它生成对象只能调用无参的构造函数