侧边栏壁纸
博主头像
青菜-halo2 博主等级

行动起来,活在当下

  • 累计撰写 74 篇文章
  • 累计创建 6 个标签
  • 累计收到 7 条评论

目 录CONTENT

文章目录

15-面向对象进阶_06(内部类)

Administrator
2025-11-16 / 0 评论 / 0 点赞 / 24 阅读 / 0 字

六 内部类

在一个类的里面,再定义一个类

//在A类的内部定义B类,B类就被称之为内部类
public class Outer { //外部类
 public class Inner{} //内部类
}
​
public class Test{ //可以外部其他类中创建内部类对象,并调用方法
 public static void main{}
}

6.1 概念

6.1.1 为什么要学习内部类?

  • B类表示的事物是A类的一部分,且B单独存在没有意义

  • 内部类表示的事物是:外部类的一部分

  • 内部类单独出现没有任何意义

示例代码:

/*
需求:写一个javabean类描述汽车
属性:汽车的品牌,年龄,颜色,发动机的品牌,使用年限
*/
​
public class Car { //外部类
    String carName;
    int carAge;
    String carColor;
    class Engine{  //内部类
        String engineName;
        int engineAge;
    }
}

6.1.2 内部类的访问特点:

  • 内部类可以直接访问外部类的成员,包括私有

  • 外部类要访问内部类的成员,必须创建对象

完整代码:

//Car.java
public class Car {
    String carName;
    int carAge;
    String carColor;
    public void show(){
        //打印调用者(车)的名字,宾利
        System.out.println(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);  //内部类可以直接访问外部类的成员(carName),包括私有
        }
    }
}
​
//Test.java
public class Test {
    public static void main(String[] args) {
        /*
            需求:写一个Javabean类描述汽车
            属性:汽车的品牌,年龄,颜色,发动机的品牌,使用年限
​
            内部类的访问特点:
                   内部类可以直接访问外部类的成员,包括私有
                   外部类要访问内部类的成员,必须创建对象
         */
        Car c = new Car();
        c.carName = "宾利";
        c.carAge = 1;
        c.carColor = "粉色";
        c.show();
    }
}

6.2 内部类的分类

6.2.1 成员内部类(了解)

6.2.1.1 如何书写:
  • 写在成员位置(类中,方法外),属于外部类的成员

  • 成员内部类可以被一些修饰符所修饰,比如:private ,默认,proctectedpublicstatic

  • 成员内部类中,JDK16之前不能定义静态变量,JDK16以后才可以

public class Car {
    String carName;
    int carAge;
    int carColor;
    
    //static class Engine //静态内部类
    class Engine{  //成员内部类
        String engineName;
        int engineAge;
    }
}

6.2.1.2 获取成员内部类对象

方式一:在外部类中编写方法,对外提供内部类对象

示例代码:

//===private修饰内部类====
//Outer.java
public class Outer {
    String name;
    private class Inner{
    }
    public Inner getInstance(){
        return new Inner();
    }
}
​
//Test.java
public class Test {
    public static void main(String[] args) {
        Outer o = new Outer();
        System.out.println(o.getInstance());
    }
}

方式二:当成员内部类被非私有修饰时,直接创建:

外部类名.内部类名 对象名 = 外部类对象.内部类对象;

//Outer.java
public class Outer {
    String name;
    class Inner{
    }
}
​
//Test.java
public class Test {
    public static void main(String[] args) {
        Outer.Inner oi = new Outer().new Inner();
        System.out.println(oi);
    }
}

6.2.1.3 成员内部类获取外部类的成员变量
System.out.println(Outer.this.变量名);

示例代码:

//Outer.java
public class Outer {
    private int a = 10;

    class Inner {
        private int a = 20;
        public void show(){
            int a = 30;
            
            // Outer.this 获取外部类对象的地址值
            System.out.println(Outer.this.a); //10 获取外部类的私有变量
            System.out.println(this.a); //20  获取本类中的私有变量
            System.out.println(a); //30  获取变量,就近原则
        }
    }
}

//Test.java
public class Test {
    public static void main(String[] args) {
        //创建内部类的对象,并调用show方法
        Outer.Inner oi = new Outer().new Inner();
        oi.show();
    }
}

内存图:

1.Test字节码文件加载进内存,然后虚拟机会自动调用main方法,main方法加载进栈内存,开始执行main方法
2.将外部类字节码文件(Outer.class)、内部类字节码文件(Outer&Inner.class)加载进内存
3.执行代码:Outer.Inner oi = new Outer().new Inner();
	堆内存中创建一个对象oi Outer.Inner类型
	在堆内存中开启子空间,记录外部类对象的地址值,记录外部类(Outer)中的私有变量 int a = 10;
	在堆内存中开启子空间,记录内部类对象的地址值,记录内部类(Inner)中的私有变量 int a = 20;
	在内部类对象中记录一个隐藏成员变量this,用来记录外部类对象的地址值
	
4.执行代码:oi.show();
	show方法加载进栈
		定义变量 int a = 30
		输出Outer.this.a变量
		输出this.a变量
		输出a变量

image-20251116213955698

6.2.2 静态内部类(了解)

  • 静态内部类只能访问外部类中的静态变量和静态方法

  • 如果想要访问非静态的,需要创建对象

public class Car {  //外部类
    String carName;
    int carAge;
    int carColor;
    static class Engine{  // 静态内部类,static修饰
        String engineName;
        int engineAge;
    }
}

书写格式:

//创建内部类对象的格式:
外部类名.内部类名 对象名 = new 外部类名.内部类名();

//调用非静态方法的格式:
//先创建对象,用对象调用

//调用静态方法的格式:
外部类名.内部类名.方法名();

示例代码:

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

    //静态内部类
    static class Inner{
        //非静态方法
        public void show1(){
            System.out.println("非静态方法被调用了");

            System.out.println(b);
            Outer o = new Outer();
            System.out.println(o.a);
        }

        //静态方法
        public static void show2(){
            System.out.println("静态方法被调用了");

            System.out.println(b);
            Outer o = new Outer();
            System.out.println(o.a);
        }
    }
}


//Test.java
public class Test {
    public static void main(String[] args) {
        //创建静态内部类的对象,只要是静态的东西,都可以用类名直接获取
        Outer.Inner oi = new Outer.Inner();
        oi.show1();

        //静态方法,不需要创建对象,直接调用即可
        Outer.Inner.show2();
    }
}

6.2.3 局部内部类(了解)

  • 将内部类定义在方法里面就叫做局部内部类,类似在方法中的局部变量

public class Outer {
    public void show(){
        //能修饰局部变量的,就能修饰局部内部类
        //不能修饰局部变量的,就不能修饰局部内部类
        int a = 10;

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

  • 外界是无法直接使用的,需要在方法内部创建对象并使用

public class Outer {
    public void show(){
        //能修饰局部变量的,就能修饰局部内部类
        //不能修饰局部变量的,就不能修饰局部内部类
        int a = 10;

        //局部内部类
        class Inner {
            String name;
            int age;

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

        }

        //无法直接使用show方法中的局部变量,需要在方法中创建对象才能使用
        //创建局部内部类对象
        Inner i = new Inner();
        System.out.println(i.name);
        System.out.println(i.age);
        i.method1();
        Inner.method2();
    }
}

  • 该类可以直接访问外部类的成员,也可以访问方法内的局部变量

//Outer.java
public class Outer {
    int b = 20;
    public void show(){
        //能修饰局部变量的,就能修饰局部内部类
        //不能修饰局部变量的,就不能修饰局部内部类
        int a = 10;

        //局部内部类
        class Inner {
            String name = "zhangsan";
            int age = 23;

            public void method1(){
                System.out.println(a); //可以访问方法内的局部变量a
                System.out.println(b); //可以直接访问外部类的成员b
                System.out.println("局部内部类中method1方法");
            }
            public static void method2(){
                System.out.println("局部内部类中method2静态方法");
            }
        }

        //无法直接使用show方法中的局部变量,需要在方法中创建对象才能使用
        //创建局部内部类对象
        Inner i = new Inner();
        System.out.println(i.name);
        System.out.println(i.age);
        i.method1();
        Inner.method2();
    }
}




//Test.java
public class Test {
    public static void main(String[] args) {
        //调用show方法,让代码执行
        Outer o = new Outer();
        o.show();
    }
}

6.2.4 匿名内部类(掌握)

  • 匿名内部类本质:隐藏了名字的内部类

  • 可以写在成员位置,也可以写在局部位置

//格式,包含(继承/实现  方法重写  创建对象)
new 类名或接口名(){
    重写方法;
};

//举例
new Inner(){
    public void show(){}
}

实现关系 -- 示例代码:

//Swim.java
public interface Swim {
    public abstract void swim();
}

//Test.java
public class Test {
    public static void main(String[] args) {
        //编写匿名内部类代码
        
        new Swim(){  //新建的内部类实现类Swim接口,所以要重写其中的所有方法
            @Override
            public void swim() {
                System.out.println("重写了Swim方法");
            }
        };
    }
}

image-20251116224207174

继承关系 -- 示例代码:

//Animal.java
public abstract class Animal {
    public abstract void eat();
}


//Test.java
public class Test {
    public static void main(String[] args) {
        new Animal(){  //新建的内部类继承了Animal类,所以要重写其中的所有方法
            @Override
            public void eat() {
                System.out.println("重写了eat方法");
            }
        };
    }
}

image-20251116224742800

使用场景:

直接创建一个匿名内部类来实现方法重写

public class Test {
    public static void main(String[] args) {
        //在测试类中调用下面的method方法
        method(new Animal() {
            @Override
            public void eat() {
                System.out.println("狗吃骨头");
            }
        });
    }

    public static void method(Animal a){ //Animal a = 子类对象 (多态)
        a.eat(); //编译看左边,运行看右边
    }
}
public class Test2 {
    public static void main(String[] args) {
        //Swim接口的实现类的对象,接口多态
        Swim s = new Swim(){
            @Override
            public void swim() {
                System.out.println("重写之后的游泳方法 -- 1");
            }
        };
        //编译看左边,运行看右边
        s.swim();
        
        new Swim(){
            @Override
            public void swim() {
                System.out.println("重写之后的游泳方法 -- 2");
            }
        }.swim();
    }
}


0

评论区