内部类
内部类概述
内部类是五大成分之一(成员变量、方法、构造方法、内部、代码块),如果一个类定义在另一个类内部,这个类就是内部类
场景:当一个类的内部,包含一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类。
1
2
3
4
5
6public class Car{
// 内部类
public class Engine{
}
}内部类有四种形式:
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
成员内部类
成员内部类就是类中的一个普通成员,类似前面我们学过的普通的成员变量、成员方法
1
2
3
4
5public class Outer{
// 成员内部类
class public Inner{
}
}使用内部类创建对象:
Outer.Inner 对象名 = new Outer().new Inner();成员内部类的实例方法中,访问其他成员有啥特点?
- 可以直接访问外部类的实例成员、静态成员
- 可以拿到当前外部类的对象,格式是
Outer.this
静态内部类
什么是静态内部类?
- 有
static修饰的内部类,属于外部类自己持有
- 有
创建对象的格式:
1
2
3
4
5
6
7
8
9class class Outer{
//静态内部类
public class Inner{
}
}
// 外部类名.内部类名 对象名 = new 外部类.内部类();
Outer.Inner in = new Outer.Inner();注意:可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员。
局部内部类
局部内部类是定义在方法中、代码块中、构造方法等执行体中(看看就好)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class Test{
public static void main(String[] args){
}
public static void go(){
class A{
}
abstract class B{
}
interface C{
}
}
}
匿名内部类
匿名内部类的书写格式:
1
2
3
4
5
6
7
8
9new 类或接口(参数值……){
类体(一般是方法重写);
};
new Animal(){
public void cry() {
}
};匿名内部类特点:
- 匿名内部类本质就是一个子类,并会立即创建出一个子对象
匿名内部类作用:
- 可以更方便的创建出一个子类对象
- 匿名内部类通常作为一个参数传输给方法
枚举
认识枚举
枚举是一种特殊的类
枚举的格式:
1
2
3
4
5
6
7
8
9修饰符 enum 枚举类名{
名称1, 名称2,……;
其他成员……
}
public enum A{
X, Y, Z;
……
}注意:
枚举类中的第一行,只能写一些合法的标识符(名称),多个名称用逗号隔开。
这写名称,本质是常量,每个常量都会记住枚举类的一个对象。
枚举的特点:
1
2
3
4
5
6
7
8
9
10
11
12
13public enum A{
X, Y, Z;
}
Compiled from "A.java"
public final class A extends java.lang.Enum<A> {
public static final A X = new A();
public static final A Y = new A();
public static final A Z = new A();
public static A[] values();
public static valueOf(java.lang.String)
}- 枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象。
- 枚举类的构造方法都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象。
- 枚举类都是最终类,不可以被继承。
- 枚举类中,从第二行开始,可以定义类的其他各种成员。
- 编译器为枚举类新增了几个方法,并且枚举类都是继承:
java.lang.Enum类的,从enum类也会继承到一些方法。
枚举的常见应用场景
- 用来表示一组信息,然后作为参数进行传输。
- 选择定义一个一个的常量来表示一组信息,并作为参数传输:参数值不受约束
- 选择定义枚举表示一组信息,并作为参数传输:代码可读性好,参数值得到了约束,对读者更友好,建议使用
泛型
认识泛型
定义类、接口、方法时,同时声明了一个或多个类型变量(如:
<E>),称为泛型类、泛型接口、泛型方法,它们统称之为泛型。1
2
3public class Array<E>{
……
}作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力!这样可以避免强制类型转换,及其可能出现的异常。
泛型的本质:把具体的数据类型作为参数传给类型变量
泛型类、泛型接口
泛型类
1
2
3
4
5
6
7修饰符 class 类名<类型变量, 类型变量, ……>{
}
public class ArrayList<E>{
……
}注意:类型变量建议使用大写的英文字母,常用的有:E、T、K、V等
泛型接口
1
2
3
4
5
6
7修饰符 interface 接口名<类型变量, 类型变量, ……>{
}
public interface A<E>{
……
}
泛型方法、泛型通配符、上下限
泛型方法:
1
2
3
4
5
6
7修饰符<类型变量, 类型变量,……> 返回值类型 方法名(形参列表){
}
public static <T> void test(){
}通配符
- 就是
?,可以在”使用泛型“的时候代表一切类型;E、T、K、V是在定义泛型的时候使用。
- 就是
泛型的上下限:
- 泛型上限:
? extends Car,?能接收的必须是Car或者其子类。 - 泛型下限:
? super Car:?能解收的必须是Car或者其父类。
- 泛型上限:
泛型的注意事项:擦除问题、基本数据类型问题
泛型的擦除问题和注意实现
- 泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除。
- 泛型不支持基本数据类型,只能支持对象类型(引用数据类型)
JDK8新特性:Lambda表达式
认识Lambda表达式
Lambda表达式是JDK8开始新增的一种语法形式,作用是用于简化匿名内部类的代码写法。
格式:
1
2
3(被重写方法的形参列表)->{
被重写方法的方法体代码;
}注意:Lambda表达式只能简化函数式接口的匿名内部类
函数式接口:
- 有且仅有一个抽象方法的接口。
- 将来我们见到的大部分函数式接口,上面都可能会有一个
@FunctionalInterface的注解,有该注解的接口就必定是函数式接口名。
Lambda表达式的省略规则
- 参数类型可以不写。
- 如果只有一个参数,参数类型可以省略,同时
()也可以省略 - 如果Lambda表达式中的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号!此时,如果这行代码是return语句,也必须去掉return不写
JDK8新特性:方法引用
静态方法的引用
- 静态方法的引用:
类名::静态方法 - 使用场景:如果某个Lambda表达式里只是调用一个静态方法,并且前后参数的形式一致,就可以使用静态方法引用。
实例方法的引用
- 实例方法的引用:
类名::实例方法 - 使用场景:如果某个Lambda表达式里只是调用一个实例方法,并且前后参数的形式一致,就可以使用实例方法引用。
特定类型方法的引用
- 特定类型方法的引用:
类型::方法 - 使用场景:如果某个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数是作为作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用指定类型的方法引用。
构造器引用
- 构造器引用:
类名::new - 使用场景:如果某个lambda表达式里只是在创建对象,并且前后参数情况一致,就可以使用构造器引用。