先上一个题:
public class Test08 {
public static void main(String[] args) {
Zi zi = new Zi();
}
}
class Fu{
private static int i = getNum("(1)i");
private int j = getNum("(2)j");
static{
print("(3)父类静态代码块");
}
{
print("(4)父类非静态代码块,又称为构造代码块");
}
Fu(){
print("(5)父类构造器");
}
public static void print(String str){
System.out.println(str + "->" + i);
}
public static int getNum(String str){
print(str);
return ++i;
}
}
class Zi extends Fu{
private static int k = getNum("(6)k");
private int h = getNum("(7)h");
static{
print("(8)子类静态代码块");
}
{
print("(9)子类非静态代码块,又称为构造代码块");
}
Zi(){
print("(10)子类构造器");
}
public static void print(String str){
System.out.println(str + "->" + k);
}
public static int getNum(String str){
print(str);
return ++k;
}
}
会做嘛??????(嘻嘻嘻)
这里面包含继承,static关键字,静态代码块,非静态代码块,初始化顺序问题。
继承
首先说继承,子类继承父类,子类会继承父类的所有属性(PS:私有的属性虽然不能被直接的访问,但是可以间接的访问,在子类的堆信息中,也会存在父类的信息。对了还有若子类父类中有相同的属性,这两个属性由于没有重写所以,在堆中有两个名称相同的属性,)
(1)父类的所有的属性、方法都会继承到子类中。
关于私有的属性和方法是否可以被继承到子类中?
A:从在子类中可直接访问的角度来说:不能
B:从子类具有的事物特征来说:可以
即在子类对象的堆内存中,需要分配对应的内存,需要存储它的值,
例如:学生对象中,需要分配name和age的内存,来存储学生的姓名和年龄。
(2)父类的构造器无法继承到子类中。
(3)子类的构造器中“必须”调用父类的构造器。
默认情况下,调用父类的无参构造。不管你是否写了super()
如果父类没有无参构造,那么子类“必须手动”调用父类的某个有参构造。使用super(实参列表)调用父类的有参构造。
为什么要调用父类的构造器?
要为从父类继承的属性进行初始化,那么父类的构造器中已经写了对应初始化代码,我们子类就不用重复,调用一下就可以了。
(4)Java只支持单继承==>即只有一个亲生父亲
(5)Java支持多层继承==>父类还可以有父类
(6)一个父类可以同时有多个子类==》一个父亲可以同时有多个孩子
子类还可以有子类 ==》代代相传
(7)子类可以扩展父类没有的特征(属性和方法)
(8)子类还可以对父类的“方法”进行“重写”
static
2、static可以修饰什么
(1)成员变量
用它修饰的成员变量称为“类变量”或“静态变量”;
不用它修饰的成员变量称为“实例变量”或“非静态成员变量”
(2)成员方法
用它修饰的成员方法称为“类方法”或“静态方法”
不用它修饰的成员方法称为“实例方法”或“非静态方法”
(3)代码块
用它修饰的代码块称为“静态代码块”,“类初始化代码块”
不用它修饰的代码块称为“非静态代码块”,“实例化代码块”,“构造块”
(4)成员内部类
用它修饰的成员内部类称为“静态成员内部类”,“静态内部类”
不用它修饰的成员内部类称为“非静态成员内部类”,或者干脆就叫做“成员内部类”
3、用它修饰的有什么不同
总:用它修饰的成员,表示是属于“类”的,不单独属于“某个对象”。
初始化顺序
类的第一次加载可以通过哪些方式?
1.new对象
2.调用静态方法
3.使用子类对象
4.反射
类初始化和实例初始化的总结:
(1)父类的类初始化
(2)子类的类初始化
(3)父类的对应的实例初始化
(4)子类的对应的实例初始化
A:顺序(1)(2)(3)(4)
B:其中的(1)(2)只会执行一次;(3)(4)每new一个对象就执行一次。
C:子类构造器中如果没有super()或super(实参列表)表示执行的是父类的无参的实例初始化方法<init>()
如果子类的构造器中有super()或super(实参列表)表示执行对应的实例初始化方法
D:如果在实例初始化过程中,涉及到调用某个方法,那么如果这个方法没有static修饰,要考虑是否被子类重写了。
那么如果这个方法有static修饰,不会被重写,在哪个类中,就执行哪个类的。
类初始化的方法的由两部分组成:
(1)静态变量的显式赋值
(2)静态代码块
它俩按顺序执行。
静态的代码块和静态的变量只执行一次
实例初始化方法由三部分组成:
(1)非静态变量的显式赋值
(2)非静态代码块
(3)构造器
其中(1)和(2)按顺序,(3)在最后。但是(3)中的super()或super(实参列表)被组装到实例初始化方法中也在首行。、实例初始化什么时候执行?执行的特点是什么?
(1)你每new一个对象,就会执行一个实例初始化方法。
每次调用哪个实例初始化方法,看你调用哪个构造器。
(2)要执行子类的实例初始化方法,会先执行父类相应的实例初始化方法
PS:无论是静态的初始化还是实例初始化,类在初始化的时候会提前的声明类中的变量,(不论修饰符)这个时候变量的值是默认值。就如下图在<clinti><inti>会先将变量放在最开始的位置,(即类里面的变量在类没有初始化的时候可以本类调用,这个时候为默认值)
再上一个题:
public class Test12 {
public static void main(String[] args) {
Father3 f = new Father3();
Son1 s = new Son1();
System.out.println(f.getInfo());
System.out.println(s.getInfo());
s.setInfo("123");System.out.println(s.getInfo());
System.out.println(f.getInfo());
}
}
class Father3{
private String info = "456";
public void setInfo(String info){
this.info = info;
}
public String getInfo(){
return info;
}
}
class Son1 extends Father3{
}
答案:
再来一个:
public class Test13 {
public static void main(String[] args) {
Father4 f = new Father4();
Son3 s = new Son3();
System.out.println(f.getInfo());
System.out.println(s.getInfo());
s.test();
System.out.println("-----------------");
s.setInfo("大硅谷");
System.out.println(f.getInfo());
System.out.println(s.getInfo());
s.test();
}
}
class Father4{
private String info = "132";
public void setInfo(String info){
this.info = info;
}
public String getInfo(){
return info;
}
}
class Son3 extends Father4{
private String info = "小硅谷";
public void test(){
System.out.println(this.getInfo());
System.out.println(super.getInfo());
}
}
答案:
首先说明这里面s和f是两个对象,他们之间并没有关系,
其次,由于子类中,没有重写任何的方法,所以代码中的getInfo()都是在调用父类中的方法,进行修改的,返回。