1、内部类概述
内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了。
内部类不是在一个java源文件中编写俩个平行的俩个类,而是在一个类的内部再定义另外一个类。 我们可以把外边的类称为外部类,在其内部编写的类称为内部类。
内部类分为四种:
1. 成员内部类
2. 静态内部类
3. 局部内部类
4. 匿名内部类
2、成员内部类(实例内部类、非静态内部类)
成员内部类中不能写静态属性和方法
定义一个内部类
//在A类中申明了一个B类,此B类就在A的内部,并且在成员变量的位置上,所以就称为成员内部类public class Outer {private int id;public void out(){ System.out.println("这是外部类方法"); }class Inner{public void in(){ System.out.println("这是内部类方法"); } } }
实例化内部类,首先需要实例化外部类,通过外部类去调用内部类
public class Outer {private int id;public void out(){ System.out.println("这是外部类方法"); }class Inner{public void in(){ System.out.println("这是内部类方法"); } } }public class Test{public static void main(String[] args) {//实例化成员内部类分两步//1、实例化外部类Outer outObject = new Outer();//2、通过外部类调用内部类Outer.Inner inObject = outObject.new Inner();//测试,调用内部类中的方法inObject.in();//打印:这是内部类方法} }
成员内部类能访问外部类的所有属性(这里的属性包括私有的成员变量,方法)
public class Outer {private int id;public void out(){ System.out.println("这是外部类方法"); }class Inner{public void in(){ System.out.println("这是内部类方法"); }//内部类访问外部类私有的成员变量public void useId(){ System.out.println(id+3);。 }//内部类访问外部类的方法public void useOut(){ out(); } } }public class Test{public static void main(String[] args) {//实例化成员内部类分两步//1、实例化外部类Outer outObject = new Outer();//2、通过外部类调用内部类Outer.Inner inObject = outObject.new Inner();//测试inObject.useId();//打印3,因为id初始化值为0,0+3就为3,其中在内部类就使用了外部类的私有成员变量id。 inObject.useOut();//打印:这是外部类方法} }
如果内部类中的变量名和外部类的成员变量名一样,要通过创建外部类对象 "."属性来访问外部类属性,通过this.属性访问内部类成员属性
借助成员内部类,来总结内部类(包括4种内部类)的通用用法:
1、要想访问内部类中的内容,必须通过外部类对象来实例化内部类。
2、能够访问外部类所有的属性和方法,原理就是在通过外部类对象实例化内部类对象时,外部类对象把自己的引用传进了内部类,使内部类可以用通过Outer.this去调用外部类的属性和方法,
一般都是隐式调用了,但是当内部类中有属性或者方法名和外部类中的属性或方法名相同的时候,就需要通过显式调用Outer.this了。
一个小例子:
public class MemberInnerClassTest {private String name;private static int age;public void run(){}public static void go(){}public class MemberInnerClass{private String name;//内部类访问外部类public void test(String name){ System.out.println(name); System.out.println(this.name); System.out.println(MemberInnerClassTest.this.name); System.out.println(MemberInnerClassTest.age); MemberInnerClassTest.this.run(); MemberInnerClassTest.go(); } }//外部类访问成员内部类//成员内部类的对象要 依赖于外部类的对象的存在public void test(){//MemberInnerClass mic = MemberInnerClassTest.this.newMemberInnerClass();//MemberInnerClass mic = this.new MemberInnerClass();MemberInnerClass mic = new MemberInnerClass(); mic.name = "tom"; mic.test("hua"); }public static void main(String[] args) {//MemberInnerClass mic = new MemberInnerClass();这个是不行的,this是动态的。//所以要使用要先创建外部类对象,才能使用MemberInnerClassTest out = new MemberInnerClassTest(); MemberInnerClass mic = out.new MemberInnerClass();//如果内部类是private,则不能访问,只能通过内部方法来调用内部类mic.name="jik"; mic.test("kkk"); } }
3、静态内部类
如其名,static修饰的内部类就叫静态内部类。
1.内部类能够调用外部类的方法和属性,在静态内部类中就行了,因为静态内部类没有了指向外部类对象的引用。除非外部类中的方法或者属性也是静态的。
2.静态内部类能够直接被外部类给实例化,不需要使用外部类对象
Outer.Inner inner = new Outer.Inner();
3.静态内部类中可以声明静态方法和静态变量,但是非静态内部类中就不可以声明静态方法和静态变量
4、局部内部类
局部内部类是在一个方法内部声明的一个类
局部内部类中可以访问外部类的成员变量及方法
局部内部类中如果要访问该内部类所在方法中的局部变量,那么这个局部变量就必须是final修饰的
public class Outer {private int id;//在method01方法中有一个Inner内部类,这个内部类就称为局部内部类public void method01(){class Inner{public void in(){ System.out.println("这是局部内部类"); } } } }
局部内部类一般的作用跟在成员内部类中总结的差不多,但是有两个要注意的地方:
1. 在局部内部类中,如果要访问局部变量,那么该局部变量要用final修饰
2.局部内部类不能通过外部类对象直接实例化,而是在方法中实例化出自己来,然后通过内部类对象调用自己类中的方法。
5、匿名内部类
匿名内部类是最常用的一种内部类。
public class Test {public static void main(String[] args) {//讲new出来的Apple实例赋给apple变量保存起来,但是我们只需要用一次,就可以这样写Apple apple = new Apple(); apple.eat();//这种就叫做匿名对象的使用,不把实例保存到变量中。new Apple().eat(); } }class Apple{public void eat(){ System.out.println("我要无了"); } }
1. 匿名内部类需要依托于其他类或者接口来创建
- 如果依托的是类,那么创建出来的匿名内部类就默认是这个类的子类
- 如果依托的是接口,那么创建出来的匿名内部类就默认是这个接口的实现类。
2. 匿名内部类的声明必须是在使用new关键字的时候
匿名内部类的声明及创建对象必须一气呵成,并且之后能反复使用,因为没有名字。
例子:A是一个类(普通类、抽象类都可以),依托于A类创建一个匿名内部类对象
main: A a = new A(){//实现A中的抽象方法//或者重写A中的普通方法}; 注:这个大括号里面其实就是这个内部类的代码,只不过是声明该内部类的同时就是要new创建了其对象, 并且不能反复使用,因为没有名字。 例如: B是一个接口,依托于B接口创建一个匿名内部类对象 B b = new B(){//实现B中的抽象方法};
1. 匿名内部类除了依托的类或接口之外,不能指定继承或者实现其他类或接口,同时也不能被其他类所继承,因为没有名字。
2. 匿名内部中,我们不能写出其构造器,因为没有名字。
3. 匿名内部中,除了重写上面的方法外,一般不会再写其他独有的方法,因为从外部不能直接调用到
不用匿名内部类和用匿名内部类实现一个接口中的方法的区别
不用匿名内部类
public class Test {public static void main(String[] args) {//如果我们需要使用接口中的方法,我们就需要走3步,1、实现接口 2、创建实现接口类的实例对象 3、通过对象调用方法//第二步Test02 test = new Test02();//第三步test.method(); } }//接口Test1interface Test01{public void method(); }//第一步、实现Test01接口class Test02 implements Test01{ @Overridepublic void method() { System.out.println("实现了Test接口的方法"); } }
使用匿名内部类:
public class Test {public static void main(String[] args) {//如果我们需要使用接口中的方法,我们只需要走一步,就是使用匿名内部类,直接将其类的对象创建出来。new Test1(){public void method(){ System.out.println("实现了Test接口的方法"); } }.method(); } }interface Test1{public void method(); }
分析:
new Test1(){实现接口中方法的代码}; Test1(){...}这个的作用就是将接口给实现了,只不过这里实现该接口的是一个匿名类,也就是说这个类没名字,只能使用这一次,我们知道了这是一个类, 将其new出来,就能获得一个实现了Test1接口的类的实例对象,通过该实例对象,就能调用该类中的方法了,因为其匿名类是在一个类中实现的,所以叫其匿名内部类,