7-Java核心:面向对象-代码块、内部类、static、final、抽象类、接口

目录

  • 一、类的其他成员
    • 1.1 代码块(初始化块)
    • 1.2 内部类
      • 1.2.1 成员内部类
      • 1.2.2 局部内部类
  • 二、关键字
    • 2.1 static
    • 2.2 final
  • 三、抽象类与抽象方法
    • 3.1 关键字 abstract
    • 3.2 abstract的使用注意点
    • 3.3 抽象类的匿名子类
  • 四、接口(interface)
    • 4.1 概述
    • 4.2 接口的多实现与接口的继承性
    • 4.3 接口的使用
  • 五、补充
    • 5.1 单例(Singleton)设计模式【static的应用】
    • 5.2 main方法的语法
    • 5.3 模板方法设计模式(TemplateMethod)【抽象类的应用】
    • 5.4 代理模式(Proxy)【接口的应用】
    • 5.5工厂模式(Proxy)【接口的应用】

一、类的其他成员

1.1 代码块(初始化块)

  • 作用:用来初始化类、对象
  • 代码块如果有修饰的化,只能使用static

代码块的分类:

  1. 静态代码块
  • 内部可以有输出语句
  • 随着的加载而执行,而且只执行一次
  • 作用: 初始化类的信息,比如,对静态变量赋值
  • 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
  • 静态代码块的执行优先于非静态代码块的执行
  • 静态代码块内只能调用静态的属性、方法,不能调用非静态的结构
  1. 非静态代码块
  • 内部可以有输出语句
  • 随着对象的创建而执行
  • 每创建一次对象,就执行一次非静态代码块
  • 作用: 可以在创建对象时,对对象的属性等进行初始化
  • 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
  • 非静态代码块可以调用静态 or 非静态的属性、方法

总结: 静态先行【代码块->static main】,由父及子

注: 对属性可以赋值的位置:

  1. 默认初始化
  2. 显式初始化
  3. 构造器初始化
  4. 有了对象以后,可以通过"对象.属性" 或 "对象.方法"的方式,进行赋值
  5. 在代码块中赋值
  • 先后执行顺序: 1-> 2 / 5 -> 3 -> 4

1.2 内部类

  • Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B为外部类

内部类可以分为成员内部类(静态、非静态)和局部内部类(方法内、代码块内、构造器内)

1.2.1 成员内部类

  1. 作为外部类的成员
    • 调用外部类的结构【所有成员属性和成员方法(包括静态成员和私有成员)】
    • 成员内部类和外部类的属性和方法名同名时,外部类的属性和方法会隐藏;但可以通过"外部类.this.成员变量 "的方式访问外部类的属性和方法
    • 可以被static关键字修饰——静态内部类
    • 可以被4种不同的权限修饰【外部类只能public 或缺省】
  2. 作为一个类
    • 类内可以定义属性、方法、构造器等
    • 可以被final关键字修饰,表示此类不能被继承<—> 不使用final,就可以被继承
    • 可以被abstract 关键字修饰

1.2.2 局部内部类

局部内部类是定义在一个方法、一个代码块、一个构造器内的类

特点:

  • 不能有private、public、protected和static等修饰符,与局部变量类似
  • 只能在定义局部内部类的方法或者作用域中实例化;
  • 局部内部类的对象不能使用该内部类所在方法或者作用域的非final局部变量

问题:
1.如何实例化成员内部类的对象?

静态会随着类的加载而加载

        //创建Dog实例(静态的成员内部类)
        PersonB.Dog dog = new PersonB.Dog();
        dog.show();
        //创建Bird实例(非静态的成员内部类)
//        PersonB.Bird bird = new PersonB.Bird();
        PersonB p = new PersonB();
        PersonB.Bird bird = p.new Bird();
        bird.sing();

2.如何在成员内部类中区分调用外部类的结构

        public void display(String name){
            System.out.println(name);//方法的形参
            System.out.println(this.name);//内部类的属性
            System.out.println(PersonB.this.name);//外部类的属性
        }

3.开发中局部内部类的使用
一个方法会返回会一个局部内部类对象,其中,局部内部类实现了某个接口,具体使用可以先定义一个实现类,或者直接返回匿名类的匿名对象

二、关键字

2.1 static

static 可以用来修饰:属性、方法、代码块、内部类【主要用来修饰类的内部结构,随着类的加载而加载:类加载中->构造器->对象,所以不包括构造器】

  1. 使用static 修饰属性:静态变量(或类变量)
  • 属性按是否用static修饰,又分为 静态属性非静态属性(实例变量)
    • 实例变量: 当创建了类的多个对象后,每个对象都独立的拥有一套类中的非静态属性;因此,当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改
    • 静态变量:创建了类的多个对象后,多个对象共享同一个静态变量;当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时是修改过的
  • 静态变量随着类的加载而加载——早于对象的创建——可以直接用 "类名.静态变量="的方式进行调用,如初始化静态变量
  • 由于类只会加载一次,则静态变量在内存中也只会存在一份。,存在方法的静态域中
  1. 使用static修饰方法:静态方法
  • 随着类的加载而加载,可以通过 "类名.静态方法="的方式进行调用
  • 静态方法中,只能调用静态的方法或属性【生命周期是一致的】;非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
  1. static 注意点:

在静态的方法内,不能使用this关键字、super关键字【这两个的声明周期在static后面,或者说是基于对象的】

  1. 开发中,如何确定一个属性/方法是否要声明为static?
  • 对于属性:
    • 可以被多个对象所共享且不会随着对象的不同而不同
    • 类中的常量也常常声明为static
  • 对于方法:
    • 操作静态属性的方法,通常设置为static
    • 工具类中的方法,习惯上声明为static,如 Math、Arrays、Collection

注: Java内部布局:

  • 栈:局部变量
  • 堆:new出来的结构——对象、数组
  • 方法区:类的加载信息、静态域、常量池

2.2 final

final 可以用来修饰的结构:类、方法、变量

  1. 使用 final 修饰一个类:此类就不能被其他类所继承;比如 String、System、StringBuffer
  2. 使用 final 修饰一个方法:此方法就不能被重写
  3. 使用 final 修饰一个变量:此时的“变量”就称为一个常量
    • final修饰属性:可以考虑的赋值位置有:显式初始化、代码块中初始化、构造器中初始化
    • final修饰局部变量:该局部变量就是常量,包括一个以final修饰的形参,此时就不能对此类变量进行重新赋值操作【此外,final B b,b这个对象不能重新赋值/重新指向,但里面的属性可以变】

static final: 用来修饰属性:全局常量

三、抽象类与抽象方法

3.1 关键字 abstract

abstract 可以用来修饰的结构:类、方法

  1. abstract 修饰类:抽象类
  • 此类不能实例化
  • 抽象类中一定有构造器,便于此类对象实例化使用(涉及子类对象实例化的全过程
  • 开发中会提供抽象类的子类,让子类对象实例化,完成相关操作
  1. abstract 修饰方法:抽象方法
  • 抽象方法只有方法的声明,没有方法体
  • 包含抽象方法的类一定是一个抽象类【要保证该方法不能被调用】,反之,抽象类里可以没有抽象方法
  • 若子类重写了父类中的所有的抽象方法,此子类方可实例化;若子类没有重写父类中的所有的抽象方法,则子类也是一个抽象类,需要使用abstract修饰

3.2 abstract的使用注意点

  1. abstract不能用来修饰:属性、构造器等结构
  2. abstract不能用来修饰:
    • 私有方法【子类不是抽象类的话就必须重写父类的抽象方法,矛盾】
    • 静态方法【静态的只有一个不需要重写,子类需要重写抽象方法,矛盾】
    • final方法【不让重写,矛盾】
    • final类【不让继承,矛盾】

注: 抽象类可以继承非抽象的类,如Object类

3.3 抽象类的匿名子类

7-Java核心:面向对象-代码块、内部类、static、final、抽象类、接口_第1张图片

//创建了一个匿名子类的对象 p
        PersonA p = new PersonA(){

            @Override
            public void eat() {
                System.out.println("匿名子类吃东西");
            }

            @Override
            public void breathe() {
                System.out.println("匿名子类呼吸");
            }
        };
        method1(p);
        System.out.println("*****************");
        //创建匿名子类的匿名对象
        method1(new PersonA() {
            @Override
            public void eat() {
                System.out.println("好好吃饭");
            }

            @Override
            public void breathe() {
                System.out.println("好好呼吸");
            }
        });
   public static void method1(PersonA p){
        p.eat();
        p.breathe();
   }

四、接口(interface)

4.1 概述

Java中,接口和类是并列的结构

如何定义接口: 定义接口中的成员

  • JDK7以前:只能定义全局常量和抽象方法
    • 全局常量: public static final,但可以省略不写
    • 抽象方法:public abstract,但可以省略不写
  • JDK8以后:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
    • 接口中定义的静态方法,只能通过接口来调用
    • 通过实现类的对象,可以调用接口中的默认方法
    • 如果实现类重写了接口中的默认方法,则调用时为实现类中重写的方法
    • 如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么在子类没有重写此方法的情况下,默认调用的是父类中的同名同参的方法——类优先原则
    • 如果实现类实现了多个接口,而者多个接口定义了同名同参的默认方法,那么在实现类没有重写此方法的情况下,报错——接口冲突解决方式为在实现类中重写此方法
    • 使用” 接口名.super.方法名"调用接口中的被重写的方法,或者"super.方法名"调用父类中的被重写的方法
      注:
  • 接口中 不能定义构造器,说明接口不可以实例化
  • 开发中,接口通过让类去实现(implements) 的方式【面向接口编程】来使用:
    • 如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
    • 如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类

4.2 接口的多实现与接口的继承性

Java类可以实现多个接口,意味着弥补了Java单继承的局限性

格式: class AA extends BB implements CC,DD,EE
7-Java核心:面向对象-代码块、内部类、static、final、抽象类、接口_第2张图片

接口与接口之间可以继承,而且可以多继承

格式: interface CC extends AA,BB{}

4.3 接口的使用

  • 接口的具体使用体现多态性
  • 接口实质上可以看作是一种规范

面试题:

  1. 代码找错
public class test0 extends B implements A{
    public void px(){
        System.out.println(x);
    }

    public static void main(String[] args) {
        new test0().px();
    }
}
interface A{
    int x = 0;
}
class B{
    int x = 1;
}

7-Java核心:面向对象-代码块、内部类、static、final、抽象类、接口_第3张图片
改正:

        //编译不通过,x模糊
        //System.out.println(x);
        System.out.println(super.x);//父类的
        System.out.println(A.x);//全局变量
		//或者,父类和接口中的名字不一样
  1. 抽象类与接口有哪些异同?
  • 相同点:不能实例化;都可以包含抽象方法;可以被继承
  • 不同点:
    • 抽象类和接口的定义、内部结构解释说明
    • 类:单继承,接口:多继承;接口:多实现

五、补充

5.1 单例(Singleton)设计模式【static的应用】

设计模式 是在大量的实践中中介和理论化之后优选的代码结构、编程风格以及解决问题的思考方式【“套路”】

单例设计模式: 采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例 ,并且该类只提供一个取得对象的方法

—— 类的构造器的访问权限设置为private:这样就不能用new操作符在类的外部产生类的对象了,只能在类内部产生该类的对象
——在类内部创建一个静态对象
——提供一个静态方法以返回类内部创建的对象
——指向类内部产生的该类对象的变量也必须定义成静态的

具体步骤:

  1. 饿汉式
public class SingletonTest0 {
    public static void main(String[] args) {
        Bank bank1 = Bank.getInstance();
        Bank bank2 = Bank.getInstance();
        System.out.println(bank1 == bank2);
    }
}
class Bank{
    //1.私有化类的构造器
    private Bank(){

    }
    //2.类内部创建类的对象
    //4.要求此对象也必须声明为静态的
    private static Bank instance = new Bank();
    //3.提供公共的静态的方法,返回内部对象
    public  static Bank getInstance(){
        return instance;
    }
}
  1. 懒汉式
public class SingletonTest1 {
    public static void main(String[] args) {
        Order o1 = Order.getInstance();
        Order o2 = Order.getInstance();
        System.out.println(o1 ==  o2);
    }
}
class Order{
    //1.私有化类的构造器
    private Order(){

    }
    //2.声明内部类对象
    //4.此对象也必须声明为static
    private static Order instance = null;//这里就是主要区别
    //3.声明公共的静态的返回内部类对象的方法
    public static  Order getInstance(){
        if(instance == null){//没有判断,那不得调一次方法创建一次对象
            instance  = new Order();
        }
        return instance;
    }

}

一点想法: 是不是可以联想装箱的valueOf,比如Integer的范围-128 ~ +127

区分饿汉式与懒汉式:

  • 饿汉式
    • 好处:线程安全
    • 缺点:对象加载时间过长
  • 懒汉式:
    • 优点:延迟对象的创建
    • 缺点:线程不安全【eg,两个线程同时进入静态方法,同时判断为null -> 同时new】---- > 后续会优化

应用场景
7-Java核心:面向对象-代码块、内部类、static、final、抽象类、接口_第4张图片

5.2 main方法的语法

  1. main()方法是程序的入口
  2. main()方法也是一个普通的静态函数
  3. main()方法可以作为与控制台交互的方式,看下图

7-Java核心:面向对象-代码块、内部类、static、final、抽象类、接口_第5张图片
7-Java核心:面向对象-代码块、内部类、static、final、抽象类、接口_第6张图片

5.3 模板方法设计模式(TemplateMethod)【抽象类的应用】

当功能内部一部分实现是确定的,一部分实现是不确定的,这时可以把不确定的部分暴露出去,让子类去实现
具体做法:类为抽象类,不确定的方法是抽象方法

5.4 代理模式(Proxy)【接口的应用】

代理设计就是为其他对象提供一种带来以控制对这个对象的访问
会用到多态
7-Java核心:面向对象-代码块、内部类、static、final、抽象类、接口_第7张图片

7-Java核心:面向对象-代码块、内部类、static、final、抽象类、接口_第8张图片

5.5工厂模式(Proxy)【接口的应用】

实现了创建者与调用者的分离,即将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的
实例化对象这个操作由工厂来做【包装new操作】

注: 设计模型和面向对象设计,原则都是为了使得开发项目更加容易扩展和维护,解决方式就是“分工”

工厂模式的分类:

  • 简单工厂模式:用于生产同一等级结构中的任意产品(对于增加新的产品,需要修改已有的代码,不能进行扩展即违反了开闭原则OCP——对扩展开放,对修改关闭
  • 工厂方法模式:用来生产同一等级结构中的固定产品——设置一个工厂接口,再细分为不同产品的产品工厂【不同的实现类】(支持增加任意产品,但还是无法正真避免代码改动,增加新产品时要么再抽象工厂【接口】中增添判断逻辑——像简单工厂一样,要么再重新写一个新产品对应的工厂——这也是写死了)—— 一种解决: Java的反射机制结合配置文件
  • 抽象工厂模式:用来生产不同产品族的全部产品(对于增加新的产品,无能为力:支持增加产品族)

你可能感兴趣的:(JAVA-SE,java)