栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java面向对象:继承,方法重写,final关键字,抽象类,接口

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java面向对象:继承,方法重写,final关键字,抽象类,接口

1、继承

       在java中,所有的类都直接或间接继承Object类,Object类称为所有Java类的祖先。java中的继承是通过extends关键字操作的。通常说被继承的类叫作父类,派生的类叫做子类,通过继承后,子类可以使用父类的成员变量和成员方法。由此特点,通常在生产中把父类设计为拥有所有子类的共同属性和行为的类,即多个类中相同的内容给提取出来定义到一个类。比如人会吃饭和睡觉,那么学生和老师也会吃饭和睡觉,如下

class Person {
    public void sleep() {
        System.out.println("人会睡觉的!");
    }
    public void eat() {
        System.out.println("人会吃饭的!");
    }
}

//继承格式:class 子类名 extends 父类名 {}

class Student extends Person{}  //Student类继承了Person类

class Teacher extends Person{} //Teacher类继承了Person类

class test {
    public static void main(String[] args) {
       Student s1 = new Student();
       s1.sleep();   //Student类对象s1调用父类的sleep()成员方法
       s1.eat();
       System.out.println("---------");
       Teacher t1 = new Teacher();
       t1.sleep();  //Teacher类对象t1调用父类的sleep()成员方法
       t1.eat();  
    }
}

//执行结果如下:

人会睡觉的!
人会吃饭的!
---------
人会睡觉的!
人会吃饭的!

  1.1、 Java中继承的特点:

        A:Java只支持单继承,不支持多继承。

            //class Son extends Father,Mother {}  // java这样的多继承是错误的
            但有些语言是支持多继承,格式:extends 类1,类2,...
        B:Java支持多层继承(继承体系)

              class GrandFather(){}

              class Father extends GrandFather(){}

              class Son extends Father(){}

java多层继承的案例

class GrandFather {
    public void show() {
        System.out.println("我是爷爷");
    }
}

class Father extends GrandFather {
    public void method(){
        System.out.println("我是老子");
    }
}

class Son extends Father {}

class ExtendsDemo2 {
    public static void main(String[] args) {
        Son s = new Son();
        s.method(); //使用父亲的
        s.show(); //使用爷爷的
    }
}

  1.2、继承注意事项
        A:子类只能继承父类所有非私有的成员(即成员方法和成员变量)
        B:子类不能继承父类的构造方法,但是可以通过super(马上讲)关键字去访问父类构造方法。(子类通过super访问父类的成员方法)
        C:不要为了部分功能而去继承。只要A和B两者关系是"A is B"或"B is A"才去继承。
继承的案例2:


class Father {
    private int num = 10;
    public int num2 = 20;
    
    //私有方法,子类不能继承
    private void method() {
        System.out.println(num);
        System.out.println(num2);
    }
    
    public void show() {
        System.out.println(num);
        System.out.println(num2);
    }
}

class Son extends Father {
    public void function() {
        //num可以在Father中访问private
        //System.out.println(num); //子类不能继承父类的私有成员变量
        System.out.println(num2);
    }
}

class ExtendsDemo3 {
    public static void main(String[] args) {
        // 创建对象
        Son s = new Son();
        //s.method(); //子类不能继承父类的私有成员方法
        s.show();
        s.function();
    }
}

  1.3、继承中成员变量和成员方法的调用

继承中成员变量的调用规则


class Father {
    public int num = 10;
    
    public void method() {
        int num = 50;
    }
}

class Son extends Father {
    public int num2 = 20;
    public int num = 30;
    
    public void show() {
        int num = 40;
        System.out.println(num);
        System.out.println(num2);
        // 找不到符号,报错
        //System.out.println(num3);
    }
}

class ExtendsDemo4 {
    public static void main(String[] args) {
        //创建对象
        Son s = new Son();
        s.show();
    }
}

继承中成员方法的调用规则:


class Father {
    public void show() {
        System.out.println("show Father");
    }
}

class Son extends Father {
    public void method() {
        System.out.println("method Son");
    }
    
    public void show() {
        System.out.println("show Son");
    }
}

class ExtendsDemo8 {
    public static void main(String[] args) {
        //创建对象
        Son s = new Son();
        s.show();
        s.method();
        //s.fucntion(); //找不到符号
    }
}

由以上两个案例可知,在继承中,无论是成员变量还是成员方法,调用顺序都遵守“就近原则”:

成员变量:子类方法局部变量-->子类成员变量-->父类成员变量
成员方法:子类成员方法-->父类成员方法
  1.4、继承中this和super关键字的作用
this和super的区别?

            this代表本类对应的引用。
            super代表父类存储空间的标识(可以理解为父类的引用,可以操作父类的成员)     

   怎么用呢?
            A:调用成员变量
                this.成员变量 调用本类的成员变量
                super.成员变量 调用父类的成员变量
            B:调用构造方法
                this(...)    调用本类的构造方法
                super(...)    调用父类的构造方法
            C:调用成员方法
                this.成员方法 调用本类的成员方法
                super.成员方法 调用父类的成员方法
继承中用this和super区分父类(成员变量)、子类(成员变量)和子类方法中(局部变量)同名num的值

class Father {
    public int num = 10;
}

class Son extends Father {
    public int num = 20;
    
    public void show() {
        int num = 30;
        System.out.println(num);   //局部变量优先级最高,num=30
        System.out.println(this.num);  //本类成员变量num=20
        System.out.println(super.num);  //父类成员变量num=30
    }
}

class ExtendsDemo5 {
    public static void main(String[] args) {
        Son s = new Son();
        s.show();
    }
}

  1.5、继承的构造方法

       在继承中,子类中所有的构造方法默认都会访问父类中无参构造方法(因为子类会继承父类中的数据,可能还会使用父类的数据。)所以,子类初始化之前,一定要先完成父类数据的初始化。

 注意:子类每一个构造方法的第一条语句默认都是:super(); 

 如下案例:

class Father {
    int age;

    public Father() {
        System.out.println("Father的无参构造方法");
    }
    
    public Father(String name) {
        System.out.println("Father的带参构造方法");
    }
}

class Son extends Father {
    public Son() {
        //super();
        System.out.println("Son的无参构造方法");
    }
    
    public Son(String name) {
        //super();
        System.out.println("Son的带参构造方法");
    }
}    

class ExtendsDemo6 {
    public static void main(String[] args) {
        //创建对象
        Son s = new Son();
        System.out.println("------------");
        Son s2 = new Son("林青霞");
    }
}

//执行结果如下:

Father的无参构造方法
Son的无参构造方法
------------
Father的无参构造方法
Son的带参构造方法

特别地,如果父类没有无参构造方法的话,那么子类的构造方法就会出现报错。解决方式如下:

解决父类没有无参构造方法的措施:

        A:在父类中加一个无参构造方法
        B:通过使用super关键字去显示的调用父类的带参构造方法 
        C:子类通过this去调用本类的其他构造方法
            子类中一定要有一个去访问了父类的构造方法,否则父类数据就没有初始化。

 注意事项:
        this(...)或者super(...)必须出现在第一条语句上。
        如果不是放在第一条语句上,就可能对父类的数据进行了多次初始化,所以必须放在第一条语句上。

class Father {
    
    
    public Father(String name) {
        System.out.println("Father的带参构造方法");
    }
}

class Son extends Father {
    public Son() {
        super("随便给");  //super调用父类的带参构造方法
        System.out.println("Son的无参构造方法");
        //super("随便给");
    }
    
    public Son(String name) {
        //super("随便给");
        this();  //通过this调用本类的无参son()构造方法中的super("随便给");调用父类的带参构造方法初始化数据  
        System.out.println("Son的带参构造方法");
    }
}

class ExtendsDemo7 {
    public static void main(String[] args) {
        Son s = new Son();
        System.out.println("----------------");
        Son ss = new Son("林青霞");
    }
}

//执行结果如下:

Father的带参构造方法
Son的无参构造方法
----------------
Father的带参构造方法
Son的无参构造方法
Son的带参构造方法

1.6、三道经典的继承案例
看程序写结果案例1:


class Fu {
    static {
        System.out.println("静态代码块Fu");
    }

    {
        System.out.println("构造代码块Fu");
    }

    public Fu() {
        System.out.println("构造方法Fu");
    }
}

class Zi extends Fu {
    static {
        System.out.println("静态代码块Zi");
    }

    {
        System.out.println("构造代码块Zi");
    }

    public Zi() {
        System.out.println("构造方法Zi");
    }
}

class ExtendsTest2 {
    public static void main(String[] args) {
        Zi z = new Zi();
    }
}


//执行的结果是:
        静态代码块Fu
        静态代码块Zi
        构造代码块Fu
        构造方法Fu
        构造代码块Zi
        构造方法Zi

super的秒用:案例2

class Person {
    //姓名
    private String name;
    //年龄
    private int age;
    
    public Person() {
    }

    public Person(String name,int age) { //"林青霞",27
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
}

//定义学生类
class Student extends Person {
    public Student() {}
    
    public Student(String name,int age) { //"林青霞",27
        //this.name = name;
        //this.age = age;
        super(name,age);  //super调用父类的this.name = name和this.age = age;
    }
}

//定义老师类
class Teacher extends Person {

}

class ExtendsTest4 {
    public static void main(String[] args) {
        //创建学生对象并测试
        //方式1
        Student s1 = new Student();
        s1.setName("林青霞");
        s1.setAge(27);
        System.out.println(s1.getName()+"---"+s1.getAge());
        
        //方式2
        Student s2 = new Student("林青霞",27);
        System.out.println(s2.getName()+"---"+s2.getAge());
        
        //补齐老师类中的代码并进行测试。
    }
}

继承面试题:案例3

//看程序写结果

class X {
    {
        System.out.print("Father");
    }
    Y b = new Y();
    X() {
        System.out.print("X");
    }
}

class Y {
    Y() {
        System.out.print("Y");
    }
}

public class test extends X {
    {
        System.out.print("Son");
    }
    Y y = new Y();
    test() {
        //super
        System.out.print("Z");
    }
    public static void main(String[] args) {
        new test(); 
    }
}

//执行结果如下

FatherYXSonYZ

//由上结果可知,继承中,子类new对象初始化时,是直接去父类中进行数据初始化后,再进子类的进行数据初始化的。

2、方法重写
方法重写Override方法重载Overload
方法重写:子类中出现了和父类中方法声明一模一样的方法。方法重载:
        本类中出现的方法名一样,但参数列表和返回值类型都不同。

class Phone {
    public void call(String name) {
        System.out.println("给"+name+"打电话");
    }
}

class NewPhone extends Phone {
    public void call(String name) {
       
        super.call(name);
        System.out.println("可以听天气预报了");
    }
}

class ExtendsDemo9 {
    public static void main(String[] args) {
        NewPhone np = new NewPhone();
        np.call("苏炳添");
    }
}

public class test {
    public static void main(String[] args){
        System.out.println(sum('a','b'));
        System.out.println(sum(3,3,3));
        System.out.println(sum(3,3,3,3));
    }

    //two char
    public static char sum(char a,char b) {
        return (char) (a+b);
    }
    //three number
    public static int sum(int a, int b, int c) {
        return a + b + c ;
    }
    //four number
    public static int sum(int a, int b, int c,int d) {
        return a + b + c + d;
    }
}

  2.1、方法重写的特点

    (1)子类对象调用方法的时候:
                    先找子类本身,再找父类。
        
    (2)方法重写的应用:
             当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。
             这样,即沿袭了父类的功能,又定义了子类特有的内容。

    (3)方法重写的注意事项
        A:父类中私有方法不能被重写
            因为父类私有方法子类根本就无法继承
        B:子类重写父类方法时,访问权限不能更低
            最好就一致
        C:父类静态方法,子类也必须通过静态方法进行重写
            其实这个算不上方法重写,但是现象确实如此,至于为什么算不上方法重写,多态中我会讲解
            
        //子类重写父类方法的时候,最好声明一模一样。

3、final关键字

       final字面意思表“最终的”,它可以修饰类,方法,变量。

  3.1、final的特点
final的特点:
        final可以修饰类,该类不能被继承。
        final可以修饰方法,该方法不能被重写。(覆盖,复写)
        final可以修饰变量,该变量不能被重新赋值。因为这个变量其实常量。
  3.2、final修饰局部变量

final修饰局部变量的问题?
        基本类型:基本类型的值不能发生改变。
        引用类型:引用类型的地址值不能发生改变,但是,该对象的堆内存的值是可以改变的。

class Student {
    int age = 10;
}
class FinalTest {
    public static void main(String[] args) {
        //局部变量是基本数据类型
        int x = 10;
        x = 100;
        System.out.println(x);
        final int y = 10;
        //无法为最终变量y分配值
        //y = 100;
        System.out.println(y);
        System.out.println("--------------");
        
        //局部变量是引用数据类型
        Student s = new Student();
        System.out.println(s.age);
        s.age = 100;
        System.out.println(s.age);
        System.out.println("--------------");
        
        final Student ss = new Student();
        System.out.println(ss.age);
        ss.age = 100;
        System.out.println(ss.age);
        
        //重新分配内存空间
        //无法为最终变量ss分配值
        ss = new Student();
    }
}
  3.3、final修饰变量的初始化时机

final修饰变量的初始化时机
        A:被final修饰的变量只能赋值一次。
        B:在构造方法完毕前。(非静态的常量)

             //就是说final的变量赋值的时机要在代码块里赋值,或在构造方法中赋值,又或者在声明final变量时直接赋值才行。

            赋值的顺序:成员方法声明>代码块>成员方法

class Demo {
    //int num = 10;
    //final int num2 = 20;
    
    int num;
    final int num2;  //final变量赋值点1
    
    {
        //num2 = 10;  //final变量赋值点2 
    }
    
    public Demo() {
        num = 100;
        //无法为最终变量num2分配值
        num2 = 200;   //final变量赋值点2 
    }
}

class FinalTest2 {
    public static void main(String[] args) {
        Demo d = new Demo();
        System.out.println(d.num);
        System.out.println(d.num2);
    }
}

  3.4、final保护父类的机密性
final保护父类的机密性:

class Fu {
    public final void show() {
        System.out.println("这里是绝密资源,任何人都不能修改");
    }
}

class Zi extends Fu {
    // Zi中的show()无法覆盖Fu中的show()
    public void show() {
        System.out.println("这是一堆垃圾");
    }
}

class ZiDemo {
    public static void main(String[] args) {
        Zi z = new Zi();
        z.show();
    }
}

4、多态

       多态:同一个对象(事物),在不同时刻体现出来的不同状态。比如水在不同的条件下可以有液体、气体和固体三个状态。

  4.1、多态的条件
多态的前提:
        A:要有继承关系。
        B:要有方法重写。
            其实没有也是可以的,但是如果没有这个就没有意义。
                动物 d = new 猫();
                d.show();
                动物 d = new 狗();
                d.show();
        C:要有父类引用指向子类对象。
            父 f =  new 子();
  4.2、 多态中的成员访问特点:
 多态中的成员访问特点:
        A:成员变量
            编译看左边(父类),运行看左边(父类)。
        B:构造方法
            创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
        C:成员方法
            编译看左边(父类),运行看右边(子类)。
        D:静态方法
            编译看左边(父类),运行看左边(父类)。
            (静态和类相关,算不上重写,所以,访问还是左边的)
            
        由于成员方法存在方法重写,所以它运行看右边。

class Fu {
    public int num = 100;

    public void show() {
        System.out.println("show Fu");
    }
    
    public static void function() {
        System.out.println("function Fu");
    }
}

class Zi extends Fu {
    public int num = 1000;
    public int num2 = 200;

    public void show() {
        System.out.println("show Zi");
    }
    
    public void method() {
        System.out.println("method zi");
    }
    
    public static void function() {
        System.out.println("function Zi");
    }
}

class DuoTaiDemo {
    public static void main(String[] args) {
        //要有父类引用指向子类对象。
        //父 f =  new 子();
        Fu f = new Zi();
        System.out.println(f.num);
        //找不到符号
        //System.out.println(f.num2);
        
        f.show();
        //找不到符号
        //f.method();
        f.function();
    }
}

  4.3、多态的向上转型和向下转型:
多态的向上转型和向下转型:

    多态的弊端:
        不能使用子类的特有功能。  
 

   我就想使用子类的特有功能?行不行?
        行。
        
    怎么用呢?
        A:创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,太占内存了)
        B:把父类的引用强制转换为子类的引用。(向下转型)
        
    对象间的转型问题:
        向上转型:
            Fu f = new Zi();
        向下转型:
            Zi z = (Zi)f; //要求该f必须是能够转换为Zi的。

//案例代码如下:

class Fu {
    public void show() {
        System.out.println("show fu");
    }
}

class Zi extends Fu {
    public void show() {
        System.out.println("show zi");
    }
    
    public void method() {
        System.out.println("method zi");
    }

}

class DuoTaiDemo4 {
    public static void main(String[] args) {
        //测试
        Fu f = new Zi();
        f.show();
        //f.method();
        
        //创建子类对象
        //Zi z = new Zi();
        //z.show();
        //z.method();
        
        //你能够把子的对象赋值给父亲,那么我能不能把父的引用赋值给子的引用呢?
        //如果可以,但是如下
        Zi z = (Zi)f;
        z.show();
        z.method();
    }
}

  4.4、多态的内存图
多态的内存图:

//内存图1

//内存图2

    4.5、多态的经典案例
多态的经典案例:


class A {
    public void show() {
        show2();
    }
    public void show2() {
        System.out.println("我");
    }
}
class B extends A {
    

    public void show2() {
        System.out.println("爱");
    }
}
class C extends B {
    public void show() {
        super.show();
    }
    public void show2() {
        System.out.println("你");
    }
}
public class DuoTaiTest4 {
    public static void main(String[] args) {
        A a = new B();
        a.show();
        
        B b = new C();
        b.show();
    }
}

//执行结果如下:

5、抽象类

       在java中用abstract关键字来声明抽象类,抽象类是不能实例化的类,是泛指的概念,需要子类去实例化。比如动物可以设计成一个抽象的类,要用猫类和狗类去实例化。吃饭和睡觉也可以设置成抽象类中抽象的方法,再通过不同的子类(猫类或狗类)去实现各自具体不同的动作。这样通过一个抽象类,由子类去实现具体的功能,提高了代码的扩展性(子类保证)和易维护(抽象的父类保护)。

  5.1、抽象类的基本特点
抽象类的基本特点

        A:抽象类和抽象方法必须用abstract关键字修饰
        B:抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类
        C:抽象类不能实例化
            因为它不是具体的。
            抽象类有构造方法。构造方法的作用是什么呢?用于子类访问父类数据的初始化。
        D:抽象的子类
            a:如果不想重写抽象方法,该子类是一个抽象类。
            b:重写所有的抽象方法,这个时候子类是一个具体的类。
            
        抽象类的实例化其实是靠具体的子类实现的。是多态的方式。
            Animal a = new Cat();

       同时 abstract不能与private、final和static关键字共存。

//abstract class Animal //抽象类的声明格式
abstract class Animal {
    //抽象方法
    //public abstract void eat(){} //空方法体,这个会报错。抽象方法不能有主体
    public abstract void eat();
    
    public Animal(){}
}

//子类是抽象类
abstract class Dog extends Animal {}

//子类是具体类,重写抽象方法
class Cat extends Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

class AbstractDemo {
    public static void main(String[] args) {
        //创建对象
        //Animal是抽象的; 无法实例化
        //Animal a = new Animal();
        //通过多态的方式
        Animal a = new Cat();
        a.eat();
    }
}

  5.2、抽象类的成员特征
    抽象类的成员特点:
        成员变量:既可以是变量,也可以是常量。
        构造方法:有。
                    用于子类访问父类数据的初始化。
        成员方法:既可以是抽象的,也可以是非抽象的。
        
    抽象类的成员方法特性:
        A:抽象方法 强制要求子类做的事情。
        B:非抽象方法 子类继承的事情,提高代码复用性。

abstract class Animal {
    public int num = 10;
    public final int num2 = 20;

    public Animal() {}
    
    public Animal(String name,int age){}
    
    public abstract void show();
    
    public void method() {
        System.out.println("method");
    }
}

class Dog extends Animal {
    public void show() {
        System.out.println("show Dog");
    }
}

class AbstractDemo2 {
    public static void main(String[] args) {
        //创建对象
        Animal a = new Dog();
        a.num = 100;
        System.out.println(a.num);
        //a.num2 = 200;
        System.out.println(a.num2);
        System.out.println("--------------");
        a.show();
        a.method();
    }
}

  5.3、经典抽象类(猫狗案例)

//定义抽象的动物类
abstract class Animal {
    //姓名
    private String name;
    //年龄
    private int age;
    
    public Animal() {}
    
    public Animal(String name,int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    //定义一个抽象方法
    public abstract void eat();
}

//定义具体的狗类
class Dog extends Animal {
    public Dog() {}
    
    public Dog(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("狗吃肉");
    }
}

//定义具体的猫类
class Cat extends Animal {
    public Cat() {}
    
    public Cat(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

//测试类
class AbstractTest {
    public static void main(String[] args) {
        //测试狗类
        //具体类用法
        //方式1:
        Dog d = new Dog();
        d.setName("旺财");
        d.setAge(3);
        System.out.println(d.getName()+"---"+d.getAge());
        d.eat();
        //方式2:
        Dog d2 = new Dog("旺财",3);
        System.out.println(d2.getName()+"---"+d2.getAge());
        d2.eat();
        System.out.println("---------------------------");
        
        Animal a = new Dog();
        a.setName("旺财");
        a.setAge(3);
        System.out.println(a.getName()+"---"+a.getAge());
        a.eat();
        
        Animal a2 = new Dog("旺财",3);
        System.out.println(a2.getName()+"---"+a2.getAge());
        a2.eat();
        
        //练习:测试猫类
    }
}

6、接口

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/270240.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号