面向对象

面向对象 - OOP

1、类和对象

概述: 类是构造对象的模板或蓝图;- 模具

1、封装

封装 - 将数据和行为组合在一个包中,并对对象的使用者隐藏具体的实现方式;

对象中的数据 称为实例字段,操作数据的过程 称为方法

实现封装的关键,绝对不能让类中的方法直接访问其他类的实例字段; - private (属性私有化)

封装后,需要使用访问器get方法访获得实例字段值;使用更改器set方法设置实例字段;

2、超类 - Object

所有的类都源于超类 Object

3、类的关系
  • 依赖

    • 如果一个类的方法使用或操作另外一个类的对象,我们就说一个类依赖于另外一个类
  • 聚合

    • 例如一个类对象包含一些其他类对象,这就意味着类A的对象包含类B的对象;
    • 例如类A 对象里面有一个属性是类B的对象;
  • 继承

    • A类继承了B类,A类 就扩展了B类,A类不但有了从B类中继承的方法,还会有一些额外的功能;
4、对象是类的实现(类是对象的模板)
  • 创建对象的几种方法:
    • new 一个对象 - 调用构造函数
    • 通过反射得到一个对象 - 调用构造函数
    • 反序列化一个对象 - 没调用构造函数
    • clone 一个对象 - 没调用构造函数
5、对象的内存分析

(基础内存分析)

1639732366412

2、构造器 - (构造函数)

构造器是一种特殊的方法,用来构造并初始化对象;

构造器快捷键:alt+insert --> 生成构造器

/*
* 构造器的作用:
*   1、new 的本质就是调用构造方法
*   2、初始化对象的值
* 构造器:(实际上就是一个没有返回值的方法)
*   1、和类名相同
*   2、没有返回值
* */
public class Constructor01 {
    String name;
    int age;

    // 无参构造器
    public Constructor01() {
    }

    // 有参构造器
    public Constructor01(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
1、构造器必须要和类同名
  • 类中一般默认有一个空参构造器;

  • 如果在类中设置有参构造器,最好也设置一个无参构造器;

  • 每个类可以有一个以上的构造器;

2、构造器需要结合 new 运算符来调用
  • 不能对已经存在的对象调用构造器来达到重新设置实例字段的目的;
3、构造器没有返回值
4、对象需要通过 new +构造器 实例出来;
  • jvm栈 中存放对象的引用,堆中存放具体的对象
5、this 和 super
  • this 关键词 指代当前对象
  • super 关键词 指代父类对象

3、修饰符

  • public - 公共

    • 标记public 的部分可以由任意类使用;
  • protected - 受保护(子类可以调用,对其他类隐藏)

  • default - 默认的

  • private - 私有

    • 标记private 的部分只能由定义他们的类使用;
  • static - 静态

    • 静态字段(属性)- 类字段 每个类的对象都可以访问这个属性,静态字段属于类,不属于任何单个对象
    • 静态常量 - 每个类的对象都可以修改公共字段,所有最好不要有公共字段;但是静态常量不同,因为被fina 修饰,不允许在将他重新赋值;
    • 静态方法 - 静态方法不是在实例对象上执行的,所以静态方法不能访问实例字段,但是静态方法可以访问静态字段,静态方法可以直接通过类名调用;
      • 静态方法常见的用法:工厂方法;
  • fina - 常量

    • fina 修饰的类,不能被继承(就不允许被扩展),该类下所有的方法都会变成fina 方法
    • fina 修饰的方法,不能被子类继承,子类只能继承其他没被fina 修饰的方法
  • abstract - 抽象

4、包

  • 使用包的主要原因是为了确保类名的唯一性

    例如:com.ze.corejava.Employee

  • 类的导入

    一个类可以使用所属包中的所有类,以及其他包中的公共类

    两种方式访问其他包的公共类:

    • 使用完全限定名 - (一般不实用,太繁琐)

      java.time.LocalDate today = java.time.LocalDate.now();
      
    • 在当前类,使用import 语句导入一个特定的类或者整个包:

      import java.time.*;
      
      LocalDate today = LocalDate.now();
      
  • 静态导入

    在类上import static 可以导入静态方法和静态字段,而不只是类

    这样就可以直接使用这些导入静态类的方法,而不必加上类的前缀

    另外还可以直接导入特定的字段或方法(不建议 - 这样代码可读性会非常差)

  • 包中增加类 - 直接在类的源文件开头写上 package+包的全限定名

    package com.ze.corejava;
    
  • 没有指定public 和private 部分(类、方法或变量)可以被同一包中的所有方法访问;

5、jar 包

jar文件 - java归档(jar)文件:

  • 一个jar 文件既可以包含类文件(应用程序、代码库),也可以包含诸如图像、声音等其他类型的文件;

  • jar文件是压缩的,它使用的是我们非常熟悉的zip压缩格式;

  • 除了类文件、资源文件 外,每个jar文件都还包含一个清单文件,用来描述归档文件的特殊特性;

6、封装

  • 属性私有,实例字段前加上 private关键子 ---> 提高代码的安全性,保护数据
  • 利用方法获取对应的实例属性 数据 ;

7、继承

  1. 使用关键字 extends 表明 继承某个父类; -- 子类相当于父类的扩展
    1. 子类可以重写父类的方法,因此完成对父类的扩展;
  2. 被继承类称为父类,继承类称为子类,子类拥有父类所有字段属性和方法;
    1. 子类在new 的过程中会先调用父类的构造方法,然后在进行子类的实例化;
  3. 只能在继承层次内进行强制转换 - 父类转换成子类,需要进行强制转换;
  4. 父类的私有属性子类不能继承,但是可通过继承父类的公共方法,通过父类方法获取父类的私有属性;
  5. 父类的私有方法子类也不能继承,也只能通过父类的其他公共方法进行调用;
  • 继承是类和类之间的关系;

  • 一个子类只能继承一个父类,一个父类可以有多个子类(一个儿子只能有一个爸爸,一个爸爸可以有多个儿子);

  • 类和类之间的其他关系;

    • 依赖
    • 聚合
    • 组合
  • 方法的重写

    • 子类中方法名与父类方法名必须相同

    • 子类方法中的参数列表与父类的相同

    • 子类方法的修饰符范围 可以扩大,不能缩小;(例如 private --> public )

    • 子类方法抛出异常的范围 可以缩小,不能扩大;(类似子类不能 “欠债” 比父类多)(ClassNotFoundException(小) --> Exception(大))

    • 方法的重写是发生在子类继承父类中;方法的重载时发生在同一类中;

8、多态

  • instanceof 关键字 - 判断一个对象是什么类型

    public class Demo01 {
        public static void main(String[] args) {
            Person person = new Person();
            Student student = new Student();
            //判断 person 是否是Student 的实例?
            System.out.println(person instanceof Student);//false
            //判断 student 是否是Person 的实例?
            System.out.println(student instanceof Person);//true
        }
    }
    
  • 多态是提升程序的扩展性;

  • 理解:同一个人在不同环境下表现出不同的状态

  • 本质:父类或者接口的引用,指向自己的子类对象

  • 多态的前提:

    • 必须有继承关系
    • 方法必须重写
    • 父类指向自己的子类
  • 注意:

    • 多态中,子类重写了父类的方法,所以父类这个方法运行的是子类的重写方法;(父类可以调用子类重写的方法,但是子类独有的方法,父类是不能进行调用的)
    • 静态的方法与对象无关,所以运行的是对应的类型的静态方法;(静态没有多态)
    • 多态是方法的多态,属性不是多态;(变量、常量没有多态)
  • 内存分析图:

1639791330058

9、抽象类

抽象关键字 abstract

  • 包含一个或多个抽象方法的类,必须被声明为抽象;

    • 抽象方法 - 相当于定义了一个方法,但是没有具体的实现,交给子类进行实现 和 接口中的方法类似;
    • 抽象方法充当占位方法的角色
  • 抽象类中还可以包含字段和具体的方法;

  • 即使不含有抽象方法也可以把类声明为抽象类

    • 抽象类不能被实例化(不能被new ,但是存在构造器 - 类都有构造器)

理解:

  • 抽象类 相当于可以继承的接口,可以有实例字段(属性)和普通方法

  • 抽象类相当是利用多态特性的一种实现,而接口就是更进一步的约束;

  • 抽象类只能单继承(类只能单继承),接口可以多实现(多继承);

普通类 - > 抽象类 - > 接口

10、接口 - interface

1、接口概述
  • 接口可以看成是抽象的规范;

  • 一个类可以实现一个或多个接口;

  • 接口可以被接口继承;

  • 接口必须要被实现,不然接口没有意义;实现接口的类,必须重写(实现)接口的全部方法;

  • 接口中的所有方法都是自动public 的,所以可以省略关键字public;

2、接口中的属性
  • 接口中一般不会有属性,如果有属性,必须是一个公开静态常量;

    接口的属性是可以被继承的,但是不能被改变;(一般不推荐接口定义属性)

    理解:接口就像是个标准结合,里面定义的方法标准

    public interface Test01 {
        String AOU_TT = "abc"; // public static final 可以省略,会自动添加
        public static final int a = 6;
    }
    
3、接口和抽象类的区别
  • 每个类只能由继承一个父类(类单继承),每个类可以实现多个接口(接口多实现);
4、接口与静态方法和私有方法
  • 理论上是接口中是可以使用静态方法的,但是违反了将接口作为抽象类的规范初衷,所以一般把接口的静态方法放在伴随的类中
    • 很多标准库中可以看到接口和实用工具类成对出现;
  • 接口中是可以定义私有方法的,但是它们的作用很有限,只能作为接口中其他方法的辅助方法;
5、接口中方法默认实现 - 关键字default
  • 接口中方法可以默认实现 - 必须要用 default 关键字修饰

    • 但是这个一般并没有什么用,因为你的实现类会重写这个方法;
  • 一些特殊情况下,这个默认方法可能有用

    • 默认方法的一个重要用法:“接口演化”
  • 默认方法冲突:

    • 1、父类优先
      • 如果一个类继承了一个父类,也实现了一个接口,如果父类中的方法,参数都和接口中默认方法一模一样,那么子类只会考虑父类的方法,接口中一样的默认方法都会被忽略 - 类优先原则
    • 2、接口冲突
      • 如果一个类实现两个接口,两个接口中有一模一样的默认方法,java编译器会报错,然后要程序员自己解决这个二义性问题;- 在子类中写一个方法,这个方法功能就是选择一个冲突方法;
6、回调

11、lambda 表达式

lambda 表达式是一个可传递的代码块,可以在以后执行一次或多次;

(参数)->{具体实现内容(方法内容/逻辑内容}

(String a,String b)->{
    if(a.length() < b.length()) return -1;
    else if(a.length() > b.length()) return 1;
    else return 0;
}
1、lambda 表达式的简化
  • 如果可以推倒出一个lambda 表达式的参数类型,则可以忽略不写

  • 如果方法只有一个参数,而且这个参数类型可以推导,还可以省略小括号

  • 无需指定lambda表达式的返回类型,lambda表达式的返回类型总是会由上下文推导得到

    (String a,String b)->a.length()-b.length()
    
2、lambda 表达式 - 函数式接口的对象

函数式接口 :就是只有一个抽象方法的接口;

函数式接口对象:可以使用lambda 表达式表示;

12、内部类

内部类:定义在另外一个类中的类;

使用内部类的两个原因:

  • 内部类可以对同一个包中的其他类隐藏;
  • 内部类方法可以访问定义这个类的作用域中的数据,包括原本的私有数据;
1、普通内部类
  • 内部类可以访问自身字段,也可以访问创建它的外围对象的数据字段;

  • 内部类两种:一个java文件中只能由一个同级 public class类,但是可以有多个class类

    • 第一种:
    public class A {
        private int id = 1;
        public class B{ // 内部类,不同级的public可以有多个
            public void in(){
                System.out.println("这是内部类的方法");
            }
        }
    }
    
    • 第二种:
    public class A{
        
    }
    class B{// 第一级的public class 只能有一个
        
    }
    class C{
        
    }
    
  • 如果只需要类的对象,并不需要这个对象名字

    public class A{
        
    }
    
2、局部内部类(方法内部类)
  • 方法内部类的作用域被限定在声明这个局部类的快中;
  • 优势:
    • 对外部世界完全隐藏,这个方法外的其他代码方法都无法访问;
    • 可以访问外部类的所有字段,还可以访问局部变量;
3、匿名内部类
  • 只需要类的对象,并不需要类的名字可以使用匿名内部类

    public class Demo01 {
        public static void main(String[] args) {
    
            new A().test();// 匿名内部类,不需要把实例对象保存到变量,直接使用这个对象的方法
    
            // 后期可以简写成 lamb 表达式
            new B() { // 匿名接口实现高阶使用,直接使用接口的实现,并现场重写方法,然后使用方法
                @Override
                public void hello() {
                    System.out.println("方法实现");
                }
            }.hello();
        }
    }
    
    class A{
        public void test(){
            System.out.println("test");
        }
    }
    
    interface B{
        public void hello();
    }
    
4、静态内部类
  • 普通内部类,加上static 关键字,就是静态内部类;
  • 静态内部类不能直接访问外围的非静态属性;
posted @ 2021-12-21 14:56  Mxiansheng泽  阅读(68)  评论(0)    收藏  举报