文章目录
一、接口
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();
}
}
注意匿名内部类的格式,创建类的同时,加上一个重写抽象方法的代码块,放在结束符;之前。