内部类
含义:一个类里面声明一个类
分类: 1.成员内部类 特点:可以调用外部类中所有的属性 2.静态内部类 特点:只能到调用外部类的静态属性 3.接口内部类 注意:接口内部类底层就是静态内部类 4.局部内部类 5.匿名内部类
内部类的应用场景1:
如果一个类的对象只在另外一个类中使用,
就可以考虑把该类变成成员内部类或者静态内部类,
如果内部类要用到外部类的所有属性就把该类变成成员内部类,
如果内部类只用到外部类的静态属性就把给类变成静态内部类内部类的应用场景2: 如果一个类的对象只在另外一个类的方法中使用,就可以考虑把该类变成局部内部类,一般不使用这种设计思想 内部类的应用场景3: 如果一个类的对象只在接口中使用,就可以考虑把该类变成接口内部类,一般不使用这种设计思想 内部类的应用场景4: 抽象类子类的对象或者是接口实现类对象只使用到一次,就可以考虑使用匿名内部类
成员内部类
理解
成员内部类,和实例属性 实例方法 动态代码块 构造器 是同一级别的事物,实例级别内容。
定义
//外部类
public class Foo {
//内部类:成员内部类
class Boo{
}
}
成员内部类成分
//外部类
public class Foo {
//内部类:成员内部类
class Boo{
int age; // OK 实例属性
static int name; //ERROR 不能定义静态属性
// OK 普通代码块
{
}
// ERROR 不可以定义
static {
}
//OK 构造器
public Boo(){
}
//OK 实例方法
public void m1(){
}
// ERROR 报错不可定义静态方法
public static void m2(){
}
}
}
不可以定义 static 相关内容,除此都可以。
成员访问规则
内部类访问外部
可以访问 实例信息和静态信息(全部),如果内部类访问外部类的同名属性默认,就近原则,通过 外部类名.this.xxx 可以强制区分外部类属性。
//外部类
public class Foo {
int fmoney;
static int fheight;
public void f1(){
}
public static void f2(){
}
//内部类:成员内部类
class Boo{
int age; //实例属性
public void m1(){ //实例方法
System.out.println( fmoney ); //OK 可直接访问
System.out.println( fheight); //OK 可直接访问
f1(); //OK 可直接访问
f2(); //OK 可直接访问
}
}
}
外部类访问内部
这个简单呀,当一个类使用即可,先创建对象,再访问实例属性和实例方法。
//外部类
public class Foo {
int fmoney;
static int fheight;
public void f1(){
Boo boo = new Boo(); // 1 创建对象
boo.m1(); // 2 对象来访问即可
}
public static void f2(){
}
//内部类:成员内部类
class Boo{
int age; //实例属性
public void m1(){ //实例方法
}
}
}
其他位置访问内部类
- 需要创建对象然后使用
public static void main(String[] args) {
//分开来写
Foo foo = new Foo();
Foo.Boo boo1= foo.new Boo();
//一步到位
Foo.Boo boo2 = new Foo().new Boo();
boo2.xx();
}
- 通过对象引用调用属性和方法。
内 部类单独使用,声明类型的时候需要带外部类名一起声明。比如 Foo.Boo
小细节
内部类也会生成单独的字节码文件,只是这个文件名规则为: 外部类名+$+内部类名.class
成员内部类使用案例
package case2;
public class Car {
//名字
String brand;
public Car(String brand){
this.brand=brand;
}
//汽车行驶方法 需要发动机提供动力
public void run(){
System.out.println(brand+"启动");
Engine engine = new Engine();
engine.zhuan();
}
//引擎,对外不公开,专门为外部类设计,为外部类提供服务
private class Engine {
public void zhuan(){
System.out.println("发动机运行");
}
}
}
package case2;
// 内部类使用案例
public class TestCar {
public static void main(String[] args) {
Car car = new Car("宝马");
car.run();
}
}
静态内部类
理解
静态内部类,和静态属性 静态方法 静态代码块 是同一级别的事物,是类级别内容。
定义
public class Foo {
//静态内部类
static class Boo{
}
}
定义成分
public class Foo {
static class Boo{
int age ; // 实例属性 OK
static int money; // 静态方法 OK
// 构造器 OK
public Boo(){
}
// 实例方法 OK
public void m1(){}
// 静态方法 OK
public static void m2(){}
// 普通代码块OK
{
}
// 静态代码块 OK
static {
}
}
}
从定义成分上看,几乎等价与一个普通外部类
成员访问规则
内部类访问外部类
只能访问到静态内容(静态属性 静态方法)
外部类访问内部类
就是一个普通类的访问方式:
- 通过类名访问静态属性和方法
- 通过对象访问实例属性和方法
其他位置访问内部类
就是一个普通类的访问方式:
- 通过类名访问静态属性和方法
- 通过对象访问实例属性和方法
方法内部类
理解
方法内部类,定义外部类的方法中,和方法的局部变量同级别。
定义
public class Foo {
public void f1(){
int age = 10;
//方法内部类
class Boo{
}
}
}
定义成分
public void f1(){
int age = 10;
// 内部类
class Boo{
//实例属性 OK
int age;
// 构造器 OK
public Boo(){
}
// 动态代码块 OK
{
}
public void m1(){ // 实例方法 OK
}
}
}
只能定义实例相关信息,不可定义静态内容,且不可添加访问权限。
成员访问规则
内部类访问外部类
可以直接访问静态和实例的信息。
外部类访问内部类
就是一个普通类的访问方式:
- 通过对象访问实例属性和方法 ,只能在内部类所在方法中使用
细节面试题
局部内部类访问 所在方法的 局部变量,要求这个变量是final修饰的,在JDK7必须强制声明为final,JDK8中无需声明,但是编译器依然要求它是一个final。
为什么呢? 需要延长局部变量的生命周期,保证对象使用该变量时,它是存在的,通过final 修饰的变量进入常量池,会一直保存。
匿名内部类
理解
添加访问权限。
成员访问规则
内部类访问外部类
可以直接访问静态和实例的信息。
外部类访问内部类
就是一个普通类的访问方式:
- 通过对象访问实例属性和方法 ,只能在内部类所在方法中使用
细节面试题
局部内部类访问 所在方法的 局部变量,要求这个变量是final修饰的,在JDK7必须强制声明为final,JDK8中无需声明,但是编译器依然要求它是一个final。
为什么呢? 需要延长局部变量的生命周期,保证对象使用该变量时,它是存在的,通过final 修饰的变量进入常量池,会一直保存。
匿名内部类
理解
没有名字的内部类,是一种特殊的局部内部类。它是把类的定义和对象创建合二为一。匿名内部类只能创建一次对象。匿名内部类必须是某个接口的实现类或者是某个类的子类。