JAVA基础06—接口与多态

一、接口

1.1 接口是什么

首先搬运一下菜鸟教程的解释,非常专业

接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。

接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。

除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。

接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。

我们可以尝试一下简单理解:

接口顾名思义是接入的口子,就像是硬件的各种接口一样,要遵循一定的规范,将程序接上去,达到数据贯通的效果,就像电流通过电源接口送进电气设备一样。

接口抽象,就好比硬件接口一样,有的接口长得很奇怪,是为了专门接入特定规格的设备而定,有的接口不可见,在设备内部,难以想象。这么类比,程序的接口是抽象类就好理解一些了吧。

接口不是类,就像是USB接口并不是U盘一样,但USB接口决定了接入的设备类型必须支持USB。

接口不能实例化,可以理解为硬件的接口并不直接参与器件工作。

1.2 接口的作用

明白了接口的定义之后,我们可以了解到,接口定义的是一种规范。

好比是USB接口,规范了某种接入方式:USB口多大,有多少根数据线等等。

接口里的方法是抽取了实现该接口的类的共性方法,实现该接口的类必须重写。

1.3 接口的定义与使用

1.3.1 创建接口:

public interface 接口名{
    //常量,因为接口定义的是一种规范,所以只能有常量,不能有变量
    public static final 常量类型 常量名 = 常量值;
    
    /**抽象方法*/
    public abstract 返回值类型 方法名();
    
    //因为接口是一种规范,能改动的地方不多,所以常量、抽象方法的关键字可以简写:
    //简写的常量:
    常量类型 常量名 = 常量值;
    
    /**简写的抽象方法*/
    返回值类型 方法名();
    
}

抽象方法: 由 abstract 修饰,没有方法体。

值得注意的是,jdk 1.8 之后,接口中也可以定义有方法体的方法了,称为默认方法,用default修饰。

1.3.2 实现接口:

public class 类名 implements 接口名1,接口名2... {
    /**
    *重写所有的抽象方法
    */
    ...
}

实现的接口可以是一个以上,所有抽象方法都要重写。这就是接口定义规范和抽取共性的体现。

1.4 接口的例子

定义一个接口:

/**
 * This class is used to learn interface
 * @author Sharry
 * */
public interface BasicAction {
	//常量
	int HP = 100;
	
	/**抽象方法,定义*/
    void eat();
}

实现类:

public class Human implements BasicAction {

	@Override
	public void eat() {
		// TODO Auto-generated method stub
		System.out.println("民以食为天");
	}

}

二、多态

多态是面向对象三大特性之一。初期怎么理解多态呢?可以顾名思义:多种状态。例如:怪兽可以有多种状态,可以是青眼白龙,也可以是黑魔法师;黑魔法师和青眼白龙都是怪兽,但是攻击力、属性、种族等都不同,这就是怪兽的多态。

多态的前提是发生了继承和重写。

2.1 多态的作用

既然多态是多种状态,那么多态的作用是提高了代码复用性、灵活性、可拓展性。

2.2 向上造型

/**父类Monster*/
public class Monster {

	//攻击力
	private int attackPower;
	//防守力
	private int defendPower;
	//星数
	private int starLevel;
    
    //效果
	private String funtion;
    
    //动作
    public String attack() {
    	return "Attacking!";
    }

    //构造方法
	public Monster(int attackPower, int defendPower, int starLevel, String funtion) {
		super();
		this.attackPower = attackPower;
		this.defendPower = defendPower;
		this.starLevel = starLevel;
		this.funtion = funtion;
	}

	public Monster() {
		//无参构造,此处的super调用的是父类Object 的方法。万物皆对象!
		super();
	}

	public int getAttackPower() {
		return attackPower;
	}

	public void setAttackPower(int attackPower) {
		this.attackPower = attackPower;
	}

	public int getDefendPower() {
		return defendPower;
	}

	public void setDefendPower(int defendPower) {
		this.defendPower = defendPower;
	}

	public int getStarLevel() {
		return starLevel;
	}

	public void setStarLevel(int starLevel) {
		this.starLevel = starLevel;
	}

	public String getFuntion() {
		return funtion;
	}

	public void setFuntion(String funtion) {
		this.funtion = funtion;

	}
}
/**子类青眼白龙继承怪兽*/
public class BlueEyesWhiteDragon extends Monster {
	//青眼白龙的名字是固定的,不能修改的,因此被final修饰。final也可以与static连用
		private static final String name = "BlueEyeWhiteDragon";
		
		//super关键字,调用父类方法
		public void testSuper() {
			super.attack();
		}
		
		//方法的重载
		public void testSuper(int j) {
			System.out.println(j);
		}
		
		//这是方法的重写,用@Override注解标注
		@Override
		public String attack() {
			return "毁灭的爆裂疾风弹";
			
		}
		
		
}

//测试类中的向上造型
/多态的体现	
//向上造型:父类指向子类。怪兽可以是青眼白龙。
		Monster b1 = new BlueEyesWhiteDragon();
		System.out.println(b1.attack());
		

2.3 向下转型

//向下转型,青眼白龙也是怪兽,但要注意类型强转以及instanceOf
		//BlueEyesWhiteDragon b2 = (BlueEyesWhiteDragon) new Monster(); 此句会报异常
		if(b1 instanceof Monster){
			b1 = new Monster();
			System.out.println(b1.attack());
		}else {
			System.out.println("你的青眼白龙继承错啦");
		}

向下转型通常与向上造型一起使用。转型的时候有时还要考虑线程的问题,还需要instance of 作if判断,或者双重if null 判断。这里作为知识的拓展项-放在支线任务慢慢学习、巩固、完成。

三、抽象类

3.1 抽象类是什么

当一个类有抽象方法的时候,该类必须被声明为抽象类,因此抽象类必须被子类继承并重写才能让定义的抽象方法有意义。

声明关键字: abstract

3.1.1 抽象类与接口的区别:(搬运自百度百科)

(1)抽象类要被子类继承,extends;接口的实现类是实现,implements。

(2)接口只能做方法声明,抽象类中可以作方法声明,也可以做方法实现。

(3)接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。

(4)接口是设计的结果,抽象类是重构的结果。

(5)抽象类和接口都是用来抽象具体对象的,但是接口的抽象级别最高。

(6)抽象类可以有具体的方法和属性,接口只能有抽象方法和不可变常量。

(7)抽象类主要用来抽象类别,接口主要用来抽象功能。

3.1.2 抽象类的特点

(1)抽象类不能被直接实例化

(2)子类只能继承一个抽象类,必须重写抽象类的抽象方法

(3)抽象类可以没有抽象方法

3.2 抽象类的作用

抽象类其实也是对子类共性方法的抽取,同样有增加代码复用性、灵活性的作用。

抽象类更偏向于将子类共有,但实现不同的方法的向上一层抽取。

3.3 抽象类的定义与使用

/**定义一个简单的小抽象类demo*/
abstract class AbstractClass {

	abstract void eat();

}

子类继承,并重写方法:

public class AbstractSonClass extends AbstractClass {

	@Override
	void eat() {
		// TODO Auto-generated method stub
		System.out.println("eating");
	}

	public static void main(String[] args) {
		AbstractSonClass abstractSonClass = new AbstractSonClass();
		abstractSonClass.eat();
	}

}

3.4 重写、重构

这里是对重写、重构概念的一个补充延申。

重写方法同名,但方法的实现或权限、返回值类型等可以不同。

重构也属于重写,即重写的一种方式,但重构更侧重于方法的实现不同,其余都相同。

因此,虽然子类对抽象方法的实现都可称作重写,但其实更注重方法的重构。

关于覆盖、重写、重构、重载的具体区别,作为支线任务学习。

四、内部类

内部类就是在类里再声明类、使用该类的对象

4.1 静态内部类

在一个类里声明一个static 修饰的内部类

/**
*@Author Sharry
*@Version V1.0
*Description:内部类的学习
*/
public class InnerClass {

	//Attributes and methods
	private static int hp = 100;
	
	public void attack() {
		System.out.println("Attacking");
	}
	
	//静态内部类
	static class StaticInnerClass {
		//Attributes
		private int age;
		
		public void eat() {
		   //静态内部类不能直接调用外部类的方法、属性,除非同为static 修饰的类属性、方法
			System.out.println(InnerClass.hp);
		   System.out.println("eating");	
		}
		
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        //实例化静态内部类:通过类名点出来
		InnerClass.StaticInnerClass innerClass = new InnerClass.StaticInnerClass();
		innerClass.eat();
	}

}

通过这个例子我们可以巩固一下static 关键字修饰的方法、类,一般情况下只能调用同为 static 修饰的方法、属性。

另外,由于该类是被static 修饰,可以用外部类名.静态内部类名 创建实例。

4.2 非静态的内部类

类里声明另一个类

public class InnerClass {

	//Attributes and methods
	private static int hp = 100;
	
	public void attack() {
		System.out.println("Attacking");
	}
	
	//静态内部类
	static class StaticInnerClass {
		//Attributes
		private int age;
		
		public void eat() {
		   //静态内部类不能直接调用外部类的方法、属性,除非同为static 修饰的类属性、方法
			System.out.println(InnerClass.hp);
		   System.out.println("eating");	
		}
		
	}
	
	//普通内部类
	class NormalInnerClass {
		
		//Attributes
		private String name;
		
		public void run() {
			System.out.println("running");
		}
		
		
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        //实例化静态内部类:通过类名点出来
		InnerClass.StaticInnerClass staticInnerClass = new InnerClass.StaticInnerClass();
		staticInnerClass.eat();
		
		//实例化内部类
		//1.实例化外部类
		InnerClass innerClass = new InnerClass();
		//2.通过外部类对象点出来
		NormalInnerClass normalInnerClass = innerClass.new NormalInnerClass();
	}

}

非静态内部类 需要通过外部类先创建对象,再通过对象. new类名 创建对象出来

4.3 匿名内部类

声明一个类的同时,现场实例化它,并且没有命名,简洁地直接使用。

匿名内部类常用于接口和抽象方法的快速子类创建。

/**
*@Author Sharry
*@Time 2021年12月3日 下午12:20:11
*@Version V1.0
*Description:
*/
abstract class AbstractNoNameClass {

	//attributes and methods
    int age ;
    
    public void programming() {
    	System.out.println("programming");
    }
    
	abstract void sleeping();
	

	public static void main(String[] args) {
		// TODO Auto-generated method stub
        //当场创建并使用
		AbstractNoNameClass a = new AbstractNoNameClass() {
			
			@Override
			void sleeping() {
				// TODO Auto-generated method stub
				System.out.println("sleeping");
			}
		};
		a.sleeping();
		
	}

}

注意匿名内部类的格式,创建类的同时,加上一个重写抽象方法的代码块,放在结束符;之前。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值