Skip to content

Latest commit

 

History

History
215 lines (178 loc) · 8.58 KB

Java基础06.md

File metadata and controls

215 lines (178 loc) · 8.58 KB
title tags grammar_cjkRuby
Java基础06
抽象类,接口,多态,构造方法
true

[TOC]

抽象类

当我们定义一个父类的时候,有些方法可能需要子类去做具体的功能,而在父类中并不能确定做哪些功能,那么我们就可以将这些方法定义成抽象方法.所谓的抽象方法就是没有方法体的方法.那么我们的类也必须定义 这个类为抽象的类.

抽象类的格式

  • 抽象方法和抽象类需要使用特定的修饰符进行修饰,这个修饰符就是 abstract 抽象类的格式为 public abstract class 类名 { }
  • 抽象方法的格式为 public abstract 返回值类型 方法名(参数);

抽象类特点

  1. 抽象类和抽象方法都需要被abstract修饰,抽象方法一定要定义在抽象类中.
  2. 抽象类也可以没有抽象方法,那么定义抽象类的意义在于不能 使用这个类创建对象.
  3. 普通类能做的事情,抽象类都可以做(定义成员变量,定义成员方法),唯独不能进行实例化.
  4. 子类继承抽象类,必须实现抽象方法,如果子类不实现抽象方法,那么子类必须是抽象类
  5. 子类重写父类的方法时,不能使用abstract关键字

抽象类注意的问题

  • 抽象类因为需要子类去实现,所以肯定得是一个父类
  • 抽象类可以不定义抽象方法,意义在于,不让该类创建对象,方法可以让子类使用
  • 一个方法如果没有方法体,则必须使用abstract进行修饰

abstract不能与那些关键字共存?

  1. private:私有的方法子类是无法继承的,也不能覆盖,而abstract和private一起使用修饰方法时,abstract既要去实现这个方法,而private修饰子类根本无法得到父类这个方法.互相矛盾.
  2. final: 因为被final定义的方法不能被重写,而抽象方法需要子类去重写进行实现功能,所以矛盾.
  3. static:因为static不用实例化可直接调用,即可直接能调用,而abstract需要子类实现后才能调用,所以矛盾.

接口

  1. 接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的.
  2. 接口中只允许出现抽象方法,不允许非抽象方法
  3. 接口的源文件也是java文件,编译后的文件也是**.class**,所以可以把接口看做是一个特殊的类.

接口的定义

  • 与定义类的class不同,接口定义时需要使用interface关键字
  • 定义的格式
public interface 接口名{
	抽象方法1;
	抽象方法2;
	抽象方法3;
}
  • 因为接口是供别的类去实现的,并且要实现他的抽象方法,所以接口中方法的修饰符必须定义成public
  • 接口中不能定义普通的成员变量,只能定义成public static final 成员变量

注意如果定义方法的时候,不写public abstract,不会报错,但是系统会默认添加;定义成员变量的时候使用public static final,如果不这样写,不会报错,但是系统会默认添加.

接口的实现

  • 一个实现类接口的格式为:
class 类名 implements 接口1,接口2{
	重写接口中方法
}
  • 一个类可以同时实现多个接口,但是需要将抽象方法进行实现,创建接口的时候修饰符可以省略,系统会自动加上,但是实现的时候,就必须添加public

接口的特点

  • 接口不能创建对象
  • 接口的变量使用public static final修饰,如果不写,默认添加
  • 子类必须重写接口中所有的抽象方法后,才能创建对象,如果子类不能够重写所有的抽象方法,那么子类必须定义成抽象类

接口可以多继承

因为接口中的方法都是没有实现的,所以就算有两个父类接口的方法名称相同,子类实现接口的时候也不会有什么影响,重写即可,所以接口与接口之间是存在多继承的.

interface MyInterface{
	void method1();
}
interface MyInterface2{
	void method2();
}
interface MyInterface3{
	void method3();
}
interface MyInterface4 extends MyInterface1,MyInterface2,MyInterface3{
	void method4();
}

接口的意义

  • 扩展原有类的功能
  • 设定了规则
  • 降低耦合性

接口和抽象类的区别

  • 相同点

    • 都位于继承的顶端,用于被其他类实现或继承;
    • 都不能直接实例化对象
    • 都包含抽象方法,其子类都必须复写这些抽象方法
  • 区别

    • 抽象类可以定义非抽象方法,避免子类重复实现这些方法,提高代码的复用率,接口只能包含抽象方法

多态

  • 多态的表现形式为父类的变量指向子类的对象
  • 多态的前提是必须有子类关系或者类实现接口关系,否则无法完成多态
  • 父类类型的变量调用方法的时候,实际上会调用子类重写的方法.

定义格式

  • 普通类多态定义的格式:父类 变量名 = new 子类();
class Father{ }
class Child extends Father{ }
//类的多态使用
Father f = new Child();
  • 抽象类多态定义的格式:抽象类 变量名 = new 抽象类子类();
abstract class Father{
	public abstrct void method();
}
class Child extends Father{
	public void method(){
		System.out.println("重写父类抽象方法");
	}
}
  • 接口多态定义的格式:接口 变量名 = new 接口实现类();
interface Facher {
	public abstract void method();
}
class Child implements Father {
	public void method(){
		System.out.println("重写接口抽象方法");
	}
}

// 接口的多态使用
Father f = new Child();

注意:同一个父类的方法会被不同的子类重写.在调用方法时,调用的是各个子类重写后的方法.

多态的特点

  • 对于成员方法: 编译的时候看=左边,运行的时候看=右边
  • 对于成员变量:编译的时候看=左边,运行的时候看=左边

多态的转型

  • 如果是多态的话,程序在进行编译的时候只会看变量的类型,而实际运行的时候则是看具体的对象,那么如果想要调用父类中没有,但是子类中有的方法该怎么办?
  • 可以使用强制类型转换,也叫做多态的向下转型,将父类类型再转换为子类类型 子类类型 变量 = (子类类型) 变量名称
  • 注意:如果强制类型转换的话,必须要保证变量的原始类型就是需要转换的类型,否则会抛出异常子类变量 变量名 = (转换类型) 变量名称

instanceof关键字

如果直接进行强制类型转换的时候可能出现问题,所以可以使用instanceof进行判断,如:对象 instanceof 类名

if(a instanceof Child){
	Child c = (Child)a;
}

构造方法

如果我们希望在创建对象的时候就能对对象的成员变量进行赋值,就需要创建构造函数,构造函数的目的就是在创建对象的时候给对象的成员变量进行赋值

构造方法的格式

修饰符 构造方法名(参数列表){
}

构造方法的特点

  • 构造方法名称必须和类型保持一致.
  • 构造方法没有具体的返回值.

默认构造方法

  • 如果我们没有定义构造方法,编译器会在编译的时候添加默认无参构造方法,这就是我们之前从未定义过构造方法,而能一致使用的原因.
  • 如果我们定义了新的构造方法,多个构造方法是以重载的形式存在的.
  • 构造方法是可以被private修饰的,作用:其他程序无法创建类该类的对象.

子类构造方法的调用

  • 子类创建对象的时候,会调用父类的构造方法,在子类构造方法中的第一行总有一个隐式的调用**super();**会默认取调用父类的无参构造方法.
public class TTTTTT {
	public static void main(String[] args) {
	new Zi();
	}
} 
class Fu{
	int a;
	Fu(){
	System.out.println("父类构造方法"+n
	um);
	a = 250;
	}
} 
class Zi extends Fu{
	Zi(){
		System.out.println("子类构造方法"+num);
	}
} 
//输出的结果是
//父类构造方法0
//子类构造方法250
  • 思考1

为什么子类的构造方法会去调用父类的构造方法呢?

因为构造方法本身就是初始化对象的成员变量的,父类的构造方法也是这个目的,如果不去调用,我们就不知道父类做了什么操作,所以才会隐式的去调用super();子类会继承父类中的内容,所以子类在初始化时,必须先到父类中去执行父类的初始化动作。这样,才可以使用父类中的内容。

  • 思考2

如果子类会默认调用父类的无参构造方法,如果父类中又没有无参的构造方法,程序会出现什么问题?编译器会自动去找到对应的有参的构造方法么?

如果父类中没有空参构造方法,那么子类的的构造方法就会报错,需要我们显示的调用父类的有参数的构造方法