Java中的四种内部类

基本介绍

一个类的内部又完整的嵌套了另外一个类的结构。被嵌套的类称为内部类,嵌套其他类的类称为外部类,是类的第五大成员(属性,方法,构造器,代码块,内部类)。内部类最大的特点就是可以直接访问私有属性。

分类:

定义在外部类的局部位置上(比如方法内):局部内部类(有类名),匿名内部类(没有类名)

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

局部内部类:

定义在外部类的局部位置,比如方法中,并且有类名

  1. 可以直接访问外部类的所有成员,包含私有
  2. 不能添加访问修饰符,因为他的地位就是一个局部变量,局部变量不能使用修饰符。但是可以用final修饰
  3. 作用域仅仅在定义它的方法或者代码块中
  4. 局部内部类访问外部类的成员,直接访问
  5. 外部类访问局部内部类的成员,先创建对象,在进行访问
  6. 外部其他类(与内部类无关联的类)不能访问局部内部类
  7. 如果外部类和局部内部类的成员重名。默认遵循就近原则,如果想要访问外部类的成员,则可以使用外部类.this.成员去访问

1--5点举例

package Learn;

 class Outer {
    private int outerNum=1;
    public void outerFunction(){
        System.out.println("外部类Test的方法");
        class Inner{
            private int innerNum=10;
            public void innerFunction(){
                System.out.println("内部类TestInner的方法");
                //可以直接调用
                System.out.println("外部类的私有的数值为"+outerNum);

            }
        }
        //在方法区中创建对象,使用内部类以及他的相关成员
        Inner inner=new Inner();
        inner.innerFunction();
        System.out.println(inner.innerNum);
    }
}
public class Test {
    public static void main(String[] args) {
        Outer outer=new Outer();
        outer.outerFunction();
    }
}

 第7点举例

public class Test {
     int a=0;
    public void sum(){
        class Inner{
            int a=6;
            public void sum1(){
                System.out.println(a+Test.this.a);
            }
        }
    }
}

匿名内部类

匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名(一定意义上说该类是拥有名字,但是不是我们所定义的,是由系统定义的,但是我们不可以直接知道他的名字),但是注意他的本质还是一个类,同时还是一个对象。匿名内部类使用是在该类仅仅使用一次,以后不会再次使用,此时重新创建一个类成本比较高,使用匿名内部类。

匿名内部类的基本语法:

new 类或者接口(参数列表){

类体}; 

下面是我们实现接口方法时常用的方法

package Learn;
public class Test {
    public static void main(String[] args) {
        Tiger tiger=new Tiger();
        tiger.cry();
    }
}
interface Animal{
    public void cry();
}
class Tiger implements Animal{

    @Override
    public void cry() {
        System.out.println("我是老虎");
    }
}

 但是如果我们仅仅使用一次tiger这个类,重新创建一个类太麻烦,这个时候我们使用匿名内部类

package Learn;
public class Test {
    public static void main(String[] args) {
        Animal tiger=new Animal() {
            @Override
            public void cry() {
                System.out.println("我是老虎");
            }
        };
        tiger.cry();
        /*我们根据下面的输出语句可以了解到,Animal tiger=new Animal() ,其编译类型为Animal,而其运行类型在jdk底层实际为
        * class Test$1 implements Animal(){
        *  @Override
        *  public void cry() {
                System.out.println("我是老虎");
            }
        * }
        */
        
        System.out.println("tiger对象对应的类名为"+tiger.getClass());
    }
}

interface Animal{
    public void cry();
    Animal tiger=new Animal() {
        @Override
        public void cry() {
            System.out.println("我是老虎");
        }
    };
}

 所以我们可以总结出匿名内部类的以下特点:

匿名内部类可以简化开发,但是该类只能使用一次,即上述例子中的Test$1只能使用一次,我们使用过后该类就直接消失了。即我们不能在创建一个Animal lion =new Test$1,但是我们创建的tiger却可以一直使用。

那么我们基于类进行匿名内部类的使用(注意与我们创建普通类对象的区别)

package Learn;
public class Test {
    public static void main(String[] args) {
        Animal tiger1=new Animal("猫猫");
        Animal tiger2=new Animal("花花") {

        };

        /*我们根据下面的输出语句可以了解到,Animal tiger2=new Animal() ,其编译类型为Animal,而其运行类型在jdk底层实际为
        * class Test$1 extend Animal(){
        *
        * }
        */
        System.out.println("tiger1对象对应的类名为"+tiger1.getClass());
        System.out.println("tiger2对象对应的类名为"+tiger2.getClass());
    }
}

class Animal{
    String name;
    public Animal(String name){

    }
}

 当我们到这里,其实也可以发现我们的匿名内部类的名称其实在外部类+$1。

匿名内部类的使用细节:

  • 匿名内部类既是一个类,也是一个对象,因此可以使用两种方法进行调用,上述刚刚使用类进行调用,看下我们利用对象进行调用。可以发现我们连tiger都忽略了,直接使用了cry方法。
package Learn;
public class Test {
    public static void main(String[] args) {
        new Animal() {
            @Override
            public void cry() {
                System.out.println("我是老虎");
            }
        }.cry();
    }
}

interface Animal{
    public void cry();
    Animal tiger=new Animal() {
        @Override
        public void cry() {
            System.out.println("我是老虎");
        }
    };
}
  • 匿名内部类不能添加访问修饰符,因为其本身就是一个局部变量。所以外部其他类不能直接访问匿名内部类

经典使用案例:我们不需要直接去写一个新的类来实现这个方法。

package Learn;
public class Test {
    public static void main(String[] args) {
        Test.f1(new AA() {
            @Override
            public void show() {
                System.out.println("输出");
            }
        });
    }
    public static void f1(AA aa){
        aa.show();
    }
}
interface AA{
    void show();
}

成员内部类

定义在外部类的成员位置上,可以访问外部类的所有成员,包括私有的,同时也可以添加修饰符。

package Learn;
public class Test {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.say();

    }
}
class Outer{
    private int a=0;
    class Inner{
        void show(){
            System.out.println(a);
        }
    }
    public void say(){
        Inner inner = new Inner();
        inner.show();

    }
}

外部其他类如何访问成员内部类

方法1,利用outer的对象实例进行调用

package Learn;
public class Test {
    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
        System.out.println(inner.b);

    }
}
class Outer{
    private int a=0;
    class Inner{
        int b=1;
        void show(){
            System.out.println(a);
        }
    }

}

方法2,利用方法进行调用

package Learn;
public class Test {
    public static void main(String[] args) {
        Outer outer = new Outer();
        System.out.println(outer.getInner().b);
    }
}
class Outer{
    private int a=0;
    class Inner{
        int b=1;
        void show(){
            System.out.println(a);
        }
    }
    public Inner getInner(){
        return new Inner();
    }

}

静态内部类

定义在成员位置,有static修饰,可以直接访问外部类的所有静态成员,包含私有的,但是不能直接访问非静态成员,可以添加任意的修饰符。而外部类访问静态内部类,需要创建实例对象才可以访问。

package Learn;
public class Test {
    public static void main(String[] args) {
        Outer outer = new Outer();
        //外部其他类访问静态内部类
        System.out.println(outer.getInner().b);
    }
}
class Outer{
    static int a=0;
    static class Inner{
        int b=1;
    }
    public Inner getInner(){
        return new Inner();
    }
    public int getB(){
        //外部类访问静态内部类
        Inner inner=new Inner();
        return inner.b;
        
    }

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值