目录
内部类
成员内部类
我们可以直接在类的内部定义 成员内部类:
定义:
内部类也是类,所以说里面也可以有成员变量、方法等,甚至可以继续套娃一个成员内部类:
public class Test {
class Inner{
public void test(){
System.out.println("我是成员内部类");
}
}
}
使用成员内部类:
成员内部类就像成员变量和成员方法一样,都是属于对象的,而不是类所有的。
不能直接new
public static void main(String[] args){
Test test=new Test(); //先创建对象
Test.Inner inner=test.new Inner(); //成员内部类的类型名称就是 外层.内部类名称
inner.test(); //可以使用成员内部类中的方法
}
成员内部类也可以使用访问权限控制,如果我们将其权限改为private,那么就像我们把成员变量访问权限变成私有一样,外部是无法访问到这个内部类的。
在成员内部类中,是可以访问到外层的变量的;
外部不能访问内部类里面的成员变量。
同名变量的使用:
public class Test {
private final String name;
public Test(String name){
this.name=name;
}
public class Inner{
String name;
public void test(String name){
System.out.println("方法参数的name="+name);//就近原则,最近的是参数
System.out.println("内部成员的name="+this.name);//在内部类中使用this关键字,只能表示内部对象
System.out.println("外部的name="+Test.this.name);
//如果需要指定为外部的对象,那么需要在前面添加外部类型名称
}
}
}
对方法的调用和super关键字的使用也是一样的:
public class Inner{
String name;
public void test(String name){
this.toString(); //内部类自己的toString方法
super.toString(); //内部类父类的toString方法
Test.this.toString(); //外部类的toString方法
Test.super.toString(); //外部类父类的toString方法
}
}
静态内部类
静态内部类就像静态方法和静态变量一样,是属于类的。
public class Test {
private final String name;
public Test(String name){
this.name=name;
}
public static class Inner{
public void test(){
System.out.println("我是静态内部类");
}
}
}
不需要依附任何对象,我们可以直接创建静态内部类的对象:
可以直接new
public static void main(String[] args){
Test.Inner inner=new Test.Inner();
inner.test();
}
静态内部类无法访问到外部的非静态内容,内部不受影响。
局部内部类
局部内部类就像局部变量一样,可以在方法中定义。
public class Test {
private final String name;
public Test(String name){
this.name=name;
}
public void hello(){
class Inner{ //局部内部类
}
Inner inner=new Inner(); //局部内部类直接使用类名
}
}
既然是在方法中声明的类,那作用范围也只在方法中。
匿名内部类
使用频率高,局部内部类的简化版。
正常情况下,要创建一个抽象类的实例对象,只能对其进行继承,先实现未实现的方法,然后创建子类对象。
而我们可以在方法中使用匿名内部类,将其中的抽象方法实现,并直接创建实例对象。
public abstract class Student {
public abstract void test();
}
import com.test.entity.Student;
public class Main {
public static void main(String[] args){
Student student=new Student() { //在new的时候后面加上{},把未实现的方法实现
@Override
public void test() {
System.out.println("我是匿名内部类的实现");
}
};
student.test();
}
}
匿名内部类同样可以使用类中的属性(因为它本质上就相当于是对应类型的子类)。
接口也是一样的。
普通的类也可以这样创建匿名内部类,一般情况下只是为了进行一些额外的初始化工作。
Lambda表达式
前面介绍了匿名内部类,我们可以通过这种方法创建一种临时的实现子类。
如果一个接口中只有一个待实现的抽象方法,那么可以将匿名内部类简写为Lambda表达式。
public static void main(String[] args){
Study study= () ->System.out.println("我是学习方法");
study.study();
}
表达式的语法:
- ([参数类型 参数名称,]...)->{代码语句,包括返回值}
- 和匿名内部类不同,Lambda仅支持接口,不支持抽象类
- 接口内部必须有且仅有一个抽象方法(可以有多个方法,但是必须保证其他方法有默认实现,必须留一个抽象方法出来)
public static void main(String[] args){
Study study= new Study() {
@Override
public String study(int a) {
return "今天学会了"+a;
}
};
System.out.println(study.study(10));
}
改为Lambda表达式:
public static void main(String[] args){
Study study= (int a)-> {
return "今天学会了"+a;
};
System.out.println(study.study(10));
}
再简写:
public static void main(String[] args){
Study study= a-> "今天学会了"+a;
System.out.println(study.study(10));
}
匿名内部类和Lambda的变量捕获:
变量a就是,捕获的变量。这个变量要么是被final修饰,如果不是被final修饰的,要保证在使用 之前没有修改(a是final或有效final)
public static void main(String[] args){
int a=10;
Study study= ()-> {
System.out.println(a);
};
study.study();
}
//复制一个a
int a=10;
a=20;
int finalA = a;
Study study= ()-> System.out.println(finalA);
优缺点:
Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。
优点:
- 代码简洁,开发迅速
- 方便函数式编程
- 非常容易进行并行计算
- Java 引入 Lambda,改善了集合操作
缺点:
- 代码可读性变差
- 在非并行计算中,很多计算未必有传统的 for 性能要高
- 不容易进行调试
方法引用
方法引用就是将一个已实现的方法,直接作为接口中抽象方法的实现(当然前提是方法定义得一样才行)
public interface Study {
int sum(int a,int b); //待实现的求和方法
}
//Lambda表达式
public static void main(String[] args){
Study study=(a,b)->a+b;
}
//Integer类中对应的实现
Study study=(a,b)->Integer.sum(a,b);
我们发现,Integer.sum的参数和返回值,跟我们在Study中定义的完全一样,所以说我们可以直接使用方法引用:
public static void main(String[] args){
Study study=Integer::sum;
}
使用双冒号来进行方法引用,静态方法使用 类名::方法名 的形式。
方法引用本质上就相当于将其他方法的实现,直接作为接口中抽象方法的实现,任何方法都可以通过方法引用作为实现:
public interface Study {
String study();
}
public class Main {
public static void main(String[] args){
Main main =new Main();
Study study=main::xxx;
System.out.println(study.study());
}
public String xxx(){
return "hhhhh";
}
}
//输出 hhhhh
成员方法通过具体的对象调用,所以只能使用 对象::方法名 的形式。
因为现在只需要一个String类型的返回值,由于String的构造方法在创建对象时也会得到一个String类型的结果,所以:
public static void main(String[] args){
Study study=String::new; //构造方法也可以被引用,使用new表示
}
只要符合接口中方法的定义的,都可以直接进行方法引用。