不是怎么还在转啊...

009-面相对象高级-2

面向对象高级

代码块

  • 代码块是类的五大成分之一(成员变量、构造器、方法、代码块、内部类)。

  • 代码块分两种

    • 静态代码块:

      • 格式

        static {
        
        }
        
      • 特点:类加载时自动执行,与类一起优先加载,由于类只会加载一次,所以静态代码块也只会执行一次。

      • 作用:完成类的初始化,例如:对静态变量的初始化赋值。

      • 举例:

        • 类似静态的普通变量可以在静态代码块中赋值,也可以在定义的那一行赋值
        • 但对于像new了一个静态数组,那么这个数组还需要初始化,就需要放在静态代码块中初始化
        • 这么做的好处是保证静态变量只会被赋值一次,如果放在其他方法中,会导致每次调用都会被重新赋值一次
      • 这是锦上添花的操作而不是必要的操作

    • 实例代码块(构造代码块):

      • 格式:

        {
        
        }
        
      • 特点:每次创建对象时,执行实例代码块,并在构造器前执行。

      • 作用:和构造器一样,都是用来完成对象的初始化的,例如:对实例变量进行初始化

内部类

  • 如果一个类定义在另一个类内部,那么这个类就是内部类
  • 例子:比如汽车类中定义一个发动机类

成员内部类

  • 内部类语法

    public class Outer {
        // 成员内部类:无static修饰,属于外部类的  *对象*  特有的
        public class Inner {
        	public void show() {
                System.out.println("show");
            }
    	}
    }
    
    public class Test {
        public static void main(String[] args) {
            // 成员内部类创建对象的格式:
            // 外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
            Outer.Inner oi = new Outer().new Inner();
        }
    }
    
  • 成员内部类访问外部类成员的特点(拓展)

    • 成员内部类可以直接访问外部类的静态成员(包括静态变量和静态方法),也可以直接访问外部类的实例成员

    • 成员内部类的实例方法中,可以直接拿到当前寄生的外部类对象:

      // 调内部类自己的内容
      this
      // 调外部类的内容
      外部类名.this
      

静态内部类

  • 有static此时的内部类,属于外部类本身持有

    public class Outer {
        // 成员内部类:无static修饰,属于外部类的  *本身*  特有的
        public static class Inner {
            public void show() {
                System.out.println("show");
            }
    	}
    }
    
    public class Test {
        public static void main(String[] args) {
            // 静态内部类创建对象的格式:
            // 外部类名.内部类名 对象名 = new 外部类名.内部类名();
            Outer.Inner inner = new Outer().Inner();
            inner.show();
        }
    }
    
  • 静态内部类中是否可以直接访问外部类中的静态成员?

    • 可以
  • 静态内部类中是否可以直接访问外部类中的实例成员?

    • 不可以
    • 外部类的实例成员属于外部类创建的对象,而静态内部类是通过外部类点内部类创建的;对于成员内部类来说,成员内部类是通过外部类的对象点内部类对象的当时创建的,可以访问到外部类的实例对象。

局部内部类

  • 局部内部类是定义在方法中、代码块中、构造器等执行体中。

  • 语法:

    public class Test {
        public static void main(String[] args) {
            
        }
        public static void go() {
            class A {
                
            }
            
            abstract class B {
                
            }
            
            interface C {
                
            }
        }
    }
    
  • 鸡肋语法,没什么用法,为匿名内部类做铺垫

匿名内部类(重点)

  • 是一种特殊的局部内部类

  • 所谓匿名:指的是程序员不需要为这个类声明名字,默认有个隐藏的名字

  • 语法(注意最后的分号):

    /**
    * new 类或接口(参数值...) {
    *     类体(一般是方法重写);
    * }
    */
    
    new Animal() {
        @Override
        public void cry() {
        }
    };
    
  • 特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象

  • 作用:用于更方便的创建一个子类对象

  • 语法举例:用在抽象类等处创建对象时,可以直接使用匿名内部类来创建对象

    public abstract class Animal {
        public abstract void cry();
    }
    
    public class Test {
        public static void main(String[] args) {
            Animal a = new Animal() {
                @Override
                public void cry() {
                    System.out.println("(>^ω^<)喵");
                };
                a.cry
            }
        }
    }
    
  • 编译后的大概样子:

    image-20250716023604764

    • 可以看的出本质就是个子类
  • 匿名内部类在开发中的常见形式

    • 通常作为一个对象参数传输给方法

    • 举例:

      • 原本需要定义实现类:

        image-20250716024116958

      • 匿名内部类可以直接创建对象时使用:

        image-20250716024324023

  • 匿名内部类应用场景示例

    • 调用别人提供的方法实现需求时,这个方法真好可以让我们传输一个匿名内部类对象给其使用。

    • 示例1:在按钮监听器中使用匿名内部类

      image-20250716025215921

    • 示例2:使用comparator接口的匿名内部类对数组进行排序

      image-20250716025309420

@Data会给类重写toString()

函数式编程(jdk8新增特性)

  • 此“函数”类似于数学中的函数(强调做什么),只要输入的数据一致返回的结果也是一致的
    • 数学中的函数实例:2x+1
    • Java中的函数(Lambda表达式):(x)->2x+1
  • 函数式编程解决了什么问题?
    • 使用Lambda函数替代某些匿名内部类对象,从而让程序代码更简洁,可读性更好。
  • 注意:C语言中函数类似Java中的方法,而Java中函数是Lambda表达式

Lambda表达式

  • JDK 8开始新增的一种语法形式,它表示函数。

  • 可以用于替代某些匿名内部类对象,从而让程序更简洁,可读性更好。

    (被重写方法的形参列表)->{
        被重写方法的方法体代码
    }
    
  • 示例以及讲解:

    • 已有Animal类

      public abstract class Animal {
          public abstract void cry();
      }
      
    • 错误示范:

      // 如下代码会报错
      Animal a1 = () -> {
        System.out.println("猫是:(>^ω^<)喵地叫");
      };
      
      • Lambda并不是可以简化全部的匿名内部类,Lambda只能简化函数式接口(只有一个抽象方法的接口)的匿名内部类。
    • 正确示范:

      • 定义一个函数式接口

        @FunctionalInterface // 声明函数式接口的注解。
        interface Swim {
            void swimming();
        }
        
      • 简化前

        Swim s1 = new Swim() {
            @Override
            public void swimming() {
                System.out.println("学生游泳贼快");
            }
        };
        
      • 简化后

        Swim s1 = () -> {
          System.out.println("学生游泳贼快");
        };
        s1.swimming();
        
    • 原理:Lambda表达式可以进行上下文推断

      • 在如下代码中,上文指的是Swim s1,下文指的是接口中唯一一个抽象方法,因为是唯一抽象方法,所以能推断出要实现Swim中的那个唯一抽象方法。

        Swim s1 = () -> {
          System.out.println("学生游泳贼快");
        };
        
    • 将来我们见到的大部分函数式接口,上面都可能会有一个@FunctionalInterface的注解,该注解用于约束当前接口必须是函数式接口

  • Lambda的省略规则

    • 参数类型全部可以省略不写

      • 省略前:

        Arrays.sort(students, (Student o1, student o2) -> {
            return o1.getAge() - o2.getAge();// 按年龄升序
        });
        
      • 省略后:

        Arrays.sort(students, (o1, o2) -> {
            return o1.getAge() - o2.getAge();// 按年龄升序
        });
        
    • 如果只有一个参数,参数类型省略的同时“()”也可以省略,但多个参数不能省略“()

    • 如果Lambda表达式中只有一行代码,大括号可以不写,同时要省略分号“;”,如果这行代码是return语句,也必须去掉return

      • 省略前

        Arrays.sort(students, (o1, o2) -> {
            return o1.getAge() - o2.getAge();// 按年龄升序
        });
        
      • 省略后

        Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge()// 按年龄升序
        );
        

方法引用

静态方法引用

  • 语法:类名::静态方法

  • 使用场景

    • 如果某个Lambda表达式里只是调用一个静态方法,并且“->”前后参数的形式一致,就可以使用静态方法引用。

      • 假设Student类中有静态方法如下:

        public static int compareByArray(Student o1, Student o2) {
            return o1.getAge() - o2.getAge();
        }
        
      • 简化前:

        Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());
        
      • 简化一步((o1, o2)Student.compareByArray(o1, o2)参数形式一致):

        Arrays.sort(students, (o1, o2) -> Student.compareByArray(o1, o2));
        
      • 使用静态方法引用简化:

        Arrays.sort(students, Student::compareByArray);
        

实例方法引用

  • 语法:对象名::实例方法

  • 使用场景:

    • 如果某个Lambda表达式里只是通过对象名称调用一个实例方法,并且"->"前后参数的形式一致,就可以使用实例方法引用。

      • 假设Student类中有实例方法如下:

        public static int compareByHeight(Student o1, Student o2) {
            return Double.compare(o1.getHeight(), o2.getHeight());
        }
        
      • 现在创建了Student对象

        Student t = new Student();
        
      • 简化前:

        Arrays.sort(students, (o1, o2) -> o1.getHeight() - o2.getHeight());
        
      • 简化一步:

        Arrays.sort(students, (o1, o2) -> t.compareByHeight(o1, o2));
        
      • 使用实例方法引用简化

        Arrays.sort(students, t::compareByHeight);
        

特定类的方法引用

  • 语法:特定类的名称::方法

  • 使用场景

    • 如果某个Lambda表达式里只是调用一个特定类型的实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是座位该实例方法的入参的,则此时就可以使用特定类型的方法引用
  • 示例及讲解:

    image-20250717023159152

    Arrays.sort(names, (o1, o2) -> o1.compareToIgnoreCase(o2) );
    
    • 上述代码可以简化为:

      Arrays.sort(names, String::compareToIgnoreCase);
      

构造器引用

  • 语法:类名::new

  • 使用场景:

    • 如果某个Lambda表达式里只是在创建对象,并且“->”前后参数情况一致,就可以使用构造器引用。
  • 示例及讲解:

    • 有汽车工厂类:

      image-20250717024509590

    • 下图注释的代码即为简化过程

      image-20250717024301359

常用API

String

  • String是什么,有什么用?

    • String代表字符串,它的对象可以封装字符串数据,并提供了很多方法完成对字符串的处理。
  • String创建字符串对象的方式(引号和new对象两种)

    image-20250717025013313

    • 两种方式有何区别?
      • 只要是以双引号"..."方式写出的字符串对象,会存储到堆中的字符串常量池,且相同内容的字符串只存储一份。相当于创建多个内容相同字符串时,地址在栈中,指向堆里字符串常量池里唯一的那个字符串。对多个引号内容相同的字符串进行比较结果是相等的。
      • 通过new方式创建字符串对象,每new一次都会产生一个新的对象放在堆内存中。相当于将字符存到堆中后,每创建一个对象都会以这些字符组成一个字符串形成一个新的对象,此时对多个内容一样的new出来的对象进行比较,得到的结果是不一致。
  • String提供的常用方法

    image-20250717030320850

  • 注意:

    • ==“号默认对地址进行比较,所以对String的比较使用equals方法

ArrasyList集合

  • 什么是集合?

    • 集合是一种容器,用来装数据的,类似于数组

    • 是泛型类,可以规定其中的数据类型

      ArrayList<String> list = new ArrayList<>();
      
  • 和数组有什么区别?

    • 数组定义完成并启动后,长度就固定了
    • 集合大小可变,功能丰富,开发中用的更多

image-20250717031647186

GUI编程

  • GUI,全称Graphical User Interface,是指图形用户界面。
  • 通过图形元素(如窗口、按钮、文本框等)与用户进行交互。
  • 与命令行界面(CLI)相比,GUI更加直观、友好。

Java的GUI编程包(企业对这个没有要求)

  • AWT(Abstract Window Toolkit)

    • 提供了一组原生的GUI组件,依赖于操作系统的本地窗口系统
  • Swing

    • 基于AWT,提供了更丰富的GUI组件,轻量级组件,不依赖于本地窗口系统。

    • 常用的Swing组件(AWT组件和Swing组件只有个J字母开头的差别)

      image-20250718013155451

    • 直接让AI生成代码

事件处理

  • GUI编程中,事件的处理是通过事件监听器(Event Listener)来完成的。

  • 常用事件监听器

    image-20250718014346728

  • 事件的集中常见写法

    image-20250718015854416

posted @ 2025-07-18 03:13  Quirkygbl  阅读(10)  评论(0)    收藏  举报