内部类

参考:一篇文章让你彻底了解Java内部类

什么是内部类

将一个类的定义,放在另一个类的内部,这就是内部类

为什么需要内部类

  • 内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据
  • 内部类可以对同一个包中的其他类隐藏起来
  • 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷. (匿名内部类是一个接口或者抽象类的实现类或者子类的对象)

内部类主要有一下几类

  • 成员内部类
  • 局部内部类
  • 静态内部类
  • 匿名内部类
    注意:
  • 定义了成员内部类后,必须使用外部类对象来创建内部类,而不能直接new一个内部类对象,即 内部类 对象名 = 外部类对象.new 内部类();
  • 外部内是不能直接使用内部类的成员和方法,可以先创建内部类的对象,然后通过内部类的对象来访问其成员变量和方法.

成员内部类

作为外部内的一个成员存在,与外部类的域,方法并列.

使用内部类访问外部类和内部类的域 访问外部类的方法

//外部类
public class test07 {
    private static int i =1;
    private int j = 10;
    private int k = 20;

    public static void outerF1(){
        System.out.println("调用类外部类的静态方法");
    }
    public void outerF2(){
        System.out.println("调用的外部类的方法");
    }

    /**
     * 定义内部类
     */
    class inner{
//        static int innerl = 100;//error   内部类中不允许定义静态变量
        int j = 100;   //内部类和外部类实例变量可以共存
        int innerl = 1;
        public void innerF1(){
            //内部类访问外部类的域(需要外部类的域没有与内部类中的重名)
            System.out.println(i);
            //在内部类中访问内部类自己的域直接使用变量名
            System.out.println(j);
            //在内部类中访问内部类自己的域也可以使用this关键字
            System.out.println(this.j);
            //访问重名的外部类的域
            System.out.println(test07.this.j);
            outerF1();
            outerF2();
        }
    }

    public static void main(String[] args) {
        test07 outer = new test07();
        test07.inner inner = outer.new inner();
        inner.innerF1();
    }
}
1
100
100
10
调用类外部类的静态方法
调用的外部类的方法

外部类调用内部类

//外部类
public class test07 {
    private static int i =1;
    private int j = 10;
    private int k = 20;

    public static void outerF1(){
        System.out.println("调用类外部类的静态方法");
    }
    public void outerF2(){
        System.out.println("调用的外部类的方法");
    }

    //外部类的非静态方法访问内部类
    public void outerF3(){
        inner i = new inner();
        System.out.println(i.innerl);
        i.innerF1();
    }
    //外部类的静态方法访问内部类,与在外部类外部访问成员内部类一样
    public static void outerF4(){
        //这里由于静态的不能访问非静态的,所以不能向outerF3()一样直接访问(原因看上一篇博客)
        test07 outer = new test07();
        inner i = outer.new inner();
        i.innerF1();
    }

    /**
     * 定义内部类
     */
    class inner{
//        static int innerl = 100;//error   内部类中不允许定义静态变量
        int j = 100;   //内部类和外部类实例变量可以共存
        int innerl = 1;
        public void innerF1(){
            //内部类访问外部类的域(需要外部类的域没有与内部类中的重名)
            System.out.println(i);
            //在内部类中访问内部类自己的域直接使用变量名
            System.out.println(j);
            //在内部类中访问内部类自己的域也可以使用this关键字
            System.out.println(this.j);
            //访问重名的外部类的域
            System.out.println(test07.this.j);
            outerF1();
            outerF2();
        }
    }

    public static void main(String[] args) {
        //非静态方法的调用
        test07 outer = new test07();
        outer.outerF3();
        System.out.println("---------------------");
        //静态方法调用
        test07.outerF4();
    }
}
1
1
100
100
10
调用类外部类的静态方法
调用的外部类的方法
---------------------
1
100
100
10
调用类外部类的静态方法
调用的外部类的方法

注意:如果要直接创建内部类的对象,不能想当然认为只需要加上外部类的名字就可以像通常一样生成内部类对象了,而必须使用外部类的一个对象来创建其内部类对象.如果是静态的内部类就不需要创建对象

内部类是一个编译时的概念,一旦编译成功,就会成为两个完全不同的类.

对于一个名为outer的外部类和其内部定义名为inner的内部类.编译完成后出现outer.class和outer$inner.class两个类.

局部内部类

在方法中定义的内部类称为局部内部类.与局部变量类似,局部内部类不能有访问说明符,因为它不是外部类的一部分,但是它可以访问当前代码块内的常量和外部类的所有成员.

public class test07{
    private int s = 100;
    private int outl = 1;

    public void f(){
        //这里(下面需要调用)在jdk8以前需要加上final关键字 final int s=200;,jdk8之后默认加上了,
        // 原因是方法中的变量在方法调用是保存在栈中,当方法调用完成之后就会被释放
        //而new的对象保存在堆中,堆是我们不可操作的,而且对象是由java虚拟机回收机制统一回收的,
        //所以有可能出现变量被回收了,而对象没有被回收,对象中使用了变量,此时就没有地址了就会出错.
        //使用final关键字就会把它变成常量而不是地址的指针
        int s = 200;
        int j = 10;
        //方法内的内部类
        class Inner{
            //可以定义与外部类同名的变量
            int s = 300;
            int innerl = 100;
//            static int m =20; //error  不可以定义静态变量
            void innerF(){
                //java内部没有与外部类重名的变量,在内部类可以直接使用外部类的变量
                System.out.println(outl);
                //可以访问外部类方法中的局部变量,在jdk8之前,变量必须加上final关键字
                System.out.println(j);
                //重名则访问的是内部类的变量
                System.out.println(s);
                //访问的外部类的成员
                System.out.println(test07.this.s);
            }
        }
        //局部内部类只能在方法中实例化
        Inner inner = new Inner();
        inner.innerF();
    }

    public static void main(String[] args) {
        //在外部类中直接调方法访问内部类
        test07 outer = new test07();
        outer.f();
    }
}
1
10
300
100

静态内部类

如果你不需要内部类对象与外部类对象之间有联系,那你可以把内部类声明为static.这通常称为嵌套类.想要理解static应用与内部类时的含义,你必须记住,普通的内部类对象隐含地保存了一个引用,指向创建它的外部类.然而外部类是static时,就不是这样的了,这就意味着:

  • 要创建内部类的对象,并不需要外部类的对象
  • 不能从内部类的对象中访问非静态的外部类(静态不能访问非静态,具体看上一篇)
public class test07{
    private static  int i =1;
    private int j = 10;

    static void outerF1(){
        System.out.println("外部类的静态方法");
    }
    public void outerF2(){
        //外部类访问内部类的静态成员:内部类.静态成员
        System.out.println(Inner.inner_i);
        Inner.innerF1();
        //外部类访问内部类的非静态成员:实例化内部类即可
        Inner inner = new Inner();
        System.out.println(inner.inneJ);
    }
    //静态内部类
     static class Inner{
        static int inner_i = 100;
        int inneJ = 200;
        static void innerF1(){
            //静态内部类只能访问外部类的静态成员(包括静态变量和静态方法)
            System.out.println("静态变量i:"+i);
            outerF1();
//            System.out.println(j); //error  不能访问外部类的非静态成员
        }
    }

    public static void main(String[] args) {
        //调用静态内部类  直接通过类名.调用,不需要创建外部类的对象
        test07.Inner.innerF1();
        System.out.println("-------------------------");
        //访问外部类的方法
        test07 outer = new test07();
        outer.outerF2();

    }
}
静态变量i:1
外部类的静态方法
-------------------------
100
静态变量i:1
外部类的静态方法
200

静态内部类和成员内部类的区别

生成一个静态内部类不需要外部类对象

匿名类

匿名类是一个接口或者抽象类的实现类或者子类的对象.

先定义一个接口

public interface Person {
    void say();
}

原始的访问方法

class Xm implements Person{
    @Override
    public void say() {
        System.out.println("say hello");
    }
}

public class test07{
    @Test
    public void testorigin(){
        //由于接口不能直接实例化,所以传统的调用方法,需要我们先写一个类实现接口,然后再调用类
        Xm xm = new Xm();
        xm.say();
    }
}

使用匿名内部类的访问方法

    @Test
    public void testInner(){
        Person person = new Person() {
            @Override
            public void say() {
                System.out.println("say hello");
            }
        };
        person.say();
    }

抽象方法是一样的调用手法.

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

原文地址:https://www.cnblogs.com/liuzhidao/p/13732809.html