【基础】内部类

【基础】内部类

内部类分为 成员内部类、局部内部类、 匿名内部类、静态内部类。

成员内部类:

1. 成员内部类是最普通的内部类,它的定义为位于另一个类的内部
2. 成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)
3. 成员内部类拥有和外部类同名成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员
4. 如果要访问外部类的同名成员,需要以下面的形式进行访问: 外部类.this.成员变量
5. 外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过这个对象来访问
6. 如果要创建成员内部类的对象,前提是必须存在一个外部类的对象

7. 内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。比如上面的例子,如果成员内部类Inner用private修饰,则只能在外部类的内部访问,如果用public修饰,则任何地方都能访问;如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。这一点和外部类有一点不一样,外部类只能被public和包访问两种权限修饰。我个人是这么理解的,由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰。
public class Test {
    public static void main(String[] args)  {
        //第一种方式:
        Outter outter = new Outter();
        Outter.Inner inner = outter.new Inner();  //必须通过Outter对象来创建
        //第二种方式:
        Outter.Inner inner1 = outter.getInnerInstance();
    }
}
class Outter {
    private Inner inner = null;
    public Outter() {
    }
    public Inner getInnerInstance() {
        if(inner == null)
            inner = new Inner();
        return inner;
    }
    class Inner {
        public Inner() {
        }
    }
}

局部内部类:

1. 局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
2. 局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。
class People{
    public People() {
    }
}
class Man{
    public Man(){
    }   
    public People getWoman(){
        class Woman extends People{   //局部内部类
            int age =0;
        }
        return new Woman();
    }
}

匿名内部类:

1. 匿名内部类在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。
2. 匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由系统自动起名为Outter$1.class。一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。
package top.yancc.java.class_.innerClass;

import top.yancc.java.class_.innerClass.pack.InnerClass_pack;
/**
 * 匿名内部类:内部类,没有名称,只在方法体中执行
 * 总结: 
  *       匿名内部类直接在方法中 创建类的结构体, 
 *        必要有接口或者基类,用来指向实例,后续调用
 */
public class AnonyInnerDemo {
	public static void main(String[] args) {
		// 1. 匿名类 继承 父类
		InnerClass inner = new InnerClass() {
			public void greet(String name) {
				System.out.println(name);
			}
		};
		inner.greet("yancy_01");
		// 2. 匿名类 实现 接口
		new InnerInterFace() {
			@Override
			public void greet() {
				System.out.println("yancy_02");
			}
		}.greet();
		// 3. 调用 不同包中的 protected 方法
		new InnerClass_pack() {
			public void testProtectMethod() {
				super.greet();
			}
		}.testProtectMethod();
	}
}

静态内部类:

1. 静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似
2. 静态内部类不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
public class Test {
    public static void main(String[] args)  {
        Outter.Inner inner = new Outter.Inner();
    }
}
class Outter {
    public Outter() {
    }
    static class Inner {
        public Inner() {
        }
    }
}

疑问:

1.为什么成员内部类可以无条件访问外部类的成员?
  成员内部类中有一个指向外部类的指针,在外部类对象创建 内部类实例时,调用无参构造,但是传递了外部类的实例,外部类的实例赋值给 内部类的指针,所以可以内部类可以通过 外部类的指针 访问外部类的成员。


2.为什么局部内部类和匿名内部类只能访问局部final变量?
    内部类调用局部变量在编译期就需要指定。通过反编译看到 内部类中访问的局部变量 其实是一个copy,并不是原来的变量,所以在调用的过程中为了避免出现不一致的现象,使用 final 修饰变量。

如果局部变量的值在编译期间就可以确定,则直接在匿名内部里面创建一个拷贝。如果局部变量的值无法在编译期间确定,则通过构造器传参的方式来对拷贝进行初始化赋值。

方法中的局部变量和形参都必须用final进行限定了。

内部类的使用场景和优势:

1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整
2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏
3.方便编写事件驱动程序
4.方便编写线程代码

注意事项:

1)成员内部类的引用方式必须为 Outter.Inner.

2)构造器中必须有指向外部类对象的引用,并通过这个引用调用super()。这段代码摘自《Java编程思想》

class WithInner {
    class Inner{
    }
}
class InheritInner extends WithInner.Inner {
    // InheritInner() 是不能通过编译的,一定要加上形参
    InheritInner(WithInner wi) {
        wi.super(); //必须有这句调用
    }
    public static void main(String[] args) {
        WithInner wi = new WithInner();
        InheritInner obj = new InheritInner(wi);
    }
}
wi.super() 必须要有,显示调用 WithInner的构造方法。 InheritInner 的构造方法用来创建 InheritInner 的实例,该实例创建会调用 WithInner.Inner 的构造方法,而WithInner.Inner 的构造方法 依赖 WithInner 实例

通过 外部类的实例调用内部类方法

continue…

0 0 vote
Article Rating
Subscribe
提醒
guest
0 评论
Inline Feedbacks
View all comments