jdk 1.8新特性 01内部类(重点是匿名内部类)和lambda

01.内部类:
1、成员内部类
在这里插入图片描述

内部类与成员外部类的关系

a.成员内部类的创建需要依赖于外部类对象-(成员方法必须通过对象调用),在没有外部类实例之前无法创建成员内部类对象

b.内部类与外部类相对独立,不是is a 的关系(发动机-汽车)

c.私有属性的互相访问,内部类可以直接访问外部类,而外部类访问内部类需要内部类的对象来访问

d.创建内部类的语法

1.在外部类内部创建内部类对象(Inner inner = new Inner())

2.在外部类外部创建内部类对象,外部类.内部类 inner = new Outter().new Inner();

e.在内部类内部使用隐藏的外部类对象(隐藏的this)

成员内部类的自定义方法访问外部类的属性:
在这里插入图片描述

成员内部类的实例化:

在这里插入图片描述

成员内部类:类比成员方法,不能拥有静态域但是可以访问外部类的静态域


2.静态内部类
定义在外部类的内部,使用static修饰,类比静态方法,静态内部类不需要外部类对象产生就能使用。

不能访问外部类的成员域,但能访问静态域
在这里插入图片描述
静态内部类的创建语法:

1.外部类内部:与成员内部类一样

2.外部类外部:StaticInnerClass.Inner inner = new StaticInnerClass.Inner();

实例化:
在这里插入图片描述


3.方法内部类
定义在方法内部:类比局部变量

a.对外部完全隐藏,因此方法内部类不能有任何访问修饰符

b.方法内部类没有访问形参是,这个形参是可以在方法中随意修改的,一旦方法内部类中使用了形参,这个形参必须被声明为final。
在这里插入图片描述


4.匿名内部类
a.必须继承一个抽象类或者实现一个接口

b.没有构造方法

通常一个接口实现类,实现接口的方法:
在这里插入图片描述
匿名内部类:(代码中有两种实现方式,上面一个实现类是一般接口实现类的运用)
在这里插入图片描述
总结:
本质上是一个没有名字的局部内部类,定义在方法中、代码块中、等。
作用:方便创建子类对象,最终目的是为了简化代码编写。

格式:(创建一个匿名内部类对象)

new 类|抽象类名|或者接口名(){
重写方法;
}

特点:
匿名内部类是一个没有名字的内部类。
匿名内部类写出来就会产生一个匿名内部类的对象。
匿名内部类的对象类型相当于是当前new的那个的接口类型的子类型。
举个例子:

在这里插入图片描述

/**
    目标:掌握匿名内部类的使用形式
 */
public class Test {
    
    
    public static void main(String[] args) {
    
    
    //使用匿名内部类替代学生类,创建的类型是new的那个类的子类
        Swimming s = new Swimming() {
    
    
            @Override
            public void Swim() {
    
    
                System.out.println("学生游的很快");
            }
        };
        go(s);
    }

    /**
        方法:学生、老师、运动员可以一起游泳
     */
    public static void go(Swimming s)
    {
    
    
        System.out.println("开始游泳了~~");
        s.Swim();
        System.out.println("结束游泳了~~");
    }
}
//创建学生类
/*class Student implements Swimming{
    @Override
    public void Swim() {
        System.out.println("学生游的很快");
    }
}*/

//定义一个接口规范游泳
interface Swimming{
    
    
    void Swim();
}


匿名内部类的好处是可以直接new 接口{接口中声明的抽象方法(重写)}

2.lambda表达式

举个例子:

01.创建一个新的线程,指定线程要执行的任务

public static void main(String[] args) {
    
    
// 开启一个新的线程
new Thread(new Runnable() {
    
    
@Override
public void run() {
    
    
System.out.println("新线程中执行的代码 :
"+Thread.currentThread().getName());
}
}).start();
System.out.println("主线程中的代码:" + Thread.currentThread().getName());
}

代码分析:

  1. Thread类需要一个Runnable接口作为参数,其中的抽象方法run方法是用来指定线程任务内容的核心
  2. 为了指定run方法体,不得不需要Runnable的实现类
  3. 为了省去定义一个Runnable 的实现类,不得不使用匿名内部类
  4. 必须覆盖重写抽象的run方法,所有的方法名称,方法参数,方法返回值不得不都重写一遍,而且不能出错,
  5. 而实际上,我们只在乎方法体中的代码

02.Lambda表达式初体验

Lambda表达式是一个匿名函数,可以理解为一段可以传递的代码

Lambda表达式的优点:
1.简化了匿名内部类的使用,语法更加简单。
2.匿名内部类语法冗余,体验了Lambda表达式后,发现Lambda表达式是简化匿名内部类的一种方式。

new Thread(() -> {
    
     System.out.println("新线程Lambda表达式..."
+Thread.currentThread().getName()); })
.start();

03.Lambda的语法规则
Lambda省去了面向对象的条条框框,Lambda的标准格式由3个部分组成:
格式说明:

(参数类型 参数名称) -> {
    
    
代码体;
}
01.(参数类型 参数名称):参数列表
02.{
    
    代码体;} :方法体
03.-> : 箭头,分割参数列表和方法体

04.两种Lambda(此时的运用的接口都是作为方法的参数)

1.无参无返回值:
定义一个接口:

public interface UserService {
    
    
void show();//接口中的抽象方法没有参数
}

然后创建主方法使用:

public class Demo03Lambda {
    
    
	public static void main(String[] args) {
    
    
		goShow(new UserService() {
    
    
			@Override
				public void show() {
    
    
					System.out.println("show 方法执行了...");//此处是打印语句,无返回值
				}
		});
		System.out.println("----------");
		goShow(() -> {
    
     System.out.println("Lambda show 方法执行了..."); });
		}
	public static void goShow(UserService userService){
    
    
		userService.show();
	}
}

2.有参有返回值的

创建一个Person对象

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    
    
	private String name;
	private Integer age;
	private Integer height;
}

然后我们在List集合中保存多个Person对象,然后对这些对象做根据age排序操作

public static void main(String[] args) {
    
    
	List<Person> list = new ArrayList<>();
		list.add(new Person("周杰伦",33,175));
		list.add(new Person("刘德华",43,185));
		list.add(new Person("周星驰",38,177));
		list.add(new Person("郭富城",23,170));
	Collections.sort(list, new Comparator<Person>() {
    
    //这个是java
		@Override
		public int compare(Person o1, Person o2) {
    
    
			return o1.getAge()-o2.getAge();
		}
	});
	for (Person person : list) {
    
    
		System.out.println(person);
	}
}

我们发现在sort方法的第二个参数是一个Comparator接口的匿名内部类,且执行的方法有参数和返回值,那么我们可以改写为Lambda表达式

public static void main(String[] args) {
    
    
	List<Person> list = new ArrayList<>();
		list.add(new Person("周杰伦",33,175));
		list.add(new Person("刘德华",43,185));
		list.add(new Person("周星驰",38,177));
		list.add(new Person("郭富城",23,170));
	/*Collections.sort(list, new Comparator<Person>() {
		@Override
		public int compare(Person o1, Person o2) {
			return o1.getAge()-o2.getAge();
		}
	});
	for (Person person : list) {
		System.out.println(person);
	}*/
	System.out.println("------");
	Collections.sort(list,(Person o1,Person o2) -> {
    
    //这里的lambda表达式,有参数,有返回值,返回值直接用return
		return o1.getAge() - o2.getAge();
	});
	for (Person person : list) {
    
    
		System.out.println(person);
	}
}

Lambda表达式的省略写法

  1. 小括号内的参数类型可以省略
  2. 如果小括号内有且仅有一个参数,则小括号可以省略
  3. 如果大括号内有且仅有一个语句,可以同时省略大括号,return 关键字及语句分号。
public class Demo05Lambda {
    
    
	public static void main(String[] args) {
    
    
	
		goStudent((String name,Integer age)->{
    
    
			return name+age+" 6666 ...";
		});
		// 省略写法
		goStudent((name,age)-> name+age+" 6666 ...");
		System.out.println("------");

		goOrder((String name)->{
    
    
			System.out.println("--->" + name);
			return 666;
		});
		// 省略写法
		goOrder(name -> {
    
    
			System.out.println("--->" + name);
			return 666;
		});
		goOrder(name -> 666);
	}
	public static void goStudent(StudentService studentService){
    
    
		studentService.show("张三",22);
	}
	public static void goOrder(OrderService orderService){
    
    
		orderService.show("李四");
	}
}

Lambda表达式的使用前提:

1.具体去实现的方法(在类中先去声明这种方法、)的参数或局部变量类型必须为接口才能使用Lambda
2. 方法中用的接口中有且仅有一个抽象方法(@FunctionalInterface)

lambda表达式和匿名内部类的区别:

  1. 抽象方法的数量不一样
    匿名内部类所需的接口中的抽象方法的数量是随意的
    Lambda表达式所需的接口中只能有一个抽象方法
  2. 实现原理不一样
    匿名内部类是在编译后形成一个class
    Lambda表达式是在程序运行的时候动态生成class

猜你喜欢

转载自blog.csdn.net/qq_38757863/article/details/132357075