毕向东Java基础教程-内部类
内部类
定义:将一个类定义在另一个类的里面,里面那个类就称为内部类(内置类,嵌套类)。
访问特点:
- 内部类可以直接访问外部类中的成员,包括私有成员。
- 而外部类要访问内部类中的成员必须要建立内部类的对象。
用法:
一般用于类的设计。分析事物时,发现该事物描述中还有事物,而且这个事物还在访问被描述事物的内容,这时就将里面的事物定义成内部类。
细节:
Example 1:为什么内部类能直接访问外部类的成员呢?是因为内部持有了外部类的引用-->外部类.this
。
class Outer
{
int num = 3;
class Inner
{
int num = 4;
void show()
{
int num = 5;
System.out.println(num); //打印5
System.out.println(this.num); //打印4,或者可写为Inner.this.num
System.out.println(Outer.this.num); //打印3
}
}
public void method()
{
new Inner().show();
}
}
class Demo
{
public static void main(String[] args)
{
new Outer().method();
}
}
成员内部类
定义:内部类定义在成员位置上。
特点:
- 可以被private static成员修饰符修饰。
- 被static修饰的内部类只能访问外部类中的静态成员。
Example 1:内部类和其成员都是非静态的
class Outer
{
private int num = 3;
class Inner
{
void show()
{
System.out.println("show run..."+num);
}
}
public void method()
{
Inner in = new Inner();
in.show();
}
}
class Demo
{
public static void main(String[] args)
{
//直接访问外部类中的内部类中的成员
Outer.Inner in = new Outer().new Inner(); //不常用,因为一般都将内部类封装了
in.show();
}
}
Example 2:内部类为静态,其成员为非静态的
class Outer
{
private static int num = 3;
static class Inner
{
void show()
{
System.out.println("show run..."+num);
}
}
public void method()
{
Inner in = new Inner();
in.show();
}
}
class Demo
{
public static void main(String[] args)
{
//如果内部类是静态的,相当于一个外部类
Outer.Inner in = new Outer.Inner();//不需要再创建Outer对象
in.show();
}
}
Example 3:内部类和其成员都为静态
class Outer
{
private static int num = 3;
static class Inner
{
static void show()
{
System.out.println("show run..."+num);
}
}
public void method()
{
Inner.show();
}
}
class Demo
{
public static void main(String[] args)
{
Outer.Inner.show();//不需要再创建Outer和Inner对象
}
}
如果内部类中定义了静态成员,则该内部类也必须是静态的。
如果类中的静态函数想访问内部类,则该内部类必须是静态的。
局部内部类
定义:内部类定义在局部位置上。
特点:
- 也可以直接访问外部类中的成员。
- 同时可以访问所在局部中的局部变量,但必须是被final修饰的。
Example 1:示例
class Outer
{
int num = 3;
void method()
{
int x = 9;
final int y = 8;
class Inner
{
void show()
{
System.out.println("show..."+num);//可以直接访问外部类中的成员。
System.out.println("show..."+x); //编译错误,从内部类中访问所在局部中的局部变量x,需要被声明为最终类型
System.out.println("show..."+y); //可以访问所在局部中的局部变量,但必须是被final修饰的。
}
}
Inner in = new Inner();
in.show();
}
//method()方法外不能访问Inner
}
class Demo
{
public static void main(String[] args)
{
new Outer().method();
}
}
Example 2:为什么局部变量需要被final修饰,局部内部类才可访问?
class Outer
{
int num = 3;
Object method()//若method函数有参数int y,如果想在内部类Inner中访问,也需要写为final int y
{
int x = 9;
class Inner
{
void show()
{
System.out.println("show..."+x);
}
}
Object in = new Inner();
return in;
}
}
class Demo
{
public static void main(String[] args)
{
Outer out = new Outer();
Object obj = out.method();
}
}
method函数执行完就出栈了,x便不存在了,而obj对象仍然存在,于是访问不了x,因此需把x声明为常量。
实质上是,java把局部内部类对象要访问的final型局部变量,复制过来变成该内部类对象中的一个成员变量,这样即使栈中局部变量(含final)已死亡,但由于它是final的,其值是不会发生改变的,因而内部类对象在局部变量死亡后,照样可以访问自己内部维护的一个值跟局部变量一样的成员变量,从而解决这个问题。
注意:java8中匿名/局部内部类访问局部变量时,局部变量已经可以不用加final了,但其实这个局部变量还是final的(表现为对该值初始化后不能再赋值了),只不过不用显式的加上而已,推测可能是编译机制发生了改变。
匿名内部类
定义:局部内部类的简化写法。
前提:内部类必须继承或实现一个外部类或者接口。
格式:new 外部类名或者接口名(){覆盖类或者接口中的代码,也可以自定义内容}
简单理解:就是建立一个带内容的外部类或者接口的子类匿名对象。
Example 1:匿名类中重写一个函数
abstract class Demo
{
abstract void show();
}
class Outer
{
int num = 4;
/*
class Inner extends Demo
{
void show()
{
System.out.println("show..."+num);
}
}
*/
public void method()
{
//new Inner().show();
new Demo()//new了Demo类的子类对象
{
void show()
{
System.out.println("show..."+num);
}
}.show();
}
}
class Demo
{
public static void main(String[] args)
{
new Outer().method();
}
}
Example 2:匿名类中重写两个函数
interface Demo
{
void show1();
void show1();
}
class Outer
{
int num = 4;
public void method()
{
Demo demo = new Demo() //类似于多态,父类引用指向了子类对象
{
public void show1()
{
System.out.println("show1..."+num);
}
public void show2()
{
System.out.println("show2..."+num);
}
}
demo.show1();
demo.show2();
}
}
应用:当函数参数是接口类型时,而且接口中的方法不超过三个,可以用匿名内部类作为实际参数进行传递。
/*---以前的写法----*/
interface Inter
{
void show1();
void show2();
}
class InterImpl implements Inter
{
public void show1(){}
public void show2(){}
}
class Demo
{
public static void main(String[] args)
{
show(new InterImpl());
}
public static void show(Inter in)
{
in.show1();
in.show2();
}
}
/*---可以改为以下写法----*/
interface Inter
{
void show1();
void show2();
}
class Demo
{
public static void main(String[] args)
{
show(new Inter()
{
public void show1(){}
public void show2(){}
});
}
public static void show(Inter in)
{
in.show1();
in.show2();
}
}
细节:
class Outer
{
void method()
{
new Object()
{
public void show()
{
System.out.println("show run");
}
}.show();//创建的Object的子类对象,调用的子类对象的方法
/*
Object obj = new Object(){
public void show()
{
System.out.println("show run");
}
};
obj.show(); //编译错误,在java.lang.Object里找不到show()方法,因为匿名内部类这个子类对象已经被向上转型为了Object类型,这样就不能使用子类特有的方法了,只能调用父类或接口中存在的方法。
*/
}
}
class Demo
{
public static void main(String[] args)
{
new Outer().method();
}
}