一、内部类
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。
1.成员内部类
定义在类中的方法外的类。
class
外部类
{
class
内部类
{
}
}
特点:
- 作为成员存在,可以被权限修饰符修饰。
- 内部类可以直接访问外部类的成员,包括私有成员。
- 外部类要访问内部类的成员,必须要建立内部类的对象。
主方法内创建内部类对象:
外部类名
.
内部类名 对象名
=
new
外部类型
().
new
内部类型
();
ps:
内部类仍然是⼀个独⽴的类,在编译之后会内部类会被编译成独⽴的
.class
⽂件,但是前⾯
冠以外部类的类名和
$符号 。比如:Person$Heart.class
代码说明
//外部类
public class Outer {
//外部类成员变量
int a = 1;
private int b = 2;
int e = 10;//相同的外部类的成员变量
//外部类成员方法
public void outM1(){
//当外部类想访问内部类的成员时,需要创建内部类的对象
Inner in = new Inner();
System.out.println(in.c+","+in.d);//内部类的私有成员变量也能获取
in.inM1();//内部类成员方法
System.out.println("外部类的成员方法outM1");
}
//成员内部类
public class Inner{
//内部类成员变量
int c = 3;
private int d = 4;
int e = 10;//相同的内部类的成员变量
//内部类的成员方法
public void inM1(){
int e = 10;//相同的外部类的局部变量
//在内部类里可以直接访问到外部类的成员,包括私有成员
System.out.println(a+","+b);//private int b = 2;
outM1();//直接调用外部类成员方法
//若出先变量名相同的情况该如何获取到想要的变量
//1.获取相同的内部类的局部变量
System.out.println(e);
//2.获取相同的内部类的成员变量
System.out.println(this.e);
//3.获取相同的外部类的成员变量
System.out.println(Outer.this.e);
System.out.println("内部类的成员方法inM1");
}
}
}
//无关类
public class Main {
public static void main(String[] args) {
//当无关类想获取内部类的成员
//1.间接调用:在外部类成员方法里创建了内部类的对象,再在无关类创建外部类的对象,通过调用外部类成员方法,间接调用内部类
Outer ou = new Outer();
ou.outM1();
//2.直接调用
Outer.Inner inOu = new Outer().new Inner();
inOu.inM1();//但如果想直接访问外部或者内部私有成员,还是需要创建get,set
}
}
2.静态内部类
定义在类中的方法外的,被static关键词修饰的类。
class
外部类
{
static class
内部类
{
}
}
特点:
- 作为静态成员属性存在,可以被任意权限修饰符修饰。
- 可以直接访问外部类static相关的属性和方法。
- 访问外部类普通属性和方法,则需要通过new外部类去访问。
代码说明
//静态内部类
public class Outer {
//外部类
//成员变量
int a;
//静态成员变量
static int b;
//成员方法
public void m1(){
System.out.println("成员方法m1");
}
//静态成员方法
public static void m2(){
System.out.println("静态成员方法m2");
}
//静态内部类
public static class inner1{
int ina;
static int inb;
public void innerM1(){
System.out.println(b);//可以直接访问外部类静态成员
m2();
// m1();//不可以直接访问外部类不是静态的成员
//访问其他属性跟方法 需要实例化外部类
Outer ou = new Outer();
ou.a = 5;
ou.m1();
}
}
}
public class Main {
public static void main(String[] args) {
//调用普通成员
Outer ou1 = new Outer();
ou1.m1();
//调用静态的成员
Outer.b = 23;
Outer.m2();
//访问内部类成员
Outer.inner1 oi = new Outer.inner1();
oi.innerM1();
oi.ina = 5;
//调用内部类静态成员
Outer.inner1.inb = 6;
}
}
3.局部内部类
定义在类中方法中的类。
class
外部类
{
public void m1(){
class
内部类
{
}
}
}
特点:
- 存在方法之中,只能在方法中使用,类前不能有访问权限。
- 局部内部类只在当前方法中有效。
- 不能定义static成员,因为在方法结束后,内存需要释放。
- 局部内部类中可以访问外部类的所有成员。
- 可以直接访问方法的局部变量,但无法修改,编译会出错。
代码说明
//局部内部类
public class Outer {
//成员变量
int a;
//成员方法
public void m1(){
//局部变量
int b=5;
//局部内部类:存在于外部类的成员方法中
//注意局部内部类的修饰词不能用访问修饰符 :4个
class Inner{
//局部内部类的成员变量
int ina;
//局部内部类的成员方法
public void m2(){
int inb =3;
System.out.println("局部内部类的成员方法m2");
//如果想在局部内部类中获取外部类成员方法的局部变量
System.out.println(b);
//b = 10;-->不能被修改因为此时的外部类方法中的局部变量默认被final修饰
//局部内部类方法中的局部变量
System.out.println(inb);//3
inb = 8;
System.out.println("inb"+inb);//8能被修改
}
};
//想要使其他类获取局部内部类的成员
//需要在外部类中,方法中,局部内部类外,创建局部内部类的对象
Inner in = new Inner();
//然后就能在方法里调用局部内部类的成员了
System.out.println(in.ina);//局部内部类的成员变量
in.m2();//局部内部类的成员方法
System.out.println("外部类的成员方法m1");
}
}
//无关类
public class Main {
public static void main(String[] args) {
Outer ou = new Outer();
ou.m1();
}
}
4.匿名内部类
跟局部内部类相似,但本质是一个为了继承抽象类,或者实现接口。
new
⽗类名或者接⼝名
() {
//
⽅法重写
@Override
public
void
method
() {
//
执⾏语句
}
};
特点:
- 没有类名的内部类,必须在创建时使用new语句来声明类。
- 匿名类和局部内部类一样,存在方法中,可以访问外部类的所有成员。
- 重写父类/接口中的抽象方法。
- 匿名类中允许使用非静态代码块进行成员初始化操作。
- 匿名类的非静态代码块会在父类的构造方法之后被执行。
代码说明(接口举例)
public interface InterfaceA {
//接口的抽象方法
public abstract void a1();
public abstract void a2();
}
//匿名内部类
public class Outer {
int num;
public void m1(){
//1.局部内部类里创建一个接口的实现类
class InterfaceImpl implements InterfaceA{
@Override
public void a1() {
System.out.println("m1,a1");
}
@Override
public void a2() {
System.out.println("m1,a2");
}
}
//创建一个实现接口A类的对象
InterfaceImpl in = new InterfaceImpl();
in.a1();//这样就可以调用实现类接口A里重写的抽象方法
in.a2();
}
//2.匿名内部类——>优化局部内部类
public void m2(){
//InterfaceImpl in = new InterfaceImpl();
//多态 InterfaceA in = new InterfaceImpl();
//下面这样的写法优化了局部内部类,称之为匿名内部类,因为class名不见了
//接口是不能new对象的,但 InterfaceA in = new InterfaceA() {}; 不是new对象,new对象没有{};
//它是对实现这个接口的实现类new的对象
//可以理解成是个引用的实现类的方法
InterfaceA in = new InterfaceA() {
@Override
public void a1() {
System.out.println("m2,a1");
}
@Override
public void a2() {
System.out.println("m2,a2");
}
};
in.a1();//直接调用
in.a1();
}
//3.匿名对象
public void m3(){
//
new InterfaceA(){//直接new接口A的实现类
@Override
public void a1() {
System.out.println("m3,a1");
}
@Override
public void a2() {
System.out.println("m3,a2");
}
}.a1();//通过在分号前.方法名调用接口A的抽象方法,但每次只能调用一个方法,
// 若想调用其他方法还需创建一个成员方法重写后调用,如 m4
}
public void m4(){
new InterfaceA(){
@Override
public void a1() {
System.out.println("m4,a1");
}
@Override
public void a2() {
System.out.println("m4,a2");
}
}.a2();
}
}
public class Main {
public static void main(String[] args) {
Outer ou = new Outer();
ou.num = 5;
ou.m1();
//m1,a1
//m1,a2
ou.m2();
//m2,a1
//m2,a1
ou.m3();
//m3,a1
ou.m4();
//m4,a2
}
}