赞
踩
目录
- class Father{
- String name;
- int age;
- Father(){}
-
- //getXxx()和setXxx()
- public void study(){
- System.out.println("学习");
- }
- }
-
- class Son{
- String name;
- int age;
- Son(){}
-
- //getXxx()和setXxx()
- public void study(){
- System.out.println("学习");
- }
- }
通过观察我们发现,这两个类的name和age这两个成员变量以及study()成员方法都是相同的,如果我们还继续定义其他的儿子类,父亲类等,每定义一次这样的类,就要把重复的内容再写一遍。
能不能把这些相同的内容定义到一个独立的类中,然后,让其他的类与这个独立的类产生一个关系,这些其他的类就具备了这个独立的类的功能
为了解决这个问题,java提供了一个思想——继承
继承:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可
通过extends关键字可以实现类与类的继承
1.语句定义格式
class 子类名 extends 父类名{...}
举例:class Fu{}
class Zi extends Fu{}
单独的这个类称为父类,基类或者超类;这多个类可以称为子类,派生类
- class Human {
- String name;
- int age;
-
- //getXxx()和setXxx()
- public void study() {
- System.out.println("学习");
- }
- }
-
- class Father extends Human {
-
- }
-
- class Son extends Father {
-
- }
-
- public class ExtendsDemo {
- public static void main(String[] args) {
- //创建一个父亲对象
- Father f1 = new Father();
- f1.study();
-
- //创建一个儿子对象
- Son s1 = new Son();
- s1.study();
- }
- }
2.继承的好处
1)提高了代码的复用性
2)提供了代码的维护性(如果功能的代码需要修改,修改一处即可)
3)让类与类之间产生关系(为后面学习多态做铺垫:要有继承才有多态)
3.继承的坏处
类的耦合性增强
打破了封装性
开发的原则:低耦合,高内聚
(耦合:类与类的关系;内聚:类自己本身可以完成的事情)
4.有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员
- class Person {
- String name;
- int age;
-
- Person() {
- }
-
- //getXxx()和setXxx()
-
- public void eat() {
- System.out.println("吃饭");
- }
-
- public void study() {
- System.out.println("学习");
- }
- }
-
- //学生类继承人类之后,拥有了人类中的成员变量和成员方法,也可以自己定义自己类特有的成员变量和成员方法
- class Student3 extends Person {
- String id;
-
- public void playGame() {
- System.out.println("打游戏");
- }
- }
-
- class Teacher3 extends Person {
-
- }
-
- public class ExtendsDemo2 {
- public static void main(String[] args) {
- //创建一个学生对象并使用
- Student3 s1 = new Student3();
- s1.eat();
- s1.study();
- s1.playGame();
-
- //创建一个老师对象并使用
- Teacher3 t1 = new Teacher3();
- t1.eat();
- t1.study();
- }
- }
5.继承的特点
1)java中的类只支持单个继承,不支持多继承
一个类只能有一个父亲,不可以有多个父亲
- class Father4{}
- class Mother4{}
- class Son extends Father4,Mother4{} //错误,不允许这样做
2)java中的类支持多层继承(形成了一个继承体系)
- class GrandFather {
- public void show() {
- System.out.println("我是爷爷");
- }
- }
-
- class Father4 extends GrandFather {
- public void show1() {
- System.out.println("我是老子");
- }
- }
-
- class Son4 extends Father4 {
- public void show2() {
- System.out.println("我是儿子");
- }
- }
-
- public class ExtendsDemo3 {
- public static void main(String[] args) {
- Son4 son4 = new Son4();
- son4.show2(); //可以使用自己的方法
- son4.show1(); //可以使用父亲的方法
- son4.show(); //可以使用爷爷的方法
- }
- }
6.继承的注意事项
1)要想初始化子类,必须先初始化父类(举例:先有父亲,才能有儿子)
2)子类只能继承父类的非私有的成员变量和成员方法(打破了封装性)
3)子类不能继承父类的构造方法,但是可以通过super关键字去访问父类的构造方法
因为要想初始化子类,必须先初始化父类,是通过构造方法进行初始化的
4)不要为了部分的功能而去使用继承
什么时候使用继承呢?
当两个类满足语法”什么是什么“的时候,例如:医生是人,可乐是液体...
- class Father5 {
- int num = 20;
- private int num2 = 30;
-
- Father5() {
- System.out.println("这是父亲的无参构造方法");
- }
-
- private void fun1() {
- System.out.println(num);
- }
- }
-
- class Son5 extends Father5 {
- public void fun2() {
- System.out.println(num);
- // System.out.println(num2); 子类不能继承父类的私有成员变量
- }
- }
-
- public class ExtendsDemo4 {
- public static void main(String[] args) {
- Son5 son5 = new Son5();
- son5.fun2();
- // son5.fun1(); //子类不能继承父类的私有成员方法
- }
- }
1.当子类中的成员变量名字和父类中的成员变量名字一样的时候
查找:(就近原则)
第一步:先在方法的局部范围内进行查找,如果找到就返回
第二步:如果在方法局部范围内找不到,去本类中成员位置上查找,如果找到就返回
第三步:如果在本类中成员位置上找不到,去父类中成员位置上查找,如果找到就返回
第四步:如果在父类中成员位置上找不到,报错
2.当子类中的成员变量名字和父类中的成员变量名字一样的时候
使用什么变量名,就访问谁
- class Father6{
- int num = 10;
- int num2 = 200;
- public void show2(){
- int num = 100;
- int num2 = 20;
- }
- }
-
- class Son6 extends Father6{
- int num = 30;
- int num3 = 300;
- public void show1(){
- // int num = 40;
- System.out.println(num);
- System.out.println(num2);
- System.out.println(num3);
- }
- }
- public class ExtendsDemo5 {
- public static void main(String[] args) {
- Son6 son6 = new Son6();
- son6.show1();
- }
- }
就这个例子来看,如果我们不仅想输出局部范围内的num,也想输出父类中的name,怎么办呢?
java提供了一个关键字给我们使用:super关键字
super的用法和this的用法很像
this代表的是调用该类的当前对象
super代表的是父类存储空间的标识(父类的引用,可以操作父类的成员)
1.用法(this和super比较学习)
1)访问成员变量
this.成员变量——访问的是本类中的成员变量
super.成员变量——访问的是父类中的成员变量
2)访问构造方法
this(...)
super(...)
3)访问成员方法
this.成员方法(...)
super.成员方法(...)
- class Father7 {
- int num = 10;
-
- public void show2() {
- System.out.println("这是父类中的show2方法");
- }
- }
-
- class Son7 extends Father7 {
- int num = 20;
-
- public void show() {
- int num = 30;
- System.out.println(num);
- System.out.println(this.num); //访问的是本类中的成员变量
- //如何访问到父类中的同名成员变量呢?
- System.out.println(super.num); //访问的是父类中的成员变量
-
- //访问父类的成员方法
- show2();
- super.show2();
-
- //访问本类的成员方法
- show3();
- this.show3();
- }
-
- public void show3() {
- System.out.println("这是Son7类中的show3方法");
- }
- }
-
- public class ExtendsDemo6 {
- public static void main(String[] args) {
- Son7 son7 = new Son7();
- son7.show();
- }
- }
——即为什么初始化子类,必须先初始化父类
因为子类会继承父类的数据,甚至可能会使用父类的数据,所以在子类初始化之前,一定会先完成父类的初始化
注意:每个子类的构造方法的第一句话默认是super();
- class Father8{
- int age;
- Father8(){
- System.out.println("这是父类中的无参构造方法");
- }
- Father8(String s){
- System.out.println("这是父类中的带参数的构造方法"+s);
- }
- }
-
- class Son8 extends Father8{
- Son8(){
- //super(); 默认
- System.out.println("这是子类中的无参构造方法");
- }
- Son8(String s){
- //super(); 默认
- System.out.println("这是子类中的带参数的构造方法"+s);
- }
- }
- public class ExtendsDemo7 {
- public static void main(String[] args) {
- Son8 s1 = new Son8("小王");
- }
- }
如果父类中没有无参构造方法,该怎么办呢?
1)子类通过super关键字带参数的形式访问父类的带参数构造方法
- class Father9 {
- int age;
-
- Father9(String s) {
- System.out.println("这是父类中的带参数的构造方法:" + s);
- }
- }
-
- class Son9 extends Father9 {
- Son9() {
- super("你好");
- System.out.println("这是子类中的无参构造方法");
- }
-
- Son9(String s) {
- super("你也好");
- System.out.println("这是子类中的带参数的构造方法:" + s);
- }
- }
-
- public class ExtendsDemo8 {
- public static void main(String[] args) {
- Son9 s1 = new Son9("小王");
- }
- }
2)子类通过this关键字调用本类的其他构造方法
注意:本类其他构造方法也必须可以访问父类拥有的构造方法,即使用this关键字间接的调用父类的构造方法
无论在哪里调用父类的构造方法,只要最后保证在子类构造方法内容执行之前完成了父类的初始化就可以了
一定注意:super(...)或者this(...)必须出现在第一条语句上,否则就会出现父类的数据进行了多次初始化——每个类只能初始化一次
- class Father9 {
- int age;
-
- Father9(String s) {
- System.out.println("这是父类中的带参数的构造方法:" + s);
- }
- }
-
- class Son9 extends Father9 {
- Son9() {
- super("你好");
- System.out.println("这是子类中的无参构造方法");
- }
-
- Son9(String s) {
- this();
- System.out.println("这是子类中的带参数的构造方法:" + s);
- //this(); 报错,对this的调用必须是构造器中的第一个语句
- }
- }
-
- public class ExtendsDemo8 {
- public static void main(String[] args) {
- Son9 s1 = new Son9("小王");
- }
- }
相关练习题:
1)看程序写结果
- class Fu {
- public int num = 10;
-
- public Fu() {
- System.out.println("fu");
- }
- }
-
- class Zi extends Fu {
- public int num = 20;
-
- public Zi() {
- //这里隐藏了一个super()
- System.out.println("zi");
- }
-
- public void show() {
- int num = 30;
- System.out.println(num);
- System.out.println(this.num);
- System.out.println(super.num);
- }
- }
-
- public class ExtendsTest1 {
- public static void main(String[] args) {
- Zi z = new Zi();
- z.show();
- }
- }
2)看程序,写结果
一个类的初始化过程:
1.栈中开辟空间
2.堆开辟空间给对象
3.成员变量的值是系统默认值
4.成员变量显式赋值
5.构造方法赋值
- class X{
- Y b = new Y(); //第一步
- X(){
- System.out.print("X"); //第三步
- }
- }
-
- class Y{
- Y(){
- System.out.print("Y"); //第二步
- }
- }
-
-
- public class ExtendsTest2 extends X{
- Y y = new Y(); //第四步
- ExtendsTest2(){
- //隐藏一个super()
- System.out.print("Z"); //第五步
- }
- public static void main(String[] args) {
- new ExtendsTest2(); //YXYZ
- }
- }
1.当子类的成员方法名与父类的成员方法名不一样的时候,该调用谁就调用谁
- class Father10 {
- public void show() {
- System.out.println("这是父类中的show方法");
- }
- }
-
- class Son10 extends Father10 {
- public void show2() {
- System.out.println("这是子类中的show2方法");
- }
- }
-
- public class ExtendsDemo9 {
- public static void main(String[] args) {
- Son10 son10 = new Son10();
- son10.show2();
- son10.show();
- }
- }
2.当子类的成员方法名与父类的成员方法名一样的时候
查找:(就近原则)
第一步:先在本类中查找,如果有方法就调用,如果没有,去父类中查找
第二步:如果父类中有方法,就调用父类的
第三步:如果父类中也没有要调用的方法名,报错,提示找不到方法
子类的方法名能不能和父类方法的声明一样?
如果子类的方法声明与父类的方法声明一样,这样的现象叫做方法的重写
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。