成员内部类
成员内部类,顾名思义在类的成员位置上,我们创建了一个Java类,这个类在已有类的内部。
编写一个S类作为示例,S类有属性和行为。相比于普通类,其中我们在S类的内部加上了一个Z类,Z类就是一个成员内部类。在z类里一样有属性和行为(方法)。在内部类Z类的方法里我们尝试输出外部类的属性,在外部类S类,我们同样尝试用过方法输出内部类的属性。由于外部类方法直接访问内部类属性时,软件提示错误,于是我们这里试着通过实例化一个对象来访问。然后试着运行。
public class S {
static String Name="张三";
int age =12;
class Z{
String id="001";
public void say(){
System.out.println("名字"+Name);
System.out.println("年龄"+age);
}
}
Z z=new Z();
public void say1(){
System.out.println("编号"+z.id);
}
编写一个main方法来测试以上代码是否能够正常运行,由于Z类在S类的内部,所以我们不能正常实例化一个对象,需要通过外部的对象进行实例化。
public static void main(String[] args) {
S s=new S();
Z z= s.new Z();//需通过外部对象实例化
s.say1();
z.say();
}
可以看到我们运行的结果,可以知道内部类的方法成功的访问了外部类的属性,并且外部类静态的和非静态的都输出了出来,同时外部类的方法也成功通过对象访问了内部的数据属性。
通过以上运行结果,可以总结出以下特点:成员内部类,可访问外部静态或非静态的属性,其次外部方法访问成员内部类,须通过实例化对象才能够访问,还有内部类实例化对象需要听过外部类的对象。
局部内部类
局部内部类,也叫方法内部类,也就是说在类的方法里面创建了一个类。依旧用上面的程序,我们将Z类移动到S类的方法里面去。局部内部类于成员内部类有异曲同工之妙。由于局部内部类在类的方法里面,所以它相较于成员内部类的作用域要小很多。
通过具体示例体现:
public class S {
static String Name="张三";
int age =12;
public void say1(){
class Z{
String id="001";
public void say(){
System.out.println("名字"+Name);
System.out.println("年龄"+age);
}
}
Z z=new Z();
z.say();
System.out.println("编号"+z.id);
}
可以看到Z类在S类的方法里面,方便比较,所以其余并没有变化。
public static void main(String[] args) {
S s=new S();
s.say1();
}
由于Z类在S类的方法里面,所以在main方法里不需要在给内部类实例化,也可以调用。
可以看到运行结果与成员内部类结果一样。依据运行结果和代码,我们可以总结出局部内部类的特点;局部内部类可以直接访问外部类的属性数据,外部类输出局部内部类的属性数据需要通过实例化的对象才可以。其次局部内部类实例化数据必须在局部的方法里面。
静态内部类
静态内部类,是在外部类里面用static关键字进行修饰的类。
简单回顾static关键字的用法:
用法 | static |
---|---|
修饰成员变量 | 变成类的成员属性,可类名.成员调用,不需new对象 |
修饰成员方法 | 变成类的成员方法,可类名.方法调用,不需new对象 |
静态块 | 类成员一起初始化 |
静态导包 | 方法名调用(便捷) |
熟悉了以上static的用法,我们可以猜测以下静态内部类的特点。
静态内部类只能访问外部静态的属性和方法。
其次static修饰了,可能可以直接实例化对象,不需要通过外部的实例化对象
通过示例尝试:
依旧用上面的Z类和S类,在S类里添加一个用static修饰的Z类,其他依旧和以前一样,以方便对比。
public class S {
static String Name="张三";
int age =12;
static class Z{
String id="001";
public void say(){
System.out.println("名字"+Name);
}
}
Z z=new Z();
public void say1(){
System.out.println("编号"+z.id);
}
编写一个main方法来运行,看能否正常运行。
public static void main(String[] args) {
S s=new S();
Z z= new Z();
s.say1();
z.say();
}
运行结果如图,可以知道我们以上的内外部类之间的属性和方法的访问,能够正常运行。说明我们的猜测是正确的。
总结一下,static修饰的静态内部类只能访问外部静态的属性。非静态的属性不能访问,
其次,静态内部类可以直接进行对象的实例化,不需要通过外部类实例化的对象。
匿名内部类
匿名内部类是掌握的重点,前面的理解就行,匿名内部类在接口中使用能够带来极大的方便。
匿名内部类顾名思义,隐藏起来的内部类。
通过一个示例来理解:
写一个抽象的Animal的类:有属性,有抽象和非抽象的方法
public abstract class Animal{
String Name;
public void say(){
System.out.println("非抽象方法");
}
public abstract void eat();
}
在写cat类,dog类等去继承Animal这个类,重写eat方法,在main方法里面输出出来。
class cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
class dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
在main方法里面,通过父类引用指向子类的对象输出。
public static void main(String[] args) {
Animal a1=new cat();
a1.eat();
Animal a2=new dog();
a2.eat();
}
运行结果如下:
可以看到输出了我们希望的结果。
但是如果有很多这样的类,,为了需要我们创建了一个一个的子类,但是子类之间只有一两处不同,就会发现程序非常的冗余。如果有一个方法让我们不需要定义子类,就可以输出想要的。
于是就有了匿名的内部类,隐含实现一个接口或实现一个类。
我们在原程序上写一个这样的代码,再次运行:
Animal a3=new Animal(){
@Override
public void eat() {
System.out.println("兔子吃草");
}
};
a3.eat();
可以看到运行结果多了一个兔子吃草,正是以上代码输出的内容
要知道Animal是抽象的,不可以实例化,但是我们在后面加一个{}就可以继续代码的编写。
我们可以看到运行结果与我们写一个子类的效果一样。
这就是匿名内部类,我们不知道这个类的名称,但是实现了与定义一个子类一样的效果。
`所以说匿名内部类隐含实现一个接口或实现一个类。
我们尝试定义一个接口,在接口里使用匿名内部类。
接口类:Animal类——有两个方法
public interface Animal {
void feed();
void eat();
}
实现类:cat类
class cat implements Animal{
@Override
public void feed() {
System.out.println("给猫喂水");
}
@Override
public void eat() {
System.out.println("猫喝水");
}
}
写一个匿名实现类,看我们的运行结果是不是一样的。
Animal a2=new Animal() {
@Override
public void feed() {
System.out.println("买饭吃");
}
@Override
public void eat() {
System.out.println("吃饱了");
}
};
在main方法里运行,结果如下:
可以看到两种方法出来的结果是一样的,匿名实现类免去了创建子类的麻烦,使得程序更加的高效。