内部类(成员内部类、局部内部类、匿名内部类、静态内部类)

外部类:单独定义的一个类,不在其他类的内部,只能用 public 和 缺省 权限修饰符

内部类:在类的内部再定义一个类,根据内部类的定义位置和修饰符的不同,可以分为:

1. 成员内部类:

语法格式:

[修饰符] class 外部类{
    [修饰符] class 内部类{    }
}

成员内部类特点:

1.不能使用static关键字,但是可以使用 static final关键字定义常量

2.内部类可以直接访问外部类的成员(包括私有成员)

3.内部类如果想要调用外部类的方法,需要使用 `外部类名.this.外部方法名`

4.可以使用final修饰内部类,表示不能被继承

5.编译以后也会有自己独立的字节码文件, Outer$Inner.class

6.外部函数的static成员的,不允许访问成员的内部类

7.可以在外部类里创建内部类对象,然后在通过方法返回,同事,也可以使用 new Outer().new Inner() 在外部直接访问内部类

public class Test {
    public static void main(String[] args) {
        // 直接使用 new Outer().new Inner() 方法创建一个Inner对象
        Outer.Inner inner1 = new Outer().new Inner();  
        
        // 创建一个 Outer 对象,
        //再调用 Outer 对象的 getInner方法,在getInner方法里创建并返回 Inner 对象
        Outer.Inner inner2 = new Outer().getInner();
    }
}
class Outer {
    int age = 19;
    private String name = "jack";
	
    private void test() {
        System.out.println("我是Outer类里的test方法");
    }
    
    class Inner {  // 可以把 Inner 想象成为和 age / name一样,只不过它的数据类型是class
        // static int a = 10;  报错,不能使用 static
        static final int b = 1;  // 可以使用 static final 定义常量
        private void test() {
            System.out.println("我是Inner类里的test方法");
        }
        public void demo() {
            // 内部类可以直接访问外部类的成员,包括私有成员。
            System.out.println(name);
            this.test();  // 等价于 test() 调用的是内部类的test方法
            Outer.this.test(); // 需要使用 Outer.this 调用外部类的 test 方法
        }
    }
    public static void foo() {
        // Inner inner = new Inner();  报错!外部static成员不允许访问非静态内部类
    }
    public Inner getInner() {
        return new Inner();
    }
}

示例:


//成员内部类
public class MemberOuter {
    private int x = 10;
    private static int m = 5;

    public final class MemberInner {
        private int a = 2;
        // private static int b = 4;
        private static final int c = 5;
        int x = 3;

        public void demo() {
            int x = 1;
            System.out.println("MemberInner类demo方法里的x = " + x);
            System.out.println("MemberInner类demo方法里的this.x = " + this.x);
            System.out.println("MemberInner类demo方法里的MemberOuter.this.x = " + MemberOuter.this.x);
            System.out.println(m);
            xxx();
        }
    }

    public void test() {
        MemberInner inner = new MemberInner();
        inner.demo();
    }

    public static void xxx() {
    }
}

public class InnerDemo {
    public static void main(String[] args) {

        
        //创建成员内部类的对象必须先创建外部类对象!
        //创建成员内部类对象必须要先创建外部类对象

        //方式a:在外部类的内部创建对象并使用
        //方式b: 也可以直接创建一个成员内部类对象(和权限修饰符有关)
                //外部类名.内部类名  变量名 = 外部类对象名.new 成员内部类名();
        MemberOuter memberOuter = new MemberOuter();
        memberOuter.test();

        // MemberOuter.MemberInner memberInner = memberOuter.new MemberInner();
        MemberOuter.MemberInner memberInner = new MemberOuter().new MemberInner();

        
    }
}

总结:

成员内部类:

1. 和成员变量一样,可以使用全部的四种权限修饰符和final修饰符

2. 在成员内部类里可以访问外部类的所有成员变量,调用所有方法,包括静态的。

3.在成员内部类里可以定义非静态成员变量,也可以使用static final 定义静态成员常量,但是不能使用static定义静态变量

4. 调用成员内部类的方法和访问成员内部类里变量,需要先创建成员内部类对象

        创建成员内部类对象必须要先创建外部类对象

                a.在外部类的内部创建对象并使用

MemberOuter memberOuter = new MemberOuter();
memberOuter.test();

                b.也可以直接创建一个成员内部类对象(和权限修饰符有关)

                        外部类名.内部类名  变量名 = 外部类对象名.new 成员内部类名();

MemberOuter.MemberInner memberInner = new MemberOuter().new MemberInner();

5. 在成员内部类里出现  内部类成员变量、内部类局部变量、外部类成员变量同名的情况

  • 在方法里直接访问,访问的是局部变量
  • 使用 this.变量名 访问内部类的成员变量
  • 使用  外部类名.this.变量名  访问外部类的成员变量

6. 成员内部类编译以后也会生成一个 .class文件,文件名是  外部类名$内部类名.class。

2.静态内部类

静态内部类也被成为 嵌套类,静态内部类不会持有外部类对象的引用

语法格式:

[修饰符] class 外部类{    
    [其他修饰符] static class 内部类{    }
}

静态内部类特点:

1. 使用static关键字修饰

2. 在静态内部类里,可以使用static关键字定义静态成员

3.只能访问外部的静态成员,不能访问外部的非静态成员

4. 外部类可以通过  静态内部类名.静态成员名  访问静态内部类的静态成员

class Outer {
    int age = 19;
    static String type = "outer";

    static class Inner {  // 需要使用 static 关键字
        static int x = 1;  // 能够定义静态变量
        public static void test() {
            // 只能访问外部的静态变量,不能访问非静态变量
            // System.out.println(age);
            System.out.println(type);
        }
    }
    public void  demo() {
        // 外部类可以直接通过 内部类.静态变量名,不需要创建对象
        System.out.println(Inner.x);  
    }
}

示例:

public class StaticOuter {
    private int x = 10;
    private static int m = 3;

    public static final class StaticInner {
        private int a = 5;
        private static int b = 7;
        private int x = 1;
        private static int m = 6;

        public void test() {
            // System.out.println(x);
            // foo();
            int x = 2;
            int m = 9;
            System.out.println("StaticInner类test方法里 x = " + x);  // 2
            System.out.println("StaticInner类test方法里 x = " + this.x);  // 1
            System.out.println("StaticInner类test方法里 m = " + m);  // 9
            System.out.println("StaticInner类test方法里 StatiInner.m = " + StaticInner.m);  // 6
            System.out.println("StaticInner类test方法里 StaticOuter.m = " + StaticOuter.m);  // 3
            demo();
        }

        public static void bar() {
            // System.out.println(x);
        }
    }

    public static void demo() {
    }

    public void foo() {
    }
}
public class InnerDemo {
    public static void main(String[] args) {
        MemberOuter memberOuter = new MemberOuter();
        memberOuter.test();

        // MemberOuter.MemberInner memberInner = memberOuter.new MemberInner();
        MemberOuter.MemberInner memberInner = new MemberOuter().new MemberInner();

        StaticOuter.StaticInner staticInner = new StaticOuter.StaticInner();
        StaticOuter.StaticInner.bar();

    }
}

总结:

静态内部类:

1. 定义的位置和成员内部类的位置一样,使用static关键字修饰

        语法上可以理解为 成员内部类前面使用static修饰

2. 可以使用 四种权限修饰符和 final修饰符

3. 不能访问外部类的非静态成员变量,可以访问外部类的静态成员变量

        总结:静态只能访问静态的。不能访问非静态的

4. 可以定义  非静态成员变量,也可以定义静态成员变量

5. 创建静态内部类对象,可以不创建外部类对象

        静态内部类就像是一个单独的类,只不过借用了外部类的命名空间

StaticOuter.StaticInner staticInner = new StaticOuter.StaticInner();

6. 也会生成独立的 .class文件,文件名是  外部类名.静态内部类名

3. 局部内部类

局部内部类定义在外部类的方法中,就像局部变量一样,并不是外部类的成员。

局部内部类在方法外是无法访问到的,但它的实例可以从方法中返回,并且实例在不在被引用之前会一直存在。

语法格式:

[修饰符] class 外部类{
    [修饰符] 返回值类型  方法名([形参列表]){
            [final/abstract] class 内部类{
        }
    }    
}

局部内部类的特点:

1. 定义在类的某个方法里,而不是直接定义在类里

2. 局部内部类前面不能有权限修饰符

3. 局部内部类里不能使用static声明变量

4. 局部内部类访问外部类的静态成员

5. 如果这个局部内部类所在的方法是静态的,它无法访问外部类的非静态成员

6. 局部内部类可以访问外部函数的局部变量,但 这个局部变量必须要非final修饰。JDK8以后,final可以省略

class Outer {
    int age = 19;
	static int m = 10;
    
    public void test() {
        // final String y = "good";
        String y = "good";  // JDK8 以后,final可以省略
        class Inner {  // 定义在外部类的某个方法里
            // static int a = 10; 不能定义静态变量!  
            private  void demo() {
                System.out.println(age);
                // 不能修改外部函数的局部变量
				// y = 'yes';
                // 只能访问被 final 修饰的外部函数的局部变量
                // JDK8 以后,如果外部函数的局部变量没有加 final,编译器会自动加 final
                System.out.println(y);
            }
        }
        Inner inner = new Inner();
        inner.demo();
    }
}

示例:

public class LocalOuter {
    private int x = 6;

    public void test() {
        int x = 10;
        int y = 0;

        class LocalInner {
            private int a = 1;
            // private static int b = 2;
            private static final int c = 3;
            private int x = 5;

            public void demo() {
                int x = 1;
                System.out.println("demo方法里的x = " + x);  // 1
                System.out.println("demo方法里的this.x = " + this.x);  // 5
                System.out.println("外部类里的成员变量x = " + LocalOuter.this.x); // 6
                // 如果出现同名的情况,无法再访问 方法里的同名局部变量
                System.out.println(y);
            }
        }
        // y = 3; 局部变量 y 被局部内部类使用了,不能再修改了

        LocalInner localInner = new LocalInner();
        localInner.demo();
    }
}

总结:

局部内部类:

1. 定义在一个方法里,和局部变量 定义的位置相同

2. 不能使用任何的权限修饰符和 static修饰符

3. 可以定义非静态成员变量、静态成员变量  但不能定义静态变量

4. 局部内部类可以访问所在方法里的局部变量

       但是如果出现同名的情况

        访问 局部内部类里的局部变量直接写变量名

        访问 局部内部类里的成员变量使用 this.变量名

        访问 外部类里的成员变量,使用 外部类名.this.变量名

        不能访问 局部内部类所在方法的同名局部 变量

5. 被局部内部类访问的 局部变量,需要被final修饰。JDK8以后,final可以省略

6. 局部内部类只能在声明它的那个方法里使用

7. 生成独立的.class文件,文件名是 外部类名.编号局部内部名

4. 匿名内部类

用来创建  一个接口或者抽象类  对象

(抽象类或者接口  本不可以直接创建对象,可使用匿名内部类方法直接创建)

语法格式:

new 父类名或者接口名(){   
    // 方法重写
    @Override 
    public void method() {
        // 执行语句
    }
};

匿名内部类特点:

1. 匿名内部类就是一种特殊的局部内部类,只不过没有名称而已,基本特点和局部内部类一致

2. 匿名内部类不能有构造器,匿名内部类没有类名,肯定无法声明构造器

3. 匿名内部类的前提是,这个内部类必须要继承自一个父类或者父接口

4. 匿名内部类是接口的一种常见简化写法,也是我们开发中最常使用的一种内部类。它的本质是一个实现类父类或者父类接口具体方法的一个匿名对象

abstract class Animal{
    abstract void shout();
}

class Demo{
    public void demo(){
        Animal animal = new Animal() {
            @Override
            void shout() {
                System.out.println("动物在叫");
            }
        };
    }
}

示例:

AInterface接口

public interface AInterface {
    void test();
}

用AInterface直接创建类,用匿名内部类方法

public class AnonymousDemo {

    public static void main(String[] args) {
        AnonymousDemo x = new AnonymousDemo();
        x.demo();
    }

    public void demo(){

        /*class Son implements AInterface{
            @Override
            public void test() {

            }
        }

        //Son s = new Son();s.test();
        new Son().test();*/

        //匿名内部类
        AInterface a = new AInterface() {
            @Override
            public void test() {
                System.out.println("helloA");
            }
        };

        //对象a的类型不是AInterface类型,而是AInterface类型的子类!这个类没有名字
        a.test();
        System.out.println(a.getClass());


        //匿名内部类 + 匿名对象 :  可以将一个方法当作另一个方法的参数使用
        new AInterface() {
            @Override
            public void test() {
                System.out.println("helloB");
            }
        }.test();
    }
}

匿名内部类的作用:可以将一个方法当作另一个方法的参数使用

public class AnonymousTest {

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

        Calculator c = new Calculator() {
            @Override
            public int doCalculator(int a, int b) {
                return a+b;
            }
        };
        int x = test.calculate(1,9,c);

        //等价
        int y = test.calculate(1, 9, new Calculator() {
            @Override
            public int doCalculator(int a, int b) {
                return a+b;
            }
        });

        System.out.println(x);
    }

    public int calculate(int a,int b,Calculator calculator){
        return calculator.doCalculator(a, b);
    }
}

interface Calculator{
    int doCalculator(int a,int b);
}

  • 10
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值