java中内部类的讲解
java中有一个内部类的概念,由于之前一直比较忙,没有单独拿出时间总结一下,今天我就把内部类的相关知识进行一下汇总,如果有不足之处,欢迎批评指正。
1)java内部类的概念。
在一个类的的内部定义的类被称为java的内部类。内部类提供了更好的封装。而且它可以直接访问外部类的private成员。
2)内部类的分类
根据内部类的位置不同,可以大致分为一下两类:
1.普通内部类又叫成员内部类,在方法体的外面定义的内部类
其中普通内部类又分为静态(static修饰的内部类)和非静态(非static修饰的内部类)
2.局部内部类又叫方法内部类,在方法体中定义的内部类
其中局部内部类又分为静态(static方法中的内部类)和非静态(非static方法中的内部类)以及匿名内部类。
3)每种内部类的详细详解
1.普通非静态内部类
package com.yonyou.test; public class Test { public static void main(String[] args) { //调用相应的内部类,下面是在调用内部类的常用方法 GeneralInnerClass gic=new GeneralInnerClass(); GeneralInnerClass.Car car=gic.new Car(); car.run(); //下面是调用内部类的简便方法 // new GeneralInnerClass().new Car().run(); //调用private修饰的内部类Car2 Speed car2=gic.getCar2();//实现了很好的隐藏 car2.run(); //你甚至连这两个内部类的名字都没有看见!隐藏你不想让别人知道的操作,也即封装性。 } } /** * 定义普通内部类 * @author lenovo * */ class GeneralInnerClass{ String carName="奥迪A8L"; protected class Car{ //内部类的修饰符可以是private,protected,public或者省略, public void run(){ //可以将相应的内部类理解为相应的类成员即可 System.out.println("小汽车的名字为:"+getCarName()); //内部类调用外部类的方法 System.out.println("小汽车\""+carName+"\"跑的很快哦~~"); //内部类调用外部类的属性 } } /** * 创建一个使用private修饰的内部类Car2 * @author lenovo * */ private class Car2 implements Speed{ @Override public void run(){ System.out.println("大家好,我是第二辆小汽车Car2哦~"); } } //返回private修饰的内部类对象Car2 public Car2 getCar2(){ return new Car2(); } public String getCarName(){ return carName; } } /** * 创建一个接口,用于测试private修饰的Car2,Car2类实现了这个接口 * 利用接口回调 * @author lenovo * */ interface Speed{ void run(); }
对于这种普通内部类除了上面标注外,需要注意一下几点:
1.普通内部类中不能有静态成员变量和静态成员方法
2.想要引用内部类,必须创建外部类的引用,即内部类不能离开外部类而独立存在
3.可以内部类理解为外部类的一个成员,一个内部类对象可以访问创建它的外部类对象的内容,需要注意的是内部类里的一个成员变量与外部类
的一个成员变量同名,也即外部类的同名成员变量被屏蔽,那么如果需要访问外部类的成员变量可以通过:外部类名.this.变量名
例如:InnerClass.this.carName
4.所有的内部类都需要注意其构造方法,所有的内部类都没有无参的构造器,系统都会为其增加一个默认的构造参数.
因为所有的内部类都有一个默认的构造参数,其值为外部类对象,这样也就更好的理解了对于外部类
而言,内部类仅仅是他的一个成员而已,即内部类不能够离开外部类而独立存在哦...
为了更好的理解请看下面的例子:
package com.yonyou.test; /** * 测试类 * @author 小浩 * @创建日期 2015-3-20 */ public class Test { public static void main(String[] args) throws InstantiationException, IllegalAccessException{ //创建内部类的实例 System.out.println(new Outter().new Inner().getStr()); //通过反射的方法创建内部类的实例 System.out.println(Outter.Inner.class.newInstance()); } } /** * 创建外部类这个测试对象 * @author 小浩 * @创建日期 2015-3-19 */ class Outter{ private String str="Hello World"; /** * 创建内部测试类对象 */ class Inner{ //访问外部类private属性 public String getStr(){ return str; } } }
上面的程序报的错误为:
Hello World Exception in thread "main" java.lang.InstantiationException: com.yonyou.test.Outter$Inner at java.lang.Class.newInstance0(Class.java:340) at java.lang.Class.newInstance(Class.java:308) at com.yonyou.test.Test.main(Test.java:1
主要原因就是因为在反射的过程中jdk会通过反射机制使用原来无参的构造方法创建相关的对象,而内部类在创建的过程中,
会默认增加一个外部类的参数,因为没有无参的构造器,所以在反射内部类的时候会出现错误...
2.普通静态内部类
package com.yonyou.test; public class Test { public static void main(String[] args) { //静态内部类的使用方式 GeneralInnerClass.Car car=new GeneralInnerClass.Car(); car.run(); } } /** * 定义普通内部类 * @author lenovo * */ class GeneralInnerClass{ static String carName="奥迪A8L"; static class Car{ //内部类的修饰符可以是private,protected,public或者省略, static String value="汽车静态内部类"; public void run(){ //可以将相应的内部类理解为相应的类成员即可 System.out.println("小汽车的名字为:"+getCarName()); //内部类调用外部类的方法,外部类方法必须是static的 System.out.println("小汽车\""+carName+"\"跑的很快哦~~"); //内部类调用外部类的属性,外部类的属性必须是static的 } } public static String getCarName(){ System.out.println(Car.value); return carName; } }
对于这种静态内部类除了上面标注的外,需要注意以下几点:
1.普通静态和非静态类的区别就在于静态内部类没有了指向外部的引用
2.普通静态内部类如果想要使用外部类中的成员(包括属性和方法),那么要求对应的成员是static的
3.静态内部类是属于相应的外部类的静态成员
3.局部非静态方法中的内部类
package com.yonyou.test; public class Test { public static void main(String[] args) { //局部非静态内部类的使用方式 MethodInnerClass car=new MethodInnerClass(); car.method(); } } /** * 定义局部内部类 * @author lenovo * */ class MethodInnerClass{ String carName2="奥迪A6L"; public void method(){ final String carName="奥迪A8L";//局部变量必须是final的,否则无法访问到 class Car{ //局部内部类除了final或者abstract外里面不能有任何修饰符 public void run(){ System.out.println("访问方法中的变量:小汽车\""+carName+"\"跑的很快哦~~"); //方法内部类调用方法中的局部变量,对应的局部变量必须是final修饰的 System.out.println("访问外部类的方法:小汽车的名字为:"+getCarName2()); //方法内部类调用外部类的方法 System.out.println("访问外部类的变量:小汽车\""+carName2+"\"跑的很快哦~~"); //方法内部类调用外部类的属性 } } //创建非静态内部类并调用非静态内部类的方法 new Car().run(); } public String getCarName2(){ return carName2; } }
定义局部内部类的时候需要主要一下事项:
1.局部内部类除了final或者abstract外里面不能有任何修饰符 ps:对于所有的java类而言,前面的修饰符可以为:public/默认/final/abstract/strictfp,而对于内部类而言其修 饰符较多可以为public/默认/protected/private/final/abstract/strictfp
2.局部非静态内部类同样可以访问外部类的成员(包括属性和方法)
3.局部非静态内部类的创建只能在方法内完成
4.局部静态方法中的内部类
package com.yonyou.test; public class Test { public static void main(String[] args) { MethodInnerClass.method(); } } /** * 定义局部内部类 * @author lenovo * */ class MethodInnerClass{ static String carName2="奥迪A6L"; public static void method(){ final String carName="奥迪A8L";//局部变量必须是final的,否则无法访问到 class Car{ //局部内部类除了final或者abstract外里面不能有任何修饰符 public void run(){ System.out.println("访问方法中的变量:小汽车\""+carName+"\"跑的很快哦~~"); //方法内部类调用方法中的局部变量,对应的局部变量必须是final修饰的 System.out.println("访问外部类的方法:小汽车的名字为:"+getCarName2()); //方法内部类调用外部类的方法 System.out.println("访问外部类的变量:小汽车\""+carName2+"\"跑的很快哦~~"); //方法内部类调用外部类的属性 } } //在静态方法中创建内部类并调用相应的方法 new Car().run(); } public static String getCarName2(){ return carName2; } }
需要注意的是:
1.静态方法中的内部类不能用static修饰
2.静态方法中的内部类可以访问方法外的static成员变量
3.静态方法中的内部类如果访问本方法中的局部变量的话,对应的局部变量必须是final修饰的
5.匿名内部类
一方面匿名内部类在使用上更加简洁,另外一方面匿名内部类属于对应的方法,会随着方法的执行完毕而被回收,资源的占用更少。
当你只需要创建一个类的对象而且用不上它的名字时,使用匿名内部类可以使代码看上去简洁清楚。
当一个内部类的类声名只是在创建此类对象时用了一次,而且要产生的新类需继承于一个已有的父类或实现一个接口,才能考虑用匿名类,由
于匿名类本身无名,因此它也就不存在构造方法,它需要显示地调用一个无参的父类的构造方法,并且重写父类的方法。
package com.yonyou.test; public class Test { public static void main(String[] args) { //创建一个接口对应的匿名内部类 new BigCar(){ @Override public void run() { System.out.println("您正在调用大卡车的匿名内部类(接口)哦~~"); } }.run(); //创建一个抽象类的对象实现匿名内部类 new SmallCar(){ @Override public void run() { System.out.println("您正在调用小卡车的匿名内部类(抽象类)哦~~"); } }.run(); //匿名类最长用的一种方式,在多线程中使用相关的内容 //使用Thread类实现多线程的相关内容 new Thread(){ @Override public void run(){ System.out.println("使用Thread类实现多线程调用的方法"); } }.start(); //实现Runnable接口实现多线过程的机制 Runnable runnable=new Runnable(){ @Override public void run() { System.out.println("使用Runnbale接口的方式实现多线程的相关机制~~"); } }; Thread thread=new Thread(runnable); thread.start(); //多线程内部匿名类的终极版 new Thread( new Runnable(){ public void run(){ System.out.println("实现多线程机制,利用内部类的方法的终极方案"); } } ).start(); } } /** * 创建一个大卡车的接口 * @author lenovo * */ interface BigCar{ public void run(); } /** * 创建一个小卡车的抽象类 */ abstract class SmallCar{ public abstract void run(); }
在使用匿名列的时候需要注意一下几点:
1.匿名类不能独立存在,必须定义在相应的方法中或者代码块中(自己没有测试)。
2.匿名类内部一般需要重写abstract方法或者是实现相关的接口。
3.匿名内部类中不能存在构造方法哦。
·匿名内部类不能定义任何静态成员、方法和类。
·匿名内部类不能是public,protected,private,static。
·只能创建匿名内部类的一个实例。
·一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
·因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。