内部类,讲完前面的特性,今天就讲下内部类这个用的比较多,出现频率挺高的知识点。
首先,顾名思义,内部类就是在类的内部,也就是类的类,嵌套在里面的。直接代码介绍,现一般分为成员内部类和局部内部类,还有一种匿名类。内部类拥有对外围对象的引用。大部分使用的都是成员内部类。 成员内部类 是一种与Field、方法、构造器和初始化块相似的类成员; 局部内部类和匿名内部类 则不是类成员。
定义在类里面的成员变量域的类,就是成员内部类。此时的内部类作为其外部类的成员,所以可以使用任意访问控制符如private、protected和public等修饰。
class A { //成员内部类,这种包含类的结构 class b{} }
成员内部类还可以分为静态内部类和非静态内部类。注意: 根据静态成员不能访问非静态成员的规则,外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例等。
static关键字的作用是把类的成员变成 类相关 ,而 不是 实例相关,即static修饰的成员属于 整个 类,而不属于单个对象。静态内部类只可以访问静态的外部类的方法和对象。但是静态内部类 可以有 非静态成员。
/** * 这一篇是用来测试静态内部类的使用的 * @author yhy * @date 1/14 */ public class StaticInner { private int num = 7; /** * 定义静态常量,这个才可以被静态内部类调用 */ private static int num2 = 6; static class Innerclass{ private static int num3; public void innerfangfa(){ // System.out.println("调用外部类的成员变量:"+num);,这个会报错,因为不能调用非静态的 System.out.println("调用外部类的成员变量:"+num2); } } }
报错信息
外部类使用静态类的代码。
public class StaticInner { private int num = 7; /** * 定义静态常量,这个才可以被静态内部类调用 */ private static int num2 = 6; /** * 定义一个静态内部类 */ static class Innerclass{ private static int num3; private int num4 = 4; public void innerfangfa(){ // System.out.println("调用外部类的成员变量:"+num);,这个会报错,因为不能调用非静态的 System.out.println("调用外部类的成员变量:"+num2); } } /** * 这是外部类的方法,用来验证访问内部类的方法 */ public static void inneracess(){ // 通过类名访问静态内部类的类成员 System.out.println("访问静态内部类:"+Innerclass.num3); // 通过实例访问静态内部类的实例成员 System.out.println("访问静态内部类:"+new Innerclass().num4); } }
内部类可以 直接 访问外部类的变量、方法等,而外部类 只能 通过显式创建类才可以。包括可以访问外部类的private。同时,在非静态内部类里 不能 有静态方法、静态field、静态初始化块。
/** * 这一篇是用来讲内部类的一些定义的 * @author yhy * @date 1/14 */ public class InnerClass { private int outernum = 9; /** * 创建内部类,同时还定义一个常量,为private */ class Inner{ private int innernum = 8; // 定义内部类的方法,去调用外部类的成员常量 public void outAcess(){ System.out.println("外部类的值:"+outernum); } } /** * 这个是外部类的成员方法 * 这里直接调用内部类会报错,不可以直接innernum使用 * 要通过显式创建内部类对象才可以实现 */ public void innerAcess(){ System.out.println("内部类的值:"+new Inner().innernum); } public static void main(String[] args) { // 创建外部类对象,没创建内部类对象 InnerClass i = new InnerClass(); i.innerAcess(); } } //非静态内部类对象必须寄存在外部类对象里,而外部类对象则不必一定有非静态内部类对象寄存其中
非静态内部类的方法内访问某个变量时,系统优先在该方法内查找(如果存在就使用)—— if not, 则到该方法所在的内部类中(存在则使用)—— if not, 则到该内部类所在的外部类(如果存在则使用)—— if not, 系统将出现编译错误。
局部内部类是定义在类的内部方法或者其他作用域里面的内部类。
class A { //局部内部类 public void B(){ class B{} } }
局部内部类的使用
package music.daima.ebook; /** * * 这一篇是用来观察局部内部类的定义使用等,thinking in java的练习九 * * @author yhy * * @date 1/14 * */ interface Ex9Interface{ /** * @param s string类型在下面给内部类调用 * 定义一个接口,同时包含一个say方法,给下面使用 */ void say(String s); } public class JuBuInner { /** * @return Inner()返回该类对此接口的引用 * // 这是一个方法,下面在里面定义一个内部类 */ Ex9Interface f() { class Inner implements Ex9Interface { @Override public void say(String s) { System.out.println(s); } } return new Inner(); } public static void main(String[] args) { JuBuInner x = new JuBuInner(); // 调用局部内部类的say方法 x.f().say("hi"); } }
这个知识点就直接看代码,是内部类的简化写版 ,本质不是类而是匿名对象(继承该类或者实现了改接口的)。
得提前存在一个类或者是接口给它用,可以是具体类也可以是抽象类。
package music.daima.ebook; /** * thinking in java * @author yhy * 匿名内部类 */ public class AnonymousInner { public static test1 getTest(int i){ // 匿名类的结构如下,这里的i会传给基类的构造器 return new test1(i) { { System.out.println(22); } // 重写f方法 @Override public void f() { System.out.println("在匿名类内"); } };//这里要注意有分号 } public static void main(String[] args) { test1 abc = getTest(55); abc.f(); } } /** *创建一个抽象类 */ abstract class test1{ // 基类的构造器 public test1(int i){ System.out.println("i is :"+i); } public abstract void f(); }
《Java的编程思想》中的练习题答案——使用匿名内部类
interface Inner12 { void modifyOuter(); } public class Outer12 { private int oi = 1; private void hi() { System.out.println("Outer hi"); } public Inner12 inner() { return new Inner12() { public void modifyOuter() { oi *= 2; hi(); } }; } public void showOi() { System.out.println(oi); } public static void main(String[] args) { Outer12 out = new Outer12(); out.showOi(); out.inner().modifyOuter(); out.showOi(); } }
下面的pd.method()方法调用结果是一样的,下面用的就是匿名内部类,相对简单一点,但是不好理解。记住它是一个对象而不是类。
内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据
内部类可以对同一个包内的其他类隐藏起来
当想要定义一个回调函数且不想编写大量代码,可以考虑使用匿名内部类比较便捷
——《Java核心技术卷一》
个人理解:
(因为静态内部类是外部类类相关的,因此创建内部类对象时无须创建外部类对象。)
/**这是用来测试在外部类以外使用静态内部类 * @author yhy */ public class innerOut { public static void main(String[] args) { Out1.In1 abc = new Out1.In1(); } } /** * 定义一个外部类 * @author yhy */ class Out1{ /** * 定义一个静态内部类,静态内部类是直接与外部类相关的 */ static class In1{ void FangFa(){ System.out.println("这是静态内部类"); } } } //output:这是静态内部类
/** * 使用教程——外部类以外使用非静态内部类 * @author yhy */ public class InnerTest { public static void main(String[] args) { // 格式,先外部再内部 = new 外部.new 内部 Out.In test = new Out().new In(); test.inner(); } } /** * 定义一个外部类 */ class Out{ /** * 定义一个非静态内部类 */ class In{ void inner(){ System.out.println("打印出内部类的信息"); } } } //output:打印出内部类的信息
静态内部类和非静态内部类区别只是在创建内部类对象时,静态的只需使用外部类即可调用构造器,而非静态则一定使用外部类对象来调用里面的方法。