代码块

认识代码块

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

代码块分为

  • 静态代码块:
    • 格式:static{}
    • 特点:类加载时自动执行(与类一起优先加载),由于类只会加载一次,所以静态代码也只会执行一次。
    • 作用:完成类的初始化,例如:对静态变量的初始化赋值。
  • 实例代码块:
    • 格式:{}
    • 特点:每次创建对象时,执行实例代码块,并在构造器前执行。
    • 作用:和构造器一样都是用来完成对象的初始化的(初始化对象的实例资源),例如:对实例变量进行初始化赋值。

内部类

认识内部类

  • 如果一个类定义在另一个类的内部,这个类就是内部类。

  • 场景:当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类

    public class Car{
        //内部类
        public class Engine{
        }
    }
    

成员内部类

  • 就是类中的一个普通成员,类似前面我们学过的普通成员变量、成员方法。

    public class Outer{
        //成员内部类
        public class Inner{
        }
    }
    
  • 成员内部类创建对象的格式:

    外部类名称.内部类名称 对象名=new 外部类名称().new 内部类名称;

    Outer.Inner oi=new Outer().new Inner();
    
  • 成员内部类访问外部成员的特点(拓展):

    • 1、成员内部类中可以直接访问外部类的实例成员、静态成员
    • 2、成员内部类的实例方法中,可以直接拿到当前寄生的外部类对象:外部类名.this / 外部类名.this.方法

静态内部类

  • 有static修饰的内部类,属于外部类自己持有。

    public class Outer{
        //静态内部类
        public static class Inner{
        }
    }
    
    外部类名.内部类名 对象类=new 外部类.内部类();
    Outer.Inner in=new Outer.Inner();
    
  • 特点:

    • 可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员。

局部内部类(了解)(鸡肋语法)

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

匿名内部类(重点)

认识匿名内部类
  • 一种特殊的局部内部类;
  • 所谓匿名:指的是程序员不需要为这个类声明名字,默认有个隐藏的名字。
new 类或接口(参数值...){
    类体(一般是方法重写);
};
  • 特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象。
  • 作用:用于方便的创建一个子类对象。
常见使用形式
  • 通常作为一个对象参数传输给方法。
  • 需求:例如:学生老师参加游泳比赛
//Swimming接口
public interface Swimming {
    void swim();
}
//Test类
public class Test {
    public static void main(String[] args) {

        Swimming s1 = new Swimming() {
            @Override
            public void swim() {
                System.out.println("学生游泳飞快~~~");
            }
        };
        go(s1);

        go(new Swimming() {
            @Override
            public void swim() {
                System.out.println("老师游泳还行~~~");
            }
        });
    }

    public static void go(Swimming s) {
        System.out.println("开始===========");
        s.swim();
    }
}

匿名内部类的使用场景
  • 调用别人提供的方法实现需求时,这个方法正好可以让我们传输一个匿名内部类对象給其使用。
  • 开发中不是我们要主动去写匿名内部类,而是用别人功能时,别人可以让我们写一个匿名内部类,我们才会写。
  • 使用comparator接口的匿名内部类实现对数组进行排序
import java.util.Arrays;
import java.util.Comparator;

public class Test {
    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("玛卡巴卡", 16, 170.1);
        students[1] = new Student("唔西迪西", 12, 158.2);
        students[2] = new Student("依古比古", 18, 168.5);
        
        // 使用Comparator接口的匿名内部类,按年龄升序排序
        Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        // 打印排序后的数组
        System.out.println(Arrays.toString(students));
    }
}

函数式编程

函数式编程解决了什么问题?

  • 使用Lambda函数替代某些匿名内部类对象,从而让程序代码更简洁,可读性更好。

Lambda

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

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

    (被重写方法的形参列表)->{
        被重写方法的方法体代码。     
    }
    
  • 注意:Lambda表达式只能替代函数式接口的匿名内部类!!!

  • 什么是函数式接口?

    • 有且仅有一个抽象式方法的接口。
    • 注意:将来我们见到的大部分函数式接口,上面都可能会有一个@FunctionalInterface 的注解,该注解用于约束当前接口必须是函数式接口。
实战实例
  • 使用Lambda简化comparator接口的匿名内部类
public class Test {
    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("玛卡巴卡", 16, 170.1);
        students[1] = new Student("唔西迪西", 12, 158.2);
        students[2] = new Student("依古比古", 18, 168.5);
        
        // 使用Comparator接口的匿名内部类,按年龄升序排序
        Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        //lambda简化后:
         Arrays.sort(students, (Student o1, Student o2)->{
                return o1.getAge() - o2.getAge();
            }
        });
        // 打印排序后的数组
        System.out.println(Arrays.toString(students));
    }
}
Lambda表达式省略规则:
  • 作用:用于进一步简化Lambda表达式的写法。

  • 具体规则:

    • 参数类型可以省略不写。
    Arrays.sort(students, (o1,  o2)->{
                    return o1.getAge() - o2.getAge();
                }
            });
    
    • 如果只有一个参数,参数类型省略的同时"()“也可以省略,但多个参数不能省略”()"
    • 如果Lambda表达式中只有一行代码,大括号可以不写,同时要省略分号";"如果这行代码是return语句,也必须去掉return。
    Arrays.sort(students, (o1,  o2) -> o1.getAge() - o2.getAge() );
    

方法引用

静态方法的引用
  • 类名::静态方法

  • 使用场景

    • 如果某个Lambda表达式里只是调用一个静态方法,并且”->“前后参数的形式一致,就可以使用静态方法引用。
    //静态方法:
    public static int compareByAge(Student o1,Student o2){
        return o1.getAge()-o2.getAge();
    }
    //简化前:
    Arrays.sort(students,(o1,o2) -> Student.compareByAge(o1,o2));
    //静态方法引用:
    Arrays.sort(students,Student::compareByAge);
    
实例方法引用
  • 对象名::实例方法

  • 使用场景

    • 如果某个Lambda表达式里只是调用一个实例方法,并且”->“前后参数的形式一致,就可以使用实例 方法引用。
    //实例方法:
    public int compareByHeight(Student o1,Student o2){
        return Double.compare(o1.getHeight(),o2.getHeight());
    }
    //调用方法
    Student s1=new Student();
    //简化前
    Arrays.sort(students,(o1,o2) -> s1.compareByHeight(o1,o2));
    //简化后:
    Arrays.sort(students,s1::compareByHeight);
    
特定型的方法引用
  • 特定类的名称::方法

  • 使用场景

    • 如果某个Lambda表达式里只是调用一个特定类型的实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。
    //Java提供的字符串按首字母忽略大小写比较的方法:compareToIgnoreCase
    Arrays.sort(names, (o1,o2) -> o1.compareToIgnoreCase(o2));
    //简化后:
     Arrays.sort(names, String::compareToIgnoreCase);
    
构造器引用
  • 类名::new

  • 使用场景

    • 如果某个Lambda表达式里只是创建对象,并且“->”前后参数情况一致,就可以使用构造器引用。
    //创建接口的匿名内部类对象:
    CarFactory cf= new CarFactory() {
        @Override
        public Car getCar(String name){
            return new Car(name);
        }
    };
    //化简前:
    CarFactory cf =name -> new Car(name);
    //简化后:
    CarFactory cf =Car::new;
    

更多推荐