面向对象的成员之一——(内部类)
一、内部类的理解:
1.1 为什么要有内部类的存在?
当一个事物的内部,还有部分需要一个完整的结构去进行描述,并且这个内部的完整的结构又为外部事物去提供服务,那么整个内部的完整结构最好是使用内部类。
内部类就是一个类的定义位于另一个类的内部,那么位于内部的类就叫做内部类,包容内部类的类就是外部类。内部类和外部类都是相对的,内部类里面可以还有内部类,只要满足需求既可以定义。
内部类英文名称为Inner Class,一般用在定义它的类或者语句块当中,在外部引用它的时候必须要给出完整的名称,因此Inner Class的名字不能与包含它的外部类类名相同。
1.2 内部类的分类
分为:
1.成员内部类(static 成员内部类和非static成员内部类)
2.局部内部类(不谈修饰符)【声明在方法内、代码块内等的内部类】、匿名对象
1.3 内部类的使用
1.3.1 关于成员内部类的使用 作为外部类的一个成员
1.相对于外部类,内部类可以用四种不同的权限修饰符,而外部类一般都是用public或者缺省
2.可以在内部类中调用外部类的成员
3.可以用static进行修饰,但是此时就不能再使用外层类的非static的成员变量
4.编译之后生成OuterClass$InnerClass.class字节码文件
1.3.2 关于局部内部类的使用
1.局部内部类可以在其类中声明属性、方法、构造器、内部类、代码块【也就是包括面向对象的基本成员】
2.局部内部类可以声明为abstract类,因此可以被其他的内部类继承
3.可以声明为final,表示不能被其他类继承
4.局部内部类编译之后也会生成OuterClass$InnerClass.class字节码文件
1.3.3 注意点
1.非static成员内部类中的成员不能声明为static,只有在外部类或者说static的成员内部类中才可以声明为static成员
2.外部内访问内部类的时候,需要“内部类.成员”或者说“内部类对象.成员”的方式
3.成员内部类可以直接使用外部类的所有成员,包括私有的数据
4.当外部类的静态成员想要部分使用内部类时,可以考虑内部类声明为静态的
如何创建成员内部类的对象、如何在成员内部类中调用外部类的属性、方法
外部类的使用
代码示例
public class InnerClassTest {
public static void main(String[] args) {
//创建静态的成员内部类
Person.Bird bird=new Person.Bird ();
//创建非静态的成员内部类
// Person.Dog dog = new Person.Dog ();
//这样会出错,因为非静态的成员内部类必须要创建对象,进行类的的实例化
Person p=new Person ();
Person.Dog dog=p.new Dog ();
//如果写成 Person.Dog dog=new p.Dog ();这样就会报错,语法出现问题
dog.info ();
dog.show ("旺财");
}
}
class Person {
String name="赵大花";
int age=1;
public void eat() {
System.out.println ("人吃饭~~");
}
//静态的成员内部类
static class Bird {
}
//非静态的成员内部类
class Dog {
String name="旺财";
public void info() {
//直接调用外部类的属性和方法
System.out.println (age);
//Person.Dog.eat();不能这么写,非静态的需要实例化
Person.this.eat ();
}
public void show(String name) {
System.out.println (name);
System.out.println (this.name);
因为非静态类的属性必须通过创建对象去调用属性,只有静态的不需要
System.out.println (Person.this.name);
}
}
}
熟悉局部内部类的基本使用
内部类的使用
代码示例
public class InnerClassTest1 {
此种方式使用局部内部类,不常见
public void method() {
声明一个局部内部类
class A {
}
}
常见如下的操作
public Comparable getComparable() {
方式一:内部声明一个接口的实现类
class MyComparable implements Comparable {
@Override
public int compareTo(Object o) {
return 0;
}
}
return new MyComparable ();
方式二:创建了接口的匿名实现类的匿名对象
return new Comparable () {
@Override
public int compareTo(Object o) {
return 0;
}
};
/new Comparable () {
@Override
public int compareTo(Object o) {
return 0; }}它表示了接口的匿名实现类的匿名对象,因为只使用一次,所以可以用接口的匿名实现类,然后通过重写方法就进行了对象的创建*/
}
}
二、关于内部类的使用细节
2.1 如何使用局部内部类?
1.只能在声明他的方法或者代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类
2.但是她的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或者说是父接口类型
3.内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号,以及数字编号。
4.只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类。
5.局部内部类可以使用外部类的成员,包括私有的。
6.局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的声明周期不同所致。
7.局部内部类和局部变量地位类似,不能使用public,protected,缺省,private
8.局部内部类不能使用static修饰,因此也不能包含静态成员
2.2 匿名内部类
1.匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
2.格式:
new 父类构造器(实参列表)|实现接口(){
//匿名内部类的类体部分
}
3.匿名内部类的特点
①匿名内部类必须继承父类或实现接口
②匿名内部类只能有一个对象
③匿名内部类对象只能使用多态形式引用
代码示例
interface A{
public abstract void fun1();
}
public class Outer{
public static void main(String[] args) {
new Outer().callInner(new A(){
//接口是不能new但此处比较特殊是子类对象实现接口,只不过没有为对象取名
public void fun1() {
System.out.println(“implement for fun1");
}
});// 两步写成一步了
}
public void callInner(A a) {
a.fun1();
}
}