目录
1. 成员内部类
1.1. 成员内部类的代码如何书写?
1.2. 如何创建成员内部类的对象?
1.3. 成员内部类如何获取外部类的成员变量?
2. 静态内部类
2.1. 什么是静态内部类?
2.2. 创建静态内部类的对象的格式:
2.3. 调用静态内部类里的方法:
3. 局部内部类
4. 匿名内部类(重要)
4.1. 什么是匿名内部类?
4.2. 定义格式:
4.3. 格式的细节:
4.4. 格式分析:
4.5. 字节码检验
4.6. 使用场景:
4.7. 拓展:
方式一(当内部类被private修饰时使用):
在外部类中编写方法,对外提供内部类的对象。
// 外部类
class Outer{
String name;
// 内部类
class Inner{
int a=10;
}
// 定义一个方法用来创建内部类的对象(返回值类型+方法名)
Inner getInstance(){
return new Inner();
}
}
//测试类
class Test{
main{
//首先创建外部类对象
Outer outer=new Outer();
// 然后用外部类对象调用getInstance方法,并可使用多态接收
Object inner = outer.getInstance();
}
}
方式二(被非private修饰时使用):
直接创建对象
格式:外部类名 . 内部类名 对象名=外部类对象 . 内部类对象;
范例:Outer.Inner oi=new Outer().new Inner();
第一种方法我可以在集合中的迭代器中得到印证:
由面试题引出问题:
解答如下:
System.out.println(Outer.this.a);
Outer.this表示外部类对象的地址值
System.out.println(this.a);
System.out.println(a);
静态内部类中只能访问外部类中的静态变量和静态方法,如果要访问非静态的需要先创建外部类对象
如下
public class Outer {
static int a;
int b;
//静态内部类
static class Inner {
// 非静态方法
public void show1() {
Outer out=new Outer();
System.out.println(a);
System.out.println(out.b);//非静态字段“b”不能直接从静态上下文中引用
}
//静态方法
public static void show2(){
Outer out=new Outer();
System.out.println(a);
System.out.println(out.b);//非静态字段“b”不能直接从静态上下文中引用
}
}
}
}
在成员内部类前加 static 的类叫静态内部类,它是成员内部类中的一种。
定义如下:
外部类名.内部类名 对象名 =new 外部类名.内部类名();
Car.Engine oi=new Car.Engine()
因为静态内部类是 static 修饰的,所以 new 的是 Car 里面的 Engine
注意要和成员内部类对象创建格式要区别开
先创建内部类对象,再用对象调用
如下:
public class Outer {
//静态内部类
static class Inner {
// 非静态方法
public void show1() {
System.out.println("非静态方法被调用");
}
// 静态方法
public static void show2(){
System.out.println("静态方法被调用");
}
}
}
//测试
class Test{
main{
// 创建内部类对象
Outer.Inner oi=new Outer.Inner();
// 调用非静态方法
oi.show1();
}
外部类名.内部类名.方法名();
Outer.Inner.show2();
一直 . 即可
定义在外部类的方法内,所以定义局部内部类的前提是定义一个方法,和局部变量同等级; //public protected private不可修饰成员变量,因此同样不可修饰局部内部类
定义如下:
public class Outer {
// show方法
public void show(){
// 局部内部类
class Inner {
}
}
}
特性:
如下:
public class Outer {
int b = 20;
//方法
public void show() {
int a = 10;
// 局部内部类
class Inner {
public void method1() {
System.out.println("局部内部类中的方法1");
System.out.println(a);//访问方法内的局部变量
System.out.println(b);//访问外部类的成员
}
}
// 创建对象,并调用show
Inner inner=new Inner();
inner.method1();
}
}
//测试
public class Test {
public static void main(String[] args) {
Outer outer=new Outer();
outer.show();
/*
局部内部类中的方法1
10
20
*/
}
}
隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置。
包含三个关系:
继承或实现、方法重写、创建对象
所以代码整体其实是一个父类的子类,或则说是一个接口的实现类的对象。
// 首先我们的要有一个接口或父类,这里以接口为例
public interface Swim{
public abstract void swim();
}
// 按以前我们要实现一个接口的,我们是这样写的;
public class Student implements Swim{
@Override
public void swim(){
System.out.println("重写Swim接口中的游泳方法")
}
}
//现在的写法:
public class Test{
main{
new Swim (){
@Override
public void swim(){
System.out.println("重写Swim接口中的游泳方法")
}
}; //注意这里要加分号
}
紫线圈起来的其实才是那个没有名字的类
它实现了 Swim 接口
new 的作用是:创建了这个类的对象。
(括号代表无参创建)
为了检验说法的正确性,我们检查字节码文件:
找到
这个路径
发现原来匿名内部类是有名字的:
外部类$序号
接着我们再当前路径下打开 cmd
分别输入 javap Test$1.class 、 javap Test$2.class
和之前的推断完全一致。
由问题引出:
在测试类中如何调用下面的 method 方法?
以前的方式如何调用?
要先写一个子类来继承 Animal 类再在测试类中创建子类对象,传递给 method 方法
Dog d=new Dog();
method(d);
弊端:如果我只使用一次 Dog,那么单独创建一个子类太麻烦了。
这时就可以用匿名内部类简化代码
/如下可在method中 使用匿名内部类的对象,
//括号内的实参表示是一个继承了Animal并重写了eat方法的子类
// 先创建一个父类
public abstract class Animal{
// 抽象方法
public abstract void eat();
}
// -------------------------------------------------------
//测试类
public class Test{
public static void main(String []args){
method(
new Animal (){
public void eat(){
System.out.println("狗吃骨头")
}
}
);//注意这里要加分号
}
//成员方法
public static void method (Animal a){
a.eat();
}
}
2.可直接用对象调用其中的方法