- 接口
- 是一种数据类型(引用类型)
- 由interface定义
- 只能包含常量和抽象方法
- 接口中的属性都是常量,默认由public static final同时修饰,可以省略,abstract不能修饰变量
- 接口不能被实例化(new对象)
- 接口是需要被实现/继承的,实现/派生类,必须重写接口中的所有抽象方法(重写时必须加public关键字)
- 一个类可以实现多个接口,用逗号分隔,implements只用写一次, 若又继承又实现时,应先继承后实现
- eg:class A extend B implements C,D
- java类是单继承的。classB Extends classA
- java接口可以多继承。Interface1 Extends Interface2, Interface3, interface……
- 不允许类多重继承的主要原因是,如果A同时继承B和C,而B和C同时有一个E方法,A如何决定该继承哪一个呢?
- 但接口不存在这样的问题,接口全都是抽象方法继承谁都无所谓,所以接口可以继承多个接口。
- 接口可以继承接口,接口不能实现接口
- 接口的方法默认都是public abstract的,也只能是public 不写会默认
- 接口中不可以定义变量,只能定义常量,所以接口的属性默认是public static final 也只能是 ,不写会默认,返回值类型 常量,且必须赋值
- 注意final 和abstract 不能同时出现
不能用来修饰 interface 的有(A,C,D)
A.private
B.public
C.protected
D.static
//修饰接口可以是public和默认
- 设计规则
- 将所有派生类所有共有的属性和行为,抽到超类中-------------抽共性
- 派生类的行为都一样,设计普通方法
- 派生类的行为不一样,设计为抽象方法
- 将部分派生类所共有的属性和行为,抽到接口中
- 接口是对继承的单根性的扩展-------------------------实现多继承
- 多态
- 行为的多态:
- 同一类型的引用在指向不同的对象时,有不同的实现(所有抽象方法都是多态的):
- (比如人跑步类型:指向刘翔,刘翔110跑了12秒91,指向小翠,小翠跑了91秒21)
- 对象的多态 :
- 同一个对象被造型为不同的类型时,有不同的功能(所有对象都是多态的)
- (有两个接口,钱接口,命接口,一个父类人。定义一个persion数组,定义了两个对象:“Gambler” 和 “God”
- 他们继承了人接口,其中Gambler实现了钱接口,God实现了加命接口;
- 这个时候,当我们获取persion[i] 就可以 instanceof 两个接口
- 即:Gambler instanceof Cash ;God instanceof Life ;这样我们就可以 向上造型了,代码如下:
- 行为的多态:
//超类 Persion
public abstract class Persion {
}
//赚钱接口
public interface Cash {
public abstract void addCash();
}
//加命接口
public abstract interface Life {
public abstract void addLife();
}
//Gambler 继承人,实现赚钱钱接口
public class Gambler extends Persion implements Cash {
int cash;
@Override
public void addCash() {
cash+=100;
System.out.println("得分:"+cash);
}
}
//God 继承人,实现加命接口
public class God extends Persion implements Life{
int life;
@Override
public void addLife() {
this.life+=1;
System.out.println("得命:"+life);
}
}
public class Test {
//测试
public static void main(String[] args) {
Test test = new Test();
test.action();
}
//类型转换,同一个对象,被造型为不同得类型,有不同得实现功能
public void action(){
Persion[] persions= new Persion[2];
persions[0] = new God();
persions[1] = new Gambler();
for(int i=0;i<persions.length;i++){
if(persions[i] instanceof Life){
Life life = (Life)persions[i];
life.addLife(); //加命:1
}
if(persions[i] instanceof Cash){
Cash cash = (Cash)persions[i];
cash.addCash(); //赚钱:100
}
}
}
}
- 向上造型/自动类型转换
- 超类型的引用指向派生类的对象
- 能造型成为的数据类型:超类+所实现的接口
- 能点出来什么,看引用的类型
- 强制类型转换成功的条件
- 引用所指向的对象,就是该类型
- 引用所指向的对象,继承了该类或实现了该接口
- instanceof 是 Java 的一个二元操作符,它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 类型的数据。
- 强转时若不符合如上两个条件,则发生ClassCastException类型转换异常,建议在强转之前应先通过instanceof来判断引用指向的对象是否时该类型(强转若发生在循环里,有变量得,所以一定要判断)
public interface EnemyAward {
public static final int FIRE = 0;
public int LIFE = 1;
public abstract int getAwardType();
}
public interface EnemyScore {
int getScore();
}
//对象的多态:同一个对象被造型为不同的类型,有不同的功能
//强转,小转大,enemies[i] 对象 实现了该接口,父类型是FlyingObject
FlyingObject[] enemies = {};
....
for(int i=0;i<enemies.length;i++){
FlyingObject f = enemies[i];
if(f instanceof EnemyAward){
EnemyAward award = (EnemyAward)f;
int type = award.getAwardType();
}
if(f instanceof EnemyScore){
EnemyScore s = (EnemyScore)f;
score += s.getScore();
}
}
- 经典面试题,父类行的引用 赋值给 子类型的 变量上,需要强制类型转换 大转小
//已知如下代码,下列选项中哪个表达式会编译出错( )
interface IFace{}
class CFace implements IFace{}
class Base{}
public class ObRef extends Base{
public static void main(String argv[]){
ObRef ob = new ObRef();
Base b = new Base();
Object o1 = new Object();
IFace o2 = new CFace();
}
}
A.o1=o2;
B.b=ob;
C.ob=b; //b 是 ob 的父类,将父类引用赋值给子类型变量上需要强制类型转换
D.o1=b;
- 关于抽象方法的一些说明
- 抽象方法不可以是静态的
- 不可以有方法体
- 不可以在普通类中定义
- 可以在接口中和抽象类中定义
- 补充:java8 以后接口的新特性
- java8以前,接口只能被类实现,类不能继承接口,遵循单继承多实现原则
- java8以后,接口中可以包含静态方法和默认方法。
- 默认方法的作用:
- 格式:public default 返回值类型 方法名 (){}
- 接口升级,可以避免改变其他实现类
- 静态方法:照旧
- 格式:publis static 返回值 方法名(){}
- 接口中的静态方法和类中的静态方法一样,只能通过接口.静态方法名的方式调用
//定义接口
public interface EnemyAward {
public static final int FIRE = 0;
public int LIFE = 1;
public default int getDefaultTest() {
return 0;
}
public static BufferedImage addStaticTest(){
return null;
}
}
//类实现接口
public class FinalEx implements EnemyAward{
public static void main(String[] args) {
//new对象
FinalEx a = new FinalEx();
//通过对象去点默认方法
a.getDefaultTest();
//通过接口名.静态方法
EnemyAward.addStaticTest();
}
}
- 注意:
- Java中,成员变量是没有重写的,成员变量不可以被继承或覆盖,即不能实现多态。
- 只有方法才能构成多态。也就是说方法可以实现动态绑定,而变量用于是静态绑定。
- 即:静态绑定就是变量本身什么类型,就用哪个里面的。
(单选题)下面的程序输出结果是( )。
public class A implements B {
int k = 20;
public static void main(String args[]) {
int i;
B c1 = new A();
i = c1.k;
System.out.println("i=" + i);
}
}
interface B {
int k = 10;
}
//输出10,因为C1事B类型,所以调用B里的