内部类
在类内部定义的类我们称这个类为内部类。包含内部类的类叫做外部类。java从JDK1.1开始引入内部类。内部类的作用如下:
1,内部类提供了更好的封装,可以把内部类隐藏在外部类之内。
2,内部类可以访问外部类的私有数据,内部类其实就相当于外部类的成员(内部类成员),同一个类中成员和成员可以互相访问。
3,匿名内部类适合用于只需要创建一次或只需要使用一次的类。
内部类的细分
定义内部类非常简单,只需要把一个类放在类的内部即可。”类的内部”可以是类的任何位置,甚至是类中方法的内部(定义在方法中的内部类称为局部内部类)。在类中(就是{}中)称为成员内部类。我们一般都会使用成员内部类。局部内部类和匿名内部类都不属于类成员。
成员内部类分为两种:静态内部类和非静态内部类。
总的来说,内部类分为:成员内部类,局部内部类和匿名内部类。
非静态内部类
下面的程序在Cow类中定义了一个CowLeg内部类。内部类CowLeg访问了外部类的私有属性weight。
public class Cow {
private double weight;
public Cow(double weight){
this.weight = weight;
}
private class CowLeg{
private double length;
private String color;
public CowLeg(double length, String color){
this.length = length;
this.color = color;
}
public void info(){
System.out.println("length:"+length+" color:"+color);
System.out.println("weight:"+weight);
}
}
public void test(){
CowLeg cowLeg = new CowLeg(12.1, "黑白猫熊色");
cowLeg.info();
}
public static void main(String [] args){
Cow cow = new Cow(123.4);
cow.test();
}
}
内部类可以访问外部类的属性,但是反过来外部类不能访问内部类的属性。因为一个内部类对象会默认依赖一个外部类对象,而外部类对象不一定包含一个内部类对象,什么时候包含内部类对象,要看代码的执行情况。
我们可以把CowLeg是类成员变量,一次他们四种访问权限:private、protected,不加任何访问修饰符(默认访问权限)、public。
最后一点需要注意的是:非静态内部类不能包含静态属性、静态方法和静态初始化块。
静态内部类
如果使用static来修饰一个内部类,那么这个类就是静态内部类。静态内部类可以看成是类的静态成员变量,静态内部类可以访问外部类的静态成员,但是不能访问外部类的非静态成员(这遵循着java静态成员不能访问非静态成员的规则)。即使是静态内部类的非静态方法也不能访问外部类的非静态成员,因为静态内部类是外部类相关的,静态内部类寄存在外部类的类本身,而不是外部类的实例对象,没有寄存对象就访问不到外部类的实例成员了。下面给出一个代码:
public class TestClassInnerClass {
private int prop1 = 5;
private static int prop2 = 9;
static class StaticClassInnerClass{
private int age;
private static int age1=25;
public static void accessOutputProp(){
System.out.println("可以访问外部类的static成员:"+prop2);
System.out.println("输出内部类的age1变量:"+age1);
//一下代码将编译错误,不允许访问外部类的实例成员
// System.out.println(prop1);
}
}
public static void main(String [] args){
StaticClassInnerClass.accessOutputProp();
}
}
局部内部类
如果把一个内部类定义在方法里,则这个内部类就是一个局部内部类。局部内部类可以看作是局部变量,而局部变量没有访问修饰符,它的作用域范围就是方法内。局部变量也不能用static修饰,因为这样修饰并没有意义,java也是不允许这样修饰的。所有局部内部类只能在方法内使用,不能使用访问修饰符符修饰,也不能是static的。代码如下:
public class LocalInnerClass {
public static void main(String [] args){
class LocalClass{
public void print(){
System.out.println("LocalClass print()");
}
}
LocalClass lc = new LocalClass();
lc.print();
}
}
匿名内部类
匿名内部类适合创建那种只需要使用一次的类(可以理解成一次性产品)。匿名内部类不能重复使用。创建匿名内部类时就会创建该匿名内部类的实例。匿名内部类的格式如下:
关于匿名类有如下两条规则:
1,匿名类不能是抽象的,因为匿名类创建时会创建该匿名类的对象。
2,匿名类没有构造器,因为匿名类没有类名。但是匿名类可以有初始化块,可以用初始化快来代替构造器。
通过匿名类创建某个接口类型的变量,这也是匿名类经常使用的方式。代码如下:
public interface Command {
void process(int [] array);
}
public class ProcessArray {
public void proocess(int [] array, Command command){
command.process(array);
}
public static void main(String [] args){
m2();
}
public static void m2(){
ProcessArray pa = new ProcessArray();
int [] array = new int[]{1,2,-2,12,4};
//这里使用匿名内部类的方式创建了一个Command类型的对象
pa.proocess(array, new Command(){
@Override
public void process(int[] array) {
System.out.println(Arrays.toString(array));
}});
}
}
proocess()方法第一个参数是需要处理的数组,第二个参数是需要处理数组的方式,也就是处理数组需要调用的方法。为了演示匿名内部类的应用场景,我们假设将数组输出的这种方式只需要使用一次,使用匿名内部类代码显得更简洁(除了简洁个人没有发现其他好处)。
注意:匿名内部类不能是抽象的,所以需要实现接口或类中的所有抽象方法。匿名内部类也可以重新父类的方法,下面将会演示。
我们再来看一下创建某一个类 类型的匿名内部类,代码如下:
public abstract class Command {
public void process(int[] array) {
System.out.println(Arrays.toString(array));
endPrint();
}
public abstract void endPrint();
}
public class ProcessArray {
public void proocess(int [] array, Command command){
command.process(array);
}
public static void main(String [] args){
m2();
}
public static void m2(){
ProcessArray pa = new ProcessArray();
int [] array = new int[]{1,2,-2,12,4};
pa.proocess(array, new Command(){
//这匿名内部类重写了Command类的process()
@Override
public void process(int[] array) {
System.out.println(Arrays.toString(array));
endPrint();
}
//这匿名内部类实现了Command类的process()
@Override
public void endPrint() {
System.out.println("处理数组结束...");
}});
}
}