文章目录

  • 三.面向对象OOP
  • 1.面向对象与面向过程
  • 2.类与对象
  • 3.面向对象的三大特性:封装
  • 4.面向对象的三大特性:继承
  • 5.面向对象的三大特性:多态
  • 6.构造方法
  • 7.this与super
  • 8.对象创建过程
  • 9.代码块与它们的执行顺序
  • 9.1静态代码块 static { }
  • 9.2构造代码块 { }
  • 9.3局部代码块 { }
  • 9.4代码块之间的顺序:
  • 10.static
  • 11.final
  • 12.异常
  • 13.抽象
  • 14.接口
  • 15.接口与类的复杂关系
  • 15.1类与类的关系
  • 15.2接口与接口的关系
  • 15.3接口与类的关系
  • 15.4接口与抽象类的区别
  • 16.内部类
  • 16.1成员内部类
  • 16.2局部内部类
  • 16.3匿名内部类


三.面向对象OOP

1.面向对象与面向过程

1.两者都是一种编程的思想
2. 面向对象强调的是事情的结果,我们通过对象完成对应的功能
3. 面向过程强调的是事情的过程,我们做任何事情,都要亲力亲为,经过每一个步骤
4. Java是一门面向对象的语言

2.类与对象

1.定义类通过关键字class来定义,类是一类事物的抽象,它是抽象的,它是模板
2. 创建对象通过new关键字触发构造函数生成,对象是根据类创建出来的具体的内容
3. 一个类可以创建出多个对象,对象是根据类的设计来创建的,所以对象具有类的所有属性与功能
4. 对象之间是相互独立的,互不影响。我们把创建对象也称作“实例化”

3.面向对象的三大特性:封装

1.前提:为了保证数据的安全,也为了程序的使用者能够按照我们预先设计好的方式来使用资源
2. 封装属性:用private修饰我们的属性
然后为属性提供对应的getXxx()【获取属性值】与setXxx()【设置属性值】
3. 封装方法:用private修饰方法,被修饰的方法只能在本类中使用,所以我们在本类的公共方法里调用这个私有方法
外界如果想要使用这个私有方法的功能,只需要调用这个公共方法就可以了

package cn.tedu.oop;
/**本类用于测试封装方法*/
public class TestPrivate3 {
    public static void main(String[] args) {
        Apple a1 = new Apple();
        a1.clean();
        //a1.eat();
    }
}
class Apple{

    public void clean(){
        System.out.println("苹果要先洗洗");
        /**当eat方法被封装,外部其他的类无法直接使用
         * 所以我们可以在本类Apple类中的clean()里直接调用eat()*/
        eat();
    }
    /**private是一个修饰符,被private修饰的资源是私有资源
     * 只能在本类中使用*/
    private  void eat (){
        System.out.println("可以吃苹果了");
    }
}

4.面向对象的三大特性:继承

1.前提 :继承可以实现程序的复用性,减少代码的冗余
2. 我们通过extends关键字建立子类与父类的继承关系:格式:子类 extends 父类
3. 继承相当于子类把父类的功能复制了一份,包括私有资源
注意:虽然私有资源继承了,但是私有资源不可用,原因是被private限制了访问,私有资源只能在本类使用
注意:构造方法不能继承,原因是:构造方法要求名字是本类的类名,我们不能在子类中出现父类名字的构造方法
4. 继承是可以传递的:爷爷的功能会传给爸爸,爸爸的功能会传给孙子
注意:爸爸从爷爷那里继承的功能,也会一起传给孙子
5. Java的类是单继承的:一个子类只能有一个父类,但是一个父类可以有多个子类
6. 子类在继承了父类以后,如果对父类的功能不满意
可以在不修改父类功能的【满足OCP原则】前提下,在子类中,重写继承过来的这个方法
重写需要满足的规则:两同 两小 一大,我们可以在重写的方法上加@Override注解验证是否写对
7. 继承是一种is a的关系,强耦合,关联性特别强,而且类的继承机会只有一次,要谨慎使用
8. 子类可以直接使用父类的所有非私有资源
练习题:

package cn.tedu.oop;

import java.util.Random;
import java.util.Scanner;

/*本类用于复习面向对象的相关知识*/
public class TestOOP {
    public static void main(String[] args) {
        //8.提示并接收用户传入的宠物昵称
        System.out.println("请您输入宠物的名字:");
        String name = new Scanner(System.in).nextLine();
        //9.触发对应的构造函数,创建小猫类的对象
        Cat c = new Cat(name);
        //10.与宠物做互动
        System.out.println("按回车执行:");
        while(true){
            new Scanner(System.in).nextLine();
            int r = new Random().nextInt(6);
            switch (r){
                case 0:c.feed();break;
                case 1:c.play();break;
                default:c.punish();break;
            }
        }

    }
}
//1.创建父类:宠物类,描述宠物这一类事物
class Pet{
    //2.定义宠物类的属性
    String name;//电子宠物的姓名
    int full;//饱食度
    int happy;//快乐度

    //3.1 生成本类的全参构造
    public Pet(String name, int full, int happy) {
        this.name = name;
        this.full = full;
        this.happy = happy;
    }
    //3.2 创建本类的含参构造
    public Pet(String name){
        //只需要用户起宠物名即可,饱食度与快乐度的初始值都是50
        //实际上底层会触发全参构造,名字是用户起的,其他两个是预先设置好的默认值
        this(name,50,50);
    }
    //4.1定义宠物类的功能1--喂宠物吃东西
    public void feed(){
        //先判断宠物是不是吃饱了,如果吃饱了,结束整个喂食方法
        if(full == 100){
            System.out.println(name+"已经吃饱啦~");
            return;//遇到return关键字,整个方法直接结束
        }
        //如果没有吃饱,就给宠物喂食,一次增加10的饱食度
        System.out.println("给"+name+"喂食:");
        full = full + 10;
        System.out.println("饱食度:"+full);
    }
    //4.2定义宠物类的功能2--陪宠物玩
    public void play(){
        //先判断宠物还有没有饱食度,如果没有饱食度了,就不能玩了,结束整个玩的方法
        if(full == 0){
            System.out.println(name+"已经饿的玩不动了...");
            return;//遇到return关键字,整个方法直接结束
        }
        //如果饱食度不为0,就可以玩耍,每次玩耍快乐度+10,饱食度-10
        System.out.println("陪"+name+"玩耍");
        happy += 10;
        full -= 10;
        System.out.println("快乐度:"+happy);
        System.out.println("饱食度:"+full);
    }
    //4.3定义宠物类的功能3--宠物的惩罚方法
    public void punish(){
        System.out.println("打"+name+"的PP,哭叫声:"+cry());
        happy -= 10;
        System.out.println("快乐度:"+happy);
    }
    //4.4定义一个哭的方法--宠物被打哭了
    public String cry(){
        return "此处有哭叫声";//这个位置没有明确的叫声,因为子类会重写
    }
}

//5.创建子类小猫类
class Cat extends Pet{
    //6.由于父类的无参构造已经没有了,所以这里要手动调用父类的含参构造
    public Cat(String name) {//养猫的时候要给猫起昵称
        super(name);//表示调用父类的含参构造
    }
    //7.重写父类的cry();
    @Override
    public String cry(){
        return "喵~";
    }
}

5.面向对象的三大特性:多态

1.前提:为了忽略子类型之间的差异,统一看作父类类型,写出更加通用的代码

比如:把Cat看作Animal,把Dog看作Animal,把Bird看作Animal,如果方法需要设置传入的参数,可以buy(Animal a)

比如:把算术异常、输入不匹配异常都看作是Exception,统一捕获处理,只写一个解决方案

2. 概念:在同一时刻,同一个对象,代表的类型不同,拥有多种形态

3. 多态的要求:继承 + 重写

4. 多态的口诀1:父类引用指向子类对象:父类型的引用类型变量保存的是子类对象的地址值

5. 多态的口诀2:编译看左边,运行看右边:

父类中定义的功能,子类才能使用,否则报错

多态中,方法的定义看的是父类的,方法的实现看的是子类重写后的功能

java开发工程师的优点_java


6. 多态中资源的使用:

1)成员变量:使用的是父类的

2)成员方法:对于方法的定义看的都是父类的,对于方法实现,重写后使用的是子类的

3)静态资源:静态资源属于类资源,不存在重写的概念,在哪个类中定义的,就属于哪个类

7. 向上造型与向下造型

1)这两种都属于多态,只不过是多态的两种不同的表现形式

2)向上造型【最常用】

可以把不同的子类型都看作是父类型,比如Parent p = new Child();

比如:花木兰替父从军,被看作是父类型,并且花木兰在从军的时候,不能使用自己的特有功能,比如化妆

3)向下造型

前提:必须得先向上造型,才能向下造型

子类的引用指向子类的对象,但是这个子类对象之前被看作是父类类型,所以需要强制类型转换

Parent p = new Child(); 然后:Child c = (Child) p;

比如:花木兰已经替她爸打完仗了,想回家织布,那么这个时候,一直被看作是父类型的花木兰必须经历“解甲归田”【强制类型转换】这个 过程,才能重新被看作成子类类型,使用子类的特有功能

为什么有向下造型:之前被看作是父类类型的子类对象,想使用子类的特有功能,那就需要向下造型\

package cn.tedu.oop3;
//本类用于多态的入门案例
public class TestDemo {
    public static void main(String[] args) {
        Animal a = new Animal();
        Cat c = new Cat();
        Dog d = new Dog();
        a.eat();
        c.eat();
        d.eat();
        /**f父类对象不可以使用子类的特殊功能*/
        //a.jump();
        c.jump();
        d.run();
        /**
         * 口诀:父类引用指向子类对象
         * 解释:创建出来的子类对象的地址值,交给父类类型的引用类型变量来保存*/
        Animal a2 = new Cat();
        Animal a3 = new Dog();
        /**口诀:编译看左边,运行看右边
         * 解释:必须要在父类中定义这个方法,才能通过编译,把多态对象看做是父类类型
         * 必须要在子类中重写这个方法,才能满足多态,实际干活的是子类*/
        a2.eat();//父类的定义,子类的方法体
    }
}
/**多态的前提
 * 1.继承
 * 2.重写
 * */
class Animal{
    public void eat(){
        System.out.println("小动物Animal吃啥都行");
    }
}
class Cat extends Animal{
    @Override
    public void eat(){
        System.out.println("小猫爱吃小鱼干");
    }
    public void jump(){
        System.out.println("小猫跳的老高了");
    }
}
class Dog extends Animal{
    @Override
    public void eat(){
        System.out.println("小猫爱吃肉骨头");
    }
    public void run(){
        System.out.println("小狗跑的老快了");
    }
}

6.构造方法

1.格式 :修饰符 类名当做方法名(){ } 注意:与类同名且没有返回值类型
2. 构造方法作用:用于创建对象,每次new对象时,都会触发对应的构造函数,new几次,触发几次
3. 一个类中默认存在无参构造,如果这个构造不被覆盖的话,我们可以不传参数,直接创建这个类的对象
4. 如果这个类中提供了其他的构造函数,默认的无参构造会被覆盖,所以记得手动添加无参构
5. 构造方法也存在重载的现象:无参构造 含参构造 全参构造【创建对象+给所有的属性赋值】

7.this与super

1.this代表的是本类,super代表的是父类
2. 当本类的成员变量与局部变量同名时,我们可以通过this.变量名指定本类的成员变量
当父类的成员变量与子类的变量同名时,我们可以通过super.变量名指定父类的成员变量
3. 我们可以在本类构造函数的第一行
使用this();调用本类的无参构造 / 使用this(参数); 调用本类对应参数的构造方法
构造函数的调用只有这一种方式,或者创建对象时被动触发,不能在外面自己主动调用
构造函数直接不能互相调用,否则会死循环
4.我们可以在子类构造函数的第一行
使用super();调用父类的无参构造 / 使用super(参数); 调用父类对应参数的构造方法
注意:子类默认调用super();父类的无参构造,如果父类没有无参构造,需要手动指定调用哪个含参构造

package cn.tedu.oop2;
//本类用于测试继承中变量的使用
public class TestExtends1 {
    public static void main(String[] args) {
        Son s = new Son();
        s.study();
    }
}
class Father{
    int sum = 1;
    int count = 2;
}
class Son extends Father{
    int sum = 10;
    int count = 30;
    public void study(){
        System.out.println("good good study,day day up");
        int sum =100;
        System.out.println(sum);//就近原则输出:100
        System.out.println(count);//就近原则输出:30
        System.out.println(this.sum);//加了this就近原则输出:10
        System.out.println(super.sum);//访问父类中的属性.输出:1
        /**当父类的成员变量与子类的成员变量同名时,可以使用super关键字指定父类的成员变量
         * 我们可以吧super看作是父类的对象;Father super = new Father()//super是关键字,不可以写
         * */
    }
}

8.对象创建过程

1.前提:对象是根据类的设定来创建的,目前我们可以在类中添加很多的元素:
属性 方法 静态方法 构造代码块 静态代码块 局部代码块 构造方法…所以不限制类里具体写什么,取决于业务
2. 对象创建的过程:Phone p = new Phone();
需要在堆内存中开辟一块空间,用来存放对象
对象需要完成初始化,比如对应的属性都有自己的对应类型的默认值
对象创建完毕后,会生成一个唯一的地址值用于区分不同的对象
将这个地址值交给引用类型变量来保存
后续如果想要使用这个类的功能,可以从引用类型变量中保存的地址值找到对应的对象做进一步的操作
3. 匿名对象:new Phone();
匿名对象是没有名字的对象,所以创建过程:
需要在堆内存中开辟一块空间,用来存放对象
对象需要完成初始化,比如对应的属性都有自己的对应类型的默认值
对象创建完毕后,会生成一个唯一的地址值用于区分不同的对象
那么我们使用匿名对象只能使用一次,并且一次只能使用一个功能
new Phone().video();//创建匿名对象1,调用看直播的方法
new Phone().message();//创建匿名对象2,调用看发短信的方法

9.代码块与它们的执行顺序

9.1静态代码块 static { }

位置:类里方法外
执行时机:随着类的加载而加载,最先加载到内存,优先于对象进行加载,直到类小消失,它才会消失
作用:一般用来加载那些只需要加载一次并且第一时间就需要加载资源,称作:初始化

9.2构造代码块 { }

位置:类里方法外
执行时机:创建对象时执行,创建几次,执行几次,并且优先于构造方法执行
作用:用于提取所有构造方法的共性功能

9.3局部代码块 { }

位置:方法里
执行时机:当其所处的方法被调用时才会执行
作用:用于限制变量的作用范围,出了局部代码块就失效

9.4代码块之间的顺序:

静态代码块 -> 构造代码块 -> 构造方法 -> 普通方法【如果普通方法里有局部代码块,局部代码块才会执行】

10.static

1.被static修饰的资源统称为静态资源,可以用来修饰变量、方法、代码块、内部类
2. 静态资源属于类资源,随着类的加载而加载,优先于对象进行加载,只加载一次
3. 静态资源可以不通过对象,使用类名直接调用,不需要创建对象
4. 静态资源只有一份,被全局所有对象共享
5. 静态的调用关系:静态资源只能调用静态资源
6. 静态资源是优先于对象的,所以静态资源不能与this和super共用

package cn.tedu.innerclass;
/*本类用于测试成员内部类被static修饰的练习*/
public class TestInner3 {
    public static void main(String[] args) {
        //Outer3.Inner3 oi3 = new Outer3().new Inner3();
        //oi3.show();
        //new Outer3().new Inner3().show();//创建匿名对象使用内部类的资源

        /*当内部类被static修饰后,new Outer3()报错*/
        Outer3.Inner3 oi3 = new Outer3.Inner3();
        oi3.show();

        Outer3.Inner3.show2();//链式加载--不推荐使用

    }
}
class Outer3{

    static class Inner3{
        public void show(){
            System.out.println("内部类....show");

        }
        public static void show2(){
            System.out.println("我是静态内部类的静态方法");
        }
    }
}

11.final

1.final表示最终
2. 被final修饰的类是最终类,也称作叶子结点,所以不能被继承
3. 被final修饰的方法是这个方法的最终实现,不能被重写
4. 被final修饰的是常量,值不可以被修改,注意常量定义时必须赋值

package cn.tedu.oop;
/**本类用于测试final关键字*/
public class TestFinal {
    public static void main(String[] args) {
    }
}
/**final可以用来修饰类,被final修饰的类是最终类,不可以被继承
 * 可以把被final修饰的类看成树结构中的叶子节点
 */
/**final可以用来修饰方法,被final修饰的方法是这个方法的最终实现,不可以被重写*/
//final class Father2{
//}
class Father2{
    //public final void work(){
    public void work(){
        System.out.println("在工厂上班");
    }
}
class Son2 extends Father2{
    @Override
    public void work(){
        System.out.println("在互联网大厂上班");
        /**被final修饰的是常量,常量的值不可以被修改
         * 注意:不管是成员位置还是局部位置,常量定义的时候必须赋值
         * 注意:常量的名称必须是大写,单词与单词之间使用用_分割*/
        int b =100;
    }
}

12.异常

当程序中遇到了异常,通常有两种处理方式:捕获或者向上抛出

当一个方法抛出异常,调用位置可以不做处理继续向上抛出,也可以捕获处理异常

大家可以结合生活中的例子:如果工作中遇到了问题,我们可以选择自己处理(捕获),或者交给上级处理(抛出)

捕获方式:

java开发工程师的优点_java开发工程师的优点_02


抛出方式:

对于不想现在处理或者处理不了的异常可以选择向上抛出

方式:在方法上设置异常的抛出管道,即:

在可能会会发生异常的方法上添加代码:

throws 异常类型

例如:void method1 throws Exception1,Exception2,Exception3{ }

TIPS:方法上有默认的异常管道:RuntimeException

package cn.tedu.oop;

import java.util.InputMismatchException;
import java.util.Scanner;

/*本类用于异常的入门案例*/
public class ExceptionDemo {
    //public static void main(String[] args) throws Exception {//问题实际未处理,还报错
    public static void main(String[] args) {
        //method1();//调用暴露异常的方法
        //method2();//调用解决异常的方法--异常解决方案1--捕获处理--自己解决
        /*main()不直接调用会抛出异常的method3()
        * 而是调用f(),f()解决了method3()可能会抛出的异常*/
        f();
        //method3();//调用解决异常的方法--异常解决方案2--向上抛出--交给调用者来解决
    }
    //相当于在main()调用method3()之前解决了method3()可能会抛出的异常
    private static void f() {
        try {
            method3();
        }catch (Exception e){
            System.out.println("您输入的数据不对~请重新输入!");
        }
    }

    /*如果一个方法抛出了异常,那么谁来调用这个方法,谁就需要处理这个异常
    * 这里的处理也有两种方案:捕获解决 或者 继续向上抛出
    * 但注意:我们一般会在main()调用之前将异常解决掉
    * 而不是将问题抛给main(),因为没人解决了,该报错还报错*/
    /*异常抛出的格式:在方法的小括号与大括号之间,写:throws 异常类型
    * 如果有多个异常,使用逗号分隔即可*/
    //0.定义一个解决异常的方法-方案2
    //private static void method3() throws ArithmeticException,InputMismatchException{
    private static void method3() throws Exception{
        //1.复写一下刚刚的代码
        System.out.println("请您输入要计算的第一个整数:");
        int a = new Scanner(System.in).nextInt();
        System.out.println("请您输入要计算的第二个整数:");
        int b = new Scanner(System.in).nextInt();
        System.out.println(a/b);
    }

    /*异常捕获处理的格式:
    * try{
    *    可能会抛出异常的代码
    * }catch(异常的类型 异常的名字){
    *    万一捕获到了异常,进行处理的解决方案
    * }
    * try-catch结构可以嵌套,如果有多种异常类型需要特殊处理的话
    * */
    //0.定义一个解决异常的方法-方案1
    private static void method2() {
        //1.按照捕获处理的格式完成结构
        try{
            //2.复写一下刚刚的代码
            System.out.println("请您输入要计算的第一个整数:");
            int a = new Scanner(System.in).nextInt();
            System.out.println("请您输入要计算的第二个整数:");
            int b = new Scanner(System.in).nextInt();
            System.out.println(a/b);
        }catch(ArithmeticException e){//异常类型 异常名
            System.out.println("除数不能为0!");
        }catch (InputMismatchException e){
            System.out.println("请输入规定的整数类型!");
        /*使用多态的思想,不论是什么子异常,统一看作父类型Exception
        * 做出更加通用的解决方案,甚至可以只写这一个,上面2个不写了*/
        }catch (Exception e){
            System.out.println("您输入的数据不对~请重新输入!");
        }
    }

    //0.定义一个用来暴露异常的方法
    private static void method1() {
        //1.提示并接收用户输入的两个整数
        System.out.println("请您输入要计算的第一个整数:");
        int a = new Scanner(System.in).nextInt();
        System.out.println("请您输入要计算的第二个整数:");
        int b = new Scanner(System.in).nextInt();
        //2.输出两个数除法的结果
        //输入11和0,报错:ArithmeticException--算术异常,除数不能为0,数学规定
        //输入11和3.4,报错:InputMismatchException--输入不匹配异常
        System.out.println(a/b);
        /*1.不要害怕BUG,真正的勇士敢于直面自己写的BUG*/
        /*2.学会看报错的信息提示,确定自己错误的方法*/
        /*3.学会看报错的行号提示,确定自己报错的位置,哪里不对点哪里
        * 注意:源码不会错,要看的是自己写的代码*/
    }
}

13.抽象

1.抽象的关键字是abstract
2. 被abstract修饰的方法是抽象方法,抽象方法没有方法体
3. 如果一个类中出现了一个抽象方法,那么这个类必须被abstract修饰
4. 关于抽象类的特点:
1)抽象类中的方法不做限制 : 全普 / 全抽 / 半普半抽
2)如果一个类中的方法都是普通方法,还要声明成抽象类,为什么?
为了不让外界创建本类的对象
3)抽象类不可以创建对象,所以常用于多态
4)抽象类中包含构造方法,但是不是为了自己创建对象时使用,而是为了子类的super()
5)抽象类中也是可以定义成员变量的
5. 如果一个子类继承了一个抽象父类,有两种解决方案:
1)作为抽象子类:不实现/实现部分 抽象父类中的抽象方法 : ”躺平”
2)作为普通子类:实现抽象父类中的所有的抽象方法 : “父债子偿”
6. 面向抽象进行编程:后天重构的结果

14.接口

1.接口不是类,定义接口的关键字interface
2. 如果一个类想要实现接口中定义的规则,需要使用implments与接口建立实现关系
注意:如果有任何一个抽象方法没有实现,那么这个类就是一个抽象子类
3. Java8中接口里的所有方法都是抽象方法
4. 接口中只有静态常量,没有普通变量,会自动拼接public static final
5. 接口中的方法也可以简写,会自动拼接public abstract
6. 接口不可以实例化
7. 接口中也没有构造方法,实现类调用的是它自己父类的构造方法,如果没有明确指定父类,那就是Object的
8. 接口更多的是规则的制定者,不做具体的实现
9. 接口降低了程序的耦合性,更加方便项目的维护与拓
10. 接口是先天设计的结果,这样可以省去后续的多次重构,节省资源

package cn.tedu.inter;
/*本接口用于创建接口的测试
 * 我们通过interface关键字来定义接口*/
public interface Inter {
    public static void main(String[] args) {
    }
    //public void eat(){} 接口中没有普通方法
    public abstract void eat();//接口中可以定义抽象方法
    public abstract void play();//接口中可以定义抽象方法
}
package cn.tedu.inter;
/*本类作为inter接口的实现类 */
/*实现类如果想要实现接口定义的功能,需要与接口建立实现关系
* 通过关键字implements来建立实现类 实现 接口的关系*/
/*如果实现类与接口建立实现关系后
* 可以选择不实现接口的抽象方法,把自己变成一个抽象类*/
//abstract public class Interlmpl implements Inter{
/*如果实现类与接口建立实现关系后
* 还可以选择实现接口中的所有抽象方法,把自己变成一个普通子类*/
public class Interlmpl implements Inter{

    @Override
    public void eat() {
        System.out.println("吃火锅");
    }

    @Override
    public void play() {
        System.out.println("玩代码");
    }
}
package cn.tedu.inter;
//本类用来接口的测试类
public class InterTest {
    public static void main(String[] args) {
        //接口不可以实例化
        //Inter i = new Inter() ;

        Inter i = new Interlmpl();
        i.eat();
        i.play();
        //创建纯纯的接口实现类对象进行测试--推荐使用
        Interlmpl i2 = new Interlmpl();
        i2.eat();
        i2.play();
    }
}

15.接口与类的复杂关系

15.1类与类的关系

Java的类只支持单继承,类与类就是继承关系,并且一个子类只能有一个父类
class Son extends Father{ }

15.2接口与接口的关系

Java的接口是不做限制的,可以多继承
interface Inter1 extends Inter2{ } – Inter1是子接口 Inter2 是父接口
interface Inter1 extends Inter2,Inter3{ } – Inter1 是子接口 Inter2 和 Inter3 都是父接口
注意:如果是情况2的话,接口1的实现类需要实现这三个接口(Inter1,2,3)的所有抽象方法

15.3接口与类的关系

Java中的类对于接口而言是多实现的,所以一个类可以实现多个接口
class InterImpl implements Inter1{}
class InterImpl implements Inter1,Inter2{}

15.4接口与抽象类的区别

接口是一种用interface定义的类型
抽象类是一种用class定义的类型
接口中的方法都是抽象方法,还有默认方法与静态方法
抽象类中的方法不做限制
接口中的都是静态常量
抽象类中可以写普通的成员变量
接口没有构造方法,不可实例化
抽象类有构造方法,但是也不可以实例化
接口是先天设计的结果,抽象是后天重构的结果
接口可以多继承
抽象类只能单继承

16.内部类

1.我们可以把内部类看作是外部类的一个特殊的资源
2. 内部类可以直接使用外部类的所有资源,包括私有资源
3. 外部类如果想要使用内部类的资源,需要创建内部类的对象才能使用
4. 对象的普通创建方式:

/*外部类名.内部类名 对象名 = 外部类对象.内部类对象*/
Outer.Inner oi = new Outer().new Inner();

16.1成员内部类

位置:类里方法外
1)被private修饰
被私有化的内部类在main()中是没有办法直接创建其对象的
可以在私有内部类所处的外部类中,创建一个公共的方法供外界调用,这个方法用来返回创建好的私有内部类对象
2) 被static修饰
静态内部类可以不创建外部类对象,直接创建静态内部类对象,格式:Outer3.Inner3 oi = new Outer3.Inner3();
如果静态内部类中还有静态方法,那么我们可以不创建对象
直接通过链式加载的方式调用:Outer3.Inner3.show2();//表示通过外部类名直接找到静态内部类,再找到静态方法

16.2局部内部类

位置:方法里
直接创建外部类对象,调用局部内部类所处的方法,并不会触发局部内部类的功能
需要在外部类中创建局部内部类的对象并且进行调用局部内部类的功能,才能触发内部类的功能

16.3匿名内部类

位置:可运行代码中,比如 main()中
匿名内部类通常与匿名对象【没有名字的对象】一起使用
格式:new Inter1(){ 我这个大括号其实是一个匿名内部类,我来实现方法 }.eat();
如果只是想使用一次接口/抽象类的某个功能,可以使用匿名内部类
匿名内部类+匿名对象的功能:创建实现类+实现方法+方法功能的一次调用【功能三合一】