一.接口
1.接口的概念
- 接口就是多个类的公共规范
2.接口的定义 (暂且先理解为接口中的方法,都是抽象方法)
public interface MyInterface {//创建了一个接口
//备注:换成了关键字interface之后,编译生成的字节码文件仍然是: .java -> .class
public abstract void methodAbs1();//这是一个抽象方法
public abstract void methodAbs2(int x,int y);//这是一个抽象方法
}
public abstract 返回值类型 方法名称(参数);//抽象方法无大括号
注意:
1.接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract
2.这两个关键字修饰符,可以选择性的省略。(今天新学,不推荐)
3.方法的三要素可以随意定义
接口存在的意义:降低耦合度,因为接口中定义的都是抽象方法,相当于只有方法的定义,没有方法的实现,等着类去实现,体现出方法的定义和实现做分离。3.接口的实现
- 接口不能实例化对象(不能直接new),必须有一个"实现类"来实现该接口。
(类与接口之间的关系,叫做实现关系 implements)
格式:
public class 实现类名称 implements 接口名称{
//...
}- 接口的实现类重写接口中所有的抽象方法,这个类就是一个普通的类,可以实例化对象。
注意:如果实现类没有重写接口中所有的抽象方法,那么这个实现类继承来的抽象方法,实现类就是一个抽象类,不可实例化对象。
- 创建实现类的对象,进行使用
public class Demo01Interface {//主程序
public static void main(String[] args) {
// MyInterface inter = new MyInterface();//报错,不能直接new对象使用
MyInterfaceImpl impl = new MyInterfaceImpl(); //创建实现类的对象使用
impl.methodAbs1();
impl.methodAbs2();
}
}
public class MyInterfaceImpl implements MyInterface{//普通类实现接口
//覆盖重写接口中所有的抽象方法
@Override
public void methodAbs1() {
System.out.println("重写了第一个方法:");
}
@Override
public void methodAbs2(int x ,int y) {
System.out.println("重写了第二个方法:");
}
}4.接口中定义成员变量
- 接口中定义"成员变量"但是必须使用public static final三个关键字进行修饰 从效果上看,这其实就是接口中的【常量】
public interface MyInterfaceConst {
//公开的 静态的 不可变
public static final int NUM_OF_MY_CLASS = 10;//这就是一个常量,一旦赋值不可以修改,永远都是10.
} - 注意事项:
- 一旦使用final关键字,说明不可改变
- 接口中的常量,可以省略public static final,不写也是这样
- 接口当中的常量,必须进行赋值,不能不赋值。
- 接口中常量的名称,使用完全大写的字母,用下划线进行分割。
- 可用类名.调用(静态的)
public class Demo05Interface {
public static void main(String[] args) {
//访问接口当中的常量
int x = MyInterfaceConst.NUM_OF_MY_CLASS;
}
} 5.接口中定义抽象方法
- 默认使用 public abstract 修饰,可以省略,但是子接口一定要写public,因为父接口为public。
6.接口中定义构造方法
7.接口中定义默认方法
格式:
public default 返回值类型 方法名称(参数列表){
//方法体
}- 备注:接口当中的默认方法,可以解决接口升级的问题。
2.接口的默认方法,也可以被接口实现类进行覆盖重写
public class Demo02Interface {//主方法
public static void main(String[] args) {
MyInterfaceDefaultA a = new MyInterfaceDefaultA(); //创建了实现类A对象
a.methodAbs();//调用抽象方法,new的是实现类A,实际运行的是实现类A的方法
a.methodDefault(); //这是新添加的默认方法!。实现类A中没有覆盖重写methodDefault();调用默认方法,如果实现类没有,会向上找接口
System.out.println("====================");
MyInterfaceDefaultB b = new MyInterfaceDefaultB();
b.methodAbs();//调用抽象方法,new的是实现类B,实际运行的是实现类B的方法
b.methodDefault();//实现类B中覆盖重写了接口的默认方法。实现类B中覆盖重写了methodDefault();
}
}
public interface MyInterfaceDefault {//这是一个接口
public abstract void methodAbs();//这是一个抽象方法
// public abstract void methodAbs2();//这是新添加的抽象方法,避免实现类A,B都重写 ==> 新添加的方法,改成默认方法
public default void methodDefault(){//接口中定义默认方法,实现类中不用重写了。default不能省略
System.out.println("这是新添加的默认方法!");
}
}
public class MyInterfaceDefaultA implements MyInterfaceDefault {//这是实现类A-实现-接口
@Override
public void methodAbs() {
System.out.println("实现了抽象方法!AAA");
}
//实现类A中没有覆盖重写public default void methodDefault
}
public class MyInterfaceDefaultB implements MyInterfaceDefault {//这是实现类B-实现-接口
@Override
public void methodAbs() {
System.out.println("实现了抽象方法!BBB");
}
@Override
public void methodDefault(){//实现类B中覆盖重写了public default void methodDefault
System.out.println("实现类B中覆盖重写了接口的默认方法");
}
}8.接口中定义静态方法
格式:
public static 返回值类型 方法名称(){
//方法体
}注:1.就是将abstract 或者 default 换成static即可
2.不能通过接口中的实现类对象来调用接口中的静态方法
3.通过接口名称,直接调用其中的静态方法。只能通过 接口名称.静态方法名(参数);
public class Demo03Interface {
public static void main(String[] args) {
//MyInterfaceStaticImpl impl = new MyInterfaceStaticImpl(); //创建了实现类对象
//impl.methodStatic(); 错误写法
MyInterfaceStatic.methodStatic();//正确调用 接口名称.静态方法名(参数);
}
}
public interface MyInterfaceStatic {//这是一个接口
public static void methodStatic(){
System.out.println("这是接口的静态方法!");
}
}
public class MyInterfaceStaticImpl implements MyInterfaceStatic {//这是一个实现类
}9.接口中定义私有方法
- 问题描述:
但是这个共有方法,不应该让实现类使用,应该是私有化的。methodCommon应单独让1,2使用
- 解决方案:接口中定义私有方法:
- 普通私有方法:解决多个默认方法之间重复代码问题。
格式:
private 返回值类型 方法名称(参数){
//方法体
} 2.静态私有方法:解决多个静态方法之间重复代码问题。 格式:
private static 返回值类型 方法名称(参数){
//方法体
}public class MyInterfacePrivateAImpl implements MyInterfacePrivateA {实现类A -实现- 接口A
public void methodAnother(){
//methodCommon();//实现类中,不能访问到了接口中的私有方法,这样是错误的。专门为了Default1和Default2来存在的
//methodCommon();一经private修饰,程序报错
}
}
public interface MyInterfacePrivateA {//接口A中含有默认方法1和默认方法2,两者中含有重复代码
public default void methodDefault1(){
System.out.println("这是一个默认方法1!");
methodCommon();
}
public default void methodDefault2(){
System.out.println("这是一个默认方法2!");
methodCommon();
}
private void methodCommon(){//解决重复代码问题,只有本接口中才能访问
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
}
============================================================================================
public class Demo04Interface {
public static void main(String[] args) {
MyInterfacePrivateB.methodStatic1();//静态方法1只能通过类名.调用
MyInterfacePrivateB.methodStatic2();//静态方法2只能通过类名.调用
// MyInterfacePrivateB.methodStaticCommon();错误写法,methodStaticCommon()人家是私有的
}
}
public interface MyInterfacePrivateB {//接口B中含有静态方法1和静态方法2,两者中含有重复代码
public static void methodStatic1(){
System.out.println("这是一个静态方法1!");
methodStaticCommon();
}
public static void methodStatic2(){
System.out.println("这是一个静态方法2!");
methodStaticCommon();
}
private static void methodStaticCommon(){//静态私有方法,只有本接口中静态方法1和静态方法2才能访问
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
}10.接口小结
1.成员变量其实是常量,格式:
[public] [static] [final] 数据类型 常量名称 = 数据值;
注意:常量必须进行赋值,而且一旦赋值不能改变。
常量名称完全大写,用下划线进行分割。
2.接口中最重要的就是抽象方法,格式:
[public] [abstract] 返回值类型 方法名称(参数);//无方法体
注意:实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类。
3.接口里允许定义默认方法,格式:
[public] default 返回值类型 方法名称(参数){ 方法体 }
注意:默认方法也可以被覆盖重写
4.接口里允许定义静态方法,格式:
[public] static 返回值类型 方法名称(参数){ 方法体 }
注意:应该通过接口名称进行调用,不能通过实现类对象调用接口静态方法
5.接口里允许定义私有方法,格式:
普通私有方法:private 返回值类型 方法名称(参数) {}
静态私有方法:static private 返回值类型 方法名称(参数) {}
注意:private的方法只有接口自己才能调用,不能被实现类或别人使用11.继承父类并实现多个接口
使用接口注意事项:
1.接口是没有静态代码块或者构造方法的
2.一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
格式:
public class MyInterfaceImpl implements MyInterfaceA , MyInterfaceB {
//覆盖重写所有抽象方法
}
3.如果实现类所实现的多个接口当中,存在重复的抽象方法,只需要重写重写一次即可。
4.如果实现类没有重写所有接口中的所有抽象方法,那么实现类就必须是一个抽象类。
5.如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行重写。
6.一个类如果直接父类当中的方法和接口当中的默认方法,产生了冲突,优先用父类当中的方法
public interface MyInterfaceA {//接口A
//1.static{} 错误写法,接口不能有静态代码块
//public MyInterface(){} 错误写法,接口不能有构造方法
public abstract void methodA();//A中抽象方法
public abstract void methodAbs();//A、B中都有抽象方法
public default void methodDefault(){
System.out.println("默认方法AAA");
}
}
public interface MyInterfaceB {//接口B
//static{} 错误写法,接口不能有静态代码块
//public MyInterface(){} 错误写法,接口不能有构造方法
public abstract void methodB();//B中抽象方法
public abstract void methodAbs();//A、B中都有抽象方法
public default void methodDefault(){
System.out.println("默认方法BBB");
}
}
public class MyInterfaceImpl /*extends Object*/ implements MyInterfaceA,MyInterfaceB { //2.实现类 -> 接口A,B
@Override
public void methodA() {
System.out.println("重写了A方法");
}
@Override
public void methodAbs() {//3.A、B接口都有的抽象方法,重写一次即可
System.out.println("重写了A、B接口都有的抽象方法");
}
@Override
public void methodB() {
System.out.println("重写了B方法");
}
@Override
public void methodDefault(){//接口A,B存在重复的默认方法,那么实现类一定要对冲突的默认方法进行重写。
System.out.println("对多个接口当中冲突的默认方法进行了重写");
}
}
==============================================================
public abstract class MyInterfaceAbstract implements MyInterfaceA , MyInterfaceB {//4.实现类没有重写所有接口中的所有抽象方法,那么实现类就必须是一个抽象类
@Override
public void methodA() {
}
@Override
public void methodB() {
}
}
===============================================================
public class Demo01Interface {//6.父类方法与接口方法重名,优先父类的方法
public static void main(String[] args) {
Zi zi = new Zi();
zi.method();
}
}
public class Fu {
public void method(){
System.out.println("父类的方法");
}
}
public class Zi extends Fu implements MyInterface{
}
public interface MyInterface {
public default void method(){
System.out.println("接口当中的默认方法");
}
}12.接口之间的多继承
- 类与接口之间的关系
- 类与类之间是单继承的,直接父类只有一个。
- 类与接口之间是多实现的,一个类可以实现多个接口。
- 接口与接口之间是多继承的
- 注意事项:
- 多个父接口当中的抽象方法如果重复,没关系。(子接口想要运行也必须定义抽象类)
- 多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的重写,而且要带着default关键字。
public interface MyInterfaceA {//接口A
public abstract void methodA();//A中特有抽象方法
public abstract void methodCommon();//A、B接口中都有重名的抽象方法
public default void methodDefault(){//父A、父B接口中都有重名的默认方法,
System.out.println("AAA");
}
}
public interface MyInterfaceB {//接口B
public abstract void methodB();//B中特有抽象方法
public abstract void methodCommon();//A、B接口中都有重名的抽象方法
public default void methodDefault(){//父A、父B接口中都有重名的默认方法
System.out.println("BBB");
}
}
public interface MyInterface extends MyInterfaceA,MyInterfaceB {//子接口MyInterface 继承了父接口A和父接口B
public abstract void method();
/* 这个子接口当中有几个方法?
* 4个
* methodA 来源于接口A
* methodB 来源于接口B
* methodCommon 同时来源于A和B
* method来源于自己
*/
@Override
public default void methodDefault() {//父A、父B接口中默认方法重复,那么子接口必须进行默认方法的重写
}
}
public class MyInterfaceImpl implements MyInterface {//实现类 -实现- 接口MyInterface,四个方法
@Override
public void method() {
}
@Override
public void methodA() {
}
@Override
public void methodB() {
}
@Override
public void methodCommon() {
}
}- 笔记本电脑案例
案例分析:进行描述笔记本类,实现笔记本使用USB鼠标、USB键盘
*USB接口,包含打开设备功能、关闭设备功能
*笔记本类,包含开机功能、关机功能、使用USB设备功能
*鼠标类,要实现USB接口,并具备点击的方法
*键盘类,要实现USB接口,具备敲击的方法
public class DemoMain {
public static void main(String[] args) {
Computer c = new Computer();
c.powerOn();//开机
//准备一个鼠标,创建鼠标实现类
//使用多态写法,向上转型
USB usbMouse = new Mouse();//左父右子,左接口右实现类
c.useDevice(usbMouse);//参数是USB类型,编译看左,运行看右,把鼠标传进去了
========================================================
//准备一个键盘,创建键盘实现类
//不使用多态写法
Keyboard keyboard = new Keyboard();
c.useDevice(keyboard);
/*c.useDevice(new Keyboard());匿名对象也是可以的*/
c.powerOff();//关机
}
}
public interface USB {//定义一个接口
public abstract void open();//打开设备,抽象方法
public abstract void close();//关闭设备,抽象方法
}
public class Computer {//定义一个笔记本类
public void powerOn(){
System.out.println("笔记本开机");
}
public void powerOff(){
System.out.println("笔记本关机");
}
public void useDevice(USB usb ){ //使用USB设备的方法,使用接口作为方法的参数,传进来时,已经向上转型
usb.open();//打开设备
//要想使用鼠标、键盘实现类特有方法,必须向下转型
if(usb instanceof Mouse){
Mouse mouse = (Mouse)usb;//向下转型成鼠标
mouse.click();
}
if (usb instanceof Keyboard){
Keyboard keyboard = (Keyboard)usb;//向下转型成键盘
keyboard.type();
}
usb.close();//关闭设备
}
}
public class Mouse implements USB {//鼠标实现类 -实现- USB接口
@Override
public void open() {
System.out.println("打开鼠标");
}
@Override
public void close() {
System.out.println("关闭鼠标");
}
public void click(){
System.out.println("鼠标点击");
}
}
public class Keyboard implements USB {//键盘实现类 -实现- USB接口
@Override
public void open() {
System.out.println("打开键盘");
}
@Override
public void close() {
System.out.println("关闭键盘");
}
public void type(){
System.out.println("键盘输入");
}
}二.四种权限修饰符
* Java中有四种权限修饰符
* public > protected > (default) > private
* 同一个类(我自己) √ √ √ √
* 同一个包(我邻居) √ √ √ ×
* 不同包,继承(我儿子) √ √ × ×
* 不同包,非继承(陌生人) √ × × ×
* 注意:
* (default) 关键字是根本不写三.内部类
- 定义: 如果一个事物包含另一个事物,这也就是一个类内部包含另一个类 例如:身体和心脏的关系、汽车和发动机的关系
1.成员内部类
格式:
修饰符 class 外部类名称{
修饰符 class 内部类名称{ }
}- 注意:内用外,随意访问 ; 外用内,需要内部类对象
- 如何使用成员内部类?
- 间接方式: 在外部类的方法当中,使用内部类 ; 然后main只是调用外部类的方法
- 直接方式:
创建内部类对象:外部类名称.成员内部类 对象名 = new 外部类名称().new 内部类名称();
public class Demo01InnerClass {
public static void main(String[] args) {
//1.间接方式 通过外部类的对象调用外部类的方法,里面间接使用内部类Heart
Body body = new Body();//外部类的对象
body.methodBody();//调用外部类的方法
System.out.println("======================================================");
//2.直接方式 外部类名称.成员内部类 对象名 = new 外部类名称().new 内部类名称
Body.Heart heart = new Body().new Heart();
heart.beat();
}
}
public class Body {//外部类
public class Heart{//成员内部类
public void beat(){//内部类的方法
System.out.println("心脏跳动,蹦蹦蹦!");
System.out.println("我叫: " + name);//正确写法
}
}
private String name; //外部类的成员变量
public void methodBody(){//外部类的方法
System.out.println("外部类的方法!");
//间接使用成员内部类,在外部类方法当中创建对象
Heart heart = new Heart();
heart.beat();
/*new Heart().beat();也可*/
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
} 2.局部内部类 (包含匿名内部类)
- 定义:
"局部" :只有当前所属的方法才能使用它,出了这个方法外面就不能用了。
格式:
修饰符 class 外部类名称{
修饰符 返回值类型 外部类方法名称(参数){
class 局部内部类名称{
}
}
}public class DemoMain {
public static void main(String[] args) {
Outer obj = new Outer();
obj.methodOuter();
}
}
public class Outer {
public void methodOuter(){//外部类方法
class Inner {//局部内部类,只能在外部类方法访问
int num = 10;
public void methodInner() {//局部内部类方法
System.out.println(num);//10
}
}
Inner inner = new Inner();//用局部内部类创建了一个对象
inner.methodInner();//调用局部内部类对象的成员方法
}
}3.内部类的同名变量访问
- 如果发生了重名:
- 内部类的局部变量 - 直接就近原则调用
- 内部类的成员变量 - this.内部类成员变量名
- 外部类的成员变量 - 外部类名称.this.外部类成员变量名
public class Demo02InnerClass {
public static void main(String[] args) {
Outer.Inner obj = new Outer().new Inner();//创建内部类对象
obj.methodInner();//内部类方法
}
}
public class Outer {//外部类
int num = 10;//外部类的成员变量
public class Inner{//内部类
int num = 20;//内部类的成员变量
public void methodInner(){//内部类的方法
int num = 30;//内部类方法的局部变量
System.out.println(num);//局部变量30
System.out.println(this.num);//内部类的成员变量20
System.out.println(Outer.this.num);//外部类的成员变量10
}
}
}4.注意事项
权限修饰符
public > protected > (default) > private
类的权限修饰符规则:
1.外部类:public / (default)
2.成员内部类:public / protected / (default) / private
3.局部内部类:么都不能写5.局部内部类的final问题
- 如果需要访问局部内部类所在方法的局部变量,那么这个局部变量必须是【有效final的】
- 所在方法的局部变量,必须用final关键字修饰,可省略,不可改变
- 原因(生命周期问题):
- new出来的对象在堆内存中。
- 局部变量跟着方法走,在栈内存中。
- 方法运行结束之后,立刻出栈,局部变量就会消失。
- 但是new出来的对象会在堆当中持续存在,直到垃圾回收消失。
public class MyOuter {//外部类
public void methodOuter(){//成员方法
final int num = 10;//所在方法的局部变量,必须用final关键字修饰,可省略,不可改变
class MyInner {//局部内部类
public void methodInner(){//实例化的对象时间更长,必须保证num静态的不变的
System.out.println(num);
}
}
}
}
6.匿名内部类
- 定义: 如果接口的实现类(或者父类的子类),只需要使用唯一的一次 可以省略该类的定义,而改为使用【匿名内部类】
格式:
--直接new接口补上一个大括号重写
接口名称 对象名 = new 接口名称(){
//覆盖重写接口中所有抽象方法 大括号相当于作为实现类存在
};- 注意事项:
- 匿名内部类,在创建对象时,只能使用一次
- 匿名对象,在调用方法的时候,只能调用唯一一次,如果希望同一个对象,调用多次方法,那么必须给对象起个名字
- 匿名内部类是省略了实现类或子类,但是匿名对象是省略了对象名称。
public class DemoMain {
public static void main(String[] args) {
/* MyInterfaceImpl impl = new MyInterfaceImpl();//定义一个接口实现类对象
impl.method(); */
/* MyInterface obj = new MyInterfaceImpl();//左父右子,左接口右实现类 多态方式
obj.method();*/
//1.使用了匿名内部类,省略了对象名称
new MyInterface() {//大括号相当于作为实现类存在
@Override
public void method1() {
System.out.println("实现类覆盖重写了方法!111");
}
@Override
public void method2() {
System.out.println("实现类覆盖重写了方法!222");
}
}.method1();
//因为匿名对象无法调用第二次方法,所以需要再创建一个匿名内部类的匿名对象。
//2.使用匿名内部类,多态写法,左接口右实现类
MyInterface objA = new MyInterface() {//大括号相当于作为实现类存在
@Override
public void method1() {
System.out.println("实现类覆盖重写了方法!111");
}
@Override
public void method2() {
System.out.println("实现类覆盖重写了方法!222");
}
};
objA.method1();
objA.method2();
}
}
public interface MyInterface {//接口
public abstract void method1();//抽象方法
public abstract void method2();//抽象方法
}
public class MyInterfaceImpl implements MyInterface {//接口实现类
@Override
public void method1() {
System.out.println("实现类覆盖重写了方法!111");
}
@Override
public void method2() {
System.out.println("实现类覆盖重写了方法!222");
}
}四.类作为成员变量的类型
String是一个类
public class DemoMain {
public static void main(String[] args) {
//创建一个英雄角色
Hero hero = new Hero();
//为英雄起一个名字,并且设置年龄
hero.setName("盖伦");
hero.setAge(20);
//创建一个武器对象
Weapon weapon = new Weapon("多兰剑" );
//为英雄配武器
hero.setWeapon(weapon);
hero.attack();//年龄为: 20的盖伦正在用多兰剑攻击水晶
}
}
public class Hero {/*英雄角色类*/
private String name;//英雄名字
private int age;//英雄年龄
private Weapon weapon;//英雄武器类 作为成员变量
public Hero() {//英雄的无参构造
}
public Hero(String name, int age, Weapon weapon) {//英雄的全参构造
this.name = name;
this.age = age;
this.weapon = weapon;
}
public void attack(){//成员方法
System.out.println("年龄为: "+ age +"的"+name+"正在用"+weapon.getCode()+"攻击水晶");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Weapon getWeapon() {
return weapon;
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
}
public class Weapon {//武器类
private String code;//武器代号
public Weapon() {//无参构造
}
public Weapon(String code) {//全参构造
this.code = code;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}五.接口作为成员变量类型
public class DemoGame {
public static void main(String[] args) {
Hero hero = new Hero();
hero.setName("艾希");//设置英雄的名称
//设置英雄技能
//使用单独定义的实现类*/
/* hero.setSkill(new SkillImpl());
//还可以使用匿名内部类
/* Skill skill = new Skill() {
@Override
public void use() {
System.out.println("pia!pia!pia!");
}
};
hero.setSkill(skill);*/
//进一步简化,同时使用匿名内部类和匿名对象
hero.setSkill(new Skill() {
@Override
public void use() {
System.out.println("晕");
}
};
hero.attack();
}
}
public class Hero {
private String name;//英雄的名称
private Skill skill;//英雄的技能
public Hero() {//无参构造
}
public Hero(String name, Skill skill) {//全参构造
this.name = name;
this.skill = skill;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Skill getSkill() {
return skill;
}
public void setSkill(Skill skill) {
this.skill = skill;
}
public void attack(){
System.out.println("我叫"+name+",开始释放技能:");
skill.use();
System.out.println("释放技能完成。");
}
}
public interface Skill {//接口
public abstract void use();//释放技能的抽象方法
}
public class SkillImpl implements Skill{//技能接口实现类
@Override
public void use() {
System.out.println("biu~biu~biu~");
}
}