2.4.面向对象高级

4.1 继承

4.1.1 定义

  • 子类继承父类的特征(属性)行为(方法)

4.1.2 子类实例化内存分析

  • 创建子类对象时先创建父类对象
  • super()关键字相当于获取父类地址

4.1.3 super

  • 子类构造方法中super和this不能同时出现
  • 调用super构造方法的代码,必须写在子类构造方法的第一行

4.2 重写(override)

  1. 参数列表、返回类型必须与被重写的方法相同
  2. 访问权限不能比父类中被重写的防范权限
  3. 声明为staticprivate的方法不能被重写,但能够被再次声明

面试题:重写和重载区别

  1. 发生位置:
  • 重写:父子类中
  • 重载:一个类中
  1. 参数列表限制:
  • 重写:必须相同
  • 重载:必须不同
  1. 返回值类型
  • 重写:必须相同
  • 重载:与此无关
  1. 访问权限:
  • 重写:子类不小于父类
  • 重载:与此无关
  1. 异常处理
  • 重写:异常范围可更小,但不能跑出新异常
  • 重载:与异常无关

4.3 final

4.3.1 作用

  1. 修饰变量
  • 修饰的局部变量,只能赋值一次,可先声明后赋值
  • 修饰的成员变量,必须在声明时赋值
  1. 修饰类
  • 不能被继承
  1. 修饰方法
  • 不能被子类重写

面试题:fianL不能改变的是引用还是对象

  • 不能改变的是引用
  1. 引用数据类型
  2. 基本数据类型

4.4 抽象类

4.4.1 原则

  1. 不能直接实例化
  2. 可以有自己的属性、非抽象方法
  3. 子类(非抽象类)需实现所有的抽象方法
  • 只实现一部分父类抽象方法,则该子类为抽象类,若加abstract修饰后,可不实现父类抽象方法
  • 若父类中有未实现的抽象方法,不管继承几代,子类(非抽象类),应实现剩余的抽象方法
  • 父类引用指向子类对象时,若子类想调用所有父类的方法,应选择最邻近的父类引用

4.4.2 常见问题

  1. 抽象类能否使用final声明
  • 不能,因为final修饰的类不能有子类,而抽象类必须有子类才有意义
  1. 抽象类能否有构造方法
  • 能,且子类实例化时和普通类一致

4.4.3 抽象类和普通类的区别

  1. 抽象类必须由public或protected修饰,缺省默认public
  2. 抽象类不能使用new创建对象,但子类实例化时,父类也会被JVM实例化
  3. 子类(非抽象类)需实现父类所有方法

4.5 接口

4.5.1 要素

  • 全局常量:默认缺省public static final,声明时赋初值
  • 抽象方法(不能含有非抽象方法):默认缺省public abstract

4.5.2 优点

  • 降低程序耦合性
  • 利于程序扩展维护

4.5.3 接口和抽象类区别

  1. 接口被实现,抽象类被继承
  2. 接口中的变量时全局常量,抽象类中的变量是普通变量
  3. 接口中的方法都是抽象方法,抽象类中的方法可以有非抽象方法
  4. 接口无构造方法,抽象类有构造方法
  5. 接口无static修饰的方法,抽象类**有*
  6. 接口可被多继承,抽象类只能被单继承

4.6 多态

4.6.1 体现

  1. 对象多态:子类是父类的一种形态
  2. 方法多态:
  • 重写:子父类方法
  • 重载:一个类中方法体现

4.6.2 instanceof

4.6.2.1 作用

  • 判断某一对象是否是该类的实例

4.6.2.2 用法

  • 实例对象 instanceof 类
    Student s=n(Student)new Person();
    if(s instanceof Student) ...

4.6.3 对象类型转换

  • 转型:看声明类型权限,权限高则为向上,反之向下
  1. 向上转型:父类实例-->子类实例(安全,父类引用指向子类对象)

  1. 向下转型:子类实例-->父类实例(不安全,需通过instanceof判断)

4.7 内部类 (不常用)

4.7.1 类型

  1. 成员内部类
  2. 静态内部类
  3. 局部内部类
  4. 匿名内部类

4.7.2 用法

4.7.2.1 成员内部类

  • 创建内部类对象需依托外部对象
  • 内部类对象创建结束后,可无条件访问外部类属性和方法
    • 访问方式:外部类.this.外部类属性/方法
  • 内部类和外部类具有相同属性或方法时,默认访问内部类的成员
public class Outer {
    int x=10;
    public static void main(String[] args) {
        Outer.Inner i=new Outer().new Inner();
        i.say();
    }

    class Inner{
        private int x=20;
        void say() {
            System.out.println("内部类方法1");
            System.out.println(x);//成员变量x的值
            System.out.println(Outer.this.x);//调用外部类属性
            Outer.this.say();//调用外部类方法
        }
    }
    
     void say() {
        System.out.println("外部类方法");
    }
}


4.7.2.2 静态内部类

  • 创建内部类对象无需依托外部类对象
  • 不能使用外部类非static成员变量和方法
    • 使用方法:外部类.属性/方法
public class Outer2 {
    static int x=10;
    public static void main(String[] args) {
        Outer2.Inner2 i = new Outer2.Inner2();
        i.say2();
    }

    static class Inner2{    
        void say2() {
            System.out.println("内部类方法2");
            System.out.println(Outer2.x);//调用外部类属性
            Outer2.say2();//调用外部类静态方法
        }
    }

    static void say2() {
        System.out.println("外部类方法2");
    }
}


4.7.2.3 局部内部类

  • 必须继承一个类实现一个接口
  • 继承的类可以是抽象类或普通类
    //person接口
    public interface Person {
    void say();
    }
    public class Outer3 {
    public static void say(Person p) {
        p.say();
    }

    public static void main(String[] args) {
        class Student implements Person{
            @Override
            public void say() {
                System.out.println("内部类方法3");
            }
        }
        Student s=new Student();
        Person p=new Student();
        say(s);
        say(p);
    }
}


    public class Animal {
        void say() {
            System.out.println("内部类方法4");
        }
    }

    public class Outer4 {

    public static void say(Animal a) {
        a.say();
    }

    public static void main(String[] args) {
        class Dog extends Animal {
            @Override
            void say() {
                super.say();
            }
        }

        Dog d=new Dog();
        say(d);
    }
}

4.7.2.4 匿名内部类

4.7.2.4.1 定义

  • 局部内部类的一种,创建形式不同
  • 内部类后加分号

4.7.2.4.2 要点

  1. 必须继承或实现一个接口
  2. 不能定义构造函数
  3. 不能存在任何的静态成员变量和静态方法
  4. 不能是抽象类,必须实现继承的类或实现的接口的所有抽象方法
  5. 只能访问final型局部变量
    public class Outer5 {

    public static void say(Person p) {
        p.say();
    }
    public static void main(String[] args) {
        Person p=new Person() {
            @Override
            public void say() {
                System.out.println("内部类方法5");
            }
        };

        say(p);
    }
}

    public class Outer6 {
    public static void say(Animal2 a2) {
        a2.say();
    }

    public static void main(String[] args) {
        Animal2 a2=new Animal2() {
            @Override
            void say() {
                System.out.println("内部类方法6");
            }
        };

        say(a2);
    }
}

面试题:内部类为何只能访问final局部变量

  • java1.8前局部变量需final定义,1.8后可缺省
  • 内部类会被单独编译成一个字节码文件,其中用到的局部变量值是通过备份所得,为了保证值一致性,系统规则限制值不可更改

4.8 包装类

4.8.1 方法

4.8.2 装箱

    Integer a=new Integer(10);//手动,已过时
    Integer b=Integer.valueOf(20);
    Integer a=20;//自动

4.8.3 拆箱

    int b=a.intValue();//手动
    int b=a;//自动

4.8.4 和字符串转换

    int a=Integer.parseInt(text);//text需为数字

4.9 可变参数(不常用)

4.9.1 位置

  • 只能出现在参数列表的最后

4.9.1 用法:参数类型+省略号+形参名

   int sing(int... nums) {
        int n=0;
        for (int i = 0; i < nums.length; i++) {
            n += nums[i];
        }
        return n;
    }

4.10 异常

4.10.1 定义

  • 异常是在程序中导致程序中断运行的一种指令流

4.10.2 体系结构

  • Throwable存在两个子类:
  1. Error:JVM发出的错误操作,只能尽量避免,无法用代码处理
  2. Exception:所有程序中的错误,所以一般在程序中将进行try…catch的处理。

4.10.2.1 类型(面试题)

  1. 受检异常(编译时异常)
  2. 非受检异常(运行时异常)

4.10.3 处理格式

    try{// 有可能发生异常的代码段 
    }catch(异常类型1 对象名1){ // 异常的处理操作 
    
    }catch(异常类型2 对象名2){// 异常的处理操作
    
    }finally{ // 异常的统一出口 }

4.10.4 处理流程

  1. 一旦产生异常,则系统会自动产生一个异常类的实例化对象
  2. 若异常发生在try语句,则会自动找到匹配的catch语句执行

4.10.5 finally

4.10.5.1 定义

  • 不管是否产生了异常,最终都要执行此段代码。

面试题:什么情况下finally语句不执行

  1. 代码情况:System.exit(0);//退出JVM
  2. 其他情况:断电,程序退出内存

扩展:即便try语句中有return,finally语句也会执行

4.10.5.2 对return值的影响

  • 引用数据类型值受影响
    class Person {
        int age;
    }

    public static void main(String[] args) {
        System.out.println("返回后的age值:" + fun2().age);//20
    }
    
    public static Person fun2() {
        Person p = new Person();
        try {
            p.age = 10;
            return p;
        } catch (Exception e) {
            return null;
        } finally {
            p.age = 20;
            System.out.println("修改后的age值:" + p.age);//20
        }
    }


  • 基本数据类型值不受影响
    public static void main(String[] args) {
        System.out.println("返回的a值为:"+fun1());//10
    }

    public static int fun1() {
        int a=10;
        try {
            return a;
        } catch (Exception e) {
            return 0;
        }finally {
            a=20;
            System.out.println("修改后的a值为:"+a);//20
        }
    }


  • 原因
  • retrun在返回值之前有个准备过程,finally在此期间执行
  • return返回的值是通过备份所得
  • 对于引用数据类型,备份的是堆空间中的地址,对于基本数据类型,备份的是初始值
  • 要点
  • 修改后的值返回后的值不一定相同

4.10.6 throws

  • 传参导致异常,应将异常抛出(方法抛)

4.10.7 throw

  • 人为抛出一个异常(代码内部抛)
posted @ 2021-03-24 22:40  芥纳须弥  阅读(44)  评论(0)    收藏  举报