内部类在字面意思上理解就是包含在一个类里面的类。Java的官方解释为:内部类是定义在另一个类中的类。
一、为什么要引入内部类?
引入内部类的原因有以下三点:
- 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据。(也就是内部类中可以访问外部类的私有成员)
- 内部类可以对同一包的其他类隐藏起来
- 当想要定义一个回调函数且不想编写大量的代码的时候,使用匿名内部类比较的便捷。(如时间响应机制,线程)
注意:内部类一般使用在只要一次调用的地方,还有对某些接口和抽象类的实现时,不想创建接口或者抽象类的具体子类的时候,可以使用抽象类,接口和抽象类的内部类的应用返回的是接口和抽象类的子类对象。
如下代码:
Runnable runnable = new Runnable() {
@Override
public void run() {
//线程中使用匿名内部类。runnable接受的是Runnable接口的子 类对象
}
};
二、内部类
通过代码来分析内部类:
OuterClass类:
public class OuterClass {
private String str1 = "private: 我是外部类的私有成员变量";
public String str2 = "public: 我是外部类的公有成员变量";
static String str3 = "static: 我是外部类的静态成员变量";
public void outerTest1() {
System.out.println("我是外部类的公有成员方法");
}
private void outerTest2() {
System.out.println("我是外部类的私有成员方法");
}
static void outerTest3() {
System.out.println("我是外部类的公有成员方法");
}
// 在外部类调用内部类的方法和变量
public void test() {
// 外部类不能直接访问内部类的东西,需要创建对象访问
InnerClass inner = new InnerClass();
System.out.println(inner.string1);
System.out.println(inner.string2);
inner.innerTest3();
inner.innerTest4();
}
class InnerClass{
private String string1 = "private:我是内部类私有成员变量";
public String string2 = "public:我是内部类的公有成员变量";
public void innerTest3() {
System.out.println("我是内部类的公有成员方法");
}
private void innerTest4() {
System.out.println("我是内部类的私有成员方法");
}
// 在内部类中调用外部类的成员变量
public void innerTest1() {
System.out.println(str1);
System.out.println(OuterClass.this.str2);
System.out.println(str3);
System.out.println(str4);
}
// 在内部类中调用外部类的成员方法
public void innerTest2() {
func();
outerTest1();
OuterClass.this.outerTest2();
OuterClass.outerTest3();
}
public void show(){
System.out.println("外围类访问外部类的内部类!!!");
}
}
public String str4 = "public: 定义在内部类后边的外部类变量";
public void func(){
System.out.println("定义在内部类的后面的外部类方法");
}
}
OuterInnerDemo类:
public class OuterInnerDemo {
public static void main(String[] args) {
OuterClass outer = new OuterClass();
System.out.println("外部类调用内部类的成员变量及方法: ");
outer.test();
System.out.println();
System.out.println("内部类调用外部类: ");
// 创建内部类对象的方式1
OuterClass.InnerClass inner = new OuterClass().new InnerClass();
inner.innerTest1();
inner.innerTest2();
System.out.println();
System.out.println("外围类调用内部类方法: ");
// 创建内部类对象的方式2
OuterClass.InnerClass inner2 = outer.new InnerClass();
inner.show();
}
}
运行截图:
常规内部类的特点,有如下:
- 在内部类中可以访问外部类的任何修饰符修饰的成员变量和方法(包括private,static,fianl,public,protected,默认的.全部测试过)
- 在内部类中访问外部类的方式有两种:
- 直接访问,就是直接调用方法名或者变量名。
System.out.println(str2);
- 通过下面这个格式访问:外部类名.this.(成员变量or方法)
System.out.println(OuterClass.this.str2);
- 外部类也可以访问内部类的任何修饰符修饰的成员变量和方法(全部测试过)
- 外部类不能直接访问内部类的成员变量和成员方法,在外部类中必须创建内部类的对象,通过内部类的对象去访问内部类的成员方法和变量。
InnerClass inner = new InnerClass();
System.out.println(inner.string1);
- 内部类访问外部类的成员变量和方法,不管它们声明在内部类之后还是之前,只要是外部类的对象,内部类就能访问。
- 在外围类中访问内部类的方法,同样和普通类一样,通过创建类的对象去访问。
- 外围类创建内部类对象的方式,如下:
OuterClassName.InnerClassName objName =
new OuterClassName().new InnerClassName();
OuterClass.InnerClass inner = new OuterClass().new InnerClass();
OuterClassName.InnerClassName objName =
OuterClassObj.new InnerClassName();
OuterClass.InnerClass inner2 = outer.new InnerClass();
- 为什么要像vii点一样创建对象的分析:
对于一个类来说,我们创建类的对象是new ClassName(),然后通过创出的对象去调用类的方法。而对于内部类来说,它是外部类的一部分,因此要创建内部类的对象则要通过外部类的对象去调用,然后在按照new ClassName()原则去创建内部类的对象即可。
三、局部内部类
局部内部类就是定义在方法中的类。
class AreaInnerClass{
public void test() {
final int age = 10;
class Inner{
public void addOne(){
System.out.println(age+1);
}
private void addTwo(){
System.out.println(age+2);
}
}
new Inner().addOne();
new Inner().addTwo();
}
}
public class AreaInnerClassDemo{
public static void main(String[] args) {
new AreaInnerClass().test();
}
}
局部内部类的特点:
- 局部内部类定义的位置在一个方法的内部。
- 局部内部类对于外界完全隐藏起来了,即使外部类也不能访问它。
- 局部内部类不能用private和public进行修饰,因为局部内部类的作用域被限制在方法块中,及时用private和public进行修饰也毫无意义。
- 局部内部类的访问,通过在方法中创建局部内部类的对象来调用内部类的方法。
四、匿名内部类
匿名内部类其实就是对局部内部类的进一步的深入,假设只是创建一个类的对象,直接new className(){ .... },这样就不需要命名了。这种方式就叫做匿名内部类。
public class SecretInnerClassDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
new Object(){
void show(){
System.out.println("匿名内部类....");
}
}.show();
}
}
a) 格式:
new className(){
// 写方法
}.funcName();
b) 特点:
- new后面的className(类)必须是一个存在的类。(也就是说你new一个对象,那么就必须要存在一个具体类才能new)
- 存在前提,必须存在一个类,抽象类or接口
c) 本质:
是继承该类or接口的子类的匿名对象。(也就是说new className()或者new interfaceName(),返回的不是它们自身对象,返回而是它们的实现子类的对象,这个在匿名抽象类和匿名接口是最好理解,因为要重写接口和抽象类的方法,这个只有它们的子类能做,因此返回的是实现子类的对象)
五、静态内部类
有时候,使用内部类只是为了把一个隐藏在另一个类的内部,并不需要内部类引用外围类对象。为此,可以将内部类声明为static,来取消产生的引用。
class StaticInnerClass {
private static int a1 = 10;
private static int b1 = 20;
static class Inner{
private int a = 10;
private int b = 20;
public int add(){
return a+b;
}
public int add2(){
return a1+b1;
}
}
public void test(){
System.out.println(new Inner().add());
}
}
public class StaticInnerClassDemo{
public static void main(String[] args) {
new StaticInnerClass().test();
}
}