一起来认识Java——继承

我们发现,一些相似的类会用到一些相同的功能。

所以,为了方便起见,就把这些常用到的类的功能单独放在一起,就可以被其他的类所调用了。

继承的定义

父类和子类

父类是被继承的类,也叫做基类,超类

继承父类的类叫做子类派生类

语法规则

//父类
class A{}
//子类
class B extends A{}

注意,这里使用的是extends,千万不要忘记“s“。

  1. 子类不可以访问父类的private属性的变量
  2. 子类只可以继承一个父类(和C++的多继承不同)

继承的构造函数——super

有了继承之后,子类和父类都需要有构造函数。

如果没有继承,两个类的构造函数就是自己的就是自己的。

但是,两个有了继承,这两个类的构造函数就必须要有一些关系了。

我们采用super来进行继承间的构造,具体如下:

super

class UserInfo{public String name="123";int age;public UserInfo(String name,int age){this.age=age;this.name=name;}
}
class Friend extends UserInfo{public Friend(String name,int age,String rename,String list){super(name,age);//必须放在子类的第一排哦this.rename=rename;this.list=list;}String rename;String list;
}

具体使用:

在子类的构造函数的第一行采用super关键字来进行父类的构造函数

!super的三种用法!

  1. super()像上面那样,用于父类的构造函数
  2. super.data调用父类的成员属性
  3. super.func调用父类的成员方法
  4. 不出现在静态方法中

我们可以发现super和this的使用非常的相像。

super和this的区别

this是对对象的本身的引用,super是对于父类对象的引用

super和继承

当子类和父类出现相同的变量名的时候,优先访问的是子类自己的,然后只有访问super.data才访问父类

class UserInfo{public String name="123";int age;public UserInfo(String name,int age){this.age=age;this.name=name;}public void func(){}}
class Friend extends UserInfo{public Friend(String name,int age,String rename,String list){super(name,age);//必须放在子类的第一排哦super.age=12;super.func();this.name=rename;this.list=list;}String name;String list;public void add(){System.out.println(super.name);//注意,这里使用了super}
}
public class TestDemo {public static void main(String[] args) {Friend friend=new Friend("1232",12,"ewqe","weq");System.out.println(friend.name);//自己的namefriend.add();//使用了super,访问的是父类的name}
}

在构造函数中调用重写的函数(注意)

就是在父类构造函数中调用了一个子类父类都有的方法,该方法被子类重写了,那么会调用谁的方法呢?

答案是:子类的,因为在这个过程中出发了动态绑定,所以会调用子类的方法。

例子:

class Animal{public  void eat() {System.out.println("Animal have to eat");}public Animal(){eat();}}
class Cat extends Animal{public int i=100;@Overridepublic void eat(){System.out.println("Cat only need to cute "+"i="+i);}
}
public class Inherit {public static void main(String[] args) {Cat cat=new Cat();}
}

子类对父类的eat进行了重写,同时在父类的构造函数中调用了eat函数,

结果却掉用的是子类重写的构造函数。因为发生了动态绑定。

结论:

  1. 不要在构造函数中调用被重写的方法
  2. 子类继承了父类,就会调用父类的构造函数

构造函数-----无参

父类有构造函数,子类没有构造函数

class Animal{public Animal(){System.out.println("aaa");}
}
public class Inherit extends Animal {public static void main(String[] args) {new Inherit();new Animal();}
}

aaa

aaa

父类和子类都有构造函数

子类的构造函数不管有没有super都是先调用父类的构造函数再调用自己的构造函数

class Animal{public Animal(){System.out.println("Animal");}}
public class Inherit extends Animal {public Inherit(){// super();System.out.println("Inherit");}public static void main(String[] args) {new Inherit();new Animal();}
}

Animal
Inherit
Animal

构造函数------有参

对于有参的构造函数,子类的构造函数内部就必须要有super(参数),表示调用父类的构造函数。

class Animal{public Animal(String s){System.out.println(s);}
}
public class Inherit extends Animal {public Inherit(String s){super(s);//必须写上super,没有super就报错System.out.println("D");}public static void main(String[] args) {new Inherit("C");}
}

构造函数——继承和组合谁先来?

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

YXYZ

访问修饰权限符

public:
同一个包的相同类,

同一个包的不同类

不同包的子类

不同包的非子类

对于public来说,都可以被访问到。


private:

同一个包的相同类

对于private来说,只有相同包的同一个类内部才可以访问


default:

同一个包的相同类

同一个包的不同类

对于不被任何修饰的类来说,只有在同一个包中才可以被访问。


protected:
同一个包的相同类

同一包的不同类

不同包的相同子类

对于protected来说,只有不同包的不同子类不可以访问,并且protected就是为了这个而设计的,就是为了让非子类不可以访问


不同包的相同子类的protected的具体访问:

采用super

import com.lxy.Test;public class Test2 extends Test {public void func(){System.out.println(super.val);//protected需要采用super来访问}public static void main(String[] args) {Test2 test2=new Test2();test2.func();}
}

final关键字

final如果修饰变量,说明这个变量不可以被修改

final如果修饰类,就是说明这个类不可以被继承了

final修饰的函数,不可以被重写

组成

组合是一个类中包含另外一个类。

继承是一个类对另外一个类进行改进

组合和继承都是代码复用的一种方式。

final class A{}
class B {}
public class Inherit {A a;B b;
}

多态

1.向上转型

由于父类一般都写在子类的上面,所以将子类赋值给父类的操作,我们就叫做向上转型。

1)直接赋值

直接的将子类赋值给父类的方法就叫做向上转型。

class Animal{}
class Cat extends Animal{}
public class Inherit {Cat smallCat=new Cat();Animal animal=smallCat;//直接将子类赋给基类
}

2)实参形参赋值

实参的子类赋给形参的父类也是向上转型

class Animal{}
class Cat extends Animal{}
public class Inherit {public static void func(Animal animal){}public static void main(String[] args) {Cat smallCat=new Cat();func(smallCat);}
}

3)方法的返回

方法的返回值应为父类,但是实际上返回子类。这样做还是可以的。

class Animal{}
class Cat extends Animal{}
public class Inherit {public static Animal func(){Cat cat=new Cat();return cat;}public static void main(String[] args) {Animal animal=func();//注意:需要的是animal,但是却将cat赋予animal也是可以的}
}

2.动态绑定

发生在重写的过程中

子类和父类具有相同的函数的时候,再去使用向上转型的话,就会涉及到动态绑定的问题

class Animal{public void eat() {System.out.println("Animal have to eat");}}
class Cat extends Animal{public void eat(){System.out.println("Cat need to cute");}
}
public class Inherit {public static void main(String[] args) {Animal animal=new Animal();animal.eat();Animal animal1=new Cat();animal1.eat();}
}

Animal和cat具有相同的方法eat().

animal指向的是Animal,所以调用的就是Animal的eat

animal1指向的是cat,所以调用的就是cat的eat

这就是动态绑定了,该引用指向的是谁,就调用谁的函数。

由于是在运行的时候才确定的指向,所以,叫做动态绑定。

静态绑定

静态绑定,也叫做编译时绑定。具体就是在发生在函数的重载中。

重载函数的个数和类型在编译的时候就确定好了

3.方法重写

在父子类中的继承中

就在上面的动态绑定来说,子类和父类具有相同的函数eat。

那么子类的eat其实就是对父类的eat的重写。

具体要求:

  1. 重写要求子类的返回值,函数参数的个数和类型都必须和父类相同。

    就是必须一模一样的函数,只是函数的实现不一样

  2. static修饰的方法不能被重写

  1. 被final修饰的也不能被重写

    final修饰方法大概就是这个作用

  2. 子类重写的函数的修饰范围不可以比父类严格

​ 父类的eat是public,子类的eat却是protected,这样是不行的。

子类的访问限定符要大于等于父类的访问限定符

  1. private修饰的变量不可以被重写

    private相当于不可以在类外调用。

  2. 一般在子类的重写函数的前面加上@Overrride

    @override可以标示这是父类的一个函数的重写

    还可以提示我们的重写有没有错误。

重写和动态绑定

只有有了重写,才可以有动态绑定。

就是子类和父类都有了相同的函数,在向上转型的时候,才会发生动态绑定。

动态绑定是子类赋予父类。

所以,该父类对象只可以调用该父类的对象,不可以调用子类的对象

4.向下转型

向下转型,一般来说,就是将父类赋予子类。

  1. 一般都搭配上向上转型来使用
  2. 有严格的类型规范
class Animal{private   void eat() {System.out.println("Animal have to eat");}}
class Cat extends Animal{//@Overridepublic void eat(){System.out.println("Cat need to cute");}
}
class Dog extends Animal{public void eat(){System.out.println("eat a lot");}}
public class Inherit {public static void main(String[] args) {Animal animal=new Cat();//向上转型//向下转型://首先判断animal是不是cat的实例if(animal instanceof Cat){Cat cat=(Cat)animal;//向下转型cat.eat();}//错误做法Animal animal1=new Dog();Cat cat=(Cat) animal1;//不可以将狗的实例强制转为catcat.eat();}
}

这个严格的规范就是:

向上转型时的引用类型,必须和向下转型时的强转类型相同

所以每次向下转换的时候要使用instanceof,来判断是不是要向下转型的类型的引用

 Animal animal=new Cat();//向上转型//向下转型://首先判断animal是不是cat的实例if(animal instanceof Cat){Cat cat=(Cat)animal;//向下转型cat.eat();}

5.理解多态

class group{public void func(){System.out.println("");}
}
class QQ extends group{@Overridepublic void func() {System.out.println("QQ");}
}
class WX extends group{@Overridepublic void func() {System.out.println("WX");}
}
class WB extends group{@Overridepublic void func() {System.out.println("WB");}
}
public class Inherit{public static void fun(group group){group.func();}public static void main(String[] args) {group[] groups={new QQ(),new WB(),new WX()};for (group group:groups) {fun(group);//真正的多态体验,只需将子类的类型传入,便可调用子类自己的函数 }}
}

抽象abstract

什么是抽象

class group{public void func(){System.out.println("");}
}
class QQ extends group{@Overridepublic void func() {System.out.println("QQ");}
}
class WX extends group{@Overridepublic void func() {System.out.println("WX");}
}
class WB extends group{@Overridepublic void func() {System.out.println("WB");}
}
public class Inherit{public static void fun(group group){group.func();}public static void main(String[] args) {group[] groups={new QQ(),new WB(),new WX()};for (group group:groups) {fun(group);}}
}

根据上面的多态,QQ,WX,WB,都继承了group,都重写了group的func函数,所以group的func函数根本就没有被使用到。

我们就把这个属于父类的没有被使用到的func但是被子类重写的函数叫做抽象函数

含有抽象函数的类叫做抽象类

抽象的语法

  1. 抽象类和抽象函数由abstract所修饰。
  2. 抽象函数没有函数体,函数的声明后面只是有分号。
abstract class group{abstract public void func();
}
  1. 抽象类不能被实例化,只能被继承

  1. 抽象方法不能是private的,要不然就不能被重写了。

  2. 抽象类内部可以有其他的方法和字段,并且方法可以被重写。

    abstract class group{abstract public void func();void fun2(){System.out.println("fun2");}}
    class WX extends group{@Overridepublic void func() {System.out.println("WX");}
    }
    public class Inherit{public static void main(String[] args) {group group=new WX();group.fun2();}
    }
    
  3. 一个普通类继承了抽象类,那么必须重写抽象类中所有的抽象方法。

  4. 一个抽象类A,如果继承了抽象类的B,那么不用去重写所有B的抽象方法

但是,如果一个类继承了上面两个抽象类的话,就需要将上面两个抽象类的抽象函数都重写

abstract class group{abstract public void func();
}
abstract class WX extends group{abstract public void func2();
}
class QQ extends WX{@Overridepublic void func() {System.out.println("QQ");}@Overridepublic void func2() {System.out.println("QQ");}
}
8. 抽象方法和抽象类都不可以被final修饰

抽象类的作用

抽象类的最大的作用就是提示我们要记得重写抽象函数,多了一个提示的作用。

接口interface

抽象类中还可以包含非抽象类的方法和字段。但是,接口中只可以拥有抽象函数,和静态常量

语法规则

  1. 采用interface来定义,而不是用abstract
  2. 接口中的方法一定是抽象方法,所以abstract可以被省略
  3. 接口中的方法还要求必须是public类型的,所以public可以省略
  4. 接口中的字段只能是final static类型的,也就是静态常量,所以我们可以省略。
  5. 子类继承接口类的时候不是用extends了,而是用implements,含义是实现。
  6. 和抽象一样,不能被实例化
  7. 接口名一般以大写的I开头

extends和implement

extends代表的是扩展,增加新的事情,

implement代表的是实施,完成什么样的事情或动作。

省略形式:

interface Igroup{//此时它就是一个接口了,不是classvoid func();//抽象函数 int num=10;//静态常量
}

完整形式:

interface Igroup{//此时它就是一个接口了,不是classpublic abstract void func();//抽象函数public static final int num=10;//静态常量
}

两个形式都可以接受

接口就是抽象的高级版本,也不要忘记实现接口的抽象函数的重写

interface Igroup{//此时它就是一个接口了,不是classvoid func();//抽象函数int num=10;//静态常量
}
class WX implements Igroup{@Overridepublic void func() {//重写该方法的时候,必须加上publicSystem.out.println("WX");}
}public class Inherit{public static void main(String[] args) {Igroup igroup=new WX();igroup.func();}
}

在接口函数中不想被设为抽象函数怎么办?采用default

interface Igroup{//此时它就是一个接口了,不是classpublic abstract void func();//抽象函数public static final int num=10;//静态常量public default void func2(){System.out.println("func2");}}

这个被default修饰的方法,子类重不重写都可以。

可以在继承类的同时实现接口

一个类只可以继承一个类,但是可以实现多个接口,接口之间用逗号隔开。

interface Igroup{void func();
}
interface IFriend{void func2();
}
class Group{}
//一个类可以继承一个类,实现多个接口
class WX extends Group implements Igroup,IFriend{public void func(){}public void func2(){}
}

重写方法的权限

在接口中,方法默认是public权限的,因为重写方法的权限要比接口中访问的权限要大。

所以,不可以不加访问权限(package),只能是public类型权限的。

接口和接口之间的关系

如果一个接口想拥有另外一个接口的功能,那么就可以使用extends关键字来拓展接口的功能。

interface Igroup{void func();
}
interface IFriend extends Igroup{void func2();
}
//实现IFriend的时候,要重写两个接口的函数
class WX implements IFriend{public void func(){}public void func2(){}
}

接口的实例

因为Java中不允许多几次继承,只允许单继承,但是允许多接口。所以,当一个类要有不同的性质的时候,就要用多接口来实现。

继承+接口的形式,比某些语言的多继承可谓是好多了。最后,多态的时候直接就赋给接口的引用就可以啦。更能够体现不同的接口所表现的不同的性质。

下面,我们就来看一下接口的实例:

class App{protected String name;public App(String name){this.name=name;}
}
interface IContact{void contact();
}
interface IShare{void share();
}
interface Ibrowse{void browse();
}
class QQ extends App implements IContact,IShare{public QQ(String name) {super(name);}@Overridepublic void share() {System.out.println(super.name+"is used to share");}@Overridepublic void contact() {System.out.println(super.name+"is used to contact");}
}
class WB extends App implements IShare,Ibrowse{public WB(String name) {super(name);}@Overridepublic void share() {System.out.println(super.name+"is used to share");}@Overridepublic void browse() {System.out.println(super.name+"is used to browse");}
}
class WX extends App implements IContact,Ibrowse,IShare{public WX(String name) {super(name);}@Overridepublic void contact() {System.out.println(super.name+"is used to contact");}@Overridepublic void share() {System.out.println(super.name+"is used to share");}@Overridepublic void browse() {System.out.println(super.name+"is used to browse");}
}
public class Inherit{public static void contacting(IContact iContact){//这里的参数是类到接口的动态绑定iContact.contact();}public static void sharing(IShare iShare){iShare.share();}public static void browsing(Ibrowse ibrowse){ibrowse.browse();}public static void main(String[] args) {QQ qq=new QQ("QQ");WB wb=new WB("Weibo");WX wx=new WX("weixin");contacting(qq);contacting(wx);sharing(qq);sharing(wx);sharing(wb);browsing(wx);browsing(wb);}
}

comparable的介绍和实例

如果我们想要为一个类中的某一个字段所排序,

比如说有了一个学生类

里面的内容是age和score,想要进行大小比较,

  1. 需要implements接口Comparable
  2. 然后,我们再重写Comparable中的compareTo函数。按照我们需要按照什么进行排序进行重写。
import java.util.Arrays;class Student implements Comparable<Student>{protected double score;protected int age;protected String name;public Student(int age,double score,String name) {this.age = age;this.score=score;this.name=name;}@Overridepublic String toString() {return "Student{" +"score=" + score +", age=" + age +", name='" + name + '\'' +'}';}@Overridepublic int compareTo(Student o) {return this.age-o.age;}
}
public class Inherit {public static void main(String[] args) {Student student1=new Student(22,23.6,"ali");Student student2=new Student(12,98.6,"tx");Student student3=new Student(42,78.6,"zj");Student[] students={student1,student2,student3};System.out.println(Arrays.toString(students));Arrays.sort(students);//根据compareTo中的按age进行排序System.out.println(Arrays.toString(students));}
}

但是如果我们不想要按照age的大小进行排序了 ,我们想要按照name进行排序就要重新的修该compareTo。

        //return this.age-o.age;return this.name.compareTo(o.name);return (int)(this.score-o.score);

对于这中comparable来说,类的侵入性太高,要根据类的一些特点进行不同的排序,就要不断的进行修改。

comparator的介绍和实例

但是,我们还有一个叫做comparator的东西可以改进这个问题,comparator就是根据不同的类的不同的属性进行不同的编写的。

import java.util.Arrays;
import java.util.Comparator;class Student {protected double score;protected int age;protected String name;public Student(int age, double score, String name) {this.age = age;this.score = score;this.name = name;}@Overridepublic String toString() {return "Student{" +"score=" + score +", age=" + age +", name='" + name + '\'' +'}';}
}
class AgeComparator implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o2.age-o1.age;}
}
class ScoreComparator implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return (int)(o1.score-o2.score);}
}
class NameComparator implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o1.name.compareTo(o2.name);}
}public class Inherit {public static void main(String[] args) {Student student1=new Student(22,23.6,"ali");Student student2=new Student(12,98.6,"tx");Student student3=new Student(42,78.6,"zj");Student[] students={student1,student2,student3};System.out.println(Arrays.toString(students));AgeComparator ageComparator=new AgeComparator();ScoreComparator scoreComparator=new ScoreComparator();NameComparator nameComparator=new NameComparator();//按age进行排序Arrays.sort(students,ageComparator);System.out.println(Arrays.toString(students));//按score进行排序Arrays.sort(students,scoreComparator);System.out.println(Arrays.toString(students));//按name进行排序Arrays.sort(students,nameComparator);System.out.println(Arrays.toString(students));}
}

我们根据我们的需要,构造了3个比较器类,这样我们要是进行比较的时候,直接引用那个特定的比较器类就好了。

【一起来学Java】继承,多态,抽象,接口相关推荐

  1. Java继承多态经典案例分享

    今天动力节点java培训机构小编为大家分享Java继承多态经典案例,希望通过此文能够帮助到大家,下面就随小编一起看看Java继承多态经典案例. public class A { public Stri ...

  2. 【零基础学Java】—笔记本USB接口案例(二十八)

    [零基础学Java]-笔记本USB接口案例(二十八) 一.笔记本电脑 笔记本电脑(laptop)通常具备使用USB设备的功能,在生产时,笔记本都预留了可以插入USB设备的USB接口,但具体什么是USB ...

  3. 继承 多态 抽象类 接口

    面向对象编程 包 继承 组合 多态 抽象类 接口 包 包(package)是组织类的一种方式. 使用包的主要目的是保证类的唯一性. java中已经提供给我们很多现成的类供我们选择,例如可以使用 imp ...

  4. java 多态 接口_从零开始的Java日常: 多态,抽象类,接口

    欢迎关注微博:@小白程序员的日常 欢迎关注微博超话:#小白程序员的日常# 本人目前在自学java,会不间断更新java知识 同为小白或者有大佬可以一起探讨一下 一.多态 1.什么是多态 同一个对象,在 ...

  5. JAVA中的“抽象接口”

    在程序设计过程中,读者很可能遇到这样一种困境:设计了一个接口,但实现这个接口的子类并不需要实现接口中的全部方法,也就是说,接口中的方法过多,对于某些子类是多余的,我们不得不浪费的写上一个空的实现. 今 ...

  6. 一起学JAVA 继承 super

    1 继承 1.1概念 继承是面向对象最显著的一个特征 继承是从已有的类中派生出新的类,新类能吸收已有类的数据属性和行为,并扩展新的能力. Java继承是会用已存在的类的定义作为基础建立新类的技术 新类 ...

  7. java自学 part2 数组 类和对象 包 继承 多态 抽象类 接口

    数组:arr 获取数组的长度:arr.length 数组转字符串: Arrays.toString(arr) 数组的拷贝: Arrays.copyOf(arr,arr.length) 数组的排序:Ar ...

  8. 稳稳当当学java之抽象类和接口(11)

    第十三章 抽象类和接口 1.作业回顾 1,编写一个Person类,包括属性(name.age),有参构造器.方法say(返回自我介绍的字符串). 2.编写一个Student类,继承Person类,增加 ...

  9. 手把手教我班小姐姐学java之多态

    文章目录 多态 动态绑定 声明类型 实际类型 工作机制 对象转换和Instanceof操作符 概念: 隐式转换(向上转型.自动类型转换) 显式转换( 向下转型.强制类型转换) instanceof关键 ...

  10. java 继承多态的一些理解和不理解

    1.向上转型的一个误区 一直以为Child 继承Parent以后, Parent p = new Child();  p可以调用Child类中拓展Parent的方法,原来必须在强制转换成Child类才 ...

最新文章

  1. 关于学习Mongodb的几篇文章
  2. 实例教程五:采用SharedPreferences保存用户偏好设置参数
  3. VMware提示:已将该虚拟机配置为使用 64 位客户机操作系统。但是,无法执行 64 位操作。解决方案
  4. linux服务器性能监控命令汇总之dstat命令(二)
  5. uva 11995——I Can Guess the Data Structure!
  6. linux 文件重命名_如何在 Linux 上重命名一组文件 | Linux 中国
  7. Oracle 空间管理
  8. Boost Asio Examples(整理)
  9. STM8S003F3 uart的使用
  10. html水平垂直居中
  11. 《XTWJ自强不息十月纯净版》ISO下载
  12. 在线购物系统 实验七 顺序图
  13. html和php网站哪个好,HTML和PHP网站设计实例
  14. Java 应该怎么学
  15. jspseverlet学习笔记
  16. Micro: 一款比 Vim 更加丝滑的终端文件编辑器
  17. C++学习笔记(十)成员变量和成员函数分开存储、this指针、空指针访问成员函数、const修饰成员函数、友元
  18. matlab三维 旋转矩阵,matlab中的三维坐标系与旋转
  19. 敏捷价值_您是否忘记了敏捷价值?
  20. DAT与MPG文件之间有什么区别(转)

热门文章

  1. 【Matlab 六自由度机器人】基于蒙特卡罗方法(Monte Carlo Method)构建机器人工作空间(附MATLAB建模仿真完整代码)
  2. 一组基于SVG矢量图库和jQuery/GSAP的精美图标动画
  3. rpc服务器打开文档,“RPC服务器不可用”解决办法
  4. 李琰php_李琰:贰拾年一觉轮滑梦
  5. LaTeX 字体、字号、字体样式
  6. 英雄联盟LOL可以免费用皮肤了!来自免费开源软件的福利
  7. NY8A050D 6 I/O 8-bit EPROM-Based MCU 台湾九齐单片机
  8. 两种方法实现等比数列(python)
  9. Verilog实现PWM呼吸灯—从原理到实现
  10. ANSYS Autodyn仿真基础到高级视频教程