面向对象高级编程Day12
10.7接口
10.7.1接口快速入门
package com.interface01;
public interface usb {//接口
//接口,规定接口的相关方法 ,即规范
public void start();
public void stopp();
}
package com.interface01;
public class camera implements usb {//实现接口,就是把接口方法实现
public void start() {
System.out.println("相机开始工作....");
}
public void stopp() {
System.out.println("相机停止工作...");
}
}
package com.interface01;
//phone要实现usb接口
//phone类需要实现usb接口 规定/声明的方法
public class phone implements usb {
public void start() {
System.out.println("手机开始工作...");
}
public void stopp() {
System.out.println("手机停止工作...");
}
}
package com.interface01;
public class computer {
//编写方法,让计算机工作
public void work(usb usb1){
//通过接口来让计算机工作
usb1.start();
usb1.stopp();
}
}
package com.interface01;
public class interface01 {
public static void main(String[] args) {
//创建手机,相机对象
camera camera1 = new camera();
phone phone1 = new phone();
//创建计算机
computer computer1 = new computer();
computer1.work(phone1);//把手机接入到计算机
computer1.work(camera1);//把相机接入到计算机
}
}
10.7.2接口的简单介绍
接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把方法写出来
语法:
interface 接口{
//属性
//方法(抽象方法,默认实现方法default,静态方法)
}
class 类名 implements 接口{
自己属性;
自己方法
必须实现的接口的抽象方法
}
注:
在接口中,抽象方法可以省略abstract关键字
JDK7之前接口里的所有方法都没有方法体,即都是抽象方法
JDK8之后接口类可以有静态方法,,也就是说接口中可以有方法的具体实现,JDK8以后,可以有默认实现方法,需要使用default关键字修饰
10.7.3接口的注意事项和使用细节
1、接口不能被实例化
2、接口中所有的方法是public方法,接口中抽象方法,可以不用abstract修饰
3、一个普通类实现接口,就必须将该接口的所有方法都实现
4、抽象类实现接口,可以不用实现接口的方法
5、一个类同时可以实现多个接口
6、接口中的属性,只能是final的,而且是public static final 修饰符
###############################################################
接口中的所有属性都是静态的,公开的,不用加载类方法
接口里面的 int n1=10;//等价于public static final int n1=10;
###############################################################
7、接口中属性的访问形式:接口名.属性名
###############################################################
package com.interface01;
public class interface02 {
public static void main(String[] args) {
B b =new B();
System.out.println(b.a);
System.out.println(A.a);
System.out.println(B.a);
}
}
interface A{
int a=23;//在这里等价于public static final int a=23;
}
class B implements A{
}
此代码的结果为3个23
###############################################################
8、一个接口不能继承其他的类,但是可以继承多个别的接口
interface A extends B,C{}
9、接口的修饰符只能是public和默认,这点和类的修饰符是一样的
10.7.4实现接口VS继承类
举个栗子
猴子和小猴子的关系就是继承的关系,继承的关系就是自然而然地接受父类的能力
但是小猴子要想实现飞翔的功能,就要去实现小鸟飞行的功能,想要游泳,就要是实现鱼的功能;而接口地话是本身所不拥有的,需要在进行实现
接口和继承解决的问题不同
继承的价值主要在于:解决代码的复用性和可复用性
接口的价值主要在于:设计号各种规范方法,让其他类自己去进行实现
接口比继承更加灵活:继承是is-a的关系;接口只需要满足like-a的关系
接口在一定程度上实现代码解耦【接口规范性+动态绑定】
10.7.5接口的多态
1、多态参数,在快速入门中的案例中就体现了
在这里接受了手机对象,又接受了相机对象,就体现了接口;多态
package com.interface01;
public class interface01 {
public static void main(String[] args) {
//创建手机,相机对象
camera camera1 = new camera();
phone phone1 = new phone();
//创建计算机
computer computer1 = new computer();
computer1.work(phone1);//把手机接入到计算机
computer1.work(camera1);//把相机接入到计算机
}
}
package com.interface01;
public class interface02 {
public static void main(String[] args) {
//接口体现的多态
//接口类型的变量if01可以指向实现了IF接口的类对象实例
IF if01 =new Monster();
if01 = new Car();
//继承体现的多态
//父类类型变量a可以指向继承AAA的子类的对象实例
AAA a = new BBB();
a= new CCC();
}
}
interface IF{ }
class Monster implements IF {}
class Car implements IF{}
class AAA{}
class BBB extends AAA{}
class CCC extends AAA{}
2、多态数组
接口型数组,可以指向实现了它的方法的对象实例
向下转型
package com.interface01;
public class interface02 {
public static void main(String[] args) {
//动态数组
IF[] if01 = new IF[2];
if01[0]=new Monster();
if01[1]=new Car();
for (int i=0;i<if01.length;i++){
if01[i].work();//动态绑定
//在此处需要进行类型的向下转型
if (if01[i] instanceof Monster){
//判断运行类型是否为Monster
((Monster) if01[i]).call();
}
}
}
}
interface IF{
void work();
}
class Monster implements IF {
public void call(){
System.out.println("被调用....");
}
@Override
public void work() {
System.out.println("恶魔正在工作中....");
}
}
class Car implements IF{
@Override
public void work() {
System.out.println("汽车正在工作中....");
}
}
3、接口存在多态传递
接口类型的变量可以指向,实现了该接口类的对象实例
package com.interface01;
public class interface03 {
public static void main(String[] args) {
//接口类型的变量可以指向,实现了该接口类的对象实例
IG ig =new teacher();
//如果IG继承了IH 接口,而teacher类实现了IG 接口
//那么实际上就相当于teacher也实现了IH 接口
//在这里就体现了接口多态的多态传递现象
IH ih = new teacher();
}
}
interface IH{
void hi();
}
interface IG extends IH{ }
class teacher implements IG{
@Override
public void hi() {
}
}
10.8内部类
10.8.1内部类的基本介绍
一个类的内部又完整的嵌套l另一个类结构,被嵌套的类称为内部类
嵌套其他类的类称为外部类
内部类的最大特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系
10.8.2基本语法
class Outer{//外部类
class Inner{//内部类
}
}
class Other{
//外部其他类
}
类的五大成员:属性,方法,构造器,代码块,内部类
10.8.3内部类的分类
定义在外部类局部位置上(比如方法内)
局部内部类(有类名)
匿名内部类(没有类名!!!!,重点)
定义在外部类的成员位置上(属性和方法的位置上)
成员内部类(没用static修饰)
静态内部类(使用static修饰)
10.8.3.1局部内部类细节说明 (本质就是一个类)
定义是指定义在外部类的局部位置上,比如方法中,并且有类名
说明:
A:可以直接访问外部类的所有成员,包含私有的
B:不能添加访问修饰符,因为它的低位就是一个局部变量,局部变量是不能使用修饰符的,但是可以使用final修饰,因为局部变量也可以使用final
C:作用域:仅仅在定义它的方法或代码块中
D:局部内部类——访问——外部类的成员【直接访问】
E:外部类——访问——局部内部类的成员
【创建对象,再访问,必须再作用域内】
F:外部其他类——不能访问——局部内部类(因为局部内部类地位是一个局部变量)
G:如果外部类和局部内部类的成员重名时,默认遵守就近原则,如果想访问外部类的成员,则可以使用**(外部类名.this.成员)**去访问
10.8.3.2匿名内部类(本质还是类,内部类,该类没有名字,是一个对象) 匿名内部类适合用于只用一次的
1、 匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
基本语法
new 类/接口 (参数列表){
类体
};
interface A{//接口
public void cry();
}
//基于接口的匿名内部类
class outer02{//外部类
private int n1 =10;//属性
public void method(){//方法
//基于接口的匿名内部类
//需求:想使用IA接口,并创建对象
//传统方式,写一个类,实现该接口,并创建对象
//Tiger类只是使用一次,后面不再使用
//可以使用匿名内部类来简化开发
//tiger1的编译类型是接口类型
//tiger1的运行类型是匿名内部类 XXXX=>outer02$1
//匿名内部类使用一次就不能再运行
//对象可以反复使用
/*
底层会分配类名
class XXXX implements A{
@Override
public void cry() {
System.out.println("老虎.....");
}
}
*/
A tiger=new A(){
public void cry() {
System.out.println("老虎.....");
}//匿名内部类的使用
};
System.out.println("tiger的运行类型为"+tiger.getClass());
//getClass就是获取运行类型
tiger.cry();
}
}
//基于类的匿名内部类
###############################################################
注:这里存在的匿名内部类其实是子类,而并非是原来的类,由于是类所以是继承关系,而上面由于是接口所以是实现
###############################################################
public class anon {
public static void main(String[] args) {
outer02 outer02 = new outer02();
outer02.method();
}
}
//基于类的匿名内部类
//father编译类型Father
//father运行类型outer02$2
//底层会创建匿名内部类
/* 这里是类和类的关系,所以继承,不是实现
class outer02$2 extends Father{
}
*/
//同时也返回了匿名内部类outer02$2的对象
//注:这里是新的类,不再是Father类
class outer02{//外部类
private int n1 =10;//属性
public void method(){//方法
Father father=new Father("jack"){
public void test() {
System.out.println("匿名内部类重写了方法");
}
};
System.out.println("father对象的运行类型="+father.getClass());
father.test();
}
}
class Father{
public Father(String name){//构造器
}
public void test(){//方法
}
}
2、匿名内部类的语法比较,匿名内部类是一个类的定义
同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征
3、可以直接访问外部类的所有成员,包含私有的
4、不能添加访问修饰符,因为它的地位就是一个局部变量
5、作用域:仅仅在定义它的方法或者代码块中
6、匿名内部类——访问——外部成员【直接访问】
7、外部其他类——不能访问——匿名内部类【局部变量】
8、如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
###############################################################
匿名内部类的最佳实践
可以当作实参进行传递
package com.charpter10;
public class anon {
public static void main(String[] args) {
f1(new IL(){
public void show() {
System.out.println("这是将匿名内部类传入");
}
});
}
//静态方法,形参是接口类型
public static void f1(IL il){
il.show();
}
}
interface IL{
void show();
}
###############################################################
10.8.3.3成员内部类
成员内部类是定义在外部类的成员位置,并且没有static修饰
1、可以直接访问外部类的所有成员,包含私有的
2、可以添加任意访问修饰符,因为它的本质就是一个成员
3、作用域和外部类的其他成员一样,为整个类体,在外部类的成员方法中创建成员内部类对象,再调用方法
4、成员内部类——访问——外部类【直接访问,因为是一个成员】
5、外部类——访问——内部类【先创建一个内部类的对象再进行访问】
6、外部其他类——访问——成员内部类
3种方式
第一种
在这里将inner()当作一个成员来对待
outer1.new inner();相当于把new inner()当做是outer的成员
outer outer1 = new outer();
outer.inner inner1 = outer1.new inner();
package com.charpter10.menber;
public class memberclass {
public static void main(String[] args) {
//第一种
outer outer1 = new outer();
outer.inner inner1 = outer1.new inner();
//外部类名.内部类名 【名称】= 外部类对象.new 内部类
//外部类的对象去新建了一个内部类
//在这里将inner()当作一个成员来对待
//outer1.new inner();相当于把new inner()当做是outer的成员
}
}
class outer{
private int n1=10;
public String name ="张三";
private void hi(){
System.out.println("hi()方法....");
}
public class inner{
private double sal=99.8;
public void say(){
System.out.println("n1="+n1+"\tname="+name);
hi();
}
}
}
第二种
在外部类中,编写一个方法,可以返回一个inner的对象
outer outer1 = new outer();
//第二种,在外部类中,编写一个方法,可以返回一个inner的对象
outer.inner getinner02 = outer1.getinner();
getinner02.say();
package com.charpter10.menber;
public class memberclass {
public static void main(String[] args) {
outer outer1 = new outer();
//第二种,在外部类中,编写一个方法,可以返回一个inner的对象
outer.inner getinner02 = outer1.getinner();
getinner02.say();
}
}
class outer{
private int n1=10;
public String name ="张三";
private void hi(){
System.out.println("hi()方法....");
}
public class inner{
private double sal=99.8;
public void say(){
System.out.println("n1="+n1+"\tname="+name);
hi();
}
}
//返回一个inner()的实例
public inner getinner(){
return new inner();
}
}
第三种
双重new
7、如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类成员,则可以使用(外部类名.this.成员)
10.8.3.4静态内部类
1、静态内部类是定义在外部类的成员位置,并且有static修饰
2、可以添加任意访问修饰符,但不能直接访问非静态成员,因为它的地位就是一个成员
3、作用域:同其他的成员,为整个类体
4、静态内部类——访问——外部类【直接访问所有静态成员】
5、外部类——访问——静态内部成员【创建对象,再访问】
6、外部其他类——访问——静态内部类
方式一:先创建一个外部类的实例,然后用new 实例.内部类去创建
方式二:编写一个方法,可以返回一个静态内部类的实例,去调用
方式三:编写一个静态方法,可以返回一个静态内部类的实例,去调用
方式四:可以不用创建外部类的实例,直接调用静态方法,返回一个静态内部类
7、如果外部类和静态内部类的成员重名时,静态内部类访问的时候,默认遵顼就近原则,如果想访问外部类的成员,可以使用(外部类名.成员)去访问