1. 一个类的内部又完整的嵌套了另一个类结构,被嵌套的类称为内部类,最大的特点为可以直接访问私有属性。
2. 类的五大成员:属性、方法、构造器、代码块、内部类。
3. 内部类分类:
3.1 定义在外部类局部位置上:
3.1.1 局部内部类
局部内部类定义在外部类的局部位置,比如方法中,并且有类名
3.1.1.1 可以直接访问外部类的所有成员包括私有成员
3.1.1.2 不能添加访问修饰符,但可以使用final修饰
因为局部内部类相当于一个局部变量,局部变量不能使用修饰符,但可以使用final
局部内部类的实例化在外部类的方法中,作用域仅限于此方法中。
外部类和局部内部类的成员重名时,可通过 外部类名.this.成员 去访问外部类成员,否则内部类成员会覆盖外部类成员。
public class LocalInnerClass {
public static void main(String[] args) {
Outer01 o1 = new Outer01();
o1.m1();
}
}
class Outer01{
private int n1 = 10;
private void m2() {
System.out.println("hello?");
}
public void m1() {
final class Inner02 {
public void f1() {
System.out.println("n1=" + n1);
m2();
//直接访问外部类的私有成员
}
}
Inner02 inner02 = new Inner02();
//在方法中实例化
inner02.f1();
}
}
3.1.2 匿名内部类
3.1.2.1 匿名内部类定义在外部类的局部位置,比如方法中,且没有类名(系统会分配类名,但程序员不可见)
匿名内部类同时是一个对象,当实现接口的类只需要使用一次时,使用匿名内部类可以简化开发
匿名内部类只能使用一次,但实例化的对象可以反复使用
实例:
public class AnonymousInnerClass {
public static void main(String[] args) {
A a = new A();
a.f1();
}
}
//定义接口
interface IA{
public void cry();
}
//定义类
class A{
public void f1() {
//匿名内部类
//tiger的编译类型为IA
//tiger的运行类型为匿名内部类,即A$1
//在类的方法中把接口实例化
IA tiger = new IA() {
@Override
//重写接口方法
public void cry() {
System.out.println("aoaoao");
}
};
tiger.cry();
System.out.println(tiger.getClass());
//tiger类型为A$1
}
}
3.1.2.2 基于类的匿名内部类
class Cat{
Cat(String name) {
}
public void f2() {}
}
class Pet{
public void f1(){
//基于类的匿名内部类
//编译类型为Cat
//运行类型为匿名内部类
Cat cat = new Cat("miumiu"){
//重写类方法
@override
public void f2(){
System.out.println("luelue")
}
};
}
}
当类的一个方法中有多个匿名内部类的时候,系统为其分配的类名递增如Pet$1,Pet$2
3.1.2.3 基于抽象类的匿名内部类
class B{
public void f1(){
C c = new C(){
//抽象类,匿名内部类中必须实现抽象类中的所有抽象方法
@Override
void cry(){
System.out.println("I'm free");
}
};
}
}
//抽象类
abstract class C{
abstract void cry();
}
3.1.2.4 匿名内部类的使用案例:
传统方法和匿名内部类使用比较:
传统方法通过实现接口的类来定义对象,属于硬编码,一旦实现接口类的内容改变,所有该类实例化的对象都会随之改变。
匿名内部类更加简洁灵活,对于只使用一次的接口实现使用匿名内部类更简单。
public class interface_ {
public static void main(String[] args) {
//匿名内部类实现
//实例化接口作为参数传入函数
f1(new IA(){
@Override
public void show() {
System.out.println("hhh");
}
});
//传统方法实现
IAA iaa = new IAA();
iaa.show();
}
//匿名内部类作用函数,接口作为形参
public static void f1(IA ia) {
ia.show();
}
}
interface IA{
void show();
}
//传统方法的接口实现
class IAA implements IA {
@Override
public void show() {
System.out.println("hello?");
}
}
//打印结果:
//hhh
//hello?
小结:匿名内部类涉及多态、动态绑定、多态
3.2 定义在外部类的成员位置上(与局部内部类的区别):
3.2.1 成员内部类:
3.2.1.1可直接访问外部类的所有成员,包括私有成员
可以添加任意访问修饰符:static,protected,final
外部类使用内部类,要先创建内部类对象(一般在方法里)再访问
3.2.1.2 外部类其他类使用成员内部类的三种方式
一:直接声明内部类
public class member_innerclass {
public static void main(String[] args) {
Outer01 outer01 = new Outer01();
Outer01.Inner01 inner = outer01.new Inner01();
//编译类型为外部类.内部类,使用对象new一个内部类
inner.f1();
}
}
class Outer01{
public class Inner01{
public void f1(){
System.out.println("hello?");
}
}
}
二:在外部类声明函数,函数中创建调用内部类
public class member_innerclass {
public static void main(String[] args) {
Outer01 outer01 = new Outer01();
outer01.f2();
}
}
class Outer01{
//内部类
public class inner01{
public void f1(){
System.out.println("hello?");
}
}
public void f2() {
//创建inner01对象
inner01 innerObj = new inner01();
//调用inner对象方法
innerObj.f1();
}
}
Tips:
如果内部类和外部类的成员重名,内部类访问的话会覆盖掉外部类的重名成员,如需访问外部类成员,可通过 外部类.this.成员名 来访问
3.2.2 静态内部类:
使用static修饰
可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
可添加任意访问修饰符(public,protected,private)
外部类访问静态内部类方式:创建对象再访问(和成员内部类相同)
外部其他类访问静态内部类:
通过类名直接访问
编写方法(可静态或者非静态)返回静态内部类的对象实例