Java内部类与接口回调

Java内部类与接口回调

1.内部类

内部类顾名思义就是定义在一个类中的类。内部类可以分为:普通内部类、静态内部类、局部内部类、匿名内部类。

2.普通内部类

1.定义方式

将内部类定义在一个类的方法外,且非static修饰的就是普通内部类。内部类限定词可以为publicprivateprotected

当为private时,只有在外部类的方法中可以构造它。

当为protected时,需要写限定词为public的内部类构造函数才能在子类中调用构造函数。

class Outer{
    private String name = "outer";

    public class Inner{
        private String name = "inner";
    }
}
2.创建内部类对象的方式
  1. 在外部类方法中可以使用如下创建方式:
Inner inner = this.new Inner();
  1. 对于public内部类,也可以先创建一个外部类对象再创建内部类对象:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
3.访问权限
  1. 内部类可以访问外部类的成员,包括 private 成员。
  2. 外部类可以调用内部类成员,但是需要通过内部类对象来调用它的成员,这样间接的方式,因为它自身是不具备这些成员的。
  3. 内部类对于同一个包下的其他类来说,是无法被看到的。
package test;

public class innerClass{
    public static void main(String[] args) {
        Outer outer = new Outer();
        test.Outer.Inner inner = outer.new Inner();

        //outer.sayName();  outer自身没有这个方法,所以通过outer对象是无法直接调用内部类inner的成员方法的
        outer.sayNameByInner(inner);    // 但是这样通过内部类inner对象调用就是可以的。
        System.out.println("===========");
        inner.sayName();
    }
}

class Outer{
    private String name = "outer";

    public String getInnerName(Inner inner){
        return inner.name;  //可以通过inner对象来间接调用其私有成员。
        // 可能这样的形式不够明显,但是如果将outer和inner改为两个类会更明显一些。
        // 在分开写成两个类的情况下,outer是无法访问inner的name属性的,就好比在main方法中写如下代码:outer.name,是错的。
        // 这证明写成内部类的形式可以让外部类访问内部类的私有成员。
    }

    public void sayNameByInner(Inner inner){
        inner.sayName();
    }

    public class Inner{
        private String name = "inner";

        public void sayName(){
            sayInnerName();
            sayOuterName();
        }

        private void sayInnerName(){
            System.out.println(name);
        }

        private void sayOuterName(){
            System.out.println(Outer.this.name);	//通过类名.this.属性名 来取得外部类的属性
        }
    }
}

结果:

​ inner

​ outer

​ ===========

​ inner
​ outer

就好像房东与租客的关系。房东有一套房子,租给了租客住,房东的洗衣机冰箱等设施,虽然属于房东,但是租客是可以随意用的。
突然有一天房东需要用锤子,刚好租客自己买了一个,那么房东就可以问租客借他的锤子,在征求得他的意见之后就可以拿到了。

3.静态内部类

1.定义方式

在普通内部类中,内部类构造器中会被编译器自动加上对外部类的引用,这样才能保证可以访问外部类的所有成员。
有时候, 使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外围类对象。为此,可以将内部类声明为 static, 以便取消产生的引用。静态内部类限定词可以为publicprivateprotected

class Outer2{
    private String name = "outer";
    private static int age = 18;
    
    static class inner2{
        private String name = "inner";
        private static int age = 18;
}
2.静态内部类对象的创建

静态内部类对象的创建可以脱离外部类实体,可以先不创建外部类就创建内部类,而非静态内部类就必须先实例化外部类对

象。

Inner2 inner2 = new Outer2.Inner2();

此外,静态类的静态方法、静态属性可以通过类名 + 成员名访问。

System.out.println(Inner2.getOuterAge());	// 假设在Inner类中有一个getOuterAge的静态方法
3.访问权限
  1. 内部类只能访问外部类静态成员
  2. 外部类可以访问内部类所有成员(间接方式)。
class Outer2{
    private String name = "outer";
    private static int age = 18;

    public static int getAge(){ // 内部类可以访问外部类的静态方法
        return age;
    }

    public String getInnerName(Inner2 inner2){
        return inner2.name; // 外部类可以访问内部类非静态属性
    }

    public int getInnerAge(Inner2 inner2){
        return inner2.age;// 外部类可以访问内部类静态属性
    }

    static class Inner2{
        private String name = "inner";
        private static int age = 18;

        public int getOuterAge(){
            //return Outer2.age;    这样也可以访问,内部类可以访问外部类的静态属性
            return getAge();
        }

        //public String getOuterName(){
        //    return Outer2.name;   //静态内部类只能访问外部类的静态成员
        //}
    }

    public static void main(String[] args) {
        Inner2 inner2 = new Outer2.Inner2();
        Outer2 outer2 = new Outer2();
        System.out.println(outer2.getInnerName(inner2));
        System.out.println(outer2.getInnerAge(inner2));
        System.out.println("==========");
        System.out.println(inner2.getOuterAge());
    }
}

结果:

​ inner

​ 18

​ ==========

​ 18

4.总结

1.静态内部类的特点

(1)使用static修饰的成员内部类叫静态内部类

(2)静态内部类跟外部类没有任何关系,只是在生成类名和类定义时有影响。静态内部类可以看做是与外部类平级的类,使用方式与外部类平级的类完全相同。

(3)创建静态内部类的实例,使用 外部类名.内部类名 实例名 = new 外部类名.内部类构造方法;

2.静态内部类有以下限制

(1)静态内部类不能与外部类重名

(2)静态内部类不能访问外部类的非静态的属性和方法,外部类也不能访问内部类的非静态的属性和方法。

4.局部内部类

1.定义方式

如果我们需要的内部类只在一个方法中被用到,就可以只在这个方法内定义一个内部类,这就是局部内部类,类似局部变量的定义。

class Outer3{

    public void test(){
        class Inner3{
			....
        }
    }
}

局部类不能用 public 或 private 访问说明符进行声明。它的作用域被限定在声明这个局部类的块中。

2.优点

局部类有一个优势, 即对外部世界可以完全地隐藏起来。 即使 Outer 类中的其他方法也不能访问它。除 test 方法之外, 没有任何方法知道Inner类的存在。

3.访问局部变量

与其他内部类相比较,局部类还有一个优点。它们不仅能够访问包含它们的外部类, 还可以访问局部变量。不过,那些局部变量必须事实上为 final。这说明, 它们一旦赋值就绝不会改变。

class Outer3{
    public void test(String name,int age){	//可以将参数声明为final保证不会被修改
        class Inner3{
            public void say(){
                System.out.println(name);
                System.out.println(age);
                //age++; 不能修改局部变量
            }
        }
        Inner3 inner3 = new Inner3();
        inner3.say();
    }

    public static void main(String[] args) {
        Outer3 outer3 = new Outer3();
        outer3.test("李华",18);
    }
}

5.匿名内部类

1.定义方式

定义类的最终目的是创建一个类的实例,但是如果某个类的实例只是用一次,则可以将类的定义与类的创建,放到与一起完成,或者说

在定义类的同时就创建一个类,以这种方法定义的没有名字的类成为匿名内部类。匿名内部类像是进一步减少使用范围的局部内部类。

class Outer4{
    public void say(){
        Inner inner = new Inner() {
            ....
            }
        };
    }
}

可能会疑惑这里明明是有类名Inner的,为什么说匿名内部类是创建一个没有类名的对象呢?那是因为这里的Inner是指一个接口或者超类,而我们实际定义的类是{}中的部分。

2.一个实例

匿名内部类必须继承一个类或实现一个接口,这里的Inner是匿名内部类所实现的接口名。但匿名内部类不能同时实现一个接口和继承一个类,也不能实现多个接口。
如果实现了一个接口,该类是Object类的直接子类,匿名类继承一个类或实现一个接口,不需要extends和implements关键字。

interface Inner{
    void sayInner();
}

class Outer4{
    public void say(){
        Inner inner = new Inner() {
            @Override
            public void sayInner() {
                System.out.println("hi");
            }
        };
        inner.sayInner();
    }

    public static void main(String[] args) {
        Outer4 outer4 = new Outer4();
        outer4.say();
    }
}

由于构造器的名字必须与类名相同, 而匿名类没有类名,所以,匿名类不能有构造器。取而代之的是,将构造器参数传递给超类构造器。尤其是在内部类实现接口的时候, 不能有任何构造参数。

3.匿名内部类的使用:接口回调

见大佬博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值