天天看点

内部类和lambda表达式

作者:小謝吖

今日目标:

1 能够创建四种内部类

2 能够知道每种内部类的特点和应用

3 能够熟练使用匿名内部类

4 lambda表达式的基本使用

5 能够学会匿名内部类和lambda表达式的转换

一 内部类--成员内部类

1.1 问题提问:

1. 什么是内部类
2. 如何创建内部类对象
3. 内部类的访问特点           

1.3 问题答案:

1. 什么是内部类
定义在一个类中的类
2. 如何创建内部类对象
外部类对象.内部类对象 对象名 = new 外部类对象().new 内部类对象();
3. 内部类的访问特点
内部类可以直接访问外部类的成员,包括私有成员.
外部类想要访问内部类的成员,必须先创建对象.           

1.4 内部类详细说明

1 内部类:其实并不是什么地方都能用上

2 内部类分类:
成员内部类
静态内部类

局部内部类
匿名内部类

3 语法:类中定义类
class A{
class B{
/*
B就是A的内部类编译之后会生成两个class文件
A.class
A$B.class
说明内部类只是在编译期有效到运行期 A和B是没有包含关系
是两个相互独立的类 所以内部类仅仅是一个编译期的语法
外部类名称$内部类名称.class
*/
}
}

4 作用:
1 防止类名冲突 同一个包内定义两个同名的类是不允许的 但是可以创建同名的内部类
public class Demo1 {
}
class B{
class Demo1{
}
}
2 实现多继承
class A extends 类名{

class B extends 类名{
//还是单继承 但是内部内部可以访问外部类的所有属性和方法 包括私有
}
}

3 内部类可以很好的实现隐藏:一般的非内部类,
是不允许有 private 与protected权限的,但内部类可以
所以内部类往往都定义了企业最核心的逻辑代码

5 缺点: 使程序结构不清晰。
           

二 静态内部类

2.1 问题提问

1 内部类能被私有吗
2 外部类如何使用私有内部类
2 静态内部类的创建格式           

2.3 问题答案

1 内部类能被私有吗
可以被private 修饰
只能在自己所在的外部类中去访问

2 可以在外部类中创建方法 在方法中去使用私有内部类

3 静态内部类的创建格式
外部类.内部类 对象名=new 外部类.内部类();

静态内部类中的静态成员访问格式
外部类.内部类.成员
           

2.4 成员内部类详解

注意点:
1成员内部类和成员属性定义位置一样
2成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)
3创建成员内部类必须先创建外部类对象,通过外部类对象.new 构造内部类对象
4成员内部类中不能有静态成员
5当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,
即默认情况下访问的是成员内部类的成员。
如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类. this .成员变量
外部类. this .成员方法
6成员内部类可以有常量

代码演示
class Outer{
private int a=100;

public Outer(int a){
this.a=a;
}
public void method(){
Inner in=new Inner();
in.print();
}
//Inner的定义位置是Outer类的成员位置上是内部类 可以用private public修饰
//里边和正常定义类一样
class Inner{
int a=20;
public void print(){
//那能不能打印a,a的作用范围是整个Outer类 所以是可以打印的
//inner在Outer类的封装范围内
System.out.println(a);
//使用外部类的同名a
System.out.println(Outer.this.a);
}
//static int b=10; //内部类不能有静态成员
final int B2=10;//可以有常量
static final int B1=10;//可以有静态常量
}
}
}

问题思考:为什么成员内部类不能有静态成员?
JVM的类加载规则 :
1. static类型的属性和方法,在类加载的时候就会存在于内存中。
2. 要想使用某个类的static属性和方法,那么这个类必须要加载到JAVA虚拟机中。
3. 非静态内部类并不随外部类一起加载,只有在实例化外部类之后才会加载。

public class Outer{
int x;
class Inner{
// static int a = 0;//这样写是不合法的.
static final int b=0;//这样写是合法的
}
}

java类加载顺序,首先加载类,执行static变量初始化,接下来执行对象的创建,
如果我们要执行代码中的变量int a 初始化,那么必须先执行加载外部类,再加载内部类,
最后初始化静态变量 a ,问题就出在加载内部类上面,我们可以把内部类看成外部类的非静态成员,
它的初始化必须在外部类对象创建后以后进行,要加载内部类必须在实例化外部类之后完成 ,
java虚拟机要求所有的静态变量必须在对象创建之前完成,这样便产生了矛盾。
将class Inner看作外部类的非静态成员,它属于对象Outer(即new 出来的Outer()),
static int a 属于类Inner 所以先于对象Inner Outer创建出来,矛盾

而java常量放在内存中常量池,它的机制与变量是不同的,编译时,加载常量是不需要加载类的,所以就没有上面那种矛盾。

静态的东西需要在编译时分配内存,而非静态内部类是在实例化的时候才分配内存。
所以现在的情况就是有了东西没地方放 static int a 没地方放,因为class Inner还没有实例化

问题思考: 为什么内部类能访问外部类的成员

因为内部类持有外部类的引用
class Outer{
private int a=100;

class Inner{
int b=20;
public void print(){
System.out.println(b);//this.b
System.out.println(a);//Outer.this.a
}
}
}

总结内部类
1 名义上内部类 实际上是外部类,每个内部类都有自己独立的.class文件命名
外部类$内部类.class
2 封装性更高 可以作成私有 内部类往往都定义了企业最核心的内容
3 大多数情况下 内部类的对象都是由外部类去创建的(也就是说在外部类中new 内部类对象)
4 成员内部类能够持有外部类的this
5 内部类不会在外部类初始化的时候被初始化           

2.5 静态内部类详解

和静态成员定义位置一样 静态内部类只能访问外部类的静态成员 所以不再需要先创建外部类对象
class Outer{
private int a=10;
private static int b=20;

public Outer(){
System.out.println("out");
}
public void method1(){
Inner.mehtod();//外部类可以直接调用内部类的静态方法和属性
int b=Inner.a;
System.out.println("outer普通方法");
}
public static void method2(){
System.out.println("outer静态方法");
}
static class Inner{
static int a=20;
public Inner(){
System.out.println("in");
}
public void print(){
//System.out.println(a);//静态内部类只能访问外部类的静态成员
System.out.println(b);
//mehtod1(); //静态内部类不能方位外部类的非静态方法
method2();
}
public static void mehtod(){
System.out.println("hello");
}
}
}

public class Demo1 {
public static void main(String[] args) {
Outer.Inner in=new Outer.Inner();
// 通过打印只是执行了静态内部类的构造方法
// 静态内部类是不需要依赖于外部类的
// 在没有外部类的对象的情况下,可以创建静态内部类的对象
in.print();
in.mehtod();
Outer.Inner.mehtod(); //通过类名点直接调用
}
}

1 静态内部类只能直接使用外部类的静态成员
2 外部类能直接使用内部类的静态成员(静态内部类名.的形式)
如果想使用静态内部类的普通方法 需要创建静态内部类的对象

           

2.6 静态内部类总结

1 不能使用外部类的非static成员变量或者方法,
静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,
因为在没有外部类的对象的情况下,可以创建静态内部类的对象,
如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。

2 属性和方法可以声明为静态的或者非静态的。

3 实例化静态内部类:比如:B是A的静态内部类,A.B b = new A.B();

4 内部类只能引用外部类的静态的属性或者方法。

5 如果属性或者方法声明为静态的,那么可以直接通过类名直接使用。
比如B是A的静态内部类,b()是B中的一个静态成员,则可以:A.B.b();

6 静态内部类不会持有外部类对象引用(外部类的this)           
内部类和lambda表达式