深入理解java之内部类

深入理解java之内部类_第1张图片

一.内部类

我们把一个类放在另一类的内部定义 称为内部类(inner class)
内部类分为 成员内部类,匿名内部类,局部内部类

深入理解java之内部类_第2张图片
内部类的两个要点:

  • 内部类提供了更好的封装,只能让外部类直接访问,不允许同一个包中的其他类直接方法
  • 内部类可以直接访问外部类的私有属性,内部类被其当成外部类的成员,但外部类不能访问内部类的内部属性(可以思想和继承差不多 子类可以访问父类,父类不可以访问子类(除非多态))

注意
内部类只是一个编译时概念,一旦我们编译成功,就会成为完全不同的两个类。对于一
个名为 Outer 的外部类和其内部定义的名为 Inner 的内部类。编译完成后会出现 Outer.class和 Outer$Inner.class 两个类的字节码文件。所以内部类是相对独立的一种存在,其成员变量/方法名可以和外部类的相同

【示例】内部类的定义和使用

/**外部类 Outer*/
class Outer {
    private int age = 10;
   public void show(){
     System.out.println(age);//10
    }
/**内部类 Inner*/
public class Inner {
//内部类中可以声明与外部类同名的属性与方法
  private int age = 20;
   public void show(){
     System.out.println(age);//20
     }
  }
}

编译后会产生两个不同的字节码文件,如图所示:
在这里插入图片描述

二.内部类的分类

深入理解java之内部类_第3张图片

1.非静态内部类

非静态内部类(外部类里使用非静态内部类和平时使用其他类没什么不同)

  1. 非静态内部类对象必须寄存在一个外部类对象里。因此,如果有一个非静态内部类对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对象。

  2. 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员。

  3. 非静态内部类不能有静态方法、静态属性和静态初始化块。

  4. 成员变量访问要点:

    *  内部类属性:this.变量名。
    *  外部类属性:外部类名.this.变量名。
    

【示例】内部类中访问成员变量

/**外部类 Outer1*/
class Outer1 {
  private int age = 10;
  public void show(){
      System.out.println(age);//10
  }
  /**内部类 Inner*/
  public class Inner1 {
      //内部类中可以声明与外部类同名的属性与方法
      private int age = 20;
      public void show(){
          System.out.println(age);//20
          System.out.println(Outer1.this.age); //10 访问外部类的普通属性
      }
  }
}

内部类的访问:

  1. 外部类中定义内部类:new Inner()。
  2. 外部类以外的地方使用非静态内部类:
    Outer.Inner varname = new Outer().new Inner()

【示例】内部类的访问

/**
* 测试非静态内部类
*/
public class TestInnerClass1 {
    public static void main(String[ ] args) {
        //先创建外部类实例,然后使用该外部类实例创建内部类实例
        Outer1.Inner1 inner = new Outer1().new Inner1();
        inner.show();
    }
}

2.静态内部类

静态内部类特点

  1. 静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static;
  2. 静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法;
  3. 静态内部类中即能声明静态成员也可以声明非静态成员。

定义方式:

static class ClassName {
//类体
}

使用要点:

  1. 静态内部类可以访问外部类的静态成员,不能访问外部类的普通成员。
  2. 静态内部类看做外部类的一个静态成员。

【示例】静态内部类的访问

/*
测试静态内部类
*/
class Outer2{
    private int a = 10;
    private static int b = 20;
    //相当于外部类的一个静态成员
    static class Inner2{
        public void test(){
// System.out.println(a); //静态内部类不能访问外部类的普通属性
            System.out.println(b); //静态内部类可以访问外部类的静态属性
        }
    }
}
public class TestStaticInnerClass {
    public static void main(String[ ] args) {
        //通过 new 外部类名.内部类名() 来创建内部类对象
        Outer2.Inner2 inner =new Outer2.Inner2();
        inner.test();
    }
}

3.匿名内部类

适合那种只需要使用一次的类。比如:键盘监听操作等等。在安卓开发、awt、swing开发中常见。
匿名内部类特点

  • 匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。

语法:

new 父类构造器(实参类表) \实现接口 () {
//匿名内部类类体!
}

示例】匿名内部类的使用

/**
 * 测试匿名内部类
 */
public class TestAnonymousInnerClass {
    public void test1(A a) {
        a.run();
    }
    public static void main(String[] args) {
        TestAnonymousInnerClass tac = new
                TestAnonymousInnerClass();
        tac.test1(new A() {
            @Override
            public void run() {
                System.out.println("匿名内部类测试! 我是新定义的 第一个匿名内部类!");
            }
        });
        tac.test1(new A() {
            @Override
            public void run() {
                System.out.println("我是新定义的第二个匿名内部类 ");
            }
        });
    }
}
interface A {
    void run();
}
 // 实现关系下的匿名内部类:
interface Dao {
	void show();
}
 
public class AnonymousDemo {
    //编写回调方法 :callInner
    public void callInner(){
        // 接口关系下的匿名内部类
        new Dao(){
            //实现子类 但是没有名字 所以叫匿名内部类
            @Override
            public void show() {
                System.out.println("接口方法...");
            }
        }.show();
    }
}
// 测试:
public class Demo {
    public static void main(String[] args) {
        AnonymousDemo anonymousDemo = new AnonymousDemo();
        anonymousDemo.callInner();
    }
}

匿名内部类可用于给方法传递实参,演示如下:

interface Dao {
	void show();
}
 
public class AnonymousDemo {
    //编写回调方法:callInner 参数类型为接口Dao
    private static void callInner(Dao d) {
        d.show();
    }
 
    public static void main(String[] args) {
        callInner(new Dao() {//接口回调
 
            //实现子类 但是没有名字 所以叫匿名内部类
            @Override
            public void show() {
                System.out.println("匿名内部类用于给方法传递实参");
            }
        });
    }
    
}

或许有些难以理解,其实过程并不复杂。
说明:首先有一个接口,然后在使用的类中编写了一个方法(参数类型是接口对象),并使用接口中未实现的方法。
我们调用此方法直接构造一个接口对象传入,此时会自动生成一个此接口的子类(匿名内部类)实现接口中的方法。本质传入的类便是此时的匿名内部类。
注意
 匿名内部类没有访问修饰符。
 匿名内部类没有构造方法。因为它连名字都没有那又何来构造方法呢。

4.局部内部类

定义在方法内部的,作用域只限于本方法,称为局部内部类。
局部内部类在实际开发中应用很少。

局部内部类的特点

  1. 局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内;
  2. 局部内部类不可使用权限修饰符 静态(static)修饰符进行修饰 同局部变量相同;
  3. 局部内部类可以直接访问方法中的属性;
  4. 局部内部类 可以直接访问方法外部类中属性和方法;
  5. 局部内部类 创建对象 要在方法内部 局部内部类的外部声明。

案例

public class Partial {
    String name = "外部类的类名";
    String type = "外部类的type属性";
    private int item = 1;
 
    public static void show() {
        System.out.println("掉用外部类中的show方法");
    }
    public void print() {
        System.out.println("调用外部类中的打印方法");
    }
 
    public void demo(){
        String name = "外部类方法deme()内部的方法名";
        String type = "外部类方法deme()内部的type属性";
        /*编写在方法的内部的类称之为局部内部类
        局部内部类不可使用权限修饰符 静态修饰符进行修饰 同局部变量相同
        局部内部类与局部变量使用范围一样 在此方法内部
        局部内部类可以直接访问方法中的属性 重名时使用参数传递完成访问*/
        class Inner{
            //局部内部类 可以访问方法外部类中属性和方法
            String name = "局部类的类名";
            public void showInner(String name){
                show();
                print();
                System.out.println("我是:"+ type);
                System.out.println("我是:"+ Partial.this.type);
                System.out.println(item);
                System.out.println("我是:" + this.name);
                System.out.println("我是:" + name);
                System.out.println("我是:" + Partial.this.name);
            }
        }
        //局部内部类 创建对象 要在方法内部 局部内部类的外部声明
        Inner inner = new Inner();
        inner.showInner(name);
    }
 
    public static void main(String[] args) {
        Partial partial = new Partial();
        partial.demo();
    }
}

【示例】方法中的内部类

/**
* 测试局部内部类
*/
public class TestLocalInnerClass {
    public void show() {
        //作用域仅限于该方法
        class Inner3 {
            public void fun() {
                System.out.println("helloworld");
            }
        }
        new Inner3().fun();
    }
    public static void main(String[ ] args) {
        new TestLocalInnerClass().show();
    }
}

你可能感兴趣的:(深入理解java,java,开发语言)