1.五大成员:属性、方法、构造方法、代码块、内部类。

2.定义:在一个类的里面,再定义一个类。

例:在A类的内部定义B类,B类就被称为内部类。

3.时机:当内部类表示的事物是外部类的一部分,且内部类单独出现没有任何意义时。

例:ArrayList的迭代器。

4.内部类的访问特点:

内部类可以直接访问外部类的成员,包括私有。
外部类要访问内部类的成员,必须创建对象。

5.练习:写一个Javabean类描述汽车。

属性:汽车的品牌,车龄,颜色,发动机的品牌,使用年限。

public class Car {
    String carName;
    int carAge;
    String carColor;

    public void show(Car this) {
        //打印调用者车的名字
        System.out.println(this.carName);
        Engine e = new Engine();
        System.out.println(e.engineName);
    }

    class Engine {
        String engineName;
        int engineAge;

        public void show() {
            //内部类可以直接访问外部类的成员,包括私有
            System.out.println(engineName);
            System.out.println(carName);
        }
    }
}
public class Test {
    public static void main(String[] args) {
        Car c = new Car();
        c.carName = "宾利";
        c.carAge = 1;
        c.carColor = "粉色";
        c.show();
    }
}

6.内部类的分类:

1)成员内部类(了解)
1、写在成员位置的,属于外部类的成员。
2、成员内部类可以被一些修饰符所修饰,比如:private,默认,protected,public,static等。
3、在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量。
4、成员内部类如何创建对象:
方法一:当成员内部类被private修饰时,在外部类中编写方法,对外提供内部类的对象。
方法二:当成员内部类被非私有修饰时,直接创建对象。
格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
Outer.Inner oi = new Outer( ).new Inner( );

public class Car {//外部类
    String carName;
    int carAge;
    int carColor;

    //成员内部类:写在成员位置的,属于外部类的成员
    class Engine {//成员内部类
        String engineName;
        int engineAge;
    }
}
public class Outer {
    private class Inner{

    }
    public Inner getInstance(){
        return new Inner();
    }
}
public class Test {
    public static void main(String[] args) {
        /*
         * 获取成员内部类对象的两种方式
         * 方法一:外部类编写方法,对外提供内部类对象
         * 方法二:直接创建
         * 格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
         * 范例:Outer.Inner oi = new Outer().new Inner();
         * */

        //创建对象方式:
        //类名 对象名 = new 类名();
        //Student s = new Student();

        //内部类若私有,则报错
        //Outer.Inner oi = new Outer().new Inner();

        Outer o = new Outer();
        //Outer.Inner inner = o.getInstance();//私有所以报错
        Object inner = o.getInstance();//多态
        System.out.println(o.getInstance());//Outer$Inner@3b07d329
    }
}

5、成员内部类如何获取外部类的成员变量
外部类成员变量与内部类成员变量重名时,在内部类如何访问?
System.out.println(Outer.this.变量名);

public class Outer {
    private int a = 10;

    class Inner {
        private int a = 20;

        public void show() {
            int a = 30;
            System.out.println(Outer.this.a);//10
            System.out.println(this.a);//20
            System.out.println(a);//30
        }
    }
}
public class Test {
    public static void main(String[] args) {
        //创建内部类的对象,调用show方法
        Outer.Inner oi = new Outer().new Inner();
        oi.show();
    }
}

2)静态内部类(了解)
1、静态内部类是一种特殊的成员内部类。
2、静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象。

public class Car {//外部类
    String carName;
    int carAge;
    int carColor;

    static class Engine {//静态内部类
        String engineName;
        int engineAge;
    }
}

3、创建静态内部类对象的格式:
外部类名.内部类名 对象名 = new 外部类名.内部类名();
Outer.Inner oi = new Outer.Inner();
4、调用静态内部类中的方法:
调用非静态方法的格式:先创建对象,用对象调用。
调用静态方法的格式:外部类名.内部类名.方法名();

public class Outer {
    int a = 10;
    static int b = 20;

    //静态内部类
    //静态内部类也是成员内部类的一种
    //静态内部类只能访问外部类中的静态变量和静态方法
    static class Inner {
        public void show1() {
            System.out.println("非静态的方法被调用了");
            //如果想要访问非静态的需要创建对象
            Outer o = new Outer();
            System.out.println(o.a);
            System.out.println(b);
        }

        public static void show2() {
            System.out.println("静态的方法被调用了");
            //如果想要访问非静态的需要创建对象
            Outer o = new Outer();
            System.out.println(o.a);
            System.out.println(b);
        }
    }
}
public class Test {
    public static void main(String[] args) {
        //创建静态内部类对象的格式:
        //外部类名.内部类名 对象名 = new 外部类名.内部类名();
        Outer.Inner oi = new Outer.Inner();
        //访问非静态需要创建外部类对象
        oi.show1();
        //调用静态方法的格式(对象也可以调用但不提倡)
        //外部类名.内部类名.方法名();
        Outer.Inner.show2();
    }
}

3)局部内部类(了解)
1、将内部类定义在方法里面,类似于方法里面的局部变量。
2、外界无法直接使用,需要在方法内部创建对象并使用。
3、该类可以直接访问外部类的成员,也可以访问方法内的局部变量。

public class Outer {
    int b = 20;

    public void show() {
        int a = 10;
        //局部内部类
        class Inner {
            String name;
            int age;

            public void method1() {
                System.out.println(a);
                System.out.println(b);
                System.out.println("局部内部类中的方法method1");
            }

            public static void method2() {
                System.out.println("局部内部类中的静态方法method2");
            }
        }

        //创建局部内部类的对象
        Inner i = new Inner();
        System.out.println(i.name);
        System.out.println(i.age);
        i.method1();
        Inner.method2();
    }
}
public class Test {
    public static void main(String[] args) {
        Outer o = new Outer();
        o.show();
    }
}

4)匿名内部类(掌握)
1、匿名内部类本质上就是隐藏了名字的内部类。
2、可以写在成员位置,也可以写在局部位置。
3、格式(整体是一个类的子类对象或者接口的实现类对象):

new 类名或者接口名( ){ //继承\实现
 重写方法; //方法重写
 }; //创建对象new Inter() {
 public void show () {
 }
 };

4、使用场景:
当方法的参数是接口或者类时,
以接口为例,可以传递这个接口的实现类对象。
如果实现类只使用一次,就可以用匿名内部类简化代码。

public abstract class Animal {
    public abstract void eat();
}
public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
}
public interface Swim {
    public abstract void swim();
}
public class Test {
    public static void main(String[] args) {
        //匿名内部类
        new Swim() {

            @Override
            public void swim() {
                System.out.println("重写了游泳的方法");
            }
        };

        new Animal() {

            @Override
            public void eat() {
                System.out.println("重写了eat方法");
            }
        };
        //应用:在测试类中调用method方法
        /*第一种:写一个子类继承Animal类
        再创建子类的对象,传递给method方法
        Dog d = new Dog();
        method(d);*/
        //如果只用一次,单独定义一个类不合适
        //第二种:匿名内部类
        method(
                new Animal() {
                    @Override
                    public void eat() {
                        System.out.println("狗吃骨头");
                    }
                }
        );

    }

    public static void method(Animal a) {//Animal a = 子类对象 多态
        a.eat();//编译看左边,运行看右边
    }
}
public class Test2 {
    //是一个没有名字的成员内部类
    Swim s = new Swim() {

        @Override
        public void swim() {
            System.out.println("重写游泳方法");
        }
    };

    public static void main(String[] args) {
        //是一个没有名字的局部内部类
        //Swim接口的实现类对象
        //接口多态
        Swim s = new Swim() {

            @Override
            public void swim() {
                System.out.println("重写游泳方法");
            }
        };
        //编译看左边,运行看右边
        s.swim();

        new Swim() {

            @Override
            public void swim() {
                System.out.println("重写游泳方法");
            }
        }.swim();
    }
}