栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

面向对象笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

面向对象笔记

文章目录
  • 面向对象
    • 封装
      • 访问修饰符
      • 封装的步骤
    • 继承
      • 继承说明
      • super 关键字
      • super 和 this 的比较
      • 方法重写/覆盖(override)
      • 重写和重载比较
    • 多态
      • 编译类型和运行类型
      • 多态细节
      • 多态的向上转型
      • 多态的向下转型
      • 属性
      • Java 动态绑定机制
    • Object类详解
      • == 和 equals 的对比
      • toString 方法
      • finalize 方法
    • 类变量
      • 定义类变量
      • 如何访问类变量
      • 类变量细节
      • 类方法细节
    • 代码块
      • 基本介绍
      • 语法
      • 代码块细节
      • 类的调用顺序
      • 创建子类对象时,类的调用顺序
    • 单例设计模式
      • 单例
      • 单例模式实现步骤
      • 饿汉式与懒汉式
    • final关键字
      • 基本介绍
      • 什么情况使用final
      • final使用细节
    • 抽象类
      • 抽象类介绍
    • 接口
      • 注意细节
    • 内部类
      • 内部类的分类
      • 局部内部类
      • 匿名内部类
      • 成员内部类
      • 静态内部类

面向对象 封装 访问修饰符
访问级别访问修饰符同类同包子类不同包
公开public√√√√
受保护protected√√√×
默认无修饰符√√××
私有private√×××
封装的步骤
  1. 将属性私有化 【不能直接修改属性】
  2. 提供一个公共的(public)set 方法,用于对属性判断并赋值
  3. 提供一个公共的(public)get 方法,用于获取属性的值
继承 继承说明
  1. 子类继承了父类所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问。
  2. 子类必须调用父类的构造器, 完成父类的初始化。
  3. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无 参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过。
  4. 如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表) 。
  5. super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)。
  6. super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器。
  7. Java 所有类都是 Object 类的子类, Object 是所有类的基类。
  8. 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)。
  9. 子类最多只能继承一个父类(指直接继承),即 Java 中是单继承机制。
  10. 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系。
super 关键字
  1. 访问父类的属性,但不能访问父类的private属性

    ​ super.属性名;

  2. 访问父类的方法,不能访问父类的private方法

    ​ super.方法名(参数列表)

  3. 访问父类的构造器

    ​ super(参数列表);只能放在构造器的第一句,只能出现一句!

super 和 this 的比较

方法重写/覆盖(override)

说明:方法是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的方法重写了父类的方法。

方法重写需要满足的条件:

重写和重载比较
名称发生范围方法名参数列表返回类型修饰符
重载(overload)本类必须一样类型,个数或者顺序至少有一个不同无要求无要求
重写(override)父子类必须一样相同子类重写的方法,返回的类型和父类返回的类型一致,或者是其子类子类方法不能缩小父类方法的访问范围
多态 编译类型和运行类型
  1. 一个对象的编译类型和运行类型可以不一致。
  2. 编译类型在定义对象时就确定了,不能改变。
  3. 运行类型可以变化。
  4. 编译类型看定义时 = 的左边,运行类型看 = 的右边。
多态细节

多态的前提是:两个对象(类)存在继承关系

多态的向上转型
  1. 本质:父类的引用指向子类的对象
  2. 语法:父类类型 引用名 = new 子类类型()
  3. 特点:编译类型看左边,运行类型看右边。
  4. 可以调用父类中的所有成员(需遵守访问权限),不能调用子类中的特有成员。
多态的向下转型
  1. 语法:子类类型 引用名 = (子类类型) 父类引用;
  2. 只能强转父类的引用,不能强转父类的对象
  3. 要求父类的引用必须指向的是当前目标类型的对象
  4. 当向下转型后,可以调用子类类型中所有的成员
属性
  1. 属性没有重写之说,属性的值看编译类型,方法的调用看运行类型。
  2. instanceOf 比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的子类型。
Java 动态绑定机制
  1. 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定。
  2. 当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用。
public class DynamicBinding {
    public static void main(String[] args) {
        //a 的编译类型 A, 运行类型 B
        A a = new B();//向上转型
        System.out.println(a.sum());//30
        System.out.println(a.sum1());//20
    }
}
class A {//父类
    public int i = 10;
    //动态绑定机制:看a运行类型调用子类B的getI()方法
    public int sum() {//父类 sum()
        return getI() + 10;
    }
    public int sum1() {//父类 sum1()
        return i + 10;//属性没有动态绑定机制,直接返回当前类的值
    }
    public int getI() {//父类 getI
        return i;
    }
}
class B extends A {//子类
    public int i = 20;
    // public int sum() {
    // return i + 20;
    // }
    public int getI() {//子类 getI()
        return i;
    }
    // public int sum1() {
    // return i + 10;
    // }
}
Object类详解 == 和 equals 的对比
  1. == :既可以判断基本类型,又可以判断引用类型。
  2. == :如果判断基本类型,判断的是值是否相等。
  3. == :如果判断引用类型,判断的是地址是否相等,即判断是不是一个对象。
  4. equals :是Object类中的方法,只能判断引用类型。
  5. 默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。
toString 方法
  1. 基本介绍:默认返回:全类名+@+哈希值的十六进制,【查看 Object 的 toString 方法】 子类往往重写 toString 方法,用于返回对象的属性信息。

  2. 重写 toString 方法,打印对象或拼接对象时,都会自动调用该对象的 toString 形式。

  3. 当直接输出一个对象时,toString 方法会被默认的调用。

    比如 System.out.println(monster); 就会默认调用 monster.toString()

finalize 方法
  1. 当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法,做一些释放资源的操作。
  2. 什么时候被回收:当某个对象没有任何引用时,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用 finalize 方法。
  3. 垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过 System.gc() 主动触发垃圾回收机制。
类变量

类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。

定义类变量

访问修饰符 static 数据类型 变量名;[推荐]
static 访问修饰符 数据类型 变量名;

如何访问类变量

类名.类变量名 对象名.类变量名

类变量细节
  1. 当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量)
  2. 类变量是该类的所有对象共享的,实例变量是每个对象独享的
  3. 加上static成为类变量或静态变量,否则成为实例变量/普通变量/非静态变量
  4. 类变量是在类加载时就初始化了,及时没有创建对象,只要类加载了,就可以使用类变量了
  5. 类变量的生命周期是随着类的加载开始,随着类的消亡而销毁。
类方法细节
  1. 类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区:类方法中无this的参数
  2. 类方法可以通过类名调用,也可以通过对象名调用
  3. 普通方法和对象有关,需要通过对象名调用,不能通过类名调用。
  4. 类方法中不允许使用和对象有关的关键字,比如this和super。
  5. 类方法(静态方法)中只能访问静态变量或静态方法。
  6. 普通成员方法,既可以访问非静态成员,也可以访问静态成员。
代码块 基本介绍

代码块又称初始代码块,属于类中的成员,类似与方法,通过{}包围起来。
代码块没有方法名,没有返回,没有参数,只有方法体,而且不用通过类加载或类显式调用,而是随着类加载时,或创建对象时隐式调用。

语法

[修饰符]{}
修饰符只能是 static,使用static修饰的叫静态代码块,没有static修饰的,叫普通代码块/非静态代码块。

代码块细节
  1. static代码块(静态代码块),作用就是对类进行初始化,她随着类的加载而执行,只会执行一次。普通代码块每创建一个对象,就执行一次。

  2. 类什么时候被加载

    • 创建对象实例时(new)
    • 创建子类对象实例,父类也会被加载
    • 使用类的静态成员时(静态属性,静态方法)
  3. 普通代码块,在创建对象实例时,会被隐式的调用。

    每创建一次,就调用一次,如果只使用类的静态成员,普通代码块不会执行。

类的调用顺序
  1. 静态代码块和静态属性初始化
  2. 普通代码块和普通属性初始化
  3. 构造器:构造器的最前面隐含了super()和调用普通代码块,因此优先于构造器和普通代码块执行的。
创建子类对象时,类的调用顺序
  1. 父类的静态代码块和静态属性
  2. 子类的静态代码块和静态属性
  3. 父类的普通代码块和普通属性
  4. 父类的构造器
  5. 子类的普通代码块和普通属性
  6. 子类的构造器
public class CodeBlockDetail04 {
    public static void main(String[] args) {
        new B02();
    }
}
class A02 { //父类
    private static int n1 = getVal01(); //静态属性
    static { //静态代码块
        System.out.println("A02 的一个静态代码块..");//(2)
    }
    { //普通代码块
        System.out.println("A02 的第一个普通代码块..");//(5)
    }
    public int n3 = getVal02();//普通属性的初始化
    public static int getVal01() { //静态方法
        System.out.println("getVal01");//(1)
        return 10;
    }
    public int getVal02() { //普通方法
        System.out.println("getVal02");//(6)
        return 10;
    }
    public A02() { //构造器
    //隐藏
    //super()
    //普通代码和普通属性的初始化......
        System.out.println("A02 的构造器");//(7)
    }
}
class B02 extends A02 { //子类
    private static int n3 = getVal03(); //静态属性
    static { //静态代码块
        System.out.println("B02 的一个静态代码块..");//(4)
    }
    public int n5 = getVal04();
    { //普通代码块
        System.out.println("B02 的第一个普通代码块..");//(9)
    }
    public static int getVal03() { //静态方法
        System.out.println("getVal03");//(3)
        return 10;
    }
    public int getVal04() { //普通方法
        System.out.println("getVal04");//(8)
        return 10;
    }
    //一定要慢慢的去品..
    public B02() {//构造器
        //隐藏了
        //super()
        //普通代码块和普通属性的初始化...
        System.out.println("B02 的构造器");//(10)
    }
}
单例设计模式 单例
  1. 单例设计模式就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。
  2. 两种单例模式:饿汉式、懒汉式
单例模式实现步骤
  1. 构造器私有化,防止直接 new
  2. 类的内部创建对象
  3. 向外暴露一个静态的公共方法
public class SingleTon01 {
    public static void main(String[] args) {
        GirlFriend instance = GirlFriend.getInstance();
        System.out.println(instance);
    }
}
//饿汉式
class GirlFriend {
    private String name;
    private static GirlFriend gf = new GirlFriend("tom");

    private GirlFriend(String name) { //私有化构造器
        System.out.println("构造器被调用");
        this.name = name;
    }
    public static GirlFriend getInstance() { //方法
        return gf;
    }
    public String toString() {
        return "name=" + name;
    }
}
public class SingleTon02 {
    public static void main(String[] args) {
        Cat instance = Cat.getInstance();
        System.out.println(instance);
    }
}
//懒汉式
class Cat {
    private String name;
    private static Cat cat; //null

    private Cat(String name) { //构造器
        System.out.println("构造器被调用");
        this.name = name;
    }
    public static Cat getInstance(){
        if (cat == null) {
            cat = new Cat("小黑");
        }
        return cat;
    }
    @Override
    public String toString() {
        return "name='" + name;
    }
}
饿汉式与懒汉式
  1. 二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建。
  2. 饿汉式不存在线程安全问题,懒汉式存在线程安全问题。
  3. 饿汉式存在浪费资源的可能。如果一个对象实例没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,不存在这样的问题。
final关键字 基本介绍

final(最终的,最后的)可以修饰类、属性、方法、局部变量。

什么情况使用final
  1. 当不希望类被继承时,可以用final修饰。
  2. 当不希望父类的某个方法被子类覆盖/重写时,可以用final修饰。
  3. 当不希望类的某个属性的值被修改,可以用final修饰。
  4. 当不希望某个局部变量被修改,可以用final修饰。
final使用细节
  1. final修饰的属性又叫常量,一般用大写字母XX_XX_XX 来命名。
  2. final修饰的属性在定义时必须赋值,并且不能再修改,复制可以在以下位置:
    • 定义时
    • 构造器中
    • 代码块中
  3. 如果final修饰的属性是静态的,则初始化的位置只能在:①定义时 ②静态代码块中
  4. final类不能被继承,但可以实例化对象。
  5. 如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承。
  6. final不能修饰构造器,如果一个类已经是final类,就不需要将方法修饰成final方法了。
  7. 包装类(Integer,Double,Float,Boolean等都是final)String也是final类。
抽象类

当父类的某些方法需要声明,但是又不确定如何实现时,可以将其声明为抽象方法,这个类就是抽象类。

抽象类介绍
  1. 用abstract关键字修饰一个类/方法时,这个类就叫做抽象类/抽象方法。
  2. 抽象类的价值更多作用在于设计,是设计者设计好后,让子类继承并实现抽象类。
  3. 抽象类不能被实例化。
  4. 抽象类不一定要包含abstract方法,抽象类可以没有abstract方法。
  5. 一旦类包含了abstract方法,则这个类必须声明为abstract。
  6. abstract只能修饰类和方法。
  7. 抽象方法不能有主体。
  8. 如果一个类继承了抽象类,则必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类。
  9. 抽象方法不能使用private、final、static来修饰。
接口
  1. 接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。
  2. 接口是更加抽象的抽象类,抽象类里的方法可以有方法体,接口里的所有方法都没有方法体,接口体系了程序设计的多态和高内聚低耦合的设计思想。jdk8.0后接口类可以有静态方法、默认方法,接口中可以有方法的具体实现。
注意细节
  1. 接口不能被实例化
  2. 接口中的所有方法是public方法,接口中抽象方法可以不用abstract修饰。
  3. 一个普通类实现接口,就必须将该接口的所有方法都实现。
  4. 抽象类实现接口,可以不用实现接口的方法。
  5. 一个类可以同时实现多个接口。
  6. 接口中的属性,只能是final的,而且是public static final修饰符。
  7. 接口中属性的访问形式:接口名.属性名
  8. 接口的修饰符只能是public 和默认,这点和类的修饰符是一样的。
内部类 内部类的分类

定义在局部位置(方法中/代码块):①局部内部类(有类名) ②匿名内部类(没有类名)
定义在成员位置:①成员内部类(没用static修饰) ②静态内部类(使用static修饰)

局部内部类
  1. 可以直接访问外部类的所有成员,包含私有的。
  2. 不能添加访问修饰符,因为它的地位就是一个局部变量,但可以用final修饰。
  3. 作用域:在定义它的方法或代码块中。
  4. 局部内部类可以直接访问外部类的成员。
  5. 外部类需要创建对象,才能访问外部类成员。
  6. 外部其他类不能访问局部内部类。
  7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果要访问外部类的成员,使用(外部类名.this.成员)访问。
public class LocallnnerClass {
    public static void main(String[] args) {
        Outer01 outer01 = new Outer01();
        outer01.m1();
        System.out.println("outer01 的 hashcode=" + outer01);
    }
}
class Outer01 { //外部类
    private int n1 = 100;
    private void m2() { //私有方法
        System.out.println("Outer01 m2()");
    }
    public void m1(){ //方法
        final class Inner01{ //内部类     
            private int n1 = 800;
            public void f1(){
                System.out.println("n1=" + n1 + " 外部类的 n1=" + Outer01.this.n1);
                System.out.println("Outer01.this hashcode=" + Outer01.this);
                m2();
            }
        }
        //外部类在方法中,可以创建 Inner02 对象,然后调用方法即可
        Inner01 inner01 = new Inner01();
        inner01.f1();
    }
}
匿名内部类

①该类没有名字 ②是一个对象 ③匿名内部类是定义在外部类的局部位置,比如方法或代码块,并且没有类名 ④语法:new 类或接口(参数列表){ 类体 };

细节:

  1. 匿名内部类既是一个类的定义,同时也是一个对象。
  2. 可以直接访问外部类的所有成员,包含私有的。
  3. 不能添加访问修饰符,因为它相当于一个局部变量。
  4. 作用域:仅仅在定义它的方法或代码块中。
  5. 匿名内部类直接访问外部类成员。
  6. 外部其他类不能访问匿名内部类。
  7. 如果外部类和匿名内部类的成员重名时,默认遵循就近原则,如果要访问外部类的成员,使用(外部类名.this.成员)访问。
public class AnonymousInnerClass {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}

class Outer04 { //外部类
    private int n1 = 10;//属性
    public void method() {//方法
        //基于接口的匿名内部类
        IA tiger = new IA() {
            @Override
            public void cry() {
                System.out.println("老虎叫唤...");
            }
        };
        System.out.println("tiger 的运行类型=" + tiger.getClass());
        tiger.cry();
        //演示基于类的匿名内部类
        Father father = new Father("jack") {
            @Override
            public void test() {
                System.out.println("匿名类重写test方法");
            }
        };
        father.test();
        //基于抽象类的匿名内部类
        Animal animal = new Animal(){
            @Override
            void eat() {
                System.out.println("吃东西");
            }
        };
        animal.eat();
    }
    interface IA {//接口
        public void cry();
    }
    class Father { //类
        public Father(String name) { //构造器
        }
        public void test() { //方法
        }
    }
    abstract class Animal { //抽象类
        abstract void eat(); //抽象方法
    }
}
成员内部类
  1. 成员内部类是定义在外部类的成员位置,没有static修饰。
  2. 可以直接访问外部类的所有成员,包含私有的。
  3. 可以添加任意修饰符(public、protected、默认、private),因为它相当于一个成员。
  4. 作用域:和外部类的其他成员一样,为整个类体。
  5. 成员内部类直接访问外部类成员。
  6. 外部类需要创建对象再访问成员内部类。
  7. 外部其他类访问成员内部类。
  8. 如果外部类和成员内部类的成员重名时,默认遵循就近原则,如果要访问外部类的成员,使用(外部类名.this.成员)访问。
public class MemberInnerClass01 {
    public static void main(String[] args) {
        Outer08 outer08 = new Outer08();
        outer08.t1();
        //第一种方法
        Outer08.Inner08 inner08 = outer08.new Inner08();
        inner08.say();
        //第二种方法 在外部类中,编写一个方法,返回 Inner08对象
        Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
        inner08Instance.say();
    }
}
class Outer08 { //外部类
    private int n1 = 10;
    public String name = "张三";
    class Inner08 { //成员内部类
        public void say() { //方法
            System.out.println("n1 = " + n1 + " name = " + name);
        }
    }
    public Inner08 getInner08Instance() { //方法
        return new Inner08();
    }
    public void t1() { //方法
        Inner08 inner08 = new Inner08();
        inner08.say();
    }
}
静态内部类
  1. 静态内部类定义再外部类的成员位置,并且用static修饰
  2. 可以添加任意修饰符(public、protected、默认、private),因为它相当于一个成员。
  3. 作用域:同其他的成员,为整个类体。
  4. 静态内部类直接访问外部类成员。
  5. 外部类需要创建对象再访问静态内部类。
  6. 外部其他类访问静态内部类。
  7. 如果外部类和静态内部类的成员重名时,默认遵循就近原则,如果要访问外部类的成员,使用(外部类名.this.成员)访问。
public class StaticInnerClass01 {
    public static void main(String[] args) {
        Outer10 outer10 = new Outer10();
        outer10.hi();
        //外部其他类 使用静态内部类  方式1
        Outer10.Inner10 inner10 = new Outer10.Inner10();
        inner10.say();
        //方式2
        Outer10.Inner10 inner101 = outer10.getInner10();
        inner101.say();
    }
}

class Outer10 { //外部类
    private int n1 = 10;
    private static String name = "张三";

    static class Inner10 { //静态内部类
        public void say() { //方法
            System.out.println(name);
        }
    }
    public void hi() { //方法
        Inner10 inner10 = new Inner10();
        inner10.say();
    }
    public Inner10 getInner10() {//方法
        return new Inner10();
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1006062.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号