类的成员之五:内部类Inner Class
1、为什么要有内部类
1.内部类场景
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。2.内部类特点
声明为内部类可以直接使用访问外部类的所有的成员,包括私有的.
3.源代码示例:
JRE核心类库集合的迭代器大量使用内部类;每一个集合实现类都有个迭代器内部类
2、内部类的分类
(1) 静态内部类
(2)非静态内部类:
- 成员内部类
- 局部内部类
- 匿名内部类
3、成员内部类
(1)如何声明成员内部类
声明的位置:在类中方法外
格式如下:
[修饰符] class 外部类{
[修饰符] class 成员内部类{
}
}
(2)成员内部类的特点
- 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。例如:Outer$Inner.class
- 成员内部类也是外部类的一个成员,可以使用所有权限修饰符 public,protected,default,private
- 成员内部类还可以使用final和abstract修饰
- 成员内部类中不可以包含静态成员
- 成员内部类可以直接使用外部类的所有成员,包括私有的。
- 如果成员内部类有与外部类的非静态属性重名时,可以通过“外部类名.this.属性”进行区别,如果与外部类的静态属性重名时,可以通过“外部类名.类变量”进行区别
(3)如何使用成员内部类
1.在外部类中使用成员内部类
- 在外部类的静态成员中不能使用非静态的成员内部类
- 在外部类的非静态成员中,直接创建内部类的对象来访问内部类的属性与方法。此时把它当做一个普通的类即可
2.在外部类的外面使用成员内部类
- 需要外部类的对象才能创建成员内部类的对象
package com.innerclass.member;
public class TestMemberClass {
public static void main(String[] args) {
Outer out = new Outer();
out.outerMethod();
Outer.Inner oi = out.new Inner();
oi.innerMethod();
Outer.Inner obj = out.getInner();
obj.innerMethod();
}
}
class Outer{
private int value = 5;
public static void outerStaticMethod(){
/*Inner in = new Inner();//错误
in.innerMethod();*/
}
public void outerMethod(){
System.out.println("外部类的方法");
/*Inner in = new Inner();//可以
in.innerMethod();*/
}
class Inner{
public void innerMethod(){
System.out.println("内部类的方法");
System.out.println("内部类的方法访问外部类的私有成员:"+value);
}
}
//通过外部类的某个方法返回内部类的对象
public Inner getInner(){
return new Inner();
}
}
4、静态内部类
(1)如何声明静态内部类
声明的位置:在类中方法外
格式如下:
[修饰符] class 外部类{
[修饰符] static class 静态内部类{
}
}
(2)什么时候声明静态内部类
- 当内部类需要包含静态成员时
- 当想要在外部类的静态成员部分使用内部类时
(3)静态内部类的特点
- 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。例如:Outer$Inner.class
- 静态内部类可以使用修饰符public,protected,default,private
- 静态内部类还可以使用final和abstract修饰
- 静态内部类中可以包含静态成员
- 静态内部类可以直接使用外部类的静态成员,包括私有的。但不能使用外部类的非静态成员。
- 静态内部类中有与外部类的静态属性重名时,如果要表示是外部类的属性,那么用“外部类名.属性”
(4)如何使用静态内部类
- 在外部类中使用静态内部类:就和使用其他普通类一样
- 在外部类的静态成员中
- 在外部类的非静态成员中
- 在外部类的外面使用成员内部类:
- 使用静态内部类的静态成员:外部类名.静态内部类名.静态内部类的静态成员
- 使用静态内部类的非静态成员:外部类名.静态内部类名 obj = new 外部类名.静态内部类名();
obj.静态内部类的非静态成员
package com.innerclass.staticinner;
public class TestStaticInnerClass {
public static void main(String[] args) {
Outer.StaticInnerClass.innerStaticMethod();
Outer.StaticInnerClass os = new Outer.StaticInnerClass();
os.innerMethod();
}
}
class Outer{
public static void outerStaticMethod(){
StaticInnerClass.innerStaticMethod();
StaticInnerClass si = new StaticInnerClass();
si.innerMethod();
}
public static void outerMethod(){
StaticInnerClass.innerStaticMethod();
StaticInnerClass si = new StaticInnerClass();
si.innerMethod();
}
static class StaticInnerClass{
public static void innerStaticMethod(){
System.out.println("内部类的静态方法");
}
public void innerMethod(){
System.out.println("内部类的非静态方法");
}
}
}
5、局部内部类
(1)如何声明局部内部类
声明的位置:在外部类的方法或代码块中
格式如下:
[修饰符] class 外部类{
方法{
class 局部内部类{
}
}
}
(2)局部内部类的特点
- 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件“外部类的类名$数字编号内部类名.class”。
- 局部内部类和局部变量地位类似,不能使用public,protected,private,static这些成员修饰符,但是可以使用abstract或final
- 局部内部类不能使用static修饰,因此也不能包含静态成员。
- 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类,因为作用域的问题。
- 局部内部类可以使用外部类的成员,包括私有的。但是是否可以使用外部类的非静态成员要看所在方法是否是非静态的。
- 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的生命周期不同所致。
(3)如何使用局部内部类
- 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类。
- 但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型。
package com.innerclass.local;
public class TestLocalInnerClass {
public static void main(String[] args) {
Outer out = new Outer();
Object obj = out.outerMethod();
System.out.println(obj);
}
}
class Outer{
int value = 5;
public Object outerMethod(){
final int localValue = 10;
class LocalInnerClass{
public void innerMethod(){
System.out.println("局部内部类的方法");
System.out.println("局部内部类的方法可以使用外部类的成员:"+value);
System.out.println("局部内部类的方法可以使用外部类的局部变量:"+localValue);
}
}
//先声明后使用
LocalInnerClass li = new LocalInnerClass();
li.innerMethod();
return li;
}
}
6、匿名内部类
(1)如何声明匿名内部类
声明的位置:任何可以创建对象的语句中
格式如下:
new 父类/父接口(){
....
}
意思是创造一个实现(继承)了接口(父类)的类的对象。
(2)匿名内部类的特点
- 匿名内部类是类,它编译后的字节码文件名是:外部类名$数字编号.class
- 匿名内部类必须继承父类或实现接口
- 匿名内部类只能有一个对象
- 匿名内部类对象只能使用多态形式引用
- 匿名内部类是特殊的局部内部类,局部内部类的所有限制对它都适用
(3)如何使用匿名内部类
三种使用方法:
- 继承式
- 接口式
- 参数式
package com.innerclass.anonymous;
import java.util.Arrays;
import java.util.Comparator;
public class TestAnonymous {
public static void main(String[] args) {
//继承式
Car car = new Car(250){
public void run(){
System.out.println("改进型:" + getSpeed());
}
};
Car[] cars = new Car[3];
cars[0] = car;
cars[1] = new Car(120);
cars[2] = new Car(140);
for (Car c : cars) {
c.run();
}
//接口式
Comparator com = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Car c1= (Car) o1;
Car c2= (Car) o2;
return c1.getSpeed() - c2.getSpeed();
}
};
Arrays.sort(cars,com);
//参数式
Arrays.sort(cars,new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Car c1= (Car) o1;
Car c2= (Car) o2;
return c1.getSpeed() - c2.getSpeed();
}
});
for (Car c : cars) {
c.run();
}
}
}
class Car{
private int speed;
public Car() {
super();
}
public Car(int speed) {
super();
this.speed = speed;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public void run(){
System.out.println("标准发动机助跑" + speed);
}
}