Java笔记整理 —— 内部类

Java笔记整理 —— 内部类,第1张

Java笔记整理 —— 内部类 内部类(难点、重点) 基本介绍 

     一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类,嵌套内部类的类称为外部类,是我们类的第五大成员(五大成员:属性、方法、构造器、代码块、内部类)内部类的最大特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。

class Outer{         // 外部类
    class Inner{     // 内部类
    
    }
}

class Other{         // 外部其它类

}
内部类的分类

1. 定义在外部类的局部位置上(方法/代码块内):A. 局部内部类(有类名) B. 匿名内部类(没有类名,重点)

2. 定义在外部类的成员位置上:A. 成员内部类(没用static修饰)B. 静态内部类(使用static修饰)

局部内部类

1. 可以直接访问外部类的所有成员,包括私有的。

2. 不能添加访问修饰符,因为它相当于一个局部变量,局部变量是不能使用修饰符的,但是可以使用final修饰,因为局部变量也可以使用final。

3. 作用域:仅仅在定义它的方法或代码块中。

4. 外部类 访问 局部内部类的成员:创建对象再访问(必须在作用域内)。

5. 局部内部类 访问 外部类成员:直接访问。

public class Outer {
    private int n1 = 10;
    public void say(){
        int n3 = 30;
        class Inner01{
            int n2 = n1;  //直接访问外部类成员
            public void show(){
                System.out.println("调用局部内部类的方法");
            }
        }
        Inner01 a = new Inner01();
        a.show();  //先创建对象再访问局部内部类的成员
    }
    Inner01 b = new Inner01();  //报错,已经不在局部内部类的作用域中了
}

6. 外部其它类不能访问 局部内部类(因为 局部内部类相当于一个局部变量)。

7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用 外部类名.this.成员 去访问,其中 外部类名.this 相当于外部类。

public class Outer {
    private int n1 = 10;
    private static String name = "张三";
    public void say(){
        int n1 = 30;
        class Inner01{
            int n1 = 1000;
            public void show(){
                System.out.println(n1);   //输出 1000,就近原则
                System.out.println(this.n1);  //输出 1000,用this还是就近原则
                System.out.println(Outer.this.n1); //输出 10,外部类定义的变量
                System.out.println(Outer.n1); //报错
            }
        }
        Inner01 a = new Inner01();
        a.show();
    }
}

class Others{
    Inner01 a = new Inner01();  //报错,外部其他类 不能访问 局部内部类
}

匿名内部类

    定义在外部类的局部位置,并且没有类名。(1)本质是类 (2)该类没有名字 (3)同时还是一个对象。

接口:

new 类或接口(参数列表){  //构造器
    类体
}; //注意返回一个指向该类或接口的实例
public class Outer {
    public void create(){   //写在方法内
        IA tiger = new IA(){
            @Override
            public void say() {
                System.out.println("老虎嗷嗷叫");
            }
        };  //匿名内部类,tiger的编译类型为IA,tiger的运行类型就是匿名内部类(也就是 Outer)
    }
}

interface IA{
    void say();
}

  实际上Jdk底层会给 匿名内部类 分配一个类名,分配的方法为 外部类类名+$(可用tiger的getClass方法查看),然后立即创建一个 Outer$1实例,并且把地址赋给 tiger。

class Outer implements IA {
    @override
    public void cry(){
        System.out.println("老虎嗷嗷叫");  
    }
}

类:


public class Outer {
    public void create(){
        Person1 a = new Person1("Jack") {
            @Override
            public void say() {
                System.out.println("在匿名内部类重写父类方法");
            }
            public void hello(){
                System.out.println("调用匿名内部类独有的方法");
            }  //无法调用,因为编译类型为Person1,不能调用子类独有的方法
        };
        //匿名内部类,不加大括号就是正常的创建类,运行类型为Person1,而加了就是匿名内部类
        a.say();
        System.out.println(a.getClass()); //输出a的运行类型,为 Outer
    }
}

class Person1 {
    private String name;
    public Person1(String name) {
        this.name = name;
    }
    public void say(){
    }
}
注意事项

1. 匿名内部类既是一个类的定义,同时它本身也是一个对象(本身就是个返回对象)。因此从语法上看,它既有定义类的特征,也有创建对象的特征,因此可以直接调用匿名内部类方法。

        new Person1("Jack") {
            @Override
            public void say() {
                System.out.println("在匿名内部类重写父类方法");
            }
        }.say();   //可以new之后直接调用

3. 可以直接访问外部类的所有成员,包含私有的。

4. 不能添加访问修饰符,因为它的地位就是一个局部变量。

5. 作用域:仅仅在定义它的方法或代码块中。

6. 匿名内部类 访问 外部类成员:直接访问。

7. 外部其它类 不能访问 匿名内部类(因为匿名内部类建立之后就销毁了)。

8. 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用 外部类名.this.成员 去访问。

实例

当作实参直接传递,简洁高效。

public class Outer{
    public static void f1(IL il){
        il.show();
    }

    public static void main(String[] args) {
        f1(new IL() {     // 把匿名内部类当作参数导入
            @Override
            public void show() {
                System.out.println("导入匿名内部类");
            }
        });
    }
}

interface IL{
    void show();
}

对比一下传统方法

public class Outer{
    public static void f1(IL il){
        il.show();  
    }

    public static void main(String[] args) {
        Picture a = new Picture();  // 创建一个对象
        f1(a);  // 利用接口的多态
    }
}

interface IL{
    void show();
}

class Picture implements IL{  // 定义一个类实现接口
    @Override
    public void show() {     
        System.out.println("传统方法");
    }
}
成员内部类

成员内部类定义在外部类的成员位置,并且没有static修饰。

1. 可以直接访问外部类的所有成员包含私有的。

2. 可以添加任意访问修饰符,因为它的地位就是一个成员。

3. 作用域:和外部类的其他成员一样,为整个类。

4. 成员内部类 访问 外部类成员:直接访问。

5. 外部类 访问 成员内部类:创建对象再访问。

class Outer{
    private int n1 = 10;
    class inner{
        public void show(){
            System.out.println(n1);  //内部成员类 调用 外部类(私有也可以访问)
        }
    }
    public void say(){
        inner a = new inner();  // 先创建对象                    
        a.show();   // 外部类 调用 内部成员类
    }
}

6. 外部其它类 访问 成员内部类

第一种方式:把 Inner01 看作 Outer01 的成员,Outer01.Inner01 为编译类型,用外部类实例new

class Others{
    Outer01 outer = new Outer01();
    Outer01.Inner01 inner = outer.new Inner01();  //相当于把 Inner01当作 Outer01的成员
}

第二种方式:在外部类中编写一个方法,可以返回 Inner01 对象

public Inner01 getInner01(){
    Inner01 a = new Inner01();
    return a;
}  //编写方法

class Others{
    Outer01 outer01 = new Outer01();
    Outer01.Inner01 inner01 = outer01.getInner01();  //用对象实例调用方法
}

7. 如果外部类和内部类的成员重名时,内部类访问遵循就近原则,如果想访问外部类的成员,则可以使用 外部类名.this.成员 去访问。

静态内部类

静态内部类定义在外部类的成员位置,并且有static修饰。

1. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员。

2. 可以添加任意访问修饰符,因为它的地位就是一个成员。

3. 作用域:同其他的成员,为整个类体。

4. 静态内部类 访问 外部类:直接访问所有静态成员。

5. 外部类 访问 静态内部类:先在外部类中创建对象再访问。

6. 外部其它类 访问 静态内部类:

第一种方法:因为是静态内部类,可以通过类名直接访问(满足访问权限)。

    Outer01.Inner01 inner01 = new Outer01.Inner01(); //直接用类名new

第二种方法:编写一个方法,可以返回静态内部类的对象实例。

public Inner01 create(){
    return new Inner01();  //返回一个 静态内部类的实例
} 

class Others{
    Outer01 a = new Outer01();
    Outer01.Inner01 inner01 = a.create();  //调用方法返回实例
}

7. 如果外部类和内部类的成员重名时,内部类访问遵循就近原则,如果想访问外部类的成员,则可以使用 外部类名.成员 去访问(因为 外部类名.this 是对象名,而静态变量可以用类名访问)。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5696412.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存