一、接口
定义类语法: [修饰符] class [类名] {}
定义接口语法:[修饰符] interface [接口名] {} 在这里我们还没有考虑接口的父接口!
接口命名问题:习惯以able结尾以表示某种功能,如:Walkable
或者以handler结尾
或者以I开头,如:IWalkable.java
和类一样,编译后依然会和类一样拥有字节码文件。
接口中存在的成员:
1.接口中没有构造器。接口不能创建对象,不能new
2.接口中定义的字段/成员变量,实质是全局静态常量(public static final)
常量接口:有人喜欢使用接口来封装多个常量信息,我们称之为常量接口,但我们不推荐这么做
标志接口:接口中无任何内容,仅仅是一个接口定义。仅仅用来标志其他的类来实现这个接口。(如:Serializable接口)不推荐
3.接口中定义的方法实质上是用public abstract
一般的,我们在接口很中定义的方法不喜欢用public
4.接口中定义的内部类都是公共的静态内部类。如:public static interface ABC{}
5.不能再接口中定义构造器以及普通方法。
接口的特点以及继承关系:
特点: 1.无构造器,也不能显示定义构造器,不能实例化
2.接口只能继承接口,不能继承类,且接口支持多继承(类是单继承)
[修饰符] interface [接口名] extends [接口1],[接口2]
3.接口里的方法全是抽象的,默认修饰符是public abstract
4.接口里的字段全都是全局静态常量,修饰符是public static final
5.接口中的内部类全是公共静态的,修饰符的public static
类和接口直接只有实现关系,没有继承关系,使用implements表示
接口和接口之间只能是继承关系,使用extends表示。
接口的实现者:实现类
接口只是仅仅定义了某一类事物应当具有某些功能,但是没有提供任何实现
此时,我们得提供类,再让该类去实现接口,并覆盖接口中的方法,从而实现类接口中定义的功能
[修饰符] class [类名] extens [父类] implements [接口1],[接口2]{}
//类实现接口的语法,可见一个类可以实现多个接口
接口和实现类之间的关系严格上来说是实现关系,使用implements表示
但是在开发中,有时候为了方便也把这个关系称之为特殊的继承关系
可以这么理解:接口是实现类的父类。实现类是接口的子类
接口 变量 = 创建实现类对象//体现了多态的思想
接口和实现类的多态关系,才是以后见到的最多的。
并非接口中没有普通方法,从java8之后,接口中可以定义默认方法,有方法体。
接口和抽象类的区别:
相同点:
1.都位于继承的顶端,用于被实现或者被继承
2.都不能被实例化
3.都可以定义抽象方法,其子类/实现类都必须覆写这些抽象方法
不同点:
1.接口中无构造器,抽象类有构造器
2.抽象类可以包含普通方法和抽象方法,接口只能包含抽象方法(java8之前)
3.一个类只能继承一个直接父类(),接口类是多继承的并且多继承的并且支持一个类实现多个接口
4.变量:接口默认是public static final ,抽象类是默认包访问权限
5.方法:接口里默认是public abstract,抽象类是默认包访问权限
6.内部类:接口里默认是public static,抽象类是默认包访问权限
如果接口和实现类可以完成相同的功能,尽量使用接口,面向接口编程
接口和抽象类集合使用:适配器模式
面向接口编程的范例:
interface IWalkable{void walk();//实质是抽象方法}interface ISwimable{void swim();}interface Amphibiousable extends IWalkable,ISwimable//多继承{}class Animal{}class Cat extends Animal implements IWalkable{public void walk()//提供方法体,否则也必须作为抽象类{System.out.println("走路!");}//因为接口中方法是抽象的,公共的,所以实现类必须覆盖接口的方法,且必须用public修饰,子类方法修饰符必须大于等于父类修饰符}class Fish extends Animal implements ISwimable{public void swim()//提供方法体,否则也必须作为抽象类{System.out.println("游泳!");}}class Frog extends Animal implements IWalkable,ISwimable//也可直接继承上面的Amphibiousable{//类实现多接口public void walk()//提供方法体,否则也必须作为抽象类{System.out.println("跳跃");}public void swim()//提供方法体,否则也必须作为抽象类{System.out.println("青蛙游泳!");}}class InterfaceDemo{public static void main(String[] args){//new IWalkable(); 这句话是不能使用的,接口不能newCat c = new Cat();//不推荐 推荐 ↓↓↓c.walk();IWalkable w = new Cat();//推荐,面向接口编程w.walk();//体现多态特征,执行Cat中的walkISwimable f = new Fish();f.swim();Frog frog = new Frog();//特殊情况 不多frog.walk();frog.swim();}}
interface IUSB{void swapData();}class Mouse implements IUSB{public void swapData(){System.out.println("鼠标运行");}}class Printer implements IUSB{public void swapData(){System.out.println("打印机运行");}}class MotherBoard {private static IUSB[] usbs = new IUSB[6];private static int index = 0;//插入位置public static void Insert(IUSB usb){if(index == usbs.length){System.out.println("插槽已满!");return ;}usbs[index] = usb;index++;}//取出主板中每一个USB设备public static void doWork(){for(IUSB usb : usbs){if(usb != null)usb.swapData();}}}class USBDemo {public static void main(String[] args) {//创建对象MotherBoard.Insert(new Mouse());MotherBoard.Insert(new Printer());MotherBoard.Insert(new Printer());MotherBoard.Insert(new Printer());MotherBoard.doWork();}}
二、内部类
内部类可以使用public/缺省/protected/private修饰
外部类访问修饰符要么使用public或者缺省,但不能用static
四种内部类:
实例内部类:内部类无static
静态内部类:内部类有static
局部内部类:在方法中定义了内部类
匿名内部类:仅用此一次使用的类,属于局部内部类的特殊情况。
实例内部类: 没有static修饰内部类,说明内部属于外部类的对象,不属于外部类本身
特点:
1.创建实例内部类之前,必须存在外部类对象,必须通过外部类对象创建内部类对象
2.实例内部类的实例自动持有外部类的实例引用,内部类可以直接访问外部类成员
3.外部类中不能直接访问内部类成员,必须通过内部类的实例去访问
4.实例内部中不能定义静态成员,只能定义实例成员
5.如果实例内部类和外部类存在同名字段或者方法abc,那么在内部类中:
this.abc表示访问内部类成员
外部类.this.abc表示访问外部类成员
静态内部类:使用static修饰的内部类
特点:
1.静态内部类的实例不会自动持有外部类的特定实例引用,
在创建内部类的实例时,不必创建外部的实例
2.在静态内部类可以直接访问外部类的静态成员,如果访问外类的实例成员必须通过外部类的实例去访问
3.在静态内部类中可以定义静态成员和实例成员
4.测试类可以通过完整的类名直接访问静态内部类的静态成员
局部内部类:(开发中不要使用)
在方法中定义的内部类,其可见范围是当前方法和局部变量
特点:
1.不能使用public/private/protected/static修饰符
2.局部内部类中能在当前方法中使用
3.局部内部类和实例内部类一样,不能包含静态成员
4.局部内部类和实例内部类,可以访问外部类所有成员
5.局部内部类访问的局部变量必须使用final修饰(Java8中不是,自动隐式加final但依然是常量不能改变其值)
原因:如果当前方法不是main方法,那么当前方法调用完毕后,当前方法栈帧被销毁,方法内部的局部变量的空间全部销毁
然后局部内部类是定义在方法中,而且在方法中会创建局部内部类对象,而局部内部类会去访问局部变量,
当当前方法被销毁的时候,对象还在堆内存,依然持有对局部变量的引用。
但是方法被销毁的时候,局部变量就被销毁
此时:在堆内存中,一个对象引用了一个不存在的数据为了避免该问题,
我们使用final修饰局部变量,从而变成常量,永驻内存空间,即使方法被销毁后,
该局部变量也在内存中,对象可以继续持有。
匿名内部类:是一个没有名称的局部内部类。在开发中经常有这样的类,只需要定义一次,使用一次就可以丢弃。在JavaSE/Android是事件处理中:不同的按钮点击之后,应该有不同的响应操作。此时首选使用内部类。
特点:
1.匿名内部类本身无构造器,但是会调用父类构造器
2.匿名类尽管没有构造器,但是在匿名类中提供一段实例化代码块,JVM在调用父类构造器后,会执行该段代码
3.内部类处理可以继承类之外,还可以实现接口
//格式:new 父类构造器(实参列表) 或者接口(){//匿名}