Java 内部类详解

  • 1 内部类概述
  • 2 成员内部类语法
  • 3 通过成员内部类解决多继承
  • 4 静态内部类语法
  • 5 通过静态内部类代替有参构造
  • 6 局部内部类
  • 7 匿名内部类


1 内部类概述

  内部类大致分为:成员内部类、静态内部类、局部内部类、匿名内部类

public class A {

    //定义成员内部类
    class B1 {}

    //静态内部类
    static class  B2{}

    void method1() {
        
        //局部内部类
        class  B3{}
    }

}

2 成员内部类语法

 为什么要使用成员内部类?

  (1)、有时需要使用成员内部类来表示一个数据结构
  (2)、可以使用内部类来结局类的多继承问题

 成员内部类特点

  (1)、内部类编译后是单独的一个字节码文件
  (2)、文件名是 Outer$Inner.class
  (3)、成员内部类和成员变量、成员方法一样是属于某一个外部类对象的
  (4)、内部类一般只在外部类的类体中使用,不在外部使用
  (5)、成员内部类可以定义实例变量、实例方法、不能定义静态成员,因为成员内部类是属于某个外部类对象,而静态成员和对象没有任何关系。
  (6)、成员内部类中可以使用外部类的实例成员
  (7)、成员内部类可以加访问权限修饰符

public class Outer {
    //成员变量
    int xx = 10;

    public void m1(){
        System.out.println("实例方法可以直接使用成员变量xx " + xx);
    }

    class Inner{
        int yy = 20;
        public void innerM1() {
            System.out.println("成员内部类的实例方法");

            //使用外部类的实例成员
            System.out.println("使用外部类的实例成员xx " + xx);
        }
        //成员内部类中不能定义静态成员
        //static int zz;
    }
}
package Innerclass;

//导入内部类
import Innerclass.Outer.Inner;


public class Test01 {
    public static void main(String[] args) {
        //通过对象访问实例成员
        Outer outer = new Outer();
        System.out.println(outer.xx);
        outer.m1();

        //使用成员内部类创建对象
        Outer.Inner inner = outer.new Inner();

        //也可以导入,一般不这样写,因为可读性差,不知道这是一个内部类
        Inner inner1 = outer.new Inner();
    }
}

3 通过成员内部类解决多继承

  OuterA类有一个方法methodA( )
  OuterB类有一个方法methodB( )

  Son类继承OuterA类,就自动拥有methodA( )方法如果还拥有methodB( ),可以定义一个内部类,让内部类继承OuterB类。

class OuterA {

    public void methodA(){}
}
class OuterB {
    public void methodB(){}
}
class Son extends OuterA{

    //1.在子类中定义一个内部类继承
    private class Inner extends OuterB{}

    //2 定义一个内部类对象
    private Inner inner = new Inner();

    //3 定义一个方法和methodB方法签名相同
    public void methodB(){
        inner.methodB();

        //因为只使用一次
        new Inner().methodB();
    }

}

class Test02{
    public static void main(String[] args) {
        Son son = new Son();
        son.methodA();

        //son的methodB方法,方法体是通过内部类对象调用的
        son.methodB();
    }
}

4 静态内部类语法

  (1)、使用static修饰的成员内部类就是静态内部类
  (2)、在静态内部类中不能访问外部类的非静态成员,可以直接访问外部类的静态成员
  (3)、在静态内部类中可以定义静态成员

public class Outer {
    //成员变量
    int xx = 10;

    //静态变量
    static int oo = 20;

    public static void sMethod(){
        System.out.println("静态方法可以使用静态变量 oo " + oo);

        //在外部类的静态方法中可以使用静态内部类
        Inner obj = new Inner();

        //静态方法中不能使用成员内部类
        //Inner2 inner2 = new Inner2();
    }

    static class Inner{
        int xx = 10;

        public void innnerMethod(){
            System.out.println("静态内部类的实例方法");
            //在静态内部类中不能访问外部类的非静态成员,可以直接访问外部类的静态成员
            System.out.println(oo);
        }

        //静态内部类中定义静态变量
        static int ss = 20;

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

    class Inner2{}
}
public class Test01 {
    public static void main(String[] args) {

        //通过类名访问它的静态成员
        System.out.println("oo==" + Outer.oo);
        Outer.sMethod();

        //通过静态内部类创建对象
        Outer.Inner inner = new Outer.Inner();
    }
}

5 通过静态内部类代替有参构造

   一般在实体类中,将字段私有化,提供对外的setter和geeter方法,只提供无参构造.因为,有参构造会破坏类的封装性,例如new Person(“zhnsgan”,1000,‘m’);一个人的年龄不可能为1000

public class Person {

    private String name;
    private int age;
    private char sex;

    public Person(){}

    //通过静态内部类代替类的有参构造
    public static class Bulider{
        //1 创建和外部类相同的字段
        private String name;
        private int age;
        private char sex;

        //2 提供变种的seeter方法
        public Bulider setName(String name) {
            this.name = name;
            return this;
        }

        public Bulider setAge(int age) {
            this.age = age;
            return this;
        }

        public Bulider setSex(char sex) {
            this.sex = sex;
            return this;
        }
        //3 提供公共的方法,返回外部类对象
        public Person bulider(){
            return new Person(this);
        }
    }

    //4 定义一个外部类的构造方法,参数是内部类对象,把内部类对象的各个属性值赋值给外部类对象
    public Person(Bulider bulider) {
        this.age = bulider.age;
        this.name = bulider.name;
        this.sex = bulider.sex;
    }

    //省略seeter方法和getter方法


    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }
}
*/
public class Test01 {
    public static void main(String[] args) {
        Person person = new Person();

        //如果没有重写toString()方法那么打印一个对象是 这个对象的完整类名+哈希码的十六进制

        //静态内部类对象 . 方法
        Person person2 = new Person.Bulider().bulider();

        System.out.println(person2);

        person2 = new Person.Bulider().setName("张三").setAge(16).setSex('m').bulider();
        System.out.println(person2);
    }
}

6 局部内部类

  (1)、局部内部类不能加访问权限修饰符
  (2)、局部内部类的作用域:从定义局部类的位置开始,到包含它的大括号位置结束

public class Outer {

    public void m1(){
        //定义局部变量
        int x = 1;

        //定义局部内部类
        class Inner{}

        Inner inner = new Inner();
    }
}

7 匿名内部类

  匿名内部类就是没有类名的内部类;
  匿名类的定义和匿名内部类对象的创建是一起的
  当某个成员内部类只使用一次时,就可以使用匿名内部类

public class Outer {

    class Inner{}
}
public abstract class Animal {

    //定义抽象类的抽象方法
    public void speak(){};
}
public interface Flyabel {

    void fly();
}
public class Test01 {
    public static void main(String[] args) {
        Outer outer = new Outer();

        //创建成员内部类对象
        outer.new Inner();

        //以上两行可以写作一行
        new Outer().new Inner();

        //创建匿名内部类对象
        new Outer(){
            //大括号中的内容就是匿名内部类的类体
            public void innereMethod(){
                System.out.println("匿名内部类对象的类体");
            }
        };

        //抽象类的引用需要赋值子类对象,当这个子类就只使用这一次时,就可以直接使用匿名内部类
        //抽象类的引用可以指向匿名内部类对象,
        // 在匿名内部类中对抽象类的抽象方法进行重写
        Animal animal = new Animal() {

            @Override
            public void speak() {
                System.out.println("狗在叫....");
            }
        };
        animal.speak();

        //接口的引用可以赋值匿名内部类对象
        Flyabel flyabel = new Flyabel() {
            @Override
            public void fly() {
                System.out.println("鸟在飞.....");
            }
        };
        flyabel.fly();
    }
}
public class Outer {
    public  int x = 88;
}

class Test01{
    public static void main(String[] args) {
        //普通类也可以赋值匿名内部来对象
        Outer outer = new Outer() {
            public void innerMehod() {
                System.out.println("1111" + x);
            }
        };
        //无法调用匿名内部类的方法,因为Outer类没有这个方法。
        //outer.innerMehod();

        //创建匿名内部类对象并调用匿名内部类的方法
        new Outer() {
            public void innerMehod() {
                System.out.println("1111" + x);
            }
        }.innerMehod();
    }
}