1.概念
我这里理解的来源1.韩顺平老师的30天学java的课件中的概念
一个类的内部又完整的嵌套了另一个类结构,被嵌套的类策划归纳为内部类(inner class),嵌套其他类的类称为外部类(outer Class)。
类的五大成员:属性、方法、构造器、代码块、内部类。
内部类的最大特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。源代码中有大量的内部类。
内部类的分类
定义在外部类局部位置上(比如方法内):
- 局部内部类(有类名)
- 匿名内部类(没有类名,重点!!!!)
定义在外部类的成员位置上
- 成员内部类(没有statc修饰)
- 静态内部类(使用static修饰)
class Outer{
class Inner {
}
}
class Other {
}
快速入门
package com.xxxx.innerclass;
public class InnerClass01 { //外部其他类
public static void main(String[] args) {
}
}
class Outer { //外部类
private int n1 = 100; //属性
public Outer(int n1) { //构造器
this.n1 = n1;
}
public void m1() { //方法
System.out.println("m1()");
}
{ //代码块
System.out.println("代码块...");
}
class Inner { //内部类, 在 Outer 类的内部
}
}
匿名内部类的使用
1.本质还是类
2.内部类
3.该类没有名字
4.同时还是一个对象
匿名内部类通常使用一次,后面不再使用。节省位置。
语法:
new 类或接口(参数列表){
类体
};
/**
* 演示匿名内部类的使用
*/
public class sss {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04 { //外部类
private int n1 = 10;//属性
public void method() {//方法
/*基于接口的匿名内部类
老韩解读
1.需求: 想使用 IA 接口,并创建对象
2.传统方式,是写一个类,实现该接口,并创建对象
3.老韩需求是 Tiger/Dog 类只是使用一次,后面再不使用
4. 可以使用匿名内部类来简化开发
5. tiger 的编译类型 ? IA
6. tiger 的运行类型 ? 就是匿名内部类 Outer04$1
*/
/*
我们看底层 会分配 类名 Outer04$1
class Outer04$1 implements IA {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
}
*/
/*7. jdk 底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例,并且把地址
返回给 tiger
8. 匿名内部类使用一次,就不能再使用*/
IA tiger = new IA() {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
};
System.out.println("tiger 的运行类型=" + tiger.getClass());
tiger.cry();
tiger.cry();
tiger.cry();
/*
普通方法这样写
IA tiger = new Tiger();
tiger.cry();
*/
/*演示基于类的匿名内部类
分析
1. father 编译类型 Father
2. father 运行类型 Outer04$2
3. 底层会创建匿名内部类*/
/*
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println("匿名内部类重写了 test 方法");
}
}
*/
/*4. 同时也直接返回了 匿名内部类 Outer04$2 的对象
5. 注意("jack") 参数列表会传递给 构造器*/
Father father = new Father("jack"){
@Override
public void test() {
System.out.println("匿名内部类重写了 test 方法");
}
};
System.out.println("father 对象的运行类型=" + father.getClass());//Outer04$2
father.test();
//基于抽象类的匿名内部类
Animal animal = new Animal(){
@Override
void eat() {
System.out.println("小狗吃骨头...");
}
};
animal.eat();
}
}
interface IA {//接口
public void cry();
}
//class Tiger implements IA {
//
// @Override
// public void cry() {
// System.out.println("老虎叫唤...");
// }
//}
//class Dog implements IA{
// @Override
// public void cry() {
// System.out.println("小狗汪汪...");
// }
//}
class Father {//类
public Father(String name) {//构造器
System.out.println("接收到 name=" + name);
}
public void test() {//方法
}
}
abstract class Animal { //抽象类
abstract void eat();
}
仔细理解代码应该都可以看懂。注释的代码是先用普通代码写的。
这里我们理解lambda表达式。这里就看清代码中的 Father类,里面有构造方法
package com.lambda;
/**
* 使用lambda表达式替换Runnable匿名内部类
* @author MingChenchen
*
*/
public class RunableTest {
/**
* 普通的Runnable
*/
public static void runSomeThing(){
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("I am running");
}
};
new Thread(runnable).start();
}
/**
* 使用lambda后的
*/
public static void runSomeThingByLambda(){
new Thread(() -> System.out.println("I am running")).start();
}
public static void main(String[] args) {
runSomeThing();
// runSomeThingByLambda();
}
}
上述代码中:
() -> System.out.println("I am running")就是一个lambda表达式,
可以看出,它是替代了new Runnable(){}这个匿名内部类。
结合上面两段代码,我讲一些我的理解
new Thread(() -> System.out.println("I am running")).start();
这里的这个()中的参数是重写的方法 run() 中的参数
这个就是匿名内部类的参数位置。
/*
也可以直接调用,匿名内部类本身也是返回对象*/
class 匿名内部类 extends Person {
new Person(){
@Override
public void hi(){
System.out.println("匿名内部类重写了 hi 方法,哈哈...");
}
@Override
public void ok(String str){
super.ok(str);
}
}.ok("jack");
}
2.使用lambda表达式实现Comparator
package com.lambda;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class SortList {
//给入一个List
private static List<String> list =
Arrays.asList("my","name","is","uber","and","uc");
/**
* 对一个String的list进行排序 - 使用老方法
*/
public static void oldSort(){
//排序
Collections.sort(list,new Comparator<String>() {
//使用新的排序规则 根据第二个字符进行逆序排
@Override
public int compare(String a,String b){
if (a.charAt(1) <= b.charAt(1)) {
return 1;
}else{
return -1;
}
}
});
}
/**
* 新的排序方法 - 使用lambda表达式实现
*/
public static void newSort(){
//lambda会自动推断出 a,b 的类型
Collections.sort(list, (a, b) -> a.charAt(1) < b.charAt(1) ? 1:-1);
}
public static void main(String[] args) {
// oldSort();
newSort();
}
}
记住匿名内部类的用法就是使用一次,那个类如果不再调用方法就不会再使用。,然后lambda就是节省了匿名内部类的书写。
关于方法的应有方面的额讲解,最近看到一篇文章,讲的更简单易懂:
方法引用(Method References)
https://www.cnblogs.com/Alay/p/15056737.html
字符串大小的比较从String.compareTo()方法。
在spring中lambda和stream可以很好的一起使用。
看下面两篇文章:
1.
JAVA8之lambda表达式详解,及stream中的lambda使用
2.
Java 中的双冒号“::”
双冒号“::”就是 Java 中的方法引用(Method references)
方法引用的格式是类名::方法名。一般是用作 Lambda表达式。
http://t.csdn.cn/i37UX
3
.
全面吃透JAVA Stream流操作,让代码更加的优雅
上面两个链接**1.,2.**中讲的stream还算清晰,不理解的可以多读两遍就好了。这个要仔细读。我第一遍就读得快,细节没掌握到就不懂。第二遍深夜读的。掌握了感觉。
然后写项目时,经常把 stream 流和 lambda 表达式结合起来使用。在【1.】中讲的stream的应用方法只能算入门。但是入门也要先看。有助于后续深入的提高。
后续深入学习 stream 和lambda 一起使用的文章在这里:3.
全面吃透JAVA Stream流操作,让代码更加的优雅
这里的这个流 stream 是 paralleleStream 管道流。(输出管道流PipedOutputStream或)。也是流的一种。不同于字符流字节流。
中间管道方法的讲解和终止管道方法大致简述如下(一定先看1.
JAVA8之lambda表达式详解,及stream中的lambda使用
这篇文章,有个大概的了解stream.但是它写的方法不全,看下面我写的的全的):
每个Stream管道操作类型都包含若干API方法,先列举下各个API方法的功能介绍。
开始管道
主要负责新建一个Stream流,或者基于现有的数组、List、Set、Map等集合类型对象创建出新的Stream流。
API | 功能说明 |
---|---|
stream() | 创建出一个新的stream串行流对象 |
parallelStream() | 创建出一个可并行执行的stream流对象 |
Stream.of() | 通过给定的一系列元素创建一个新的Stream串行流对象 |
中间管道
负责对Stream进行处理操作,并返回一个新的Stream对象,中间管道操作可以进行叠加。
API | 功能说明 |
---|---|
filter() | 按照条件过滤符合要求的元素, 返回新的stream流 |
map() | 将已有元素转换为另一个对象类型,一对一逻辑,返回新的stream流 |
flatMap() | 将已有元素转换为另一个对象类型,一对多逻辑,即原来一个元素对象可能会转换为1个或者多个新类型的元素,返回新的stream流 |
limit() | 仅保留集合前面指定个数的元素,返回新的stream流 |
skip() | 跳过集合前面指定个数的元素,返回新的stream流 |
concat() | 将两个流的数据合并起来为1个新的流,返回新的stream流 |
distinct() | 对Stream中所有元素进行去重,返回新的stream流 |
sorted() | 对stream中所有的元素按照指定规则进行排序,返回新的stream流 |
peek() | 对stream流中的每个元素进行逐个遍历处理,返回处理后的stream流 |
终止管道
顾名思义,通过终止管道操作之后,Stream流将会结束,最后可能会执行某些逻辑处理,或者是按照要求返回某些执行后的结果数据。
API | 功能说明 |
---|---|
count() | 返回stream处理后最终的元素个数 |
max() | 返回stream处理后的元素最大值 |
min() | 返回stream处理后的元素最小值 |
findFirst() | 找到第一个符合条件的元素时则终止流处理 |
findAny() | 找到任何一个符合条件的元素时则退出流处理,这个对于串行流时与findFirst相同,对于并行流时比较高效,任何分片中找到都会终止后续计算逻辑 |
anyMatch() | 返回一个boolean值,类似于isContains(),用于判断是否有符合条件的元素 |
allMatch() | 返回一个boolean值,用于判断是否所有元素都符合条件 |
noneMatch() | 安徽一个boolean值, 用于判断是否所有元素都不符合条件 |
collect() | 将流转换为指定的类型,通过Collectors进行指定 |
toArray() | 将流转换为数组 |
iterator() | 将流转换为Iterator对象 |
foreach() | 无返回值,对元素进行逐个遍历,然后执行给定的处理逻辑 |
上面的还是没有看懂的话看这几个其他网站的讲解:(先把下面这个**【全面吃透JAVA Stream流操作,让代码更加的优雅】**看完)
-
https://tobebetterjavaer.com/java8/stream.html
-
https://juejin.cn/post/6844903830254010381
-
https://blog.51cto.com/u_15430445/5203512
**3.**下面是整个页面我插入进来了: