1 继承
继承的实现:public class 子类 extends 父类 {… }
注释:子类可直接使用,父类(保护,公开)的属性和方法
优点:减少重复代码,缺点:只能单继承
// 父类
public class Test {
private String str1; //私有
String str2; //默认
protected String str3;// 保护
public String str4; //公开
private void fn1() {} //私有
void fn2() {} //默认
protected void fn3() {}// 保护
public void fn4() {} //公开
}
// 子类
public class SubTest extends Test {
public void subFn1() {
String t3 = str3;
String t4 = str4;
fn3();
fn4();
}
}
2 子类实例化
子类构造器默认先调用父类无参构造器(可省略),父类没有无参构造器(必须先显示调用有参构造器)
public class 子类 extends 父类 {
public 子类() {
[super();] // 可省略
子类处理…
}
}
3 方法重写
注释:子类定义了与父类相同的方法(方法重写)
// 父类
public class Test {
public String name = "张三";
public void doTest() {
System.out.println(name);
}
}
测试类1:子类未重写方法,调父类方法使用的是父类属性(不会输出子类同名属性)
// 子类
public class SubTest1 extends Test {
public String name = "李四";
}
public class Main {
public static void main(String[] args) {
SubTest1 s = new SubTest1();
System.out.println(s.name); //输出 李四
s.doTest(); //输出 张三(子类没有该方法,父类该方法输出父类名字)
}
}
测试类2:子类重写属性方法后,使用的是子类的属性
//子类
public class SubTest2 extends Test {
public String name = "李四";
public void doTest() {
System.out.println("son:"+name);
}
}
public class Main {
public static void main(String[] args) {
SubTest2 s = new SubTest2();
System.out.println(s.name); // 输出 李四
s.doTest();// 输出 son:李四
}
}
测试类3:子类对象定义为父类类型,输出父类属性,调用的是子类方法
//子类
public class SubTest2 extends Test {
public String name = "李四";
public void doTest() {
System.out.println("son:"+name);
}
}
public class Main {
public static void main(String[] args) {
Test s = new SubTest2();
System.out.println(s.name); // 输出 张三
s.doTest(); // 输出 son:李四
}
}
测试类4:子类对象强转父类类型,输出父类属性,调用的是子类方法
//子类
public class SubTest2 extends Test {
public String name = "李四";
public void doTest() {
System.out.println("son:"+name);
}
}
public class Main {
public static void main(String[] args) {
SubTest2 s = new SubTest2();
Test ss = (Test)s;
System.out.println(ss.name); // 输出 张三
ss.doTest(); // 输出 son:李四
}
}
4 方法重载
方法名(相同),参数(个数或类型)(不同),与返回值无关
public class Test {
public String fn(String str){
}
// 重载1,参数类型不同
public String fn(int num) {
}
// 重载2,参数个数不同
public String fn(int age, int num) {
}
}
5 super关键字
注释:只可在子类内部使用,使子类可以使用父类原生方法与属性
(1) 调用父类构造器:super([参数…]);
(2) 调用父类属性:super.属性; // 获取与更改父类的属性,不影响子类同名属性
(3) 调用父类方法:super.方法(); // 调用父类的方法,与子类是否重写无关
// 父类
public class Test {
private String str1 = "私有";
String str2 = "默认";
protected String str3 = "保护";
public String str4 = "公开";
private String fn1() { return str1; }
String fn2() { return str2; }
protected String fn3() { return str3; }
public String fn4() { return str4; }
}
// 子类
public class SubTest extends Test {
protected String str3 = "保护(son)";
public String str4 = "公开(son)";
protected String fn3() { return str3; }
public String fn4() { return str4; }
// 调用父类构造器(默认不写也调用)
public SubTest() {
super();
}
// 调用父类方法
public void test() {
System.out.println(super.str3); // 输出 父类 保护
System.out.println(super.str4); // 输出 父类 公开
System.out.println(super.fn3()); // 输出 父类 保护
System.out.println(super.fn4()); // 输出 父类 公开
}
public void testSub() {
System.out.println(str3); // 输出 子类 保护(son)
System.out.println(str4); // 输出 子类 公开(son)
System.out.println(fn3()); // 输出 子类 保护(son)
System.out.println(fn4()); // 输出 子类 公开(son)
}
}
6 代码执行顺序
6.1 静态方法
// 初次调用:类名.静态方法()
1.类加载(静态变量初期化,只执行1次)
2.类加载(静态代码块,只执行1次)
3.静态方法执行
// 之后再调用:类名.静态方法() // 只重复执行3
3.静态方法执行
6.2 实例化对象
// 初次实例化:new 对象()
1.类加载(静态变量初期化,只执行1次)
2.类加载(静态代码块,只执行1次)
3.代码块(执行)
4.构造器(执行)
// 之后再实例化:new 对象() // 只重复执行3,4
3.代码块(执行)
4.构造器(执行)
6.3 子类静态方法
// 初次调用:子类.静态方法()
1.父类加载(静态变量初期化,只执行1次)
2.父类加载(静态代码块,只执行1次)
3.子类加载(静态变量初期化,只执行1次)
4.子类加载(静态代码块,只执行1次)
5.子类静态方法(执行)
// 之后再调用:子类.静态方法() // 只重复执行5
5.子类静态方法(执行)
6.4 子类实例化对象
// 初次调用:new 子类对象()
1.父类加载(静态变量初期化,只执行1次)
2.父类加载(静态代码块,只执行1次)
3.子类加载(静态变量初期化,只执行1次)
4.子类加载(静态代码块,只执行1次)
5.父类代码块(执行)
6.父类构造器(执行)
7.子类代码块(执行)
8.子类构造器(执行)
// 之后再调用:new 子类对象() // 只重复执行5,6,7,8
5.父类代码块(执行)
6.父类构造器(执行)
7.子类代码块(执行)
8.子类构造器(执行)
总结:1 只有初次类加载初始化静态变量,执行静态代码块。2 父类(变量,代码块,构造器)优先于子类执行。3 代码块优先于构造器执行。