Java内部类

内部类

将一个类放在另一个类内部,这个在其他类内部的类称为内部类, 或嵌套类。包含内部类的类称为外部类,或宿主类。
成员内部类分为两种:
静态内部类
非静态内部类
使用 static 修饰的内部类为 静态内部类。
一个Java源文件中定义多个类,不属于内部类。

//下面这两个不属于内部类
class A{}
public class B{}

非静态内部类

访问权限

外部类有默认和 public两种权限:默认为包, public为任何位置
内部类由4个访问权限:
private : 同一个类
默认: 同一个包
protected : 父子类
public类: 任何位置

访问变量

非静态内部类访问某个变量时:
先从方法内找是否存在该名字的局部变量,找到就使用,
如果找不到,就从内部类中查找是否存在该名字的成员变量, 找到就使用。
找不到就从所在的外部类找, 存在就是用。
找不到就出现编译错误。
外部内部成员可以使用 外部类名.this 获取,
内部类可以用 this. 获取

public class Outter {
    private String str = "Outter str";

    private class Inner{
        private String str = "Inner str";

        public void info(){
            String str = "local str";

            //访问外部
            System.out.println(Outter.this.str);
            //访问内部类
            System.out.println(this.str);
            //访问局部变量
            System.out.println(str);
        }
    }

    public void test(){
        Inner inner = new Inner();
        inner.info();
    }

    public static void main(String[] args){
        new Outter().test();
    }
}
//输出
Outter str
Inner str
local str

非静态内部类的成员可以访问外部类的 private 成员, 外部类的不能访问内部类的 private 成员。
外部类使用内部类的 private 成员时, 必须显式的创建内部类对象来调用。因为创建外部类对象时, 并不会创建内部类对象。

静态成员

静态成员不能访问非静态成员。
外部类的静态方法,静态代码块,不能访问非静态内部类。

非静态内部类不能有静态方法,静态成员变量,静态初始化块。
但可以有普通初始化块。

使用

调用内部类

        Outter.Inner inner = new Outter().new Inner();
        //或下面这样
        Outter.Inner inner1;
        Outter outter = new Outter();
        inner = outter.new Inner();

创建子类:
创建子类时,必须保证子类构造器可以调用内部内构造器,调用时必须存在一个外部类对象。

class SubInner extends Outter.Inner{
    public SubInner(Outter outter){
        outter.super();
    }
}

静态内部类

使用 static 修饰的内部类是静态内部类,属于外部类本身,不属于外部类的某个对象。
static 是把类的成员变成类相关, 而不是实例相关, 外部类的上一级程序单元是包, 所以不可使用 static 修饰外部类,但可以修饰内部类。

静态内部类的实例方法,不能访问外部类的实例变量,只能访问静态变量。

public  class Outter {
    private String str = "Outter str";
    
    private static int b = 2;
    
    static class StaticInner{
        private static int a = 1;
        private int c = 3;
        public void test(){
            //不能访问外部类的实例变量
//            System.out.println(str);
            
            System.out.println(b);
        }
    }
    
    public void accessTest(){
        //不能访问静态内部类成员
//        System.out.println(c);
        System.out.println(StaticInner.a);
        
        System.out.println(new StaticInner().c);
    }
}

接口

接口中允许定义内部类, 默认为 public static 修饰。
接口内部类只能是静态内部类。

静态内部类使用

调用时,无需创建外部类对象。

Outter.StaticInner inner2 = new Outter.StaticInner();

创建子类也比较简单

class SubStaticInner extends Outter.StaticInner{
    
}

局部内部类

放在方法里的类,称为局部内部类。
仅在方法内有效。
由于不能做方法以外调用, 所以局部内部类不能使用访问控制符和static修饰符。

    public static void main(String[] args){
        class InnerClass{
            int a;
        }

        class InnerSubClass extends InnerClass{
            int b;
        }

        InnerSubClass innerSubClass = new InnerSubClass();
        innerSubClass.a = 1;
        innerSubClass.b = 2;

        System.out.println(innerSubClass.a + innerSubClass.b);
    }
//输出 3

实际开发中很少用到局部内部类。

匿名内部类

匿名内部类是继承一个父类,或实现一个接口。
匿名内部类不能是抽象类:当创建匿名内部类时,会立即创建对象
不能定义构造器: 因为没有类名,所以不能定义构造器。但是可以定义初始化块。

interface Product{
    public String getName();
}
public class AnonymousTest {
    public void info(Product p){
        System.out.println("name is :" + p.getName());
    }

    public static void main(String[] args){
        AnonymousTest at = new AnonymousTest();

        at.info(new Product() {
            @Override
            public String getName() {
                return "Milk";
            }
        });
    }
}

//输出
name is :Milk

上面 info() 需要 Product 参数, Product 只是接口,不能创建对象,
因此定义一个匿名内部类实现Product接口。
定义匿名内部类,不需要 class 关键字。
匿名内部类必须实现它的抽象父类或接口里包含的所有抽象方法。
看下面的例子

abstract class Dev{
    private String name;
    public abstract int getPrice();
    public Dev(){}

    public Dev(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class AnonymousTest {
    public void info(Product p){
        System.out.println("name is :" + p.getName());
    }

    public void test(Dev d){
        System.out.println("Dev name : " + d.getName() + " price: " + d.getPrice());
    }
    public static void main(String[] args){
        AnonymousTest at = new AnonymousTest();
        at.test(new Dev("M2") {
            @Override
            public int getPrice() {
                return 50;
            }
        });

        Dev d = new Dev() {
            @Override
            public int getPrice() {
                return 100;
            }

            public String getName(){
                return "M3";
            }
        };

        at.test(d);
    }
}
//输出
Dev name : M2 price: 50
Dev name : M3 price: 100

包含了有参和无参构造器,
实现了抽象类里的所有抽象方法, 还可以重写父类的普通方法。

局部变量

访问局部变量必须是 final 修饰的,
JAVA 8会自动加上 final.
这种称为 effectively final

    public static void main(String[] args){
        AnonymousTest at = new AnonymousTest();
        int a = 8;
        Dev d = new Dev() {
            @Override
            public int getPrice() {
                //使用局部变量
                System.out.println(a);
                return 100;
            }

            public String getName(){
                return "M3";
            }
        };
        //不能重新赋值
     //   a = 3;
    }

局部变量被匿名内部类使用后,不能修改值了,因为系统自动加上了final 修饰符。

地址: https://blog.csdn.net/yonggang7/article/details/86709708

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值