八、面向对象编程(高级)

一、类变量与类方法

1.1 类变量快速入门

在这里插入图片描述

class Child{
    private String name;
    // 定义一个变量count,是一个类变量(静态变量)static 静态
    // 改变量最大的特点就是会被Child类的所有对象实例访问
    public static int count = 0;

    public Child(String name){
        this.name = name;
    }

    public void join(){
        System.out.print(name + "加入了游戏");
    }
}

在这里插入图片描述

  • 注意:JDK1.8之前,静态变量在方法区中的静态域中;JDK1.8及之后,静态域存储于定义类型的Class对象中,Class对象如同堆中其他对象一样,存在于GC堆中

  • 记住一点:static变量是对象共享的,不管 static 变量在哪里,共识 (1) static 变量被同一个类所有对象共享 (2) static类变量,在类加载的时候就生成了

1.2 什么是类变量

  • 类变量 是随着类的加载而创建的,所以即使没有创建对象实例也可以通过类访问
package com.codeblock;

public class CodeBlockDetail01 {
    public static void main(String[] args) {

        // AA被加载时,按顺序初始化类变量(n2 --> n1)
        // out:   1. getN1被执行(初始化时的打印)    2. 200(调用类变量的返回)
        
        System.out.println(AA.n2); 
    }
}

class AA{

    public static int n2 = 200;
    public static int n1 = getN1();

    public static int getN1(){
        System.out.println("getN1被执行");
        return 100;
    }

}

在这里插入图片描述

1.3 类变量使用注意事项和细节讨论

在这里插入图片描述

在这里插入图片描述

1.4 类方法基本介绍

在这里插入图片描述

1.5 类方法使用场景

在这里插入图片描述

1.6 类方法的注意事项和细节讨论

在这里插入图片描述

在这里插入图片描述

二、理解main方法 static

在这里插入图片描述

在这里插入图片描述

三、代码块

3.1 基本介绍

  • 代码块 仅用于 加载类创建对象
    在这里插入图片描述

在这里插入图片描述

3.2 代码块使用注意事项和细节讨论

在这里插入图片描述

package com.codeblock;

public class CodeBlockDetail01 {
    public static void main(String[] args) {
        AA a = new AA(); // 执行静态代码块的内容
        AA aa = new AA(); // 由于AA类已被加载,则不会执行静态代码块中的内容
    }
}

class AA{
    // 静态代码块
    static{
        System.out.println("AA的静态代码块1");
    }

}

在这里插入图片描述

public class CodeBlickDetail2{
    public static void main(String[] args){
        // 类变量的显示初始化 与 静态代码块中的内容按顺序执行
        // 属性的显示初始化 与 成员代码块中的内容按顺序执行
        A a = new A(); // 1. getN1被执行...   2. 静态代码块被执行...  3. getN2被执行...  4. 普通代码块被执行...
    }
}

class A{
    private int n2 = getN2();
    {
        System.out.println("普通代码块被执行...");
    }

    public static int n1 = getN1();
    static{
        System.out.println("静态代码块被执行...");
    }

    public static int getN1(){
        System.out.println("getN1被执行...");
        return 100;
    }
    
public static int getN2(){
        System.out.println("getN2被执行...");
        return 200;
}

}

在这里插入图片描述

class A{
    public A(){ // 构造器
        // 这里隐藏的执行要求
        // (1) super();
        // (2) 代用普通代码块与属性初始化
        System.out.println("ok");
    }
}

在这里插入图片描述

package com.codeblock;

public class CodeBlockDetail01 {
    public static void main(String[] args) {
        new BB();
    }
}

class AA{

    public int aa02 = getAa02();

    {
        System.out.println("AA code block 执行..."); // (6)
    }

    public int getAa02(){
        System.out.println("getAa02执行..."); // (5)
        return 200;
    }

    public static int aa01 = getAa01();
    static {
        System.out.println("AA static code block 执行..."); // (2)
    }

    public static int getAa01() {
        System.out.println("getAa01执行..."); // (1)
        return 1;
    }

    public AA(){
        // 调用Object的构造器(略)
        // 执行 代码块 与 属性初始化
        System.out.println("AA 的构造器"); // (7)
    }

}

class BB extends AA{
    public int bb02 = getBb02();

    {
        System.out.println("BB code block 执行..."); // (9)
    }

    public int getBb02(){
        System.out.println("getBb02执行..."); // (8)
        return 100;
    }

    static {
        System.out.println("BB static code block 执行..."); // (3)
    }

    public static int bb01 = getBb01();

    public static int getBb01() {
        System.out.println("getBb01执行..."); // (4)
        return 10;
    }

    public BB(){
        // 调用AA的构造器
        // 执行 代码块 与 属性初始化
        System.out.println("BB 的构造器"); // (10)
    }

}

四、单例模式

在这里插入图片描述

  • 什么是单例模式
    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

五、final关键字

5.1 final的基本介绍

在这里插入图片描述

5.2 final使用注意事项和细节讨论

在这里插入图片描述

  • 注意如果对方法的形式参数使用 final ,则在方法内部不能对该形参变量重新赋值;但是,如果是引用类型的形参变量被加了 final,是可以对其属性进行修改的 (本质是该局部变量的值一直都是引用变量的地址)
    在这里插入图片描述

六、抽象类

6.1 抽象类的引入

在这里插入图片描述

abstract class Animal{
    public String name;
    public int age;
    public Animal(String name, int age){
        this.name = name;
        this.age = age;
    }
    
    // 这里 eat 实现了,其实也没有什么意义
    // 即:父类方法不确定性的问题
    // ====> 考虑将该方法设计为抽象(abstract)方法
    // ====> 所谓抽象方法就是没有实现的方法
    // ====> 所谓没有实现就是指,没有方法体
    // ====> 当一个类中存在抽象方法时,需要将该类声明为 abstract 类
    // public void eat(){
    //     System.out.println();
    // }
    public abstract void eat();
    
}

在这里插入图片描述

6.2 抽象类基本介绍

在这里插入图片描述

  • 抽象类使用的注意事项和细节讨论
    在这里插入图片描述

在这里插入图片描述

// 对于上述第7点
abstract class E{
    public abstract void hi();
}

// 继承抽象类的,第一种情况:可以不对抽象方法进行实现
abstract class F extends E{
    
}

// 继承抽象类的,第二种情况
abstract class G extends E{
    public abstract void hi(){ // 重写了抽象类的方法

    }
}

在这里插入图片描述

注意:Java中类方法不能被重写,而 抽象方法 存在的意义就是被子类重写

6.3 抽象类的最佳实践

在这里插入图片描述

在这里插入图片描述

七、接口

7.1 接口的引入

在这里插入图片描述

7.2 接口的基本介绍

在这里插入图片描述

package com.interface_;

public class TestInterface {

}

interface Interface{
    // 属性强制是 public static final 修饰,可以不写
    // 方法(除默认方法)强制是 public abstract 修饰,可以不写
    // 默认方法是 public 修饰的

    // 写属性,默认是 public static final 可以省略不写
    public static final String str = "Hello";

    // 写方法
    // 在接口中,抽象方法,可以省略abstract关键字 和 public修饰符
    void hi();

    // 在jdk1.8后,可以有默认实现方法,需要使用 default关键字修饰
    default void ok(){
        System.out.println("ok ....");
    }

    // 在jdk1.8后,可以有静态方法
    static void test1(){

    }

}

7.3 接口的深度讨论

在这里插入图片描述

在这里插入图片描述

7.4 接口的注意事项和细节

在这里插入图片描述

在这里插入图片描述

  • 注:接口之间是继承(支持多继承),接口之间是实现。

7.5 实现接口 vs 继承类

在这里插入图片描述

  1. 注:接口是对java单继承的扩展。当子类继承了父类,就自动的拥有父类的功能。如果子类需要扩展功能,可以通过实现接口的方式扩展
  2. 更通俗的理解,继承 主要使子类中拥有父类的方法,侧重于复用性; 接口实现 主要使类中实现接口的抽象方法 侧重于 重写

在这里插入图片描述

7.5 接口的多态特性

在这里插入图片描述

// 接口多态传递现象
public class InterfacePolyPass{
    public static void main(String[] args){
        IG ig = new Teacher(); // 接口引用可以指向
        IH ih = new Teacher(); // 接口多态传递
    }

interface IH{}
interface IG extends IH{} // 继承了 IH 接口
class Teacher implements IG{}
}

八、内部类

8.1 内部类基本介绍

  • 类的五大属性:属性方法构造器代码块内部类
    在这里插入图片描述

在这里插入图片描述

8.2 局部内部类

  • 方法体代码块 中定义的 (常见的是在方法体中定义类)
    在这里插入图片描述

在这里插入图片描述

package com.innerclass;

public class InnerTest {
    public static void main(String[] args) {
        Outer o = new Outer();
        System.out.println(o.f1());
    }
}

class Outer {
    private int n1 = 1;

    public int f1() {
        class Inner { // 方法中的局部内部类
            private int n1 = 1; // 与外部类的属性重名
            private int n2 = 2;

            public int getN2() {
                return this.n2;
            }

            public void test() {
                // 需要访问外部类的属性(与内部类中属性重名)
                // Outer.this 的本质就是外部类的对象,即哪个对象调用了f1,  Outer.this 就是哪个对象
                System.out.println(Outer.this.n1);
            }
        }
        Inner inner = new Inner();
        inner.test();
        return inner.getN2();
    }

}

8.3 匿名内部类

在这里插入图片描述

package com.innerclass;

public class InnerAnonyClass {
    public static void main(String[] args) {
        Outer04 o = new Outer04();
        o.method();
    }
}

class Outer04 { // 外部类
    private int n1 = 10;

    public void method() {
        // 基于接口的匿名内部类
        // 解读
        // 1. 需求:想使用IA接口,并创建对象
        // 2. 传统方式,是写一个类,实现该接口,并创建对象
        // 3. 老韩需求是 Tiger 类只是使用一次,后面再不使用
        // 4. 可以使用匿名内部类来简化开发
        // 5. tiger 的编译类型? IA
        // 6. tiger 的运行类型? 就是匿名内部类  Outer04$1
        /*
        底层 会分配 类名 Outer04&1
        class Outer04$1 implements IA {
            @Override
            public void call() {
                System.out.println("老虎叫唤...");
            }
        }
         */
        // 7. jdk底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例,并且把地址
        // 放回 tiger
        // 8. 匿名内部类只能使用一次,就不能再使用(指的是该类的实例被加载进堆后,其类信息就被释放掉)
        IA tiger = new IA() {
            @Override
            public void call() {
                System.out.println("老虎叫唤...");
            }
        };
        tiger.call();

        // 演示基于类的匿名内部类
        // 分析
        // 1. father的编译类型? Father
        // 2. father的运行类型? Outer04$2
        // 3. 底层会创建匿名内部类
        /*
        class Outer04$2 extends Father {
            @Override
            public void test() {
                System.out.println("匿名内部类重写了test方法");
            }
        }
         */
        // 4. 同时也直接返回了 匿名内部类 outer04$2的对象
        // 5. 注意 ("jack") 参数列表会传递给 构造器
        Father father = new Father("jack") {
            @Override
            public void test() {
                System.out.println("匿名内部类重写了test方法");
            }
        };
        father.test();

        // 基于抽象类的匿名内部类
        Animal animal = new Animal() {
            @Override
            public void eat() {
                System.out.println("小狗吃骨头...");
            }
        };

        animal.eat();

    }
}

interface IA {
    void call();

}

class Father {
    private String name;

    public Father() {
    }

    public Father(String name) {
        this.name = name;
    }

    public void test() {
        System.out.println("test...");
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

abstract class Animal {
    public abstract void eat();
}

8.3.1 匿名内部类的使用注意事项

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

8.3.2 匿名内部类的最佳实践

在这里插入图片描述

8.4 成员内部类

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

8.5 静态内部类

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

九、细节

9.1 static变量

  • 注意:JDK1.8之前,静态变量在方法区中的静态域中;JDK1.8及之后,静态域存储于定义类型的Class对象中,Class对象如同堆中其他对象一样,存在于GC堆中

  • 记住一点:static变量是对象共享的,不管 static 变量在哪里,共识 (1) static 变量被同一个类所有对象共享 (2) static类变量,在类加载的时候就生成了

9.2 类变量与类方法

  • 子类是不继承父类的static变量和方法的。因为这是属于类本身的。但是子类是可以访问的。
  • 子类父类同名的static变量和方法都是相互独立的,并不存在任何的重写的关系。
  • 在多态的情况下调用 类变量类方法 均看均由 编译类型
  • 类方法可以在同一类重载

public class Test{
    public static void main(String args){
        Base sub = new Sub();
        System.out.print(sub.n); // 1
        System.out.print(sub.getNum()); // 1
        
        Sub s = new Sub();
        System.out.print(s.n); // 2
        System.out.print(s.getNum()); // 2
        
    }

}

class Base{
    public static int n = 1;
    
    public static int getNum(){
        return 1;
    }
}

class Sub{
    public static int n = 2;
    
    public static int getNum(){
        return 2;
    }
    
}

9.3 类成员的初始化与实例对象成员的初始化

  • 类成员:类变量、类方法
    • 类变量:
      1. 可以显示赋值 public static String str = "1"
      2. static 代码块
    • 类方法:在随类的加载而被加载进方法区
  • 实例对象成员:属性和方法
    • 属性:
      1. 可以显示赋值
      2. 在代码块中
      3. 在构造器中

9.4 接口在JDK 8 后的特性

在这里插入图片描述

package com.interface_;

public class TestInterface {

}

interface Interface{
    // 属性强制是 public static final 修饰,可以不写
    // 方法(除默认方法)强制是 public abstract 修饰,可以不写
    // 默认方法是 public 修饰的

    // 写属性,默认是 public static final 可以省略不写
    public static final String str = "Hello";

    // 写方法
    // 在接口中,抽象方法,可以省略abstract关键字 和 public修饰符
    void hi();

    // 在jdk1.8后,可以有默认实现方法,需要使用 default关键字修饰
    default void ok(){
        System.out.println("ok ....");
    }

    // 在jdk1.8后,可以有静态方法
    static void test1(){

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ModelBulider

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值