java基础学习的文章目录
一、对象与数组的内存分析
类的定义、对象的创建
public class Dog {
public int age;
public double weight;
public void run() {
System.out.println(age + "_" + weight + "_run");
}
public void eat(String food) {
System.out.println(age + "_" + weight + "_eat_" + food);
}
}
对象的创建
public static void main(String[] args) {
// TODO Auto-generated method stub
Dog dog = new Dog();
dog.weight = 5.6;
dog.age = 20;
dog.run();
dog.eat("apple");
}
对象的内存
java中素有对象都是new出来的,所有对象的内存都在堆空间,所有保存对象的变量都是引用类型
java运行时有个垃圾回收器(garbage collector),会自动回收不再使用的内存
当一个对象没有任何引用指向时,会被GC回收掉
对象数组的内存
数组内存储的是对象的地址
方法存储在哪里?
在方法区
java程序的内存划分
java 虚拟机在执行java程序时,会将内存划分为若干个不同的数据区域,主要有
- PC寄存器(Program Counter Register)存储java虚拟器正在执行的字节码指令地址
- java虚拟机栈(java virtual machine stack) 存储栈帧
- 堆(heap) 存储GC所管理的各种对象
- 方法区(method area) 存储一个类的结构信息,比如字段、构造方法、普通方法的字节码
- 本地方法栈(Native method stack) 用来支持native方法的调用(比如c语言编写的方法)
二、构造方法
- 构造方法,也叫构造器,能够方便的创建一个对象
- 方法名必须和类名一样
- 没有返回类型
- 可以重载
public class Dog {
public int age;
public double weight;
public Dog() {
}
public Dog(int age) {
this.age = age;
}
public Dog(int age , double weight) {
this.age = age;
this.weight = weight;
}
public void run() {
System.out.println(age + "_" + weight + "_run");
}
public void eat(String food) {
System.out.println(age + "_" + weight + "_eat_" + food);
}
}
使用构造函数
public static void main(String[] args) {
// TODO Auto-generated method stub
Dog dog = new Dog();
dog = new Dog(18);
dog = new Dog(30, 55);
dog.run();
dog.eat("apple");
}
this
- this 是一个指向当前对象的引用,常见用途是
- 访问当前类中定义的成员变量
- 调用当前类中定义的方法(包括构造函数)
- this的本质是一个隐藏的,位置最靠前的方法参数
- 只能在构造方法中使用this调用其他构造函数
- 如果在构造方法中调用了其他构造方法
- 构造方法调用语句必须是构造方法中的第一条语句
dog.run(); //等价于 run(dog)
this 调用构造函数的示例:
public Dog(int age) {
this(age, 0);
}
public Dog(int age , double weight) {
this.age = age;
this.weight = weight;
}
默认构造方法
- 如果一个类没有自定义构造方法,编译器会自动为他提供无参的默认构造方法
- 一旦自定义了构造方法,默认构造方法就不再存在
三、包(package)
- java中包就是其他语言中的命名空间,包的本质是文件夹,常见作用是
- 将不同的类进行组织管理,访问控制
- 解决命名冲突
命名建议 * 为了保证报名的唯一性,一般包名都是以公司的域名的倒写开头,如 com.baidu.* * 全小写(以避免与某些类名或者接口名冲突)
类的第一句代码必须使用package 生命属于哪个包
- 比如package com.mj.model
如何使用一个类
要想正常使用一个类,必须得知道这个类的具体位置(在那个包), 有3中常见方式来使用一个类
- 使用类的全名 com.mj.model.Dog dog = new com.mj.model.Dog();
- 使用import 导入指定的类名 import com.mj.model.Dog
- 使用import导入整个包的所有类 import com.mj.model.*
导入细节
为了方便,java编译器会为每个源文件自动导入两个包
- import java.lang.*; 包含了java开发中最常用的一些类型
- import 源文件所在的包.*;
import aa.bb.*;
- 仅仅是import了直接存放在aa.bb包中的类型
- 并不包含import aa.bb.xx.*;
四、继承 Inheritance
Persion的定义
package com.lijian.lession4;
public class Persion {
public int age;
public void run() {
System.out.println(age + "_run");
}
}
Student的定义
package com.lijian.lession4;
public class Student extends Persion{
public int no;
public void study() {
System.out.println(age + "_" + no + "_study");
}
}
测试代码
package com.lijian.lession4;
public class Main {
public static void main(String[] args) {
Persion persion = new Persion();
persion.age = 15;
persion.run();
Student student = new Student();
student.age = 20;
student.no = 2014;
student.run();
student.study();
}
}
Object
任何类最终都继承自java.lang.Object, 一般称它为基类
同名的成员变量
子类可以定义根父类同名的成员变量(但不推荐这么做)
public class Persion {
public int age = 1;
}
public class Student extends Persion{
public int age = 2;
public void show() {
System.out.println(age); //2
System.out.println(this.age); // 输出2
System.out.println(super.age); // 输出1
}
}
public class Main {
public static void main(String[] args) {
Student student = new Student();
student.show();
}
}
就近原则
五、重写(override)
重写: 子类的方法签名与父类的方法签名一样。
子类的返回值类型 <= 父类的返回值类型
super
super的常见用途是:
- 访问父类中定义的成员变量
- 调用父类中定义的方法(包括构造函数)
public class Persion {
public int age = 1;
public Persion(int age) {
this.age = age;
}
}
public class Student extends Persion{
public Student(int age) {
super(age);
}
}
public class Main {
public static void main(String[] args) {
Student student = new Student(10);
System.out.println(student.age); //10
}
}
六、构造函数的细节
- 子类的构造函数必须先调用父类的构造方法,再执行后面的代码
- 如果子类的构造方法中没有显示的调用父类的构造方法
- 编译器会自动调用父类无参的构造方法
- 此时如果父类没有无参的构造方法,编译器会报错
七、注解Annotation
3种常见的注解
- @Override:告诉编译器 这是一个重写方法
- @SuppressWarnnings("警告类型"):让编译器不生产警告信息
- @SuppressWarning({"rawtypes", "unused"})
- @SuppressWarning("unused") *@Deprecated: 表示这个内容已经过期,不推荐使用
八、访问控制
java 中有4个访问权限,从高到底如下所示:
- public:在任何地方都是可见的
- protected:仅在自己的包中、自己的子类中可见
- 无修饰符(package-private):仅在自己的包中可见
- private:仅在自己的类中可见
使用注意
- 上述4个访问权限都可以修饰类的成员,比如成员变量、方法、嵌套(Nested class)等
- 只有public、无修饰符可以修饰顶级类(Top level class)
- 上述4个访问权限不可以修饰局部类、局部变量
- 一个java源文件中可以定义多个顶级类,public顶级类的名字必须和文件名一样
| 修饰符 | class | Package | subclass | world |
|---|---|---|---|---|
| public | ok | ok | ok | ok |
| protected | ok | ok | ok | no |
| 无修饰符 | ok | ok | no | no |
| private | ok | no | no | no |
九、封装
成员变量private化,提供public的getter、setter
toString 方法:打印一个对象时,会自动调用toString方法。
十、static
static 常用来修饰的成员:成员变量、方法、嵌套类
变量:
- 被static修饰:类变量、静态变量、静态字段
- 在程序运行过程中只占用一份固定的内存(存储在方法区)
- 可以通过实例、类访问
- 没有被static修饰:实例变量
- 每个实例内部都有一份内存
- 只能通过实例访问,不能通过类访问
- 不推荐使用实例访问类变量、类方法
- 在同一个类中
- 不能有同名的示例变量和类变量,不能有相同签名的示例方法和类方法【为什么:因为实例变量能访问静态变量,如果两个都有,那么到时访问的是哪个,就有歧义了】
方法:
- 被static修饰:类方法、静态方法
- 可以通过实例、类访问
- 内部不能使用this
- 可以直接访问类变量、类方法
- 不可以直接访问实例变量、实例方法
- 没有被static修饰: 实例方法
- 只能通过实例访问、不能通过类访问
- 内部可以使用this
- 可以直接访问实例变量、实例方法
- 可以直接访问类变量、类方法【为什么:因为实例方法中有this, 又应为通过实例能访问类变量,所以在实例方法中可以直接访问类变量、方法】
十一、静态导入
使用了静态导入后,就可以省略类名来访问静态成员(成员变量、方法、嵌套类)
- 静态导入:可以消除一些重复的类名,提高代码的可读性
- 过度使用静态导入:会导致读者分不清静态成员在哪个类中定义
- 建议:谨慎使用静态导入
package com.lijian.lession5;
public class Persion {
public static int age = 37;
public static void show() {
System.out.println("age is "+ age);
}
public static class Foot {
public void run() {
System.out.println("run");
}
}
}
// 静态导入,*表示导入Persion中的所有静态成员,建议只导入使用的成员
import static com.lijian.lession5.Persion.*;
public class Main {
public static void main(String[] args) {
System.out.println(age); // 37
show(); // age is 37
Foot foot = new Foot();
foot.run(); //run
}
}
十二、初始化
成员变量的初始化
编译器会自动为未初始化的成员变量设置初始值
如何手动给实例变量提供初始值
- 在声明中
- 在构造方法中
- 在初始化块中
编译器会讲初始化块复制到每个构造方法的头部(每创建一个实例对象,就会执行一次初始化块)
如何手动给类变量提供初始值
- 在声明中
- 在静态初始化块中
当一个类被初始化的时候执行静态初始化块 当一个类第一次被主动使用时,JVM对类进行初始化
public class Persion {
static {
System.out.println("static block 1");
}
static {
System.out.println("static block 2");
}
{
System.out.println("block");
}
public Persion() {
System.out.println("Persion construct");
}
public Persion(int age) {
System.out.println("Persion(int) construct");
}
}
class Main {
public static void main(String[] args) {
new Persion();
System.out.println("---------");
new Persion(37);
}
}
输出如下
static block 1
static block 2
block
Persion construct
---------
block
Persion(int) construct
- 可以有多个(静态)初始化模块,按照在源码中出现的顺序被执行
14、单例模式
如果一个类设计成单例模式,那么在程序运行过程中,这个类只能创建一个实例
public class Rocket {
// 静态的类成员
private static Rocket instance = new Rocket();
// 构造函数私有化
private Rocket() { }
// 静态的方法获取实例
public static Rocket getInstance() {
return instance;
}
}
15、final常量
- 被 final 修饰的类:不能被子类化,不能被继承
- 被 final 修饰的方法:不能被重写
- 被 final 修饰的变量:只能进行1次赋值
常量(Constant)
- 常量的写法
- 如果将基本类型或字符串定义为常量,并且在编译时就能确定值
- 编译器会使用常量值替代各处的常量名(类似于 C 语言的宏替换)
- 称为编译时常量( compile-time constant)
16、内部类
嵌套类: 定义在另一个类中的类
public class OuterClass {
//静态嵌套类
static class StaticNestClass {
}
// 非静态嵌套类--内部类
class InnerClass {
}
}
在嵌套类外层的类,称为:外部类(Outer Class)
最外层的外部类,称为:顶级类(Top-level Class)
- 内部类:没有被 static 修饰的嵌套类,非静态嵌套类
- 跟实例变量、实例方法一样,内部类与外部类的实例相关联
- 必须先创建外部类实例,然后再用外部类实例创建内部类实例
- 内部类不能定义除编译时常量以外的任何 static 成员
- 内部类可以直接访问外部类中的所有成员(即使被声明为 private)
- 外部类可以直接访问内部类实例的成员变量、方法(即使被声明为 private)
内部类举例
public class Persion {
private int age;
public class Hand {
private int weight;
}
}
public class Main {
Persion p1 = new Persion();
Hand h1 = p1.new Hand();
Persion p2 = new Persion();
Hand h2 = p2.new Hand();
}
使用示例
package com.lijian.lession5;
public class Company {
private String name;
public Company(String name) {
this.name = name;
}
public void fire(Employee e) {
System.out.println(name + " fire " + e.no);
}
public class Employee {
private int no;
public Employee(int no) {
this.no = no;
}
public void show() {
System.out.println(name + ":" + no);
}
}
}
package com.lijian.lession5;
public class Main {
public static void main(String[] args) {
Company c = new Company("Google");
Company.Employee e = c.new Employee(1);
e.show();
c.fire(e);
}
}
输出
Google:1
Google fire 1
内部类使用细节
package com.lijian.lession5;
public class OuterClass {
private int x = 1;
public class InnerClass {
private int x = 2;
public void show() {
System.out.println(x);
System.out.println(this.x);
System.out.println(OuterClass.this.x);
}
}
public static void main(String[] args) {
new OuterClass().new InnerClass().show();
}
}
输出
2
2
1
17、静态嵌套类
- 静态嵌套类:被 static 修饰的嵌套类
- 静态嵌套类在行为上就是一个顶级类,只是定义的代码写在了另一个类中
- 对比一般的顶级类,静态嵌套类多了一些特殊权限
- 可以直接访问外部类中的成员(即使被声明为 private)
什么情况使用嵌套类
-
如果类 A 只用在类 C 内部,可以考虑将类 A 嵌套到类 C 中
- 封装性更好
- 程序包更加简化,看着类会减少
- 增强可读性、维护性,一眼看到是两个类相关。
-
如果类 A 需要经常访问类 C的非公共成员,可以考虑将类 A嵌套到类 C 中
- 另外也可以根据需要将类 A 隐藏起来,不对外暴露
-
如果需要经常访问非公共的实例成员,设计成内部类(非静态嵌套类),否则设计成静态嵌套类
- 如果必须先有 C 实例,才能创建 A 实例,那么可以将 A 设计为 C 的内部类
18、局部类
- 局部类:定义在代码块中的类(可以定义在方法中、 for 循环中、 if 语句中等)
- 局部类不能定义除编译时常量以外的任何 static 成员
- 局部类只能访问 final 或者 有效 final 的局部变量
- 从 Java 8 开始,如果局部变量没有被第二次赋值,就认定为是有效 final
- 局部类可以直接访问外部类中的所有成员(即使被声明为 private)
- 局部类只有定义在实例相关的代码块中,才能直接访问外部类中的实例成员(实例变量、实例方法)
public class Persion {
public void test() {
int a = 10; // 有效final
class Test {
int age = 1;
void test() {
// 这里类似是值捕获,如果是引用捕获(如多线程的情况),可能a的内存已经释放,访问就不安全
System.out.println(a);
}
}
Test t = new Test();
t.test();
}
}
package com.lijian.lession5;
public class Persion {
private int age;
public void test() {
class Dog {
void speak() {
System.out.println(age);
}
}
//在实例方法中,有实例对象,所有可以直接访问实例变量
Dog dog = new Dog();
dog.speak();
}
}
局部类举例
public class TestLocalClass {
private int a = 1;
private static int b = 2;
private static void test1() {};
private void test2() {};
public void test3() {
int c = 2;
class LocalClass {
static final int d = 4;
void test4() {
//a 是外部类的实例变量, 应为test3调用的时候,有this指针,可以访问
// b 是静态的,作用于内可见,所以可以访问
// c 没有被进行二次赋值,编译器认为是常量,可以访问。
System.out.println(a + b + c + d);
test1();
test2();
}
}
new LocalClass().test4();
}
}
19、抽象类
抽象方法
- 抽象方法:被 abstract 修饰的实例方法
- 只有方法声明,没有方法实现(参数列表后面没有大括号,而是分号)
- 不能是 private 权限(因为定义抽象方法的目的让子类去实现)
- 只能定义在抽象类、接口中
抽象类
- 抽象类:被 abstract 修饰的类
- 可以定义抽象方法
- 不能实例化,但可以自定义构造方法
- 子类必须实现抽象父类中的所有抽象方法(除非子类也是一个抽象类)
- 可以像非抽象类一样定义成员变量、常量、嵌套类型、初始化块、非抽象方法等
- 也就说,抽象类也可以完全不定义抽象方法
- 常见使用场景
- 抽取子类的公共实现到抽象父类中,要求子类必须要单独实现的定义成抽象方法
抽象类的目的就是用来继承的。
抽象类在非抽象类的基础上增加了定义抽象方法的功能,同事也减少了一个功能:实例化。
抽象类的功能其实普通的类也能实现,为什么要用抽象类呢?
- 不是实例化
- 强制子类实现
package com.lijian.lession5;
public abstract class Shape {
protected double area;
protected double girth;
public double getArea() {
return area;
}
public double getGirth() {
return girth;
}
public void show() {
calculate();
System.out.println(area + "_" + girth);
}
protected abstract void calculate() ;
}
子类:
package com.lijian.lession5;
public class Rectangle extends Shape{
private double width;
private double height;
public Rectangle(double width, double height) {
super();
this.width = width;
this.height = height;
}
@Override
protected void calculate() {
area = width * height;
girth = (width + height)*2;
}
public static void main(String[] args) {
Rectangle rectangle = new Rectangle(10, 20);
rectangle.show();
}
}
子类2:
package com.lijian.lession5;
public class Circle extends Shape{
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
protected void calculate() {
double half = Math.PI *radius;
area = half * radius;
girth = half*2;
}
public static void main(String[] args) {
Circle circle = new Circle(10);
circle.show();
}
}
20、接口基本使用
- 看到“接口”二字首先想到的什么?
- 网线接口? USB 接口?
- 接口的英文单词是 Interface, 这个单词是否很熟悉?
- API(Application Programming Interface)
- 应用编程接口,提供给开发者调用的一组功能(无须提供源码)
- Java 中的接口
- 一系列方法声明的集合
- 用来定义规范、标准
接口可以定义的内容
- 可以定义:抽象方法、常量、嵌套类型,从 Java 8 开始可以定义:默认方法、静态方法(类方法)
- 上述可以定义的内容都是隐式 public 的,因此可以省略 public 关键字
- 从 Java 9 开始可以定义 private 方法
- 常量可以省略 static、 final
- 抽象方法可以省略 abstract
- 不能自定义构造方法、不能定义(静态)初始化块、不能实例化
21、接口细节
- 接口名称可以在任何使用类型的地方使用
- 一个类可以通过 implements 关键字实现一个或多个接口
- 实现接口的类必须实现接口中定义的所有抽象方法,除非它是个抽象类
- 如果一个类实现的多个接口中有相同的抽象方法,只需要实现此方法一次
- extends 和 implements 可以一起使用, implements 必须写在 extends 的后面
- 当父类、接口中的方法签名一样时,那么返回值类型也必须一样
- 一个接口可以通过 extends 关键字继承一个或者多个接口
- 当多个父接口中的方法签名一样时,那么返回值类型也必须一样
接口升级问题
- 如果接口需要升级,比如增加新的抽象方法
- 会导致大幅的代码改动,以前实现接口的类都得改动
- 若想在不改动以前实现类的前提下进行接口升级,从 Java 8 开始,有 2 种方案
- 默认方法(Default Method)
- 静态方法(Static Method)
22、对比抽象类
- 抽象类和接口的用途还是有点类似,该如何选择?
- 何时选择抽象类?
- 在紧密相关的类之间共享代码
- 需要除 public 之外的访问权限
- 需要定义实例变量、非 final 的静态变量
- 何时选择接口?
- 不相关的类实现相同的方法
- 只是定义行为,不关心具体是谁实现了行为
- 想实现类型的多重继承
23、默认方法
- 用 default 修饰默认方法
- 默认方法只能是实例方法
package com.lijian.lession6;
public interface Eatable {
default void eat(String name) {
System.out.println("Eatable - eat" + name);
}
}
Cat类
package com.lijian.lession6;
public class Cat implements Eatable {
@Override
public void eat(String name) {
Eatable.super.eat(name);
System.out.println("Cat eat - " + name);
}
public static void main(String[] args) {
Cat cat = new Cat();
//Eatable - eatbone
//Cat eat - bone
cat.eat("bone");
}
}
Dog 类
package com.lijian.lession6;
public class Dog implements Eatable {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat("bone"); //Eatable - eatbone
}
}
默认方法的使用
- 当一个类实现的接口中有默认方法时,这个类可以
- 啥也不干,沿用接口的默认实现
- 重新定义默认方法,覆盖默认方法的实现
- 重新声明默认方法,将默认方法声明为抽象方法(此类必须是抽象类)
- 当一个接口继承的父接口中有默认方法时,这个接口可以
- 啥也不干,沿用接口的默认实现
- 重新定义默认方法,覆盖默认方法的实现
- 重新声明默认方法,将默认方法声明为抽象方法
默认方法实现细节
- 如果父类定义的非抽象方法与接口的默认方法相同时,最终将调用父类的方法
- 如果父类定义的抽象方法与接口的默认方法相同时,要求子类实现此抽象方法
- 可以通过 super 关键字调用接口的默认方法
- 如果(父)接口定义的默认方法与其他(父)接口定义的方法相同时,要求子类型实现此默认方法
24、静态方法
接口中定义的静态方法只能通过接口名调用,不能被继承
public interface Eatable {
static void eat(String name) {
System.out.println("eatable - eat -" + name);
}
}
public class Main {
public static void main(String[] args) {
Eatable.eat("bone");
}
}
25、多态 Polymorphism
- 什么是多态?
- 具有多种形态
- 同一操作作用于不同的对象,产生不同的执行结果
- 多态的体现
- 父类(接口)类型指向子类对象
- 调用子类重写的方法
- JVM 会根据引用变量指向的具体对象来调用对应的方法
- 这个行为叫做:虚方法调用(virtual method invocation)
- 类似于 C++ 中的虚函数调用
package com.lijian.lession6;
public class Animal {
public static void run() {
System.out.println("Animal - run");
}
}
package com.lijian.lession6;
public class Dog extends Animal{
public static void run() {
System.out.println("Dog - run");
}
public static void main(String[] args) {
Dog.run(); //Dog - run
Animal.run(); //Animal - run
Dog dog1 = new Dog();
dog1.run(); //Dog - run
Animal dog2 = new Dog();
dog2.run(); //Animal - run
//这说明了静态方法没有多态的特性
}
}
成员宾利的访问细节
成员变量访问也没有多态的特性。
package com.lijian.lession6;
public class Persion {
public int age = 1;
public int getPAge() {
return age;
}
}
package com.lijian.lession6;
public class Student extends Persion{
public int age = 2;
public int getSAget() {
return age;
}
public static void main(String[] args) {
Student student1 = new Student();
System.out.println(student1.age); //2
System.out.println(student1.getPAge()); // 1
System.out.println(student1.getSAget()); //2
Persion student2 = new Student();
System.out.println(student2.age); //1
System.out.println(student2.getPAge()); // 1
}
}
instanceof
- 可以通过 instanceof 判断某个类型是否属于某种类型
26、使用接口的好处
27、匿名类的基本使用 Anonymous Class
- 当接口、抽象类的实现类,在整个项目中只用过一次,可以考虑使用匿名类
package com.lijian.lession6;
public interface Eatable {
String name();
int energy();
}
package com.lijian.lession6;
public class Persion {
public void eat(Eatable e) {
System.out.println("eat- " + e.name() + "-" + e.energy());
}
public static void main(String[] args) {
Persion persion = new Persion();
//输出: eat- apple-100
persion.eat(new Eatable() {
@Override
public String name() {
return "apple";
}
@Override
public int energy() {
return 100;
}
});
Eatable beefEatable = new Eatable() {
@Override
public String name() {
return "Beef";
}
@Override
public int energy() {
return 500;
}
};
//输出: eat- Beef-500
persion.eat(beefEatable);
}
}
匿名类注意事项
- 匿名类不能定义除编译时常量以外的任何 static 成员
- 匿名类只能访问 final 或者 有效 final 的局部变量
- 匿名类可以直接访问外部类中的所有成员(即使被声明为 private)
- 匿名类只有在实例相关的代码块中使用,才能直接访问外部类中的实例成员(实例变量、实例方法)
- 匿名类不能自定义构造方法,但可以有初始化块
- 匿名类的常见用途
- 代码传递
- 过滤器
- 回调
28、匿名类的用途
实现一个统计代码执行功能的工具类。 接口定义如下:
public interface Block {
public void execute();
}
工具类定义如下:
public class Times {
public static void test(Block block) {
long begin = System.currentTimeMillis();
block.execute();
long end = System.currentTimeMillis();
double duration = (end - begin)/ 1000.0;
System.out.println("耗时:" + duration + "s");
}
}
调用类:
public class Main {
public static void main(String[] args) {
Times.test(new Block() {
@Override
public void execute() {
int age = 100;
for(int i = 0; i < age; i++) {
System.out.println(i); //耗时:0.002s
}
}
});
}
}
29、匿名类_排序
30、lambda基本使用
- Lambda 表达式是 Java 8 开始才有的语法,发音:美 [ˈlæmdə]
- 函数式接口(Functional Interface):只包含 1 个抽象方法的接口
- 可以在接口上面加上 @FunctionalInterface 注解,表示它是一个函数式接口
- 当匿名类实现的是函数式接口时,可以使用 Lambda 表达式进行简化
public class Main {
@FunctionalInterface
public interface Caculator {
int caculate(int v1, int v2);
}
static void execute(int v1, int v2, Caculator c) {
System.out.println(c.caculate(v1, v2));
}
public static void main(String[] args) {
execute(10, 20, (int v1, int v2) -> {
return v1 + v2;
}); //30
execute(11, 22, (v1, v2) -> v1 + v2); //33
}
}
31、lambda使用注意
Lambda 只能访问 final 或者 有效 final 的局部变量 Lambda 没有引入新的作用域
32、方法引用
如果lambda中内容仅仅是某个方法,可以使用方法引用(method reference)来简化
| 种类 | 用法 |
|---|---|
| 引用静态方法 | ClassName::staticMethodName |
| 引用特定对象的实例方法 | ObjectName::instanceMethodName |
| 引用特定类型的任意对象的实例方法 | ClassName::methodName |
| 引用构造方法 | ClassName::new |
| 引用当前类中定义的实例方法 | this::instanceMethodName |
| 引用父类中定义的实例方法 | supper::instanceMethodName |