内部类
类分为内部类和外部类,在Java中,可以将一个类定义在另一个类中或者一个方法的内部,这样的类称为内部类,内部类可以简单的理解成定义在类内部的类,内部类主要分为:匿名内部类、实例内部类、静态内部类、局部内部类;本章节就详细的讲解几种内部类的使用方式,几种内部类的限制。
先来看一下内部类的语法:
//外部类
public class Test1 {
//内部类
class innerClass{
}
}
只有定义在类内部的类才能称为内部类;
内部类和外部类共用一个java文件,但是经过编译后,会分开生成两个.class文件;
匿名内部类
匿名内部类的定义
下面看一下如何定义内部类:
下面就是匿名内部类的定义,可以看到,只是实现了接口,并没有定义class…….,不像外部类一样,class后面还定义了一个名字。
interface IEntrance{
void method();
}
//外部类
public class Test1 {
//匿名内部类
public static void main(String[] args) {
//实现接口
new IEntrance(){
//重写接口中的方法
@Override
public void method() {
}
};
}
}
匿名内部类访问
访问接口中的方法有两种方式:一种在内部类花括号后面直接访问,第二种是用接口类型定义的引用指向匿名内部类,通过引用访问;注意:而在匿名内部类中,不可以访问被修改过后的变量,最好是用final修饰,以防止不小心被修改
interface IEntrance{
void method();
}
//外部类
public class Test1 {
//匿名内部类
public static void main(String[] args) {
int a = 10;//定义一个局部变量
a = 20;//对a进行修改,
new IEntrance(){
@Override
public void method() {
System.out.println("这是在匿名内部类中");
//在匿名内部类中不能访问修改过后的变量
System.out.println("a的值" + a);//在这里会报错
}
}.method();//第一种访问方式
//第二种访问方式,通过接口的引用访问
IEntrance iEntrance = new IEntrance(){
@Override
public void method() {
System.out.println("这是在匿名内部类中");
}
};
//在匿名内部类外可以访问
System.out.println("a的值:"+a);
iEntrance.method();
}
}
内部类的特点
1、匿名内部类必须继承一个抽象类或者实现一个接口
2、匿名内部类不能定义任何静态成员和静态方法
3、当所在的方法的形参需要被匿名内部类使用时,必须声明成final
4、匿名内部类不能是抽象的,它必须要实现继承的类中的所有抽象方法,或者实现接口中所有的抽象方法
实例内部类
实例内部类的定义
实例内部类语法定义:
public class OuterClass {
//实例内部类
//是有名字的
class InnerClass{
}
}
实例内部类的如何实例化对象
下面请看代码是如何实例化内部类对象的:
public class OuterClass {
//实例内部类
class InnerClass{
}
}
class Test {
public static void main(String[] args) {
//实例化外部类对象
OuterClass outerClass = new OuterClass();
//实例化内部类对象
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
//先实例化外部类对象,通过外部类调用内部类去定义指向内部类对象的引用,而内部类对象需要依靠外部类的引用去实例化
}
}
先实例化外部类对象,通过外部类调用内部类去定义指向内部类对象的引用,而内部类对象需要依靠外部类的引用去实例化
注意:
所以,先有外部类对象才能实例化 实例内部类对象,实例内部类对象依赖于外部类对象
实例内部类访问情况
以下代码有点多,但干货满满,请一定要认真的看!!!
public class OuterClass {
public int a = 10;
public int b = 20;
private int k = 88;//被private修饰
InnerClass innerClass = new InnerClass();//在外部类中可以直接实例化内部类对象
public void method1() {
System.out.println("这是一个外部类中的method1");
}
public void method4() {
System.out.println("这是外部类的方法");
}
//访问内部类中的成员
public void method8() {
innerClass.method2();
}
//实例内部类
class InnerClass{
//和外部类同名的成员变量
public int a = 4;
public int c = 30;
//public static int d = 90;这个是错误的
public static final int d = 90;
OuterClass outerClass = new OuterClass();//在内部类中实例化外部类对象
public void A() {
System.out.println(outerClass.k);
}
//和外部类同名的成员方法
public void method1() {
System.out.println("这是内部类中的method1");
}
public void method2() {
System.out.println("这是内部类中的method2");
}
//在实例内部类中可以直接访问外部类成员变量和方法
public void method3() {
System.out.println("在实例内部类中访问外部类成员"+b+k);//在内部类中可以访问外部类中被任意修饰符修饰的成员
method4();
}
//在内部类中调用和外部类同名的成员变量a进行测试
public void method5() {
System.out.println(a);//优先访问内部类中的同名a
a = 2;//修改的是内部类中的a
System.out.println(a);
System.out.println(OuterClass.this.a);//通过外部类和this访问的是外部类中的a
}
public void method6() {
method1();//优先调用内部类中的同名方法
OuterClass.this.method1();//通过外部类名和this访问同名的外部类方法
}
}
}
class Test {
public static void main(String[] args) {
//实例化外部类对象
OuterClass outerClass = new OuterClass();
//在其他类当中,实例化内部类对象
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.method3();//访问实例内部类的method3方法
innerClass.method1();//访问的是内部类中的method1
innerClass.method5();//访问实例内部类的method5方法测试同名成员变量的情况
innerClass.method6();//访问访问实例内部类的method5方法测试同名成员方法的情况
outerClass.method8();//在外部类中访问内部类中的成员
innerClass.A();
}
}
通过以上代码,总结以下几点:
1、在其他类当中,实例内部类的对象必须在先有外部类对象的情况下创建,而在外部类或者内部类中,实例化内部类或外部类对象时,直接通过类的实例化方式就可以,但是不可以在内部类中实例化外部类对象;
2、在实例内部类中,可以访问被任意修饰符修饰的外部类成员变量和方法;
3、当外部类成员变量和成员方法与实例内部类中的成员变量和成员方法同名时,通过实例内部类的引用去访问时,优先访问内部类中的成员变量和方法;
4、如果要访问外部类中同名的成员变量和方法时,需要通过外部类名.this.同名的方法;
5、外部类中不能直接访问内部类中的成员变量和方法,如果要访问的话,需要先在外部类中实例化内部类的对象,通过对象的引用访问;
6、在内部类当中,成员不能被static修饰,但可以被static+final修饰。
因为:被static修饰的成员时不依赖于类的,而内部类又是依赖于外部类的,而被final修饰的成员是一个常量,是在经过汇编是就已经确定的
静态内部类
在实例化内部类对象时,需要先实例化外部类对象,但是,有没有办法让内部类不依赖于对象呢?答案是有的,那就是静态内部类,下面请看代码:
public class OuterClass {
public int a = 10;
public int b = 20;
public static void method1() {
System.out.println("这是一个外部类");
}
//被static修饰的类称为静态内部类
static class InnerClass{
public int c = 30;
public int d = 40;
public void method2() {
System.out.println("这是一个内部类");
//method1();无法在内部类中访问外部类成员
}
//通过实例化外部类对象来访问外部类成员
OuterClass outerClass = new OuterClass();
public void method3() {
outerClass.method1();//调用外部类成员方法
}
}
}
class Test {
public static void main(String[] args) {
//静态内部类的实例化,不依赖外部类对象
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
innerClass.method2();
innerClass.method3();
}
}
总结:
1、内部类对象的创建不依赖与外部类对象,不需要先实例化外部类对象;
2、在静态内部类中,不能调用外部类成员,如果想要调用外部类成员的话,需要在静态内部类中先实例化外部类,通过外部类对象的引用访问外部类成员;
局部内部类
局部内部类是定义在方法里面的内部类,只能在方法里面使用,无法在方法外部使用;功能非常受限制,大家了解一下就可以了;
public class OuterClass {
public int a = 10;
public int b = 20;
public void method1() {
System.out.println("这是一个外部类");
}
public static void main(String[] args) {
//这是一个局部内部类,需要定义在方法里面
class Chamber{
public int c = 30;
public void method2() {
System.out.println("这是一个局部内部类");
}
}
//实例化内部类
Chamber chamber = new Chamber();
chamber.method2();
}
}
内部类的优点
1、一个内部类对象可以访问它的外部类对象的内容,包括私有数据!
2、内部类不会被同一包的其他类可见,具有很好的封装性!
3、内部类有效的实现了“多继承”,优化了java单继承的缺陷