Java学习总结之继承和多态

7Java学习总结之继承和多态

时间:2022年8月8日

1.继承

继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。

1.1语法格式

//父类
class A{
  //...
}
//子类继承父类使用extends
class B extends A{
  //...
}
  • 子类会将父类中的成员变量或者成员方法继承到子类中了
  • 子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了

1.2父类成员访问

1.2.1子类访问父类的成员变量时

在子类方法中 或者 通过子类对象访问成员时:

  • 如果访问的成员变量子类中有,优先访问自己的成员变量。
  • 如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
  • 如果访问的成员变量与父类中成员变量同名,则优先访问自己的。

成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找。

public class Base {
	int a;
	int b;
}
public class Derived extends Base{
	int c;
	public void method(){
		a = 10; // 访问从父类中继承下来的a	
		b = 20; // 访问从父类中继承下来的b
		c = 30; // 访问子类	自己的c
	}
}
1.2.2子类访问父类的成员方法
  • 通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,否则编译报错。

    class Base {
    	public void methodA(){	
    		System.out.println("Base中的methodA()");
    	}
    }
    public class Derived extends Base{
    	public void methodB(){
    		System.out.println("Derived中的methodB()方法");
    	}
    	public void methodC(){
    		methodB(); // 访问子类自己的methodB()
    		methodA(); // 访问父类继承的methodA()
    	}
    }
    
  • 通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,如果没有则报错;

class Base {
	public void methodA(int a){	
      System.out.println(a);
	}
}
public class Derived extends Base{
	public void methodA(int a,int b){
		System.out.println(a+b);
	}
	public void methodC(){
		methodA(1); // 访问父类的methodA()
		methodA(1,2); // 访问子类的methodA()
	}

1.3super关键字

super关键字,该关键字主要作用:在子类方法中访问父类的成员。

  • 只能在非静态方法中使用
  • 在子类方法中,访问父类的成员变量和方法。
class Base {
    int a = 1;
	public void methodA(int a){	
      System.out.println(a);
	}
}
public class Derived extends Base{
    int b = 2;
	public void methodA(int a,int b){
		System.out.println(a+b);
	}
	public void methodC(){
		methodA(super.a); // 访问父类的成员变量 访问父类的methodA()
		methodA(super.a,b); // 访问子类的methodA()
	}

1.4子类构造方法

子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法。

public class Base {
	public Base(){
	System.out.println("Base()");
	}
}
public class Derived extends Base{
	public Derived(){
		// super(); // 注意子类构造方法中默认会调用基类的无参构造方法:super(),
		// 用户没有写时,编译器会自动添加,而且super()必须是子类构造方法中第一条语句,
		// 并且只能出现一次
		System.out.println("Derived()");
	}
}
public class Test {
	public static void main(String[] args) {
	Derived d = new Derived();
	}
}

//执行结果
Base()
Derived()
  • 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构造方法
  • 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。
  • 在子类构造方法中,super(…)调用父类构造时,必须是子类构造函数中第一条语句。
  • super(…)只能在子类构造方法中出现一次,并且不能和this同时出现

1.5super和this的异同

相同点

  • 都是Java中的关键字
  • 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
  • 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在

不同点

  • this是当前对象的
  • 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性
  • 在构造方法中:this(…)用于调用本类构造方法,super(…)用于调用父类构造方法,两种调用不能同时在构造方法中出现
  • 构造方法中一定会存在super(…)的调用,用户没有写编译器也会增加,但是this(…)用户不写则没有

1.6继承方式

  • 单继承

    class A{
       
    }
    //单继承
    class B extends A{
    
    }
    
  • 多层继承

    class A{
       
    }
    
    class B extends A{
    
    }
    
    class C extends B{
    
    }
    //C类继承于B类,而B类继承于A类,这就是多层继承
    
  • 不同类继承同一个类

    class A{
       
    }
    
    class B extends A{
    
    }
    
    class C extends A{
    
    }
    //B类和C类都继承于A类ava不支持多继承
    
  • Java不支持多继承

1.7final关键字

final关键可以用来修饰变量、成员方法以及类。

  • 修饰变量或者字段,表示为常量,不能被修改

    final int a = 1;
    a = 2;
    //编译出错
    
  • 修饰类:表示此类不能被继承

    final class A{
       
    }
    
    class B extends A{
    
    }
    //编译出错
    
  • 修饰方法:表示该方法不能被重写

    class A{
    	public fianl int method(int a){
           return a++;
    	}   
    }
    
    class B extends A{
        @Override
        public fianl int method(int a){
           return a--;
    	}   
    }
    //编译报错
    

1.8继承与组合

继承表示对象之间是is-a的关系 组合表示对象之间是has-a的关系

1.8.1区别和联系
  • 在继承结构中,父类的内部细节对于子类是可见的。所以我们通常也可以说通过继承的代码复用是一种白盒式代码复用。(如果基类的实现发生改变,那么派生类的实现也将随之改变。这样就导致了子类行为的不可预知性;)

  • 组合是通过对现有的对象进行拼装(组合)产生新的、更复杂的功能。因为在对象之间,各自的内部细节是不可见的,所以我们也说这种方式的代码复用是黑盒式代码复用。(因为组合中一般都定义一个类型,所以在编译期根本不知道具体会调用哪个实现类的方法)

  • 继承,在写代码的时候就要指名具体继承哪个类,所以,在编译期就确定了关系。(从基类继承来的实现是无法在运行期动态改变的,因此降低了应用的灵活性。)

  • 组合,在写代码的时候可以采用面向接口编程。所以,类的组合关系一般在运行期确定。

1.8.2优缺点对比
组 合 关 系组 合 关 系
优点:不破坏封装,整体类与局部类之间松耦合,彼此相对独立缺点:破坏封装,子类与父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性
优点:具有较好的可扩展性缺点:支持扩展,但是往往以增加系统结构的复杂度为代价
优点:支持动态组合。在运行时,整体对象可以选择不同类型的局部对象缺点:不支持动态继承。在运行时,子类无法选择不同的父类
优点:整体类可以对局部类进行包装,封装局部类的接口,提供新的接口缺点:子类不能改变父类的接口
缺点:整体类不能自动获得和局部类同样的接口优点:子类能自动继承父类的接口
缺点:创建整体类的对象时,需要创建所有局部类的对象优点:创建子类的对象时,无须创建父类的对象

示例

class A{
   
}

class B extends A{

}
//继承
class A{
   
}

class B {

}
class c{
	private A a;   //可以复用A中的属性和方法
	private B b;   //可以复用B中的属性和方法
}
//组合

2.多态

具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态

2.1多态实现条件

  • 必须在继承体系下
  • 子类必须要对父类中方法进行重写
  • 通过父类的引用调用重写的方法

多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法

class A{
	public void method(){
		System.out.println("A类");
	}
}

class B extends A{
	@Override
	public void method(){
		System.out.println("B类");
	}
}
class C extends A{
	@Override
	public void method(){
		System.out.println("C类");
	}
}
public class D extends A{
	@Override
	public static void method(A a){
		a.method();
	}
	public static void main(String[] args) {
		C c = new C();
		B b = new B();
		eat(B);
		eat(C);
	}
	}
}
//执行结果
BC

2.2重写

重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。**即外壳不变,核心重写!**重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

class A{
	public void method(){
		System.out.println("A类");
	}
}

class B extends A{
    //重写父类的method方法
	@Override
	public void method(){
		System.out.println("B类");
	}
}

规则

  • 子类在重写父类的方法时,一般必须与父类方法原型一致: 返回值类型 方法名 (参数列表) 要完全一致
  • 被重写的方法返回值类型可以不同,但是必须是具有父子关系的
  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方
    法就不能声明为 protected
  • 父类被static、private修饰的方法、构造方法都不能被重写。
  • 重写的方法, 可以使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验. 例如不小心将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法构成重写

2.3向上转型和向下转型

2.3.1向上转型

向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。小范围向大范围的转换。
语法格式:父类类型 对象名 = new 子类类型()

class A{

}

class B extends A{

}
A b = new B(); //这里发生了向上转型
  • 向上转型的优点:让代码实现更简单灵活。
  • 向上转型的缺陷:不能调用到子类特有的方法
2.3.2向下转型

将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换。

class A{

}

class B extends A{
	public void method(){
		System.out.println("B类");
	}
}
A b = new B(); //这里发生了向上转型
b.method();  //错误
b = (B)b;//发生了向下转型
b.method();  //正确
//使用instanceof判断,提高安全性
if(b instanceof B){
	b = (B)b;//发生了向下转型
	b.method();  
}

2.4多态的优缺点

优点

  • 能够降低代码的 “圈复杂度”, 避免使用大量的 if - else
  • 可扩展能力更强

缺点

  • 代码的运行效率降低
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值