Java 内部类详解

一、内部类概述

  • 内部类只是一个编译时概念,编译成功就会成为完全不同的两个类,会有两个类的字节码文件;
  • 内部类是相对独立的一种存在,其成员变量和方法名可以和外部类的相同;

1、内部类和外部类比较

  • 内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员, 但外部类不能访问内部类的内部属性;
  • 内部类可以使用public、default、protected 、private以及static修饰,而外部类只能使用public和default修饰;

2、什么时候使用内部类

  • 只为外部类提供服务的情况下可以优先考虑使用内部类;
  • 使用内部类间接实现多继承,每个内部类都能独立地继承一个类或者实现某些接口;
  • 可以说接口在一定程度上解决了单继承的问题,但是也存在局限性,内部类进一步进行完善了 java 的多继承机制,但这里只是说间接实现了多继承

二、常用内部类

1、非静态内部类

  • 非静态内部类必须寄存在一个外部类对象里;
  • 非静态内部类可以直接访问外部类的成员,外部类不能直接访问非静态内部类成员;
  • 非静态内部类不能有静态方法、静态属性和静态初始化块
  • 外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例;

变量访问

  • 内部类看起来是可以直接访问外部类的成员即使是 private 的,但本质来说内部类只是持有了外部类的一个引用,然后通过这个引用来访问外部类的成员
  • 这里的 Outer.this就是持有的外部类引用
class Outer {
    private int age = 10;
    class Inner {
        int age = 20;
        public void show() {
            int age = 30;
            System.out.println("内部类方法里的局部变量age:" + age);// 30
            System.out.println("内部类的成员变量age:" + this.age);// 20
            System.out.println("外部类的成员变量age:" + Outer.this.age);// 10
        }
    }
}

访问内部类

//外部类中
new Inner()
//外部类外
Outer.Inner varname = new Outer().new Inner()

2、静态内部类

static  class   ClassName {
//类体
}

使用要点

  • 当一个静态内部类对象存在,并不一定存在对应的外部类对象
  • 静态内部类的实例方法不能直接访问外部类的实例方法
  • 静态内部类的访问,这里注意外部访问的写法
//外部类中
new Inner()
//外部类外
Outer.Inner inner =new Outer.Inner()

3、匿名内部类

匿名内部类示例

  • 原始代码
public class Hello {
	public static void main(String[] args) {
		String str="haha";
		new Thread() {
			@Override
			public void run() {
				System.out.println(str);
			}
		}.start();
	}
}
  • class 反编译得到的代码
public class Hello$1 extends Thread {
	
	private String val$str;
	
	Hello$1(String paramString) {
		this.val$str = paramString;
	}
 
	public void run() {
		System.out.println(this.val$str);
	}
 
}

注意事项

  • 匿名内部类没有访问修饰符,无法用 static 进行修饰,所以就是非静态内部类
  • 匿名内部类的使用往往是在方法中,所以也是局部内部类
  • 使用匿名内部类时必须是继承一个类或者实现一个接口,同时也只能继承一个类或者实现一个接口
  • 匿名内部类中是不能定义构造函数的,因为没有具体的类名,但是反编译后的代码可以看出匿名内部类实际是有构造器的,编译器为我们加的,但是我们无法使用
  • 匿名内部类中不能存在任何的静态成员变量和静态方法,这个就是非静态内部类的限制
  • 匿名内部类的初始化可以使用构造代码块

匿名内部类使用 final 修饰局部变量

  • 就是匿名内部类要使用局部变量的话,这个变量需要使用 final 进行修饰
  • 用final修饰实际上就是为了保护数据的一致性
  • 简单理解就是,匿名内部类使用局部变量是通过拷贝引用来实现的,为了避免引用值发生改变,例如被外部类的方法修改等,而导致内部类得到的值不一致,于是用final来让该引用不可改变
  • jdk8以前的版本不用 final 修饰的话,是无法通过编译的,但是 jdk8 的话不加也是可以的,据说是编译器自动帮你加了

4、局部内部类

  • 定义在方法内部的,作用域只限于本方法,称为局部内部类,这个基本不用
public class Parcel5 {
    public Destionation destionation(String str){
        class PDestionation implements Destionation{
            private String label;
            private PDestionation(String whereTo){
                label = whereTo;
            }
            public String readLabel(){
                return label;
            }
        }
        return new PDestionation(str);
    }
    
    public static void main(String[] args) {
        Parcel5 parcel5 = new Parcel5();
        Destionation d = parcel5.destionation("chenssy");
    }
}

你可能感兴趣的:(Java基础)