java学习笔记(拾忆版)

基础语法

1、使用long、float这种数据类型时需要在数字后面加'l'、'f'后缀,因为你写个整数默认是Int类型,小数默认是double类型

2、方法重载:只要传入的参数不同就允许存在重复方法名

3、类型转换:范围小的可以转成范围大的,反之则不能,否则会发生强制截断导致数据错误

4、表达式的自动类型转换:都会向精度高的靠拢,比如小数和整数的运算会自动转化成小数类型

数组

1、动态初始化数组:先确定类型和容量但是不赋值,二维数组也相同

Stirng[] array = new String[8]

面向对象

类、对象、方法与jvm虚拟机内存中方法区、栈内存、堆内存之间的关系

1、类(Class)
        比喻:你可以把类看作是建筑设计图纸。它详细描述了要建造的建筑物的各种特性,比如尺寸、材料等。
        内存对应:在JVM中,类的信息(包括类名、方法信息、静态变量等)存储在方法区。方法区就像是存放所有建筑设计图纸的地方。
2、对象(Object)
        比喻:对象则是根据建筑设计图纸实际建造出来的房子。每个对象都是类的一个实例,就像每栋建筑都是按照特定的设计图建造的一样。
        内存对应:对象被创建后,会被分配到堆内存中。堆内存就像是放置所有实际建造出来的建筑的地方。在这里,每个对象都有自己的空间来存储其状态(即成员变量的值)。
3、方法(Method)
        比喻:方法就像是施工过程中执行的具体操作指南,比如如何打地基、如何砌墙等。不同的方法指导着完成不同的任务。
        内存对应:当一个方法被调用时,会在栈内存中为这个方法创建一个栈帧(Stack Frame),用来存储该方法执行期间的局部变量、操作数栈等信息。栈内存就像是记录每个施工步骤的临时笔记本,每次执行方法就像是记录下当前步骤的操作。
4、JVM内存概述
        方法区:存储类的信息,包括类的结构(字段和方法数据)、运行时常量池、静态变量等。
        堆内存:用于存储对象实例及数组,是垃圾回收器主要管理的区域。
        栈内存:每个线程都有自己的栈,用于存储方法调用的栈帧。栈帧包含局部变量表、操作数栈、动态链接、方法出口等信息。

构造器

1、分为有参构造器和无参构造器,如果自定义了有参构造器则会将默认的无参构造器覆盖(除非你专门写了一个无参构造器)

2、子类构造器使用父类构造器:

public class Main {
    public static void main(String[] args) {
        Student student = new Student("kaka", 20, "龙岩学院");
    }
}

class People{
    String name;
    int age;

    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

class Student extends People{
    String school;

    public Student(String name, int age, String school) {
        super(name, age); // 调用父类的有参构造器
        this.school = school;
    }

}

3、调用兄弟构造器(设置默认值):

class Student {
    String name;
    int age;
    String school;

    public Student(String name, int age, String school) {
        this.name = name;
        this.age = age;
        this.school = school;
    }

    public Student(String name, int age) {
        this(name, age, "清华大学");
    }
}

引用关键字this

1、访问类的成员变量

        当你在一个方法或构造器中需要区分局部变量和成员变量时,可以使用this关键字来指代当前对象的成员变量。例如:

public class Person {
    String name;

    public Person(String name) {
        this.name = name; // 使用this区分成员变量name和参数name
    }
}

        这里,this.name指的是类的成员变量,而name是构造函数的参数。

2、调用另一个构造器(构造器链)

public class Car {
    private String brand;
    private String color;
    private int year;

    public Car(String brand, String color, int year) {
        this.brand = brand;
        this.color = color;
        this.year = year;
    }

    public Car(String brand, String color) {
        this(brand, color, 2025); // 默认年份为2025
    }
}

使用场景:设置默认值

3、返回当前对象

        有时候你可能希望方法返回当前对象的引用,以便于链式调用(method chaining)。这时可以使用this返回当前对象:

public class Person {
    private String name;

    public Person setName(String name) {
        this.name = name;
        return this; // 返回当前对象
    }
}

        这样,你就可以链式调用方法,如person.setName("John").setAge(30)(假设还有setAge方法并且也返回this)。

面向对象三大特征:封装、继承、多态

1、封装:合理隐藏、合理暴露

        就像创建实体类时你需要将属性全部设为私有(不允许外部变量直接访问并赋值)进行合理隐藏,然后设置get/set方法对其进行合理暴露。


        实体类是专门用来存放数据的,如果要对数据进行操作要在专门的实体操作类中操作。例如:

/*
* 实体类
* */
public class Student {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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


/*
* 实体操作类
* */
public class StudentOperator {
    private final Student student;
    public StudentOperator(Student student) {
        this.student = student;
    }
    public void printStudentName(){
        System.out.println(student.getName());
    }
}


/*
* 调用处
* */
Student student = new Student("lisi", 29);
new StudentOperator(student).printStudentName();

        static静态变量:类和对象共享的变量,不管是用类还是用对象引用该变量都会使其发生改变。这里推荐直接用类引用该变量。

        static静态变量实际上也是跟对象一样存在堆内存中的,但是对象在新建时一直会在堆内存不断开辟空间,而静态变量不会随着对象数量的增加而增加,它只有一个

        static静态方法:如果一个方法不需要访问对象中的数据,则可以将其定义为实例方法,可以直接使用类来进行调用了(常用于写工具类中的方法)

        使用工具类时因为没有必要创建对象,所以可以直接将工具类对象的无参构造器进行私有化

        静态方法和实例方法访问的相关注意事项:

                静态方法中可以直接访问静态成员,不可以直接访问实例成员。
                实例方法中既可以直接访问静态成员,也可以直接访问实例成员。
                实例方法中可以出现this关键字,静态方法中不可以出现this关键字的。


2、继承:使用了extends关键字,能让一个类与另一个类建立起父子关系。子类能继承父类的非私有成员(变量、方法)。

        继承的特点:不支持多继承(因为继承对象如果存在相同的方法将无法执行),但是可以多层继承。java中所有的类都是继承Object类。

        访问父类属性或方法可以使用super关键字,super关键字就是访问父类对象。子类不能访问父类的父类对象,除非将子类对象向上转型或者父类的父类定义相应的get/set方法。


        方法重写:1️⃣子类重写父类方法时,访问权限必须大于或者等于父类该方法的权限 (public>protected>缺省)

                          2️⃣重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小。

                          3️⃣私有方法、静态方法不能被重写,如果重写会报错的。

        简单来说方法重写就八个大字:声明不变,重新实现

        方法重写应用场景:如输出对象时默认会调用   对象名.toString ,而这个输出的是对象的地址,若在对象内将toString方法重写,则可以自定义输出的内容


3、权限修饰符:

4、多态(对象多态、行为多态、属性不多态):

        简单来说多态就是一个对象的多种形态

        多态的前提:

        1️⃣有继承、实现关系

class Animal {
    String name = "Animal";

    public void eat() {
        System.out.println("动物吃东西了");
    }
}

class Cat extends Animal {
    String name = "Cat";

    @Override
    public void eat() {
        System.out.println("猫吃东西了");
    }
}

class Dog extends Animal {
    String name = "Dog";

    @Override
    public void eat() {
        System.out.println("狗吃东西了");
    }
}

        2️⃣存在父类引用子类对象

Animal cat = new Cat(); //父类引用子类对象
cat.eat(); //行为多态,编译看左边,运行看右边(优先从子类查找是否有重写方法)
System.out.println(cat.name); //属性不多态,编译、运行都看左边(优先从父类找属性)
Animal dog = new Dog(); //父类引用子类对象
dog.eat();//行为多态,编译看左边,运行看右边
System.out.println(dog.name); //属性不多态,编译、运行都看左边(优先从父类找属性)

        3️⃣子类存在方法重写(1️⃣中子类的eat方法)


        多态的好处(具有解耦性):

public class Main {
    public static void main(String[] args) {
        Animal cat = new Cat();
        cat.eat(cat); //将cat对象传入
        Animal dog = new Dog();
        dog.eat(dog); //将dog对象传入
    }
}


class Animal {
    String name = "Animal";

    public void eat() {
        System.out.println("动物吃东西了");
    }

    public void eat(Animal animal) {
        System.out.println("动物们开始吃东西了...");
        animal.eat(); //分别调用了cat和dog类中的eat方法
    }

}

class Cat extends Animal {
    String name = "Cat";

    @Override
    public void eat() {
        System.out.println("猫吃东西了");
    }
}

class Dog extends Animal {
    String name = "Dog";

    @Override
    public void eat() {
        System.out.println("狗吃东西了");
    }
}

        这里使用animal.eat()能够分别调用子类中重写的eat方法其实是多态中的动态方法调度 

        缺点:不能调用子类中自己的方法,因为是之前通过animal.eat()调用了子类重写父类的方法,因此如果子类中具有自己的方法,如cat类中:

class Cat extends Animal {
    String name = "Cat";

    @Override
    public void eat() {
        System.out.println("猫吃东西了");
    }

    public void eatFish() {
        System.out.println("猫吃鱼了");
    }
}

        这时候我们就不能通过animal.eatFish()调用了,需要向下转型:

Animal cat = new Cat();
cat.eat(cat); //将cat对象传入
Cat cat1 = (Cat) cat;  //强制类型转换可以调用子类的非重写方法
cat1.eatFish();

        强转时需要注意先判断对象的真实类型,再进行转换,否则会报类型转换异常:ClassCastException错误。在父类的公共方法中需判断参数对象的真实类型然后向下转型:

public class Main {
    public static void main(String[] args) {
        Animal cat = new Cat();
        cat.eat(cat); //将cat对象传入
        Animal dog = new Dog();
        dog.eat(dog); //将dog对象传入
    }
}


class Animal {
    String name = "Animal";

    public void eat() {
        System.out.println("动物吃东西了");
    }

    public void eat(Animal animal) {
        System.out.println("动物们开始吃东西了...");
        animal.eat(); //分别调用了cat和dog类中的eat方法
        //判断类型并向下转型,调用子类非重写方法
        if(animal instanceof Dog){
            Dog dog = (Dog) animal;
            dog.eatBone();
        }else if(animal instanceof Cat){
            Cat cat = (Cat) animal;
            cat.eatFish();
        }
    }

}

class Cat extends Animal {
    String name = "Cat";

    @Override
    public void eat() {
        System.out.println("猫吃东西了");
    }
    public void eatFish() {
        System.out.println("猫吃鱼了");
    }
}

class Dog extends Animal {
    String name = "Dog";

    @Override
    public void eat() {
        System.out.println("狗吃东西了");
    }

    public void eatBone() {
        System.out.println("狗吃骨头了");
    }
}

final关键字

1、修饰类:该类被称为最终类,特点是不能被继承了。
      修饰方法:该方法被称为最终方法,特点是不能被重写了。
      修饰变量:该变量有且仅能被赋值一次。

2、final修饰基本类型的变量,变量存储的数据不能被改变。
      final修饰引用类型的变量(如数组、对象),变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的

3、使用场景:用于声明配置文件的属性(属性名一般由大写字母和下划线组成)

单例设计模式

1、饿汉式单例(直接在属性中new)

class A {
    public static final A a = new A(); //直接在属性中new对象

    private A() {
    } //必须将构造器私有保证外部无法创建

    public static A getObject() { //外部只能通过这个方法获得对象
        return a;
    }
}

2、懒汉式单例(在需要时才new)

class A {
    public static A a;

    private A() {
    } //必须将构造器私有保证外部无法创建

    public static A getObject() { //外部只能通过这个方法获得对象
        if (a == null) { //需要时才new
            a = new A();
        }
        return a;
    }
}

枚举类

1、代码示例:

public class Main {
    public static void main(String[] args) {
        System.out.println(A.X); //输出X,因为父类的Enum重写了Object的toString方法,所以可以直接输出对象名
        System.out.println(A.Y);
        System.out.println(A.Z);
        System.out.println(A.X.ordinal());//输出对象的位置索引
    }
}

enum A {
    X,Y,Z
}

2、反编译完之后的样子:

final class A extends java.lang.Enum<A> {
  public static final A X;
  public static final A Y;
  public static final A Z;
  public static A[] values();
  public static A valueOf(java.lang.String);
  static {};
}

        枚举类底层就是不可修改的常量,但是它属于多例模式,因为它每定义一个属性都会新建一个对象 

3、应用场景:跟定义常量的应用场景类似,但是比常量更加规范

public class Main {
    public static void main(String[] args) {
        move(3);
        move2(A.DOWN);
    }

    //使用定义常量的方法
    public static void move(int d) {  //此处的参数值没有受约束,也就是你传0、1以外的整数值都行
        switch (d) {
            case B.UP:
                System.out.println("向上");
                break;
            case B.DOWN:
                System.out.println("向下");
                break;
            default:
                System.out.println("输入有误");
        }
    }

    //使用枚举定义的方法
    public static void move2(A a) {  //此处的参数值受约束,你只能传枚举类型A的参数
        switch (a) {
            case UP:
                System.out.println("向上");
                break;
            case DOWN:
                System.out.println("向下");
        }
    }
}

enum A {
    UP, DOWN
}

class B {
    public static final int UP = 0;
    public static final int DOWN = 1;
}


抽象类

1、抽象类示例:

public class Main {
    public static void main(String[] args) {
        //抽象类不能被创建,会报错
        //A a = new A();
        new B().show();
    }
}

abstract class A { //可以定义为就是为了"生孩子"的类
    public void show2() {
        System.out.println("该方法不用重写");
    }

    public abstract void show();//抽象方法只有方法体没有方法声明
}

class B extends A {  //只能通过继承的方式,并且还要重写抽象类中所有抽象方法
    @Override
    public void show() {
        System.out.println("重写了抽象类的show方法");
    }
}


2、抽象类的好处:

        父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现,我们抽出这样的抽象类,就是为了更好的支持多态

3、抽象类的模版方法设定

public class Main {
    public static void main(String[] args) {
        B b = new B();
        b.template();
        C c = new C();
        c.template();
    }
}

abstract class A {
    public final void template() {
        System.out.println("这是模版开头");
        customize(); //相当于父类调用子类的方法
        System.out.println("这是模版结尾");
    }

    public abstract void customize();
}

class B extends A {
    @Override
    public void customize() {
        System.out.println("这是B的自定义内容");
    }
}

class C extends A {
    @Override
    public void customize() {
        System.out.println("这是C的自定义内容");
    }
}

注意:模版方法是给子类直接使用的,不能被子类重写(一旦被重写了模版的意义就失效了),所以最好要加个final修饰

接口

1、概念:

        (1)实现类可以实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类

        (2)接口中的属性会默认加上一系列修饰关键字:public static final;方法前面会默认加上:public abstract。

2、示例:

// 定义接口
interface Animal {
    void makeSound();  // 动物发出声音的方法
}

// 实现接口的第一个类
class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("汪汪!");
    }
}

// 实现接口的第二个类
class Cat implements Animal {
    @Override
    public void makeSound() {
        System.out.println("喵~");
    }
}

// 测试类
public class Main {
    public static void main(String[] args) {
        // 声明接口类型的变量,指向不同的实现类对象,体现多态
        Animal animal1 = new Dog();
        Animal animal2 = new Cat();

        // 调用方法,根据实际对象执行不同的行为
        animal1.makeSound();  // 输出:汪汪!
        animal2.makeSound();  // 输出:喵~
    }
}

3、JDK8以后新增的接口特性:

(1)默认方法:

interface Animal {
    default void breathe() {
        System.out.println("Animal is breathing.");
    }
}

        实现类可以继承默认实现,也可以重写它。

(2)静态方法:

interface Animal {
    static void info() {
        System.out.println("This is an animal interface.");
    }
}

        常用于工具方法或辅助方法,调用时直接使用:"接口名.方法名"

(2)私有方法(JDK9+):

interface Animal {
    default void method1() {
        System.out.println("Method 1");
        helper();
    }

    private void helper() {
        System.out.println("Helper method");
    }
}

        只能在接口内部调用

4、接口的注意事项:

(1)接口与接口可以实现多继承,一个接口可以同时继承多个接口

          类与类:单继承一个类只能继承一个直接父类

          类与接口:多实现,一个类可以同时实现多个接口。

          接口与接口:多继承,一个接口可以同时继承多个接口。

          示例:

interface A {
    public void a();
}
interface B {
    public void b();
}
interface C extends A , B{
    public void c();
}
class D implements C {

    @Override
    public void c() {
        
    }

    @Override
    public void a() {

    }

    @Override
    public void b() {

    }
}

(2)一个接口继承多个接口,如果多个接口中存在方法签名冲突(返回类型不一样但是方法名一样),则此时不支持多继承,也不支持多实现(报错)

(3)一个类维承了父类,又同时实现了接口,如果父类中和接口中有同名的方法,实现类会优先用父类的:

interface A {
    default void show(){
        System.out.println("A");
    }
}
class B {
    public void show() {
        System.out.println("B");
    }
}
class C extends B implements A {
    public void go(){
        show(); //优先调父类的show方法(就近)
        A.super.show(); //调接口A的方法
    }
}

        使用 .super 可以引用某个特定父类或接口中的成员。当它与接口一起使用时,允许你访问该接口中定义的默认方法

(4)一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可

interface A {
    default void show() {
        System.out.println("A");
    }
}

interface B {
    default void show() {
        System.out.println("B");
    }
}

class C implements A, B {
    @Override
    public void show() {
        A.super.show(); //只调用A接口的方法
        B.super.show(); //只调用B接口的方法
    }
}

抽象类和接口的对比

1、相同点:
(1)多是抽象形式,都可以有抽象方法,都不能创建对象
(2)都是派生子类形式:抽象类是被子类继承使用,接口是被实现类实现
(3)一个类继承抽象类,或者实现接口,都必须重写完他们的抽象方法或自己要成为抽象类,否则就报错
(4)都能支持的多态,都能够实现解耦合
2、不同点:
(1)抽象类中可以定义类的全部普通成员,接口只能定义常量,抽象方法(JDK8新增的三种方式)

(2)抽象类只能被类单继承,接口可以被类多实现
(3)一个类继承抽象类就不能再继承其他类,一个类实现了接口(还可以继承其他类或者实现其他接口)

(4)抽象类体现模板思想:更利于做父类,实现代码的复用性(最佳实践)
(5)接口更适合做功能的解耦合:解合性更强更灵活(最佳实践)

综合案例(家电的开关操作)

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        JD[] jds = new JD[3];
        jds[0] = new Light("吊灯", false);
        jds[1] = new Fridge("冰箱", false);
        jds[2] = new Washer("洗衣机", false);
        Controller controller = Controller.getInstance();
        while (true) {
            controller.printAllStatus(jds);
            System.out.println("\n请输入你要按要开关的电器");
            String command = new Scanner(System.in).nextLine();
            switch (command) {
                case "1":
                    controller.operate(jds[0]);
                    break;
                case "2":
                    controller.operate(jds[1]);
                    break;
                case "3":
                    controller.operate(jds[2]);
                    break;
                default:
                    System.out.println("输入有误");
            }
        }
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class JD implements Switch {
    private String name;
    private Boolean status;

    @Override
    public void press() {
        this.status = !this.status;
    }

    public String getStatusName() {
        return this.status ? "开" : "关";
    }
}

class Light extends JD {
    public Light(String name, Boolean status) {
        super(name, status);
    }
}

class Fridge extends JD {
    public Fridge(String name, Boolean status) {
        super(name, status);
    }
}

class Washer extends JD {
    public Washer(String name, Boolean status) {
        super(name, status);
    }
}

interface Switch {
    public void press();
}

//设置成单例模式
class Controller {
    private static Controller controller;
 
    private Controller() {
    }

    public static Controller getInstance() {
        if (controller == null) {
            controller = new Controller();
        }
        return controller;
    }

    public void printAllStatus(JD[] jds) {
        System.out.println("\n所有电器状态 ===============");
        for (int i = 0; i < jds.length; i++) {
            System.out.println(jds[i].getName() + "开关状态为" + jds[i].getStatusName());
        }
    }

    public void operate(JD jd) {
        System.out.println("\n正在操作==============");
        System.out.println(jd.getName() + "开关原始状态:" + jd.getStatusName());
        jd.press();
        System.out.println("点击了开关按钮");
        System.out.println(jd.getName() + "开关现有状态:" + jd.getStatusName());
    }
}

代码块

1、静态代码块:static {  },属于类,类加载时它也加载,并且只自动执行一次 。多用于对静态资源的初始化(用static修饰的成员)

2、代码块:{  },属于对象,对象每被创建一次代码块就自动执行一次。多用于非静态资源的初始化

内部类

1、成员内部类

(1)就是类中的一个普通成员,类似前面我们学过的普通成员变量、成员方法
(2)创建对象:外部类名.内部类名 对象名 =new 外部类(...).new 内部类(...)

2、静态内部类

(1)有static修饰的内部类
(2)创建对象:外部类名.内部类名 对象名 =new 外部类.内部类(...)
(3)可以直接访问外部类的静态成员,不能直接访问外部类的实例成员(因为静态成员会比实例成员更优先加载)

3、匿名内部类

(1)示例:

public class test {
    public static void main(String[] args) {
        Animal animal = new Animal(){
            @Override
            public void cry() {
                System.out.println("喵喵喵");
            }
        };
        animal.cry();
    }
}

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

        匿名内部类实际上是有名字:外部类名$编号.class(如此示例中为test$1.class)

        匿名内部类本质是一个子类,同时会立即构建一个子类对象

(2)常见的使用形式

public class test {
    public static void main(String[] args) {
        //完整写法
        Animal animal = new Animal() {
            @Override
            public void cry() {
                System.out.println("喵喵喵");
            }
        };
        start(animal);

        //缩写
        start(new Animal() {
            @Override
            public void cry() {
                System.out.println("汪汪汪");
            }
        });
    }
    public static void start(Animal animal) {
        System.out.println("开始叫....");
        animal.cry();
        System.out.println("结束...");
    }
}
interface Animal{
    public abstract void cry();
}

(3)使用场景:开发中不是我们要主动去写匿名内部类,而是用别人的功能的时候,别人可以让我们写一个匿名内部类,我们才会写

        比如,数组排序:

import java.util.Arrays;
import java.util.Comparator;

public class test {
    public static void main(String[] args) {
        Integer[] arr = {6, 2, 5, 8, 0, 7, 10, 100, 88};
        Arrays.sort(arr,new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });
        System.out.println(Arrays.toString(arr));
    }
}

Lambda表达式

1、概念:

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

(2)可以用于替代并简化函数式接口的匿名内部类,例如:

public class test {
    public static void main(String[] args) {
        //普通写法
        Animal animal = new Animal() {
            @Override
            public void cry() {
                System.out.println("11111");
            }
        };
        //lambda写法
        Animal animal2 = () -> {
            //相当于直接编辑重写方法中的方法体
            System.out.println("11111");
        };
        animal.cry();
        animal2.cry();
    }
}

//声明函数式接口的注解
@FunctionalInterface
interface Animal {
    //在函数式接口中有且只能有一个方法,多了会报错
    public void cry();
}

2、简化方式:

(1)参数类型可以省略(自动类型推断)

Calculator c = (x, y) -> {
    return x + y;
};

(2)如果只有一个语句,可以省略 return 和 {}

Calculator c = (x, y) -> x + y;

(3)如果只有一个参数,可以省略小括号 () 

Calculator c = x -> x + 1;

3、可以引用方法(使用方法引用 ::

        (1)静态方法引用:

                使用方法:"类名::静态方法"

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

public class test {
    public static void main(String[] args) {
        Integer[] ints = new Integer[3];
        ints[0] = 9;
        ints[1] = 2;
        ints[2] = 100;
        Arrays.sort(ints,intComparator::compare);
    }
}

class intComparator {
    public static int compare(int a, int b) {
        return a - b;
    }
}

        (2)实例方法引用:

                使用方法:"对象名::静态方法"

                使用场景:跟静态方法一致

public class test {
    public static void main(String[] args) {
        Integer[] ints = new Integer[3];
        ints[0] = 9;
        ints[1] = 2;
        ints[2] = 100;
        Arrays.sort(ints, IntComparator::compare);
        IntComparator intComparator = new IntComparator(); //实例方法引用就比静态方法要多创建一个对象
        Arrays.sort(ints, intComparator::compare2);
    }
}

class IntComparator {
    public static int compare(int a, int b) {
        return a - b;
    }

    public int compare2(int a, int b) {
        return a - b;
    }

}

        (3)特定类型方法引用:  

                 使用方法:"特定类的名称::方法"

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

String[] strs = {"hello", "Hello" ,"apple" ,"Apple"};
//简化前
Arrays.sort(strs,((o1, o2) ->  o1.compareToIgnoreCase(o2)));
//简化后
Arrays.sort(strs,(String::compareToIgnoreCase));

        (4)构造方法引用: 

                使用方法:"类名::new"

                使用场景:如果某个Lambda表达式里只是在创建对象,并且“→”前后参数情况一致,就可以使用构造器引用

public class test {
    public static void main(String[] args) {
        //简化前
        CreateAnimal createAnimal = new CreateAnimal() {
            @Override
            public Animal createAnimal(String name) {
                return new Animal(name);
            }
        };
        //简化中
        CreateAnimal createAnimal2 = name ->  new Animal(name);
        //简化后
        CreateAnimal createAnimal3 = Animal::new;
    }
}


interface CreateAnimal{
    public Animal createAnimal(String name);
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Animal {
    String name;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值