1.继承语法
1.语法的定义
class peopel{
public String name;
public int age;
public peopel(String name){//父类构造方法
this.name=name;
System.out.println("name:"+name);
}
public void study(){
System.out.println(name+"在学习");
}
}
class student extends peopel{
public student(String name) {
super(name);//对父类的成员进行初始化
}
public void study(){
System.out.println(name+"在看书");//成员方法的重写
}
}
这段代码中父类为people,子类为student,在引用子类时,会调用父类中的成员,避免了在不同类中书写相同成员的情况。
继承的格式如下:
2.子类访问父类成员方法
1)成员方法名不相同
public class test1 {
public void methodA(){
System.out.println("父类的中的methodA");
}
}
class son extends test1{
public void methodB(){
System.out.println("子类中的methodB");
}
public void methodA(){//与父类中的成员方法名相同
System.out.println("子类中的methodA");
}
}
class c{
public static void main(String[] args) {
son x = new son();
x.methodA();
x.methodB();
}
}
运行结果:
由上述代码和结果不难看出,在成员方法名不同时,遵循着就近原则
2)成员方法名相同
我们对上一段代码做一些修改:
public class test1 {
public int num;
public void methodA(){
System.out.println("父类的中的methodA");
}
public void methodC(int num){
this.num=num;
System.out.println("父类中的methodC");
}
}
class son extends test1{
public void methodB(){
System.out.println("子类中的methodB");
}
public void methodA(){//与父类中的成员方法名相同
System.out.println("子类中的methodA");
}
public void methodC(){
System.out.println("子类中的methodC");//与父类中的成员方法名相同
}
}
class c{
public static void main(String[] args) {
son x = new son();
x.methodA();
x.methodB();
x.methodC();//子类中的是无参成员方法
x.methodC(10);//此处含有参数,所以调用的是父类
}
}
运行结果:
不出所料,在成员方法名相同时一样遵循了就近原则,但不同的是,当方法名相同而参数列表不同
时,子类的同名方法是不会把父类的方法取代的,如代码中的methodC和methodC(10)。
小总结:
-
通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中
-
找,找到 则访问,否则编译报错。
-
通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同 ( 重载 ) ,根据调用 方法适传递的参数选择合适的方法访问,如果没有则报错;
3.继承关系上的执行顺序
class person{
public String name;
public int age;
public person(String name,int age){
this.age=age;
this.name=name;
System.out.println("父类的构造方法执行");
}
{
System.out.println("父类实例代码块执行");
}
static{
System.out.println("父类静态执行");
}
//static {
//System.out.println("子类静态执行");
// }
}
class son1 extends person {
public son1(String name, int age) {
super(name, age);
System.out.println("子类的构造方法执行");
}
{
System.out.println("子类实例代码块执行");
}
static {
System.out.println("子类静态执行");
}
}
public class test2 {
public static void main(String[] args) {
son1 c = new son1("zhangsan",20);
person b = new person("xiaoming",15);
}
}
根据代码显而易见,父类永远大于子类,静态代码大于实例代码块大于构造代码块
结论:
- 父类静态代码块优先于子类静态代码块执行,且是最早执行。
- 父类实例代码块和父类构造方法紧接着执行。
-
子类的实例代码块和子类构造方法紧接着再执行
-
第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行
2.super关键字
产生原因:由于设计不好,或者因场景需要,子类和父类中可能会存在相同名称的成员,如果要在
子类方法中访问父类同名成 员时,该如何操作?直接访问是无法做到的,Java提供了super关键
字,该关键字主要作用:在子类方法中访问父 类的成员。
值得注意的是:super关键字只能在非静态方法中使用。
1)当父类含有无参构造方法的情况
class father{
public father(){//无参构造方法
System.out.println("无参的执行");
}
}
class son2 extends father{
public son2(){
System.out.println("子类的执行");
}
}
public class test3 {
public static void main(String[] args) {
son2 a = new son2();
}
}
结果:
子类构造方法中会默认调用父类的无参构造方法,用户没有写时,编译器会自动添加,而且super()
必须是子类构造方法中第一条语句, 并且只能出现一次。
2.super.成员/方法和super(成员)的作用
我们先用一段代码来稍微体会一下这两者的区别
class Baba{
public int age=10;
public String name="lihua";
public Baba(String name,int age){
this.age=age;
this.name=name;
}
public void fun(){
System.out.println("父类成员方法");
}
}
class erzi extends Baba{
//int age = 100;
public erzi(String name,int age){
super(name,age);//在子类中对父类的成员进行初始化
}
public void fun1(){
System.out.println("子类成员方法");
}
public void fun2(){
System.out.println("用super调用父类");
super.fun();
}
public void fun3(){
age=15;
name="zw";
super.age=10;
super.name="lihua";
System.out.println(name+age);
}
}
public class test4 {
//public static void
public static void main(String[] args) {
erzi a = new erzi("xiaoming",100);
System.out.println(a.age);
System.out.println(a.name);
a.fun1();
a.fun2();
a.fun3();
}
}
结果:
看过代码后不难知道,子类在继承父类之后,如果需要调用父类中的成员,就要利用super(成员
变量)来将父类的成员初始化,否则将报错。而super.成员/方法则是直接调用,调用时需要在子类
的方法中,而不能自己自成一条语句。
3.final关键字
4.多态
1.基础实现
1)条件:必须在继承体系下
子类必须要对父类中方法进行重写
通过父类的引用调用重写的方法
接下来拿狗和猫做一个具体实现:
public class Animal {
String name;
int age;
public Animal(String name,int age){
this.age=age;
this.name=name;
}
public void eat(){
System.out.println(name+"在吃");
}
}
class Dog extends Animal{
public Dog(String name,int age){
super(name,age);
}
public void eat(){
System.out.println(name+"在吃肉");
}
}
class Cat extends Animal{
public Cat(String name,int age){
super(name,age);
}
public void eat(){
System.out.println(name+"在吃🐟");
}
}
class test{
public static void eat(Animal a){
a.eat();
}
public static void main(String[] args) {
Cat m = new Cat("五月",3);
Dog g = new Dog("大黄",4);
m.eat();
g.eat();
eat(m);
eat(g);
}
}
输出结果:
2.重写与重载
3.向上转型和向下转型(重点)
1)向上转型的概念和写法
2)向上转型的两种方法
方法一:子类直接赋值给父类
方法二:方法传参:形参为父类型引用,可以接收任意子类的对象
public class person {
String name;
int age;
public person(String name,int age){
this.name=name;
this.age=age;
}
public void life(){
System.out.println(name+"生活了"+age+"年");
}
public void study(){
System.out.println(name+"上学");
}
}
class student1 extends person{
public student1(String name,int age){
super(name, age);
}
public void study(){
System.out.println(name+"读书");
}
}
class student2 extends person{
public student2(String name,int age){
super(name, age);
}
public void study(){
System.out.println(name+"写作业");
}
public void sport(){
System.out.println(name+"打球");
}
}
class test2{
public static void study(person a){//方法二:方法传参:形参为父类型引用,可以接收任意子类的对象
a.study();
}
public static void main(String[] args) {
person a = new student1("lihua",18);//方法一:子类直接赋值给父类
person b = new student2("xiaoming",17);
//student1 c = new student1("xiaohong",16);
a.study();
b.study();
student2 c = new student2("zhangsan",20);
c.sport();
}
}
上述代码体现了向上转型的两种方法,其中有个现象:向上转型后无法调用到子类特有的成员方法。
如b对象为向上转型,在输入b.时,提示栏没有student2特有的sport成员方法。
而c对象不为向上转型,在输入c.时,提示栏就出现了sport方法。
3)向下转型
本质:一个已经向上转型的子类对象,将父类引用转为子类引用。
特点:
- 要求父类的引用必须指向的是当前目标类型的对象
- 只能强制转换父类的引用,不能强制转换父类的对象
- 当向下转型后,可以调用子类类型中所有的成员
class test4{
public static void fun(father a){
a.fun();
}
public static void main(String[] args) {
father a = new son("lihua",12);
son b = (son) a;
a.fun();
b.fun2();
((son) a).fun2();
}
}
在没有向下转型之前a对象中无法引用fun2方法,而向下转型之后就可以了
4.多态数组
class test3{
public static void teach(teacher a){
a.teach();
}
public static void main(String[] args) {
teacher[] teacher1 = new teacher[4];
teacher1[0]=new teacher("lihua",25);//此处的数组名为前面定义的对象
teacher1[1]=new english("xm",26);
teacher1[2]=new math("xh",24);
teacher1[3]=new sport("xk",28);
for (int i=0;i<teacher1.length;i++){
teacher1[i].teach();
//teach(teacher1[i]);
}
}
}
多态数组:数组的定义类型为父类类型,里面保存的实际元素类型为子类类型。
代码示例:(循环调用基类对象,访问不同派生类的方法)
此次继承和多态的分享就到这了!谢谢观看!!
如有建议和意见欢迎的评论区交流!!!