目录
1 什么是内部类?
面向对象程序设计中,可以在一个类的内部定义另一个类。内部类分为两种,即静态内部类和非静态内部类。非静态内部类又分为成员内部类,方法内部类,匿名内部类。
2 为什么需要使用内部类?
- 内部类对象可以访问创建它的对象的实现,包括私有数据;
- 内部类不为同一包的其他类所见,具有很好的封装性;
- 使用内部类可以很方便的编写事件驱动程序;
- 匿名内部类可以方便的定义运行时回调;
- 内部类可以方便的定义;
每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。
3 几种内部类的区别(重点)
3.1 静态内部类
和普通类一样,内部类也可以由静态的。不过和非静态内部类相比,区别就在于静态内部类没有了指向外部类的引用。除此之外,在任何非静态内部类中,都不能有静态数据,静态方法或者又一个静态内部类(内部类的嵌套可以不只一层)。不过静态内部类中可以拥有者一切。这也算俩者的第二个区别吧。
- 静态内部类,不能访问外部类的非静态成员
- 静态内部类 不需要创建外部类的对象就可访问(外部类名.内部类 比如new MyMain.Person().display();就创建了静态内部类对象)
- 静态内部类可以有public、protected、默认的、private等多种类型 (这个功能我倒是从来没听说,通过实验的确ok)
- 静态内部类可以继承其他普通类。
package com.dh.neibuleiDemo.staticInnerClass;
public class Main1 {
private static String name = "kobe bryant";
private String num = "001";
// 静态内部类可以用public,protected,private修饰
public static class Person extends InnerTest{
// 静态内部类中可以定义静态或者非静态的成员
private String address = "Los angeles";
private static String x = "Laker";
public String mail = "kobe@yahoo.com.cn";// 内部类公有成员
public void display() {
// System.out.println(num);//不能直接访问外部类的非静态成员
// 静态内部类不能访问外部类的非静态成员(包括非静态变量和非静态方法)
System.out.println(name);// 只能直接访问外部类的静态成员
// 静态内部类只能访问外部类的静态成员(包括静态变量和静态方法)
System.out.println("Inner " + address);// 访问本内部类成员。
}
}
public void printInfo() {
Person person = new Person();
// 外部类访问内部类的非静态成员:实例化内部类即可
person.display();
//父类中的方法
person.method1();
// System.out.println(mail);//不可访问
// System.out.println(address);//不可访问
//访问内部类的成员,都要通过内部类的对象
System.out.println(person.address);// 可以访问内部类的私有成员
System.out.println(Person.x);// 外部类访问内部类的静态成员:内部类.静态成员
System.out.println(person.x);// 这样也能访问,但是不推荐
System.out.println(person.mail);// 可以访问内部类的公有成员
}
public static void main(String[] args) {
Main1 staticTest = new Main1();
staticTest.printInfo();
}
}
3.2 成员内部类
成员内部类和静态内部类可以类比为非静态的成员变量和静态的成员变量,注意在创建非静态内部类对象时,一定要先创建起相应的外部类对象
作为外部类的一个成员存在,与外部类的属性、方法并列,它可以访问它的外部类的所有成员变量和方法,不管是静态的还是非静态的都可以。
- 内部类中不能有静态成员
- 可以访问外部类的成员变量(外部类名.this.变量名)
- 可以定义在方法外(可以有访问修饰符)和方法内(不能有访问修饰符,这个就是匿名内部类了)
- 可以继承普通类。
package com.dh.neibuleiDemo.innerClass;
import com.dh.neibuleiDemo.staticInnerClass.InnerTest;
public class Main2 {
private static String name = "kobe bryant";
private String num = "001";
private String address = "GreenLand";
class Person extends InnerTest {
private String address = "Los angeles";
public String mail = "kobe@yahoo.com.cn";// 内部类公有成员
public void display() {
System.out.println(name);// 只能直接访问外部类的静态成员
System.out.println(Main2.this.address);//访问外部类的同名非静态成员变量
System.out.println(address);// 访问本内部类成员。
}
}
public static void main(String[] args) {
Main2 test = new Main2();
//即使在本类中想要调用Person类,都必须这样写,而不能直接 new Person()
test.new Person().display();
System.out.println(test.new Person().mail);
}
}
3.3 方法内部类
- 方法内部类的地位和方法里面的局部变量相似,所以不能用public等修饰词修饰。
- 方法内部类只能在声明的方法里面是可见的,请记住,一定要先声明方法,后使用内部类,否则,编译器就会说找不到这个内部类。
- 方法内部类只能包含非静态成员。
- 方法内部类中的方法可以访问该方法所属的类中的属性。
- 方法内部类也可以继承外部普通类。
package com.dh.neibuleiDemo.methodInnerClass;
import com.dh.neibuleiDemo.staticInnerClass.InnerTest;
public class Main3 {
public static void main(String[] args) {
Main3 main3 = new Main3();
main3.new Test4().method1();
}
class Test4{
public String s = "这是内部类pulbic变量";
private String s1 = "这是内部类private变量";
public void method1(){
int a = 4;
class Test5 extends InnerTest {
public void meth2(){
System.out.println("方法内部类中的打印函数");
System.out.println(a);
System.out.println(s);
System.out.println(s1);
}
}
new Test5().meth2();
new Test5().method1();
}
}
}
3.4 匿名内部类
匿名内部类是局部内部类的一种简化形式.本质上是一个对象,是实现了该接口或继承了该抽象类的子类对象。
- 语法格式:new 类名或者接口名(){重写方法;};
- 给匿名内部类命名:虽然这是匿名内部类,但是仍然可以利用多态来给匿名内部类命名。
- 匿名内部类可以作为参数或者返回值,使用方便。
package com.dh.neibuleiDemo.nimingneibulei;
public class Main3 {
public static void main(String[] args) {
//匿名内部类
new AA() {
@Override
public void aa() {
System.out.println("aaaaaaaaaaaaaaaa");
}
@Override
public void hehe() {
System.out.println("hehehehehehhehehhe");
}
}.aa();
//此时,要想用同一个对象调用多个方法时,就会很难办到.这个时候给匿名内部类名命就可以解决了!
//利用多态进行名命
AA aa = new AA() {
@Override
public void aa() {
System.out.println("aaaaaaaaaaaaaa744444aa");
}
@Override
public void hehe() {
System.out.println("hehehehehe888877777hhehehhe");
}
};
//这样就可以调用多个方法了
aa.aa();
aa.hehe();
//利用多态传参数
test(aa);
}
//方法的形参要一个抽象类类型,传递一个该抽象类的子类对象.
public static void test(AA a){
a.hehe();
}
}
abstract class AA {
public abstract void aa();
public abstract void hehe();
}