1 继承的概述
- 先观察如下代码
package java007; /** * 2017/9/9 * 说明:学生 */ public class Student { String name; int age; public void study(){ System.out.print("我叫"+name+",今年"+age+",我是一名学生,正在学习"); } }
package java007; /** * 2017/9/9 * 说明:工人 */ public class Worker { String name; int age; public void work(){ System.out.print("我叫"+name+",今年"+age+",我是一名工人,正在工作"); } }
package java007; /** * 2017/9/9 * 说明: */ public class StudentAndWorkderTest { public static void main(String[] args) { Student s = new Student(); s.name = "张三"; s.age = 15; s.study(); Worker w = new Worker(); w.name = "李四"; w.age = 34; w.work(); } }
-
- 我们可以发现学生类和工人类中都有姓名和年龄属性,属于重复字段,那么如何解决?,且看如下代码。
package java007; /** * 2017/9/9 * 说明: */ public class Person { String name; int age; }
package java007; /** * 2017/9/9 * 说明:学生 */ public class Student extends Person { public void study(){ System.out.print("我叫"+name+",今年"+age+",我是一名学生,正在学习"); } }
package java007; /** * 2017/9/9 * 说明:工人 */ public class Worker extends Person{ public void work(){ System.out.print("我叫"+name+",今年"+age+",我是一名工人,正在工作"); } }
package java007; /** * 2017/9/9 * 说明: */ public class StudentAndWorkderTest { public static void main(String[] args) { Student s = new Student(); s.name = "张三"; s.age = 15; s.study(); Worker w = new Worker(); w.name = "李四"; w.age = 34; w.work(); } }
- 继承的好处:
- ①提高了代码的复用性。
- ②让类与类之间产生关系,给第三个特征多态提供了前提。
2 继承的特点
- Java中支持单继承(一个子类只能有一个父类),不直接直接多继承,支持多层继承。
3 super关键字
- 当本类的成员变量和局部变量同名的时候,使用this区分。
- 当子父类的成员变量同名的时候,使用super区分父类。
- this和super的用法很相似。
- 示例1:本类的成员变量和局部变量同名的时候
package java007; /** * 2017/9/9 * 说明: */ class Fu{ private int age = 20; public void show(){ int age = 10; System.out.print("局部变量:"+age+",成员变量:"+this.age); } } public class ExtendsDemo { public static void main(String[] args) { Fu f = new Fu(); f.show(); } }
-
-
解释说明:
- ①先使用javac ExtendsDemo.java命令将ExtendsDemo编译成class文件,当然,顺便将Fu.java也编译成class文件。
- ②使用java ExtendsDemo命令,虚拟机会从方法区中,将main()方法识别,并加载到栈中。
- ③执行了new Fu();会在堆内存中开辟一个空间,(将Fu(){}加载到栈内存中,因为这一部分对本程序而言不是很重要,所以省略相关描述),用来存储对象,并初始化age=0。然后执行到private int age = 20;的时候,就将20赋值给age,此时age在堆内存中是20。
- ④Fu f = new Fu();main()方法所在的栈内存中,开辟了一个引用变量f,然后将堆内存中的对象的地址赋值给f,那么此时f就指向堆内存中的对象。
- ⑤f.show();从方法区将show()方法加载到栈中,此时,注意的是,show()方法内部就包含了this关键字,同时f变量的地址值给了this,因为this表示的是当前对象的引用,而调用show()方法的恰恰是f,所有this和f此时的值是相同的,那么show()方法也指向了堆内存中的对象,然后在show()方法内部开辟了一个age变量,这个age变量是栈内存中show()方法内部的局部变量,而想获取堆内存中的age变量,只能通过show()方法内存的this关键字了。
-
解释说明:
- 示例2:子类和父类的成员变量不同的时候
package java007; /** * 2017/9/9 * 说明: */ class Fu{ int age1 = 20; } class Zi extends Fu{ int age2 = 30; public void show(){ System.out.print(age1+" "+age2); } } public class ExtendsDemo { public static void main(String[] args) { Zi z = new Zi(); z.show(); } }
-
- 解释说明:通过上面的程序貌似可以这样解释,第一,变量名是不一样的,第二,子类是继承了父类,而子类中没有age1成员变量,所以从父类中继承(拷贝)了age1成员变量。
- 示例3:子父类的成员变量相同的时候
package java007; /** * 2017/9/9 * 说明: */ class Fu{ int age = 20; } class Zi extends Fu{ int age = 30; public void show(){ System.out.print(age); } } public class ExtendsDemo { public static void main(String[] args) { Zi z = new Zi(); z.show(); } }
package java007; /** * 2017/9/9 * 说明: */ class Fu{ int age = 20; } class Zi extends Fu{ int age = 30; public void show(){ System.out.print(age+" "+super.age); } } public class ExtendsDemo { public static void main(String[] args) { Zi z = new Zi(); z.show(); } }
-
- 解释说明:通过上面的程序貌似可以这样解释,子类和父类成员变量相同的时候,子类可以将父类相同成员变量覆盖,其实不然,且看下面分解。
4 函数覆盖(重写)
- 示例:子父类中的方法名不同
package java007; /** * 2017/9/10 * 说明: */ class Fu{ public void show1(){ System.out.print("Fu的show1方法"); } } class Zi extends Fu{ public void show2(){ System.out.print("Zi的show2方法"); } } public class ExtendsDemo2 { public static void main(String[] args) { Zi z = new Zi(); z.show1(); z.show2(); } }
- 示例:子父类中的方法名同名
package java007; /** * 2017/9/10 * 说明: */ class Fu{ public void show(){ System.out.print("Fu的show方法"); } } class Zi extends Fu{ public void show(){ System.out.print("Zi的show方法"); } } public class ExtendsDemo2 { public static void main(String[] args) { Zi z = new Zi(); z.show(); } }
- 当子类中出现成员函数和父类的一样的时候,会运行子类的成员函数,从表现上看。好像是子类的成员函数“覆盖”了父类的成员函数,这种现象,被称为重写或者覆盖。
- 函数的两个特性:
- 重载。同一个类中。
- 覆盖。子类中,也称为重写。
- 重写的注意事项:子类方法覆盖父类方法时,子类方法的权限必须>=父类方法的权限。
5 子类的实例化过程
- 示例:
package java007; /** * 2017/9/10 * 说明: */ class Fu{ public Fu(){ System.out.println("Fu的构造方法"); } } class Zi extends Fu{ public Zi(){ System.out.println("Zi的构造方法"); } } public class ExtendsDemo2 { public static void main(String[] args) { Zi z = new Zi(); } }
- 在子类构造对象的时候,发现,访问子类构造函数的时候,父类也运行了。这是为什么?因为,在子类构造方法中的第一行有一个默认的隐式语句:super();j如下代码所示。
package java007; /** * 2017/9/10 * 说明: */ class Fu{ public Fu(){ System.out.println("Fu的构造方法"); } } class Zi extends Fu{ public Zi(){ super();//调用的是父类的默认的空参数构造函数 System.out.println("Zi的构造方法"); } } public class ExtendsDemo2 { public static void main(String[] args) { Zi z = new Zi(); } }
- 示例:
package java007; /** * 2017/9/10 * 说明: */ class Fu{ public Fu(){ show(); } public void show(){ System.out.print("fu show"); } } class Zi extends Fu{ int num = 8; public Zi(){ } public void show(){ System.out.print("zi show:"+num); } } public class ExtendsDemo2 { public static void main(String[] args) { Zi z = new Zi(); z.show(); } }
-
- 解释:先将父类进行初始化,再将子类进行初始化。
6 final关键字
- final可以修饰类、方法和变量。
- final修饰的类不可以被继承。
- final修饰的方法不可以被重写。
- final修饰的变量是一个常量,只能被赋值一次。
- 内部类只能访问被final修饰的局部变量。
- 示例:final修饰变量,变为常量
class Person{ private final int age = 10; }
- 示例:final修饰变量,变为常量
class Person{ private final int age ; { age = 20; } }
- 示例:final修饰变量,变为常量
class Person{ private final int age ; public Person(int age){ this.age = age; } }